/** ****************************************************************************************************************************** * *@file driver_touch_key.c * *@brief Source file for Touch Key Driver * *@Create date: 2023-03-23 * * *Copyright (c) 2023, BLUETRUM ****************************************************************************************************************************** **/ #include "driver_touch_key.h" #include "driver_gpio.h" #define TRACE_EN 0 #if TRACE_EN #define TRACE(...) printf(__VA_ARGS__) #else #define TRACE(...) #endif void touch_key_dump(void) { TRACE ("\n"); TRACE ("INPCON: %08X\n", INPCON ); TRACE ("INPCPND: %08X\n", INPCPND); TRACE ("TKCON: %08X\n", TKCON); TRACE ("TKCON1: %08X\n", TKCON1); TRACE ("TKCON2: %08X\n", TKCON2); TRACE ("TKACON0: %08X\n", TKACON0); TRACE ("TKACON1: %08X\n", TKACON1); TRACE ("TKCNT: %08X\n", TKCNT); TRACE ("TKBCNT: %08X\n", TKBCNT); TRACE ("TKCDPR0: %08X\n",TKCDPR0); TRACE ("TKCDPR1: %08X\n",TKCDPR1); TRACE ("TKVARI: %08X\n", TKVARI); TRACE ("TKTMR: %08X\n", TKTMR); if (GETF_REG_TKCON_TK0_PND_EN() & GETF_REG_TKCON_TK0_EN()) { TRACE("touch key ch0 enable\n"); } if (GETF_REG_TKCON_TK1_PND_EN() & GETF_REG_TKCON_TK1_EN()) { TRACE("touch key ch1 enable\n"); } if (GETF_REG_TKCON_TK2_PND_EN() & GETF_REG_TKCON_TK2_EN()) { TRACE("touch key ch2 enable\r"); } if (GETF_REG_TKCON_TK3_PND_EN() & GETF_REG_TKCON_TK3_EN()) { TRACE("touch key ch3 enable\r"); } TRACE("touch key ch = 0x%02x\r\n", GET_REG_TKCON_TKSEL()); } AT(.com_periph.touch.get_key) u8 touch_key_get_key(void) { if (!GETF_REG_TKCON_TKEN()) { return 0; } return 1; } #if 1 //Already been implemented internal AT(.com_periph.tkey.isr) u32 tkey_tcnt_variance_calc(tk_cb_t *s, u16 tkcnt) { u32 i; u32 sum = 0, dela, variance = 0; s->buf[s->cnt++] = tkcnt; if (s->cnt > 7) { s->cnt = 0; } for (i = 0; i < 8; i++) { sum += s->buf[i]; } s->avg = sum >> 3; for (i = 0; i < 8; i++) { if (s->buf[i] > s->avg) { dela = s->buf[i] - s->avg; } else { dela = s->avg - s->buf[i]; } variance += (dela * dela); } return variance; } //根据方差检测进行range exception校准 AT(.com_periph.tkey.isr) void tkey_bcnt_range_exception(tk_cb_t *s, u16 tkcnt) { u16 bcnt; u32 variance = tkey_tcnt_variance_calc(s, tkcnt); if (variance < s->limit) { s->anov_cnt++; bcnt = s->bcnt_sfr[0] & 0xfff; if ((s->avg > (bcnt+3)) && (s->avg < (bcnt + s->range_thresh))) { s->stable_cnt++; if (s->stable_cnt > s->fil_except) { if (s->range_en) { s->bcnt_sfr[0] = bcnt + 3; } s->stable_cnt = 0; } } else if(s->avg < bcnt - 3) { s->bcnt_sfr[0] = bcnt - 3; } else { s->stable_cnt = 0; } } else { s->anov_cnt = 0; s->stable_cnt = 0; } } #endif AT(.com_periph.tkey.isr) void touch_key_isr(void) { u32 inpcon = INPCON; u32 tk_exp_pnd = (inpcon >> 21) & (inpcon >> 5) & 0xf; u32 tk_pto_pnd = (inpcon >> 29) & (inpcon >> 13) & 0x1; u32 tk_pnd = (inpcon >> 16) & (inpcon >> 0) & 0x1; tk_exp_pnd |= (tk_pto_pnd << 4); //bit0-smaller exception pending //bit1-larger exception pending //bit2-range exception pending //bit3-timeout exception pending //bit4-press timeout exception pending if (tk_exp_pnd) { //touch key exception pending INPCPND = BIT(21); } if (tk_pnd) { //touch key timer pending INPCPND = BIT(16); touch_key_range_isr(inpcon >> 30, TKCNT & 0xfff); } } /** * @brief Touch key interrup enable and isr registered. * * @params[in] touch_pin To makesure touch key pin data from APP is legal. * * @retval none */ void touch_key_isr_init(u32 touch_pin) { u32 inpcon; sys_irq_init(IRQn_FREQUENCY_DET_TOUCH_KEY, 0, touch_key_isr); inpcon = BIT(0); //touch key pending interrupt enable if (touch_pin & 0x0f) { //inpcon |= BIT(4) //touch key bcnt valid pending interrupt enable inpcon |= (0xf << 5); //touch key exception pending interrupt enable inpcon |= BIT(13); //tkey press timeout interrupt enable //inpcon |= BIT(14); //touch key variance interrupt enable } INPCON = inpcon; } /** * @brief To reset touch key,so that we can change REGISTER value without power off. * * @retval none */ void touch_key_sw_reset(void) { RTCCON0 |= BIT(4); INPCPND = BIT(0); //inpwr_swrst RTCCON0 &= ~BIT(19); //osc core disable } /** * @brief To init touch key clock. * * @params[in] touch_key_reg Touch Key Register Base Address * @params[in] clk_sel Touch Key Clock Select. * @params[in] tkclk_div2_enable CLK2M_TK to CLK2M_P divide * * @retval none */ void touch_key_clk_init(touch_key_typedef *touch_key_reg, CLK_TOUCH_KEY_TYPEDEF clk_sel, uint8_t tkclk_div2_enable) { u32 clk_freq; clk_touch_key_clk_set(clk_sel); clk_freq = clk_touch_key_clk_get(CLK_VALUE_MODE_FREQ); INPCPND = BIT(0); //inpwr_swrst touch_key_reg->tkcon1 = 0; if (tkclk_div2_enable) { SETF_REG_TKCON1_DIV2SEL(); //CLK2M_TK to CLK2M_P divide SET_REG_TKCON1_TKCLK2MDIV((u32)(clk_freq / (125 * 2048))); //CLK2M to 32k divide } else { SET_REG_TKCON1_TKCLK2MDIV((u32)(clk_freq / (125 * 1024))); //CLK2M to 32k divide } SETF_REG_TKCON1_TKAEN(); //touch key analog enable SETF_REG_TKCON1_TKCEN(); //touch key clock enable SETF_REG_TKCON1_TKVCEN(); //touch key variance clock enable TRACE("%s: %x, %d\n", __func__, touch_key_reg->tkcon1, clk_freq); } /** * @brief To init touch key configuration,including clock and other registers. * * @params[in] touch_key_reg Touch Key Register Base Address * @params[in] tkey_cfg Touch Key Params From APP. * @params[in] first_pwron To Tell The Driver Whether Touch Key Is First Time Init Or Not. * @params[in] clk_sel Touch Key Clock Select. * @params[in] tkclk_div2_enable CLK2M_TK to CLK2M_P divide, typical value is 0. * * @retval -1: If failed 0: If success */ int touch_key_init(touch_key_typedef *touch_key_reg, void *tkey_cfg, u32 first_pwron, CLK_TOUCH_KEY_TYPEDEF clk_sel, uint8_t tkclk_div2_enable) { int ret_code = 1; u32 touch_pin = 0; u16 tkbcnt; uint32_t tkcdpr0 = 0, tkcdpr1 = 0; if (tkey_cfg == NULL) { return -1; } tkey_cfg_t *p = (tkey_cfg_t *)tkey_cfg; INPCPND = BIT(0); // BGUV Reset TKSWRSTN disable RTCCON0 &= ~BIT(21); // Between Core Interface Enable, SNF_RC_EN RTCCON0 |= BIT(4) | BIT(19); if ((first_pwron) || (!(RTCCON0 & BIT(5)))) { //Touch Key Reset, or it will cause register write failure RTCCON0 |= BIT(5); touch_key_clk_init(touch_key_reg, clk_sel, tkclk_div2_enable); touch_key_reg->tkbcnt = 0xfff; touch_key_reg->tkcon = 0; ret_code = 0; } tkbcnt = touch_key_reg->tkbcnt & 0xfff; for (u8 i = 0; i < 4; i++) { tkey_ch_t *ch = (tkey_ch_t *)p->key[i]; if (ch != NULL) { if (i == 0) { tkcdpr0 |= ((tkcdpr0 & (~BIT_REG_TKCDPR0_TKCDPR0)) | ((ch->cdpr) << POS_REG_TKCDPR0_TKCDPR0)); SET_REG_TKACON0_CTRIM0(ch->ctrim); SET_REG_TKACON0_ITRIM0(ch->itrim); SETF_REG_TKCON_TK0_EN(); //touch key 0 enable SETF_REG_TKCON_TK0_PND_EN(); //touch key 0 pending enable RTCCON1 &= ~(1 << 4); //WK pull up disable, or may cause TKCNT error RTCCON1 |= BIT(8); //10s reset source 0:WKO 1 touch key if (ch->type) { SETF_REG_TKACON0_ENCHN0(); } } else if (i == 1) { tkcdpr0 |= ((tkcdpr0 & (~BIT_REG_TKCDPR0_TKCDPR1)) | ((ch->cdpr) << POS_REG_TKCDPR0_TKCDPR1)); SET_REG_TKACON0_CTRIM1(ch->ctrim); SET_REG_TKACON0_ITRIM1(ch->itrim); SETF_REG_TKCON_TK1_EN(); //touch key 1 enable SETF_REG_TKCON_TK1_PND_EN(); //touch key 1 pending enable if (ch->type) { SETF_REG_TKACON0_ENCHN1(); } } else if (i == 2) { tkcdpr1 |= ((tkcdpr1 & (~BIT_REG_TKCDPR1_TKCDPR2)) | ((ch->cdpr) << POS_REG_TKCDPR1_TKCDPR2)); SET_REG_TKACON1_CTRIM2(ch->ctrim); SET_REG_TKACON1_ITRIM2(ch->itrim); SETF_REG_TKCON_TK2_EN(); //touch key 2 enable SETF_REG_TKCON_TK2_PND_EN(); //touch key 2 pending enable if (ch->type) { SETF_REG_TKACON1_ENCHN2(); } } else if (i == 3) { tkcdpr1 |= ((tkcdpr1 & (~BIT_REG_TKCDPR1_TKCDPR3)) | ((ch->cdpr) << POS_REG_TKCDPR1_TKCDPR3)); SET_REG_TKACON1_CTRIM3(ch->ctrim); SET_REG_TKACON1_ITRIM3(ch->itrim); SETF_REG_TKCON_TK3_EN(); //touch key 3 enable SETF_REG_TKCON_TK3_PND_EN(); //touch key 3 pending enable if (ch->type) { SETF_REG_TKACON1_ENCHN3(); } } if (ch->type == 1) { SET_REG_TKCON_TKSEL(0); //Select WKO for hardware wakeup // Touch Key Pin Select touch_pin |= BIT(i); } } } SET_REG_TKCON1_TKARTRIM(2); //touch key configure if (touch_pin & 0x0f) { touch_key_reg->tkbcnt = tkbcnt; touch_key_reg->tktmr = p->reg_tktmr; touch_key_reg->tkpthd = p->reg_tkpthd; touch_key_reg->tkethd = p->reg_tkethd; touch_key_reg->tkvari = p->reg_tkvari; touch_key_reg->tkvarithd = p->reg_tkvarithd; touch_key_reg->tkcon2 = p->reg_tkcon2; touch_key_reg->tkcdpr0 = tkcdpr0; touch_key_reg->tkcdpr1 = tkcdpr1; SETF_REG_TKCON_TKPTOUPDBEN(); //press timeout update base_cnt enable SETF_REG_TKCON_TKSTAWKEN(); //touch key wakeup enable SETF_REG_TKCON_TKSUPDBEN(); //small pending update base_cnt enable SETF_REG_TKCON_TKLUPDBEN(); //large pending update base_cnt enable SETF_REG_TKCON_TKRUPDBEN(); //range pending update base_cnt enable //SETF_REG_TKCON_TKTOUPDBEN(); //timerout pending update base_cnt enable SETF_REG_TKCON_TKBCNTVAL(); //touch key base_cnt valid enable } /*tkcon bit 4 5 is key channel*/ TKCON &= ~(BIT(5) | BIT(4)); // TKCON |= BIT(4); // TKCON |= BIT(5); // TKCON |= (BIT(5) | BIT(4)); /*tkcon1 bit 14 15 is key along channel*/ TKCON1 &= ~(BIT(14) | BIT(15)); // TKCON1 |= BIT(14); // TKCON1 |= BIT(15); // TKCON1 |= (BIT(14) | BIT(15)); /*small thmod*/ TKCON |= BIT(1); /*range thmeod*/ // TKCON &= ~BIT(25); SETF_REG_TKCON_TKEN(); //touch key enable SETF_REG_TKCON_TKAEN_ATSEL(); //touch key auto enable SETF_REG_TKCON_TK_MODE(); delay_5ms(10); touch_key_isr_init(touch_pin); touch_key_dump(); return ret_code; }