#include "include.h" #define TRACE_EN 0 #if TRACE_EN #define TRACE(...) printf(__VA_ARGS__) #define TRACE_K(...) printk(__VA_ARGS__) AT(.com_rodata) const char str_xy[] = "%d: %d, %d\n"; #else #define TRACE(...) #define TRACE_K(...) #endif //TP相关配置 #define CTP_CNT_SHORT_MOV 10 //CTP短划阈值(屏幕距离) #define CTP_CNT_LONG_MOV (GUI_SCREEN_WIDTH / 3) //CTP长划阈值(屏幕距离) #define CTP_CNT_LONG 40 //CTP长按时间阈值(CTP INT时钟个数) #define I2C_WRITE_ADDR(ADDR) ((ADDR) << 1) //CTP IIC写地址 #define I2C_READ_ADDR(ADDR) ((ADDR) << 1 | 1) //CTP IIC读地址 enum { CTP_STA_IDLE, CTP_STA_PRESS, CTP_STA_PRESS_LONG, CTP_STA_MOV_SHORT, CTP_STA_MOV_LONG, }; static struct ctp_cb_t { s32 x; //当前坐标 s32 y; s32 sx; //起始坐标 s32 sy; s32 last_dx; //最后一次相对偏移 s32 last_dy; u8 cnt; u8 sta; bool flag_last; } ctp_cb; AT(.com_text.ctp) void ctp_int_isr(void) { if (WKUPEDG & BIT(21)) { WKUPCPND = BIT(21); #if (CTP_SELECT == CTP_CST8X) ctp_cst8x_readkick(); #elif (CTP_SELECT == CTP_CHSC6X) ctp_chsc6x_readkick(); #endif } } //处理TP的消息 AT(.com_text.ctp) void ctp_msg_deal(bool press) { if (press) { reset_sleep_delay_all(); int mx, my; mx = abs_s(ctp_cb.x - ctp_cb.sx); my = abs_s(ctp_cb.y - ctp_cb.sy); switch (ctp_cb.sta) { case CTP_STA_IDLE: ctp_cb.sta = CTP_STA_PRESS; //按下 ctp_cb.sx = ctp_cb.x; ctp_cb.sy = ctp_cb.y; msg_enqueue(MSG_CTP_TOUCH); //触摸事件 ctp_cb.cnt++; break; case CTP_STA_PRESS: case CTP_STA_PRESS_LONG: case CTP_STA_MOV_SHORT: if (ctp_cb.sta == CTP_STA_PRESS) { ctp_cb.cnt++; if (ctp_cb.cnt >= CTP_CNT_LONG) { msg_enqueue(MSG_CTP_LONG); //长按 ctp_cb.sta = CTP_STA_PRESS_LONG; return; } } if (mx >= my) { if (mx >= CTP_CNT_LONG_MOV) { if (ctp_cb.x < ctp_cb.sx) { if (ctp_cb.sta != CTP_STA_MOV_SHORT) { msg_enqueue(MSG_CTP_SHORT_LEFT); //补发左短划 } msg_enqueue(MSG_CTP_LONG_LEFT); //左长划 ctp_cb.sta = CTP_STA_MOV_LONG; } else { if (ctp_cb.sta != CTP_STA_MOV_SHORT) { msg_enqueue(MSG_CTP_SHORT_RIGHT); //补发右短划 } msg_enqueue(MSG_CTP_LONG_RIGHT); //右长划 ctp_cb.sta = CTP_STA_MOV_LONG; } return; } if (ctp_cb.sta != CTP_STA_MOV_SHORT && mx >= CTP_CNT_SHORT_MOV) { if (ctp_cb.x < ctp_cb.sx) { msg_enqueue(MSG_CTP_SHORT_LEFT); //左短划 ctp_cb.sta = CTP_STA_MOV_SHORT; } else { msg_enqueue(MSG_CTP_SHORT_RIGHT); //右短划 ctp_cb.sta = CTP_STA_MOV_SHORT; } return; } } else { if (my >= CTP_CNT_LONG_MOV) { if (ctp_cb.y < ctp_cb.sy) { if (ctp_cb.sta != CTP_STA_MOV_SHORT) { msg_enqueue(MSG_CTP_SHORT_UP); //补发上短划 } msg_enqueue(MSG_CTP_LONG_UP); //上长划 ctp_cb.sta = CTP_STA_MOV_LONG; } else { if (ctp_cb.sta != CTP_STA_MOV_SHORT) { msg_enqueue(MSG_CTP_SHORT_DOWN); //补发下短划 } msg_enqueue(MSG_CTP_LONG_DOWN); //下长划 ctp_cb.sta = CTP_STA_MOV_LONG; } return; } if (ctp_cb.sta != CTP_STA_MOV_SHORT && my >= CTP_CNT_SHORT_MOV) { if (ctp_cb.y < ctp_cb.sy) { msg_enqueue(MSG_CTP_SHORT_UP); //上短划 ctp_cb.sta = CTP_STA_MOV_SHORT; } else { msg_enqueue(MSG_CTP_SHORT_DOWN); //下短划 ctp_cb.sta = CTP_STA_MOV_SHORT; } return; } } break; case CTP_STA_MOV_LONG: default: break; } } else { if (ctp_cb.sta == CTP_STA_PRESS) { msg_enqueue(MSG_CTP_CLICK); //单击 } ctp_cb.cnt = 0; ctp_cb.sta = CTP_STA_IDLE; } } AT(.com_text.ctp) void ctp_isr(void) { bool press; if (IIC1CON0 & BIT(31)) { IIC1CON0 |= BIT(29); s32 last_x = ctp_cb.x; s32 last_y = ctp_cb.y; #if (CTP_SELECT == CTP_CST8X) press = ctp_cst8x_get_point(&ctp_cb.x, &ctp_cb.y); #elif (CTP_SELECT == CTP_CHSC6X) press = ctp_chsc6x_get_point(&ctp_cb.x, &ctp_cb.y); #endif if (press) { if (ctp_cb.flag_last) { ctp_cb.last_dx = ctp_cb.x - last_x; ctp_cb.last_dy = ctp_cb.y - last_y; } else { ctp_cb.flag_last = true; ctp_cb.last_dx = 0; ctp_cb.last_dy = 0; } } else { ctp_cb.flag_last = false; } TRACE_K(str_xy, press, ctp_cb.x, ctp_cb.y); ctp_msg_deal(press); } } //获取坐标,返回触屏点击状态 AT(.com_text.ctp) bool ctp_get_cur_point(s32 *sx, s32 *sy, s32 *x, s32 *y) { bool press; GLOBAL_INT_DISABLE(); *sx = ctp_cb.sx; *sy = ctp_cb.sy; *x = ctp_cb.x; *y = ctp_cb.y; press = (ctp_cb.sta != CTP_STA_IDLE); GLOBAL_INT_RESTORE(); return press; } //获取坐标差量,返回触屏点击状态 AT(.com_text.ctp) bool ctp_get_dxy(s32 *dx, s32 *dy) { bool press; GLOBAL_INT_DISABLE(); press = (ctp_cb.sta != CTP_STA_IDLE); if (press) { *dx = ctp_cb.x - ctp_cb.sx; *dy = ctp_cb.y - ctp_cb.sy; } GLOBAL_INT_RESTORE(); return press; } //获取起始X,Y坐标 AT(.com_text.ctp) point_t ctp_get_sxy(void) { point_t pt; GLOBAL_INT_DISABLE(); pt.x = ctp_cb.sx; pt.y = ctp_cb.sy; GLOBAL_INT_RESTORE(); return pt; } //获取最后一次偏移 AT(.com_text.ctp) point_t ctp_get_last_dxy(void) { point_t pt; GLOBAL_INT_DISABLE(); pt.x = ctp_cb.last_dx; pt.y = ctp_cb.last_dy; GLOBAL_INT_RESTORE(); return pt; } //读数据KICK AT(.com_text.ctp) void ctp_iic_readkick(void *buf, u8 addr, int len) { IIC1CMDA = (I2C_READ_ADDR(TP_IIC_ADDR) << 24) | (addr << 8) | I2C_WRITE_ADDR(TP_IIC_ADDR); //0x2A IIC1DMAADR = DMA_ADR(buf); IIC1DMACNT = ((len - 1) << 16) | BIT(0); IIC1CON0 |= BIT(28); //KICK } //读数据接口(开中断前) bool ctp_iic_read(void *buf, u8 addr, int len) { u32 ticks; ctp_iic_readkick(buf, addr, len); ticks = tick_get(); while (!(IIC1CON0 & BIT(31))) { if (tick_check_expire(ticks, 20)) { return false; } } IIC1CON0 |= BIT(29); //Clear Pending return true; } //复位 void ctp_reset(void) { GPIOBCLR = BIT(7); delay_5ms(2); GPIOBSET = BIT(7); delay_5ms(10); } //初始化 void ctp_init(void) { bool res; memset(&ctp_cb, 0, sizeof(ctp_cb)); //配置时钟 CLKGAT2 |= BIT(1); CLKCON1 |= BIT(8); //x26m_clkdiv8 RSTCON0 |= BIT(7); //Release IIC1 GPIOBDIR &= ~BIT(7); //RST GPIOBSET = BIT(7); GPIOBDE |= BIT(7); GPIOBFEN &= ~BIT(7); GPIOBDIR |= BIT(6) | BIT(5); //SCL SDA GPIOBPU |= BIT(6) | BIT(5); GPIOBDE |= BIT(6) | BIT(5); GPIOBFEN |= BIT(6) | BIT(5); FUNCMCON2 = (4 << 12); //配置IIC模块 IIC1CON0 = BIT(10) | (8 << 4) | BIT(0); //WSCL_OPT, POSDIV, IIC EN IIC1CON1 = BIT(12) | BIT(11) | BIT(9) | BIT(8) | BIT(7) | BIT(5) | BIT(4) | BIT(3) | 1; //复位TP/等待模块使能 ctp_reset(); #if (CTP_SELECT == CTP_CST8X) res = ctp_cst8x_init(); #elif (CTP_SELECT == CTP_CHSC6X) res = ctp_chsc6x_init(); #endif if (!res) { TRACE("CTP ERROR!\n"); return; } sys_irq_init(IRQ_CTP_VECTOR, 0, ctp_isr); IIC1CON0 |= BIT(1); //IIC INT EN //INT信号中断 port_irq_register(PORT_INT5_VECTOR, ctp_int_isr); port_wakeup_init(IO_PB4, 1, 1); //开内部上拉, 下降沿唤醒 } void ctp_exit(void) { IIC1CON0 = 0; RSTCON0 &= ~BIT(7); //reset iic1 CLKGAT2 &= ~BIT(1); GPIOBPU &= ~(BIT(6) | BIT(5)); GPIOBDE &= ~(BIT(7) | BIT(6) | BIT(5)); //analog io status GPIOBDIR |= BIT(7); port_irq_free(PORT_INT5_VECTOR); port_wakeup_exit(IO_PB4); } //升级写KICK void ctp_iic_write_update_kick(u8 dev_addr, u16 addr, u8 *cmd, int len) { IIC1CMDA = ((addr >> 8) << 8) | I2C_WRITE_ADDR(dev_addr); //2Bytes的reg addr放高位到addr0 u8 buf[8]; buf[0] = addr & 0xff; //2Bytes的reg addr低位放到数据第一字节 if(len > 1) { memcpy(&buf[1], cmd, len - 1); } IIC1DMAADR = DMA_ADR(buf); IIC1DMACNT = ((len - 1) << 16) | BIT(1) | BIT(0); IIC1CON0 |= BIT(28); //KICK delay_ms(2); } //升级写 bool ctp_iic_update_write(u8 dev_addr, u16 addr, u8 *cmd, int len) { IIC1CON1 = BIT(11) | BIT(10) | BIT(5) | BIT(4) | BIT(3) | len; u32 ticks; ctp_iic_write_update_kick(dev_addr, addr, cmd, len); ticks = tick_get(); while (!(IIC1CON0 & BIT(31))) { if (tick_check_expire(ticks, 20)) { printf("WRITE UPDATE IIC TOUT\n"); return false; } WDT_CLR(); } IIC1CON0 |= BIT(29); //Clear Pending // delay_5ms(2); return true; } //升级读KICK void ctp_iic_update_readkick(u8 dev_addr, void *buf, int len) { IIC1CMDA = (I2C_READ_ADDR(dev_addr)) << 24; IIC1DMAADR = DMA_ADR(buf); IIC1DMACNT = ((len - 1) << 16) | BIT(0); IIC1CON0 |= BIT(28); //KICK } //升级读 bool ctp_iic_update_read(u8 dev_addr, void *rbuf, int rlen, u16 w_addr, u8 *w_cmd, int wlen) { ctp_iic_update_write(dev_addr, w_addr, w_cmd, wlen); IIC1CON1 = BIT(12) | BIT(11) | BIT(9) | BIT(8) | BIT(7) | rlen; u32 ticks; ctp_iic_update_readkick(dev_addr, rbuf, rlen); ticks = tick_get(); while (!(IIC1CON0 & BIT(31))) { if (tick_check_expire(ticks, 20)) { printf("READ UPDATE IIC TOUT\n"); return false; } } IIC1CON0 |= BIT(29); //Clear Pending delay_ms(2); return true; }