293 lines
9.0 KiB
C
293 lines
9.0 KiB
C
#include "device/gpio.h"
|
||
#include "key/key_driver.h"
|
||
#include "key/ctmu_key.h"
|
||
#include "key/touch_key.h"
|
||
#include "asm/ctmu.h"
|
||
#include "app_config.h"
|
||
|
||
#if TCFG_CTMU_TOUCH_KEY_ENABLE
|
||
|
||
#define CTMU_CON0 JL_CTM->CON0
|
||
#define CTMU_CON1 JL_CTM->CON1
|
||
#define CTMU_RES JL_CTM->RES
|
||
|
||
static sCTMU_KEY_VAR ctm_key_value;
|
||
static const struct touch_key_platform_data *__this;
|
||
static u8 port_index_mapping_talbe[CTMU_KEY_CH_MAX];
|
||
|
||
//=================================================================================//
|
||
/*
|
||
ctmu原理:
|
||
|
||
1.三个时钟源:
|
||
1)闸门时钟源(可选), 分频值可以选
|
||
2)放电时钟源(固定是lsb), 分频值可以选
|
||
3)充电时钟源(不可选), 分频值不可选
|
||
|
||
2.闸门时间内
|
||
_________________________________
|
||
__| |__
|
||
__ __ __ __ __
|
||
放电时计数 __| |__| |__| |__| |__| |__
|
||
|
||
3. 过程: 放电 --> 充电(计数) --> 放电[该过程可选]
|
||
|
||
4.分析计数值
|
||
*/
|
||
//=================================================================================//
|
||
|
||
//时钟闸门时钟源选择, 可分频
|
||
enum {
|
||
GATE_SOURCE_LSB = 0,
|
||
GATE_SOURCE_OSC,
|
||
GATE_SOURCE_RTOSC,
|
||
GATE_SOURCE_PLL12M,
|
||
};
|
||
|
||
enum {
|
||
GATE_SOURCE_PRE_DIV1 = 0,
|
||
GATE_SOURCE_PRE_DIV2,
|
||
GATE_SOURCE_PRE_DIV4,
|
||
GATE_SOURCE_PRE_DIV8,
|
||
GATE_SOURCE_PRE_DIV16,
|
||
GATE_SOURCE_PRE_DIV32,
|
||
GATE_SOURCE_PRE_DIV64,
|
||
GATE_SOURCE_PRE_DIV128,
|
||
GATE_SOURCE_PRE_DIV256,
|
||
GATE_SOURCE_PRE_DIV512,
|
||
GATE_SOURCE_PRE_DIV1024,
|
||
GATE_SOURCE_PRE_DIV2048,
|
||
GATE_SOURCE_PRE_DIV4096,
|
||
GATE_SOURCE_PRE_DIV8192,
|
||
GATE_SOURCE_PRE_DIV16384,
|
||
GATE_SOURCE_PRE_DIV32768,
|
||
};
|
||
|
||
//放电时钟源硬件上默认是lsb, 不可分频
|
||
enum {
|
||
DISCHARGE_SOURCE_PRE_DIV1 = 0,
|
||
DISCHARGE_SOURCE_PRE_DIV2,
|
||
DISCHARGE_SOURCE_PRE_DIV4,
|
||
DISCHARGE_SOURCE_PRE_DIV8,
|
||
DISCHARGE_SOURCE_PRE_DIV16,
|
||
DISCHARGE_SOURCE_PRE_DIV32,
|
||
DISCHARGE_SOURCE_PRE_DIV64,
|
||
DISCHARGE_SOURCE_PRE_DIV128,
|
||
};
|
||
|
||
//充电时钟源不可选择, 不可分频
|
||
enum {
|
||
CHARGE_SOURCE_OSC = 0,
|
||
CHARGE_SOURCE_LRC,
|
||
CHARGE_SOURCE_PLL240M,
|
||
CHARGE_SOURCE_PLL480M,
|
||
};
|
||
|
||
static const u8 ctmu_ch_table[] = {
|
||
IO_PORTC_00, IO_PORTC_01, IO_PORTC_02, IO_PORTC_03,
|
||
IO_PORTC_04, IO_PORTC_05, IO_PORTC_06, IO_PORTC_07,
|
||
IO_PORTC_08, IO_PORTC_09, IO_PORTC_10, IO_PORTH_00,
|
||
IO_PORTH_01, IO_PORTH_02, IO_PORTH_03, IO_PORTH_04,
|
||
};
|
||
|
||
static void ctm_irq(sCTMU_KEY_VAR *ctm_key_var, u32 ctm_res, u8 ch)
|
||
{
|
||
u16 temp_u16_0, temp_u16_1;
|
||
s16 temp_s16_0, temp_s16_1;
|
||
s32 temp_s32_0;
|
||
u32 i;
|
||
|
||
for (i = 0; i < CTMU_KEY_CH_MAX; ++i) {
|
||
if (port_index_mapping_talbe[i] == ch) {
|
||
/* printf("res : 0x%x, i : %d, ch : %d\n", ctm_res, i, ch); */
|
||
ch = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == CTMU_KEY_CH_MAX) {
|
||
return;
|
||
}
|
||
|
||
//..............................................................................................
|
||
//取计数值/通道判断
|
||
//..............................................................................................
|
||
if (ctm_key_var->touch_init_cnt[ch]) {
|
||
ctm_key_var->touch_init_cnt[ch]--;
|
||
/* ctm_key_var->touch_cnt_buf[ch] = ctm_res << (ctm_key_var->FLT0CFG + 1); */
|
||
/* ctm_key_var->touch_release_buf[ch] = ctm_res << (ctm_key_var->FLT1CFG0 + 1); */
|
||
ctm_key_var->touch_cnt_buf[ch] = ctm_res << ctm_key_var->FLT0CFG;
|
||
ctm_key_var->touch_release_buf[ch] = ctm_res << ctm_key_var->FLT1CFG0;
|
||
}
|
||
//..............................................................................................
|
||
//当前计数值去抖动滤波器
|
||
//..............................................................................................
|
||
temp_u16_0 = ctm_key_var->touch_cnt_buf[ch];
|
||
temp_u16_1 = temp_u16_0;
|
||
temp_u16_1 -= (temp_u16_1 >> ctm_key_var->FLT0CFG);
|
||
temp_u16_1 += ctm_res;
|
||
ctm_key_var->touch_cnt_buf[ch] = temp_u16_1;
|
||
temp_u16_0 += temp_u16_1;
|
||
temp_u16_0 >>= (ctm_key_var->FLT0CFG + 1);
|
||
//..............................................................................................
|
||
//各通道按键释放计数值滤波器
|
||
//..............................................................................................
|
||
temp_s32_0 = ctm_key_var->touch_release_buf[ch];
|
||
temp_u16_1 = temp_s32_0 >> ctm_key_var->FLT1CFG0; //获得滤波器之后的按键释放值
|
||
temp_s16_0 = temp_u16_0 - temp_u16_1; //获得和本次检测值的差值,按下按键为负值,释放按键为正值
|
||
temp_s16_1 = temp_s16_0;
|
||
|
||
// if(ch == 1)
|
||
// {
|
||
/* printf("ch%d: %d %d", (short)ch, temp_u16_0, temp_s16_1); */
|
||
// }
|
||
|
||
if (!(ctm_key_var->touch_key_state & BIT(ch))) { //如果本通道按键目前是处于释放状态
|
||
if (temp_s16_1 >= 0) { //当前计数值小于低通值,放大后参与运算
|
||
if (temp_s16_1 < (ctm_key_var->FLT1CFG2 >> 3)) {
|
||
temp_s16_1 = temp_s16_1 * 8; //temp_s16_1 <<= 3; //放大后参与运算
|
||
} else {
|
||
temp_s16_1 = ctm_key_var->FLT1CFG2; //饱和,防止某些较大的正偏差导致错判
|
||
}
|
||
} else if (temp_s16_1 >= ctm_key_var->FLT1CFG1) { //当前计数值小于低通值不多,正常参与运算
|
||
|
||
} else { //当前计数值小于低通值很多,缩小后参与运算
|
||
temp_s16_1 = temp_s16_1 / 8; //temp_s16_1 >>= 3;(有符号数右移自动扩展符号位???)
|
||
}
|
||
} else { //如果本通道按键目前是处于按下状态, 缓慢降低释放计数值
|
||
if (temp_s16_1 <= ctm_key_var->RELEASECFG1) {
|
||
temp_s16_1 >>= 3; //缩小后参与运算
|
||
} else {
|
||
temp_s16_1 = 0;
|
||
}
|
||
}
|
||
|
||
temp_s32_0 += (s32)temp_s16_1;
|
||
ctm_key_var->touch_release_buf[ch] = temp_s32_0;
|
||
|
||
//..............................................................................................
|
||
//按键按下与释放检测
|
||
//..............................................................................................
|
||
if (temp_s16_0 <= ctm_key_var->PRESSCFG) { //按键按下
|
||
ctm_key_var->touch_key_state |= BIT(ch);
|
||
} else if (temp_s16_0 >= ctm_key_var->RELEASECFG0) { //按键释放
|
||
ctm_key_var->touch_key_state &= ~BIT(ch);
|
||
}
|
||
}
|
||
|
||
___interrupt
|
||
static void ctmu_isr_handle(void)
|
||
{
|
||
u32 res = CTMU_RES;
|
||
u8 ch = CTMU_CON1 & 0xf;
|
||
|
||
if (CTMU_CON1 & BIT(7)) {
|
||
CTMU_CON1 |= BIT(6);
|
||
ctm_irq(&ctm_key_value, res, ch);
|
||
}
|
||
}
|
||
|
||
static void ctmu_port_init(const struct touch_key_port *port_list, u8 port_num)
|
||
{
|
||
u8 i, j;
|
||
|
||
for (i = 0; i < port_num; i++) {
|
||
gpio_set_pull_down(port_list[i].port, 0);
|
||
gpio_set_pull_up(port_list[i].port, 0);
|
||
gpio_set_die(port_list[i].port, 0);
|
||
gpio_set_direction(port_list[i].port, 1);
|
||
|
||
for (j = 0; j < ARRAY_SIZE(ctmu_ch_table); j++) {
|
||
if (ctmu_ch_table[j] == port_list[i].port) {
|
||
CTMU_CON1 |= (BIT(j) << 16);
|
||
port_index_mapping_talbe[i] = j;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static void touch_ctmu_init(const struct touch_key_port *port, u8 num)
|
||
{
|
||
CTMU_CON0 = 0;
|
||
CTMU_CON1 = 0;
|
||
|
||
//闸门时钟选择
|
||
CTMU_CON0 |= (GATE_SOURCE_OSC << 2); //24 MHz
|
||
CTMU_CON0 |= (GATE_SOURCE_PRE_DIV32768 << 5); //1.36ms
|
||
/* CTMU_CON0 |= (1 << 8); //PRD 2.72ms */
|
||
|
||
//振荡器电流配置,值越大,振荡器工作电流越大,振荡频率越高,应该根据芯片外围触摸按键实际的固有电容大小来配置,让振荡器的工作频率在1MHz附近
|
||
CTMU_CON1 |= 3 << 8; //0 ~ 7 2ua //8ua
|
||
//LDO enable
|
||
CTMU_CON1 |= BIT(11);
|
||
CTMU_CON1 |= BIT(13); //2.7V
|
||
|
||
CTMU_CON1 |= BIT(6); // Clear Pending
|
||
|
||
ctmu_port_init(port, num);
|
||
}
|
||
|
||
static void touch_ctmu_enable(u8 en)
|
||
{
|
||
if (en) {
|
||
CTMU_CON0 |= BIT(1); //Int Enable
|
||
CTMU_CON0 |= BIT(0); //Moudle Enable
|
||
} else {
|
||
CTMU_CON0 &= ~BIT(1); //Int Disable
|
||
CTMU_CON0 &= ~BIT(0); //Moudle Disable
|
||
}
|
||
}
|
||
|
||
int ctmu_init(void *_data)
|
||
{
|
||
const struct touch_key_platform_data *user_data = (const struct touch_key_platform_data *)_data;
|
||
if (!user_data) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
__this = user_data;
|
||
memset(&ctm_key_value, 0x0, sizeof(sCTMU_KEY_VAR));
|
||
|
||
/*触摸按键参数配置*/
|
||
ctm_key_value.FLT0CFG = 0;
|
||
ctm_key_value.FLT1CFG0 = 7;
|
||
ctm_key_value.FLT1CFG1 = -80;
|
||
ctm_key_value.FLT1CFG2 = 10 * 128; //128 = 2^7
|
||
|
||
///调节灵敏度的主要参数
|
||
ctm_key_value.PRESSCFG = user_data->press_cfg;
|
||
ctm_key_value.RELEASECFG0 = user_data->release_cfg0;
|
||
ctm_key_value.RELEASECFG1 = user_data->release_cfg1;
|
||
|
||
memset(&ctm_key_value.touch_init_cnt, 0x10, CTMU_KEY_CH_MAX);
|
||
|
||
if (user_data->num > CTMU_KEY_CH_MAX) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
touch_ctmu_init(user_data->port_list, user_data->num);
|
||
|
||
request_irq(IRQ_CTM_IDX, 1, ctmu_isr_handle, 0);
|
||
|
||
touch_ctmu_enable(1);
|
||
|
||
return 0;
|
||
}
|
||
|
||
u8 get_ctmu_value(void)
|
||
{
|
||
u8 key = NO_KEY;
|
||
|
||
for (u8 i = 0; i < __this->num; i++) {
|
||
if (ctm_key_value.touch_key_state & (u16)(BIT(i))) {
|
||
key = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return key;
|
||
}
|
||
|
||
#endif
|
||
|