2025-02-18 15:40:42 +08:00

237 lines
6.5 KiB
C

#include "includes.h"
#include "asm/plcnt.h"
#include "asm/gpio.h"
static u8 port_index_mapping_talbe[PLCNT_KEY_CH_MAX] = {0};
static u32 touch_pre_value[PLCNT_KEY_CH_MAX] = {0};
static u32 touch_normal_value[PLCNT_KEY_CH_MAX] = {0};
#define TOUCH_VAL_CALIBRATE_CYCLE (200)//周期大约2秒
static u32 touch_calibrate_cnt[PLCNT_KEY_CH_MAX] = {0};
static u32 touch_calibrate_tmp_value[PLCNT_KEY_CH_MAX] = {0};
static u8 touch_state = 0;
static const struct touch_key_platform_data *user_data = NULL;
static JL_PORT_FLASH_TypeDef *PLCNT_IO_PORTx = NULL;
static u8 PLCNT_IO_xx;
void plcnt_io_out(struct touch_key_port *key)
{
if (key->port > IO_MAX_NUM) {
return;
} else if ((key->port / 16) == 0) {
PLCNT_IO_PORTx = JL_PORTA;
} else if ((key->port / 16) == 1) {
PLCNT_IO_PORTx = JL_PORTB;
}
PLCNT_IO_xx = key->port % 16;
PLCNT_IO_PORTx->DIE |= BIT(PLCNT_IO_xx);
PLCNT_IO_PORTx->PU &= ~BIT(PLCNT_IO_xx);
PLCNT_IO_PORTx->PD |= BIT(PLCNT_IO_xx);
PLCNT_IO_PORTx->OUT |= BIT(PLCNT_IO_xx);
PLCNT_IO_PORTx->DIR &= ~BIT(PLCNT_IO_xx);
}
void plcnt_io_in(struct touch_key_port *key)
{
if (key->port > IO_MAX_NUM) {
return;
} else if ((key->port / 16) == 0) {
PLCNT_IO_PORTx = JL_PORTA;
} else if ((key->port / 16) == 1) {
PLCNT_IO_PORTx = JL_PORTB;
}
PLCNT_IO_xx = key->port % 16;
PLCNT_IO_PORTx->DIE |= BIT(PLCNT_IO_xx);
PLCNT_IO_PORTx->PU &= ~BIT(PLCNT_IO_xx);
PLCNT_IO_PORTx->PD |= BIT(PLCNT_IO_xx);
PLCNT_IO_PORTx->OUT |= BIT(PLCNT_IO_xx);
PLCNT_IO_PORTx->DIR |= BIT(PLCNT_IO_xx);
}
void plcnt_iomc(struct touch_key_port *key)
{
//放电计数引脚选择intputchannel2
gpio_set_fun_input_port(key->port, PFI_GP_ICH6);
SFR(JL_IOMAP->CON1, 8, 4, 6);
}
static u32 key_or = 0;
void plcnt_flt(u32 cur_val, u32 ch)
{
/* printf("ch%d : %d\n", ch, cur_val); */
//简单滤波
if (touch_pre_value[ch] == 0) {
touch_pre_value[ch] = cur_val;
} else if (cur_val >= touch_pre_value[ch]) {
touch_pre_value[ch] = touch_pre_value[ch] + (u32)((cur_val - touch_pre_value[ch]) * 0.2f);
} else {
touch_pre_value[ch] = touch_pre_value[ch] - (u32)((touch_pre_value[ch] - cur_val) * 0.2f);
}
//处理滤波之后的值
if (touch_pre_value[ch] > (touch_normal_value[ch] + user_data->port_list[ch].press_delta)) {
key_or |= BIT(ch);
touch_calibrate_cnt[ch] = 0;
} else {
key_or &= ~BIT(ch);
touch_calibrate_cnt[ch] ++;
}
//定期标定常态下的基准值
if (touch_calibrate_cnt[ch] > TOUCH_VAL_CALIBRATE_CYCLE) {
touch_normal_value[ch] = touch_calibrate_tmp_value[ch] / 10;
touch_calibrate_tmp_value[ch] = 0;
touch_calibrate_cnt[ch] = 0;
} else if (touch_calibrate_cnt[ch] >= (TOUCH_VAL_CALIBRATE_CYCLE / 2)) {
if (touch_calibrate_cnt[ch] < ((TOUCH_VAL_CALIBRATE_CYCLE / 2) + 10)) {
touch_calibrate_tmp_value[ch] += touch_pre_value[ch];
}
} else {
touch_calibrate_tmp_value[ch] = 0;
}
}
void scan_capkey_async(void *priv)
{
if (!user_data) {
return;
}
static u8 cur_ch = 0;
static u32 new_val = 0;
static u32 old_val = 0;
u8 pre_ch = cur_ch - 1;
u8 net_ch = cur_ch + 1;
if (cur_ch == 0) {
pre_ch = user_data->num - 1;
}
if (net_ch >= user_data->num) {
net_ch = 0;
}
new_val = JL_PCNT->VAL;
u32 delta_val = 0;
if (new_val >= old_val) {
delta_val = new_val - old_val;
} else {
delta_val = (u32) - new_val + old_val;
}
plcnt_flt(delta_val, pre_ch);
old_val = JL_PCNT->VAL;
plcnt_iomc(&(user_data->port_list[cur_ch]));
plcnt_io_in(&(user_data->port_list[cur_ch]));
if (net_ch != cur_ch) {
plcnt_io_out(&(user_data->port_list[net_ch]));
}
cur_ch = net_ch;
}
void scan_capkey(void *priv)
{
if (!user_data) {
return;
}
for (u8 ch = 0; ch < user_data->num; ch ++) {
plcnt_io_out(&(user_data->port_list[ch]));
plcnt_iomc(&(user_data->port_list[ch]));
u32 tmp_val, start_val, end_val, delta_val = 0;
for (u8 i = 0; i < 5; i ++) {
delay(100);
start_val = JL_PCNT->VAL;
PLCNT_IO_PORTx->DIR |= BIT(PLCNT_IO_xx);
__asm__ volatile("csync");
while (PLCNT_IO_PORTx->IN & BIT(PLCNT_IO_xx));
end_val = JL_PCNT->VAL;
PLCNT_IO_PORTx->DIR &= ~BIT(PLCNT_IO_xx);
if (end_val > start_val) {
tmp_val = end_val - start_val;
} else {
tmp_val = (u32) - start_val + end_val;
}
delta_val += tmp_val;
}
delta_val = delta_val / 5;
/* printf("%d: %d\n", ch, delta_val); */
plcnt_flt(delta_val, ch);
}
}
/*
@brief 引脚放电计数模块初始化
*/
int plcnt_init(void *_data)
{
if (_data == NULL) {
return -1;
}
user_data = (const struct touch_key_platform_data *)_data;
if (user_data->num > PLCNT_KEY_CH_MAX) {
return -1;
}
for (u8 ch = 0; ch < user_data->num; ch ++) {
touch_normal_value[ch] = 0 - (2 * user_data->port_list[ch].press_delta);
}
for (u8 ch = 0; ch < user_data->num; ch ++) {
plcnt_iomc(&(user_data->port_list[ch]));
plcnt_io_out(&(user_data->port_list[ch]));
}
JL_PCNT->CON = 0;
JL_PCNT->CON |= (0b11 << 2); //选择PLL240M为时钟源
JL_PCNT->CON |= BIT(1); //引脚放电计数使能
/* sys_s_hi_timer_add(NULL, scan_capkey_async, 2); //2ms */
sys_s_hi_timer_add(NULL, scan_capkey, 10); //10ms
return 0;
}
static u8 key_filter(u8 key)
{
static u8 used_key = 0xff;
static u8 old_key;
static u8 key_counter;
if (old_key != key) {
key_counter = 0;
old_key = key;
} else {
key_counter++;
if (key_counter == 3) {
used_key = key;
}
}
return used_key;
}
u8 get_plcnt_value(void)
{
/* printf("%d %d %d\n", touch_pre_value[0], touch_pre_value[1], touch_pre_value[2]); */
static u8 pre_i = 0;
u8 key_num = 0xff;
if (key_or) {
if (key_or & BIT(pre_i)) {
key_num = pre_i;
} else {
for (u8 ch = 0; ch < user_data->num; ch ++) {
if (key_or & BIT(ch)) {
key_num = ch;
pre_i = ch;
break;
}
}
}
/* printf("key_num : %d\n", key_num); */
}
return key_filter(key_num);
}