352 lines
12 KiB
C
352 lines
12 KiB
C
|
#include "matrix_keyboard.h"
|
|||
|
#include "key_driver.h"
|
|||
|
#include "gpio.h"
|
|||
|
#include "system/event.h"
|
|||
|
#include "app_config.h"
|
|||
|
#include "timer.h"
|
|||
|
#include "asm/power_interface.h"
|
|||
|
#include "asm/power/p33.h"
|
|||
|
|
|||
|
#if TCFG_MATRIX_KEY_ENABLE && !TCFG_EX_MCU_ENABLE
|
|||
|
#define MATRIX_NO_KEY 0x1 //没有按键时的IO电平
|
|||
|
#define MATRIX_LONG_TIME 35
|
|||
|
#define MATRIX_HOLD_TIME 35+10
|
|||
|
#define MATRIX_KEY_FILTER_TIME 2
|
|||
|
|
|||
|
int (*matrix_key_data_send)(u8 report_id, u8 *data, u16 len) = NULL;
|
|||
|
|
|||
|
static volatile u8 is_key_active = 0;
|
|||
|
static volatile u8 keep_wakeup_hold = 0;
|
|||
|
static int matrix_key_wakeup_hold_timer = 0;
|
|||
|
static int matrix_key_timer = 0;
|
|||
|
static matrix_key_st key_st[ROW_MAX][COL_MAX];
|
|||
|
static matrix_key_param *this = NULL;
|
|||
|
|
|||
|
u8 notify_key_array[8] = {0};
|
|||
|
u8 key_map[COL_MAX] = {0};
|
|||
|
static u16 key_status_array[6] = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
|
|||
|
|
|||
|
|
|||
|
static void full_key_array(u8 row, u8 col, u8 st)
|
|||
|
{
|
|||
|
u8 offset = 0;
|
|||
|
u8 mark = 0, mark_offset = 0;
|
|||
|
//最多推6个按键出来,如果需要推多个按键需要自行修改,每个u16 低八位标识row 高八位标识col
|
|||
|
u16 key_value = (row | col << 8);
|
|||
|
for (offset = 0; offset < sizeof(key_status_array) / sizeof(u16); offset++) {
|
|||
|
if (key_status_array[offset] == key_value && st == MATRIX_KEY_UP) { //找到列表中有当前按键且按键状态抬起,则将按键移除列表
|
|||
|
mark = 1; //记录相同键值所在位置
|
|||
|
mark_offset = offset;
|
|||
|
if (mark_offset == sizeof(key_status_array) / sizeof(u16) - 1) {
|
|||
|
key_status_array[mark_offset] = 0xffff;
|
|||
|
break;
|
|||
|
}
|
|||
|
} else if (key_status_array[offset] == 0xffff) {
|
|||
|
if (mark) {
|
|||
|
memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (offset - mark_offset - 1) * 2);
|
|||
|
key_status_array[offset - 1] = 0xffff;
|
|||
|
} else if (st == MATRIX_KEY_SHORT) { //需要状态为短按才会把键值填充到数组中,防止按键满了之后把抬起也填充进去
|
|||
|
key_status_array[offset] = key_value;
|
|||
|
}
|
|||
|
break;
|
|||
|
} else if (mark && (offset == sizeof(key_status_array) / sizeof(u16) - 1)) {
|
|||
|
memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (sizeof(key_status_array) / sizeof(u16) - mark_offset - 1) * 2);
|
|||
|
key_status_array[sizeof(key_status_array) / sizeof(u16) - 1] = 0xffff;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void full_key_map(u8 row, u8 col, u8 st)
|
|||
|
{
|
|||
|
if (st) {
|
|||
|
key_map[col] |= BIT(row);
|
|||
|
} else {
|
|||
|
key_map[col] &= ~BIT(row);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void P33_AND_WKUP_EDGE(u8 data);
|
|||
|
void P33_OR_WKUP_EDGE(u8 data);
|
|||
|
|
|||
|
enum {
|
|||
|
IO_STATUS_HIGH_DRIVER = 0,
|
|||
|
IO_STATUS_OUTPUT_HIGH,
|
|||
|
IO_STATUS_OUTPUT_LOW,
|
|||
|
IO_STATUS_INPUT_PULL_DOWN,
|
|||
|
IO_STATUS_INPUT_PULL_UP,
|
|||
|
};
|
|||
|
|
|||
|
void matrix_key_set_io_state(u8 state, u32 *io_table, u8 len)
|
|||
|
{
|
|||
|
u8 i = 0;
|
|||
|
u32 porta_value = 0;
|
|||
|
u32 portb_value = 0;
|
|||
|
u32 portc_value = 0;
|
|||
|
u32 portd_value = 0;
|
|||
|
|
|||
|
for (; i < len; i++) {
|
|||
|
switch (io_table[i] / IO_GROUP_NUM) {
|
|||
|
case 0: //JL_PORTA
|
|||
|
porta_value |= BIT(io_table[i] % IO_GROUP_NUM);
|
|||
|
break;
|
|||
|
case 1: //JL_PORTB
|
|||
|
portb_value |= BIT(io_table[i] % IO_GROUP_NUM);
|
|||
|
break;
|
|||
|
case 2: //JL_PORTC
|
|||
|
portc_value |= BIT(io_table[i] % IO_GROUP_NUM);
|
|||
|
break;
|
|||
|
case 3: //JL_PORTD
|
|||
|
portd_value |= BIT(io_table[i] % IO_GROUP_NUM);
|
|||
|
break;
|
|||
|
default://USB
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
switch (state) {
|
|||
|
case IO_STATUS_HIGH_DRIVER:
|
|||
|
JL_PORTA->DIR |= porta_value;
|
|||
|
JL_PORTA->DIE |= porta_value;
|
|||
|
JL_PORTA->PU &= ~porta_value;
|
|||
|
JL_PORTA->PD &= ~porta_value;
|
|||
|
JL_PORTB->DIR |= portb_value;
|
|||
|
JL_PORTB->DIE |= portb_value;
|
|||
|
JL_PORTB->PU &= ~portb_value;
|
|||
|
JL_PORTB->PD &= ~portb_value;
|
|||
|
JL_PORTC->DIR |= portc_value;
|
|||
|
JL_PORTC->DIE |= portc_value;
|
|||
|
JL_PORTC->PU &= ~portc_value;
|
|||
|
JL_PORTC->PD &= ~portc_value;
|
|||
|
JL_PORTD->DIR |= portd_value;
|
|||
|
JL_PORTD->DIE |= portd_value;
|
|||
|
JL_PORTD->PU &= ~portd_value;
|
|||
|
JL_PORTD->PD &= ~portd_value;
|
|||
|
break;
|
|||
|
case IO_STATUS_OUTPUT_HIGH:
|
|||
|
JL_PORTA->DIR &= ~porta_value;
|
|||
|
JL_PORTA->OUT |= porta_value;
|
|||
|
JL_PORTB->DIR &= ~portb_value;
|
|||
|
JL_PORTB->OUT |= portb_value;
|
|||
|
JL_PORTC->DIR &= ~portc_value;
|
|||
|
JL_PORTC->OUT |= portc_value;
|
|||
|
JL_PORTD->DIR &= ~portd_value;
|
|||
|
JL_PORTD->OUT |= portd_value;
|
|||
|
break;
|
|||
|
case IO_STATUS_OUTPUT_LOW:
|
|||
|
JL_PORTA->DIR &= ~porta_value;
|
|||
|
JL_PORTA->OUT &= ~porta_value;
|
|||
|
JL_PORTB->DIR &= ~portb_value;
|
|||
|
JL_PORTB->OUT &= ~portb_value;
|
|||
|
JL_PORTC->DIR &= ~portc_value;
|
|||
|
JL_PORTC->OUT &= ~portc_value;
|
|||
|
JL_PORTD->DIR &= ~portd_value;
|
|||
|
JL_PORTD->OUT &= ~portd_value;
|
|||
|
break;
|
|||
|
case IO_STATUS_INPUT_PULL_DOWN:
|
|||
|
JL_PORTA->DIR |= porta_value;
|
|||
|
JL_PORTA->DIE |= porta_value;
|
|||
|
JL_PORTA->PU &= ~porta_value;
|
|||
|
JL_PORTA->PD |= porta_value;
|
|||
|
JL_PORTB->DIR |= portb_value;
|
|||
|
JL_PORTB->DIE |= portb_value;
|
|||
|
JL_PORTB->PU &= ~portb_value;
|
|||
|
JL_PORTB->PD |= portb_value;
|
|||
|
JL_PORTC->DIR |= portc_value;
|
|||
|
JL_PORTC->DIE |= portc_value;
|
|||
|
JL_PORTC->PU &= ~portc_value;
|
|||
|
JL_PORTC->PD |= portc_value;
|
|||
|
JL_PORTD->DIR |= portd_value;
|
|||
|
JL_PORTD->DIE |= portd_value;
|
|||
|
JL_PORTD->PU &= ~portd_value;
|
|||
|
JL_PORTD->PD |= portd_value;
|
|||
|
break;
|
|||
|
case IO_STATUS_INPUT_PULL_UP:
|
|||
|
JL_PORTA->DIR |= porta_value;
|
|||
|
JL_PORTA->DIE |= porta_value;
|
|||
|
JL_PORTA->PU |= porta_value;
|
|||
|
JL_PORTA->PD &= ~porta_value;
|
|||
|
JL_PORTB->DIR |= portb_value;
|
|||
|
JL_PORTB->DIE |= portb_value;
|
|||
|
JL_PORTB->PU |= portb_value;
|
|||
|
JL_PORTB->PD &= ~portb_value;
|
|||
|
JL_PORTC->DIR |= portc_value;
|
|||
|
JL_PORTC->DIE |= portc_value;
|
|||
|
JL_PORTC->PU |= portc_value;
|
|||
|
JL_PORTC->PD &= ~portc_value;
|
|||
|
JL_PORTD->DIR |= portd_value;
|
|||
|
JL_PORTD->DIE |= portd_value;
|
|||
|
JL_PORTD->PU |= portd_value;
|
|||
|
JL_PORTD->PD &= ~portd_value;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if 1
|
|||
|
void port_edge_wakeup_control(u16 data);
|
|||
|
void matrix_key_scan(void)
|
|||
|
{
|
|||
|
|
|||
|
u8 row, col;
|
|||
|
u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
|
|||
|
static u8 wk_toggle = 0;
|
|||
|
|
|||
|
//g_printf("scan...\n");
|
|||
|
//P33_LEVEL_WKUP_EN(0);
|
|||
|
port_edge_wakeup_control(0);
|
|||
|
//p33_tx_1byte(P3_WKUP_EN, 0); //关掉wakeup防止扫描过程一直唤醒
|
|||
|
|
|||
|
//不直接调用gpio.c的接口主要是由于想控制扫描时间。这样能把时间从1.8ms缩减到800us
|
|||
|
matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, this->col_pin_list, this->col_num);
|
|||
|
|
|||
|
is_key_active = 0;
|
|||
|
for (col = 0; col < this->col_num; col ++) {
|
|||
|
matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, &(this->col_pin_list[col]), 1);
|
|||
|
//gpio_direction_output(this->col_pin_list[col], !MATRIX_NO_KEY);
|
|||
|
for (row = 0; row < this->row_num; row ++) {
|
|||
|
cur_key_value = gpio_read(this->row_pin_list[row]);
|
|||
|
if (cur_key_value != MATRIX_NO_KEY) {
|
|||
|
is_key_active = 1;
|
|||
|
}
|
|||
|
if (cur_key_value != (key_st[row][col]).last_st) {
|
|||
|
if (cur_key_value == MATRIX_NO_KEY) { //按键抬起判断
|
|||
|
(key_st[row][col]).press_cnt = 0;
|
|||
|
//printf("row:%d col:%d [UP]\n", row, col);
|
|||
|
(MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
|
|||
|
//P33_AND_WKUP_EDGE(row);
|
|||
|
full_key_map(row, col, 0);
|
|||
|
notify = 1;
|
|||
|
} else { //按键初次按下
|
|||
|
printf("row:%d col:%d [SHORT]\n", row, col);
|
|||
|
full_key_map(row, col, 1);
|
|||
|
(MATRIX_NO_KEY) ? P33_AND_WKUP_EDGE(row) : P33_OR_WKUP_EDGE(row);
|
|||
|
//P33_OR_WKUP_EDGE(row);
|
|||
|
notify = 1;
|
|||
|
}
|
|||
|
} else { //判断是否按键抬起
|
|||
|
if (cur_key_value != MATRIX_NO_KEY) {
|
|||
|
(key_st[row][col]).press_cnt ++;
|
|||
|
if ((key_st[row][col]).press_cnt == MATRIX_LONG_TIME) {
|
|||
|
/* printf("row:%d col:%d [LONG]\n", row, col); */
|
|||
|
} else if ((key_st[row][col]).press_cnt == MATRIX_HOLD_TIME) {
|
|||
|
/* printf("row:%d col:%d [HOLD]\n", row, col); */
|
|||
|
(key_st[row][col]).press_cnt = MATRIX_LONG_TIME;
|
|||
|
} else {
|
|||
|
//press_cnt还未累加够
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
(key_st[row][col]).last_st = cur_key_value;
|
|||
|
}
|
|||
|
//gpio_direction_input(this->col_pin_list[col]);
|
|||
|
matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, &(this->col_pin_list[col]), 1);
|
|||
|
}
|
|||
|
|
|||
|
matrix_key_set_io_state((MATRIX_NO_KEY == 1) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, this->col_pin_list, this->col_num);
|
|||
|
|
|||
|
port_edge_wakeup_control(0xff);
|
|||
|
//p33_tx_1byte(P3_WKUP_EN, 0xff);
|
|||
|
//P33_LEVEL_WKUP_EN(1);
|
|||
|
|
|||
|
|
|||
|
if (notify) {
|
|||
|
struct sys_event e;
|
|||
|
e.type = SYS_MATRIX_KEY_EVENT;
|
|||
|
e.u.matrix_key.map = key_map;
|
|||
|
e.arg = (void *)DEVICE_EVENT_FROM_KEY;
|
|||
|
sys_event_notify(&e);
|
|||
|
}
|
|||
|
}
|
|||
|
#else
|
|||
|
|
|||
|
void matrix_key_scan(void)
|
|||
|
{
|
|||
|
u8 row, col;
|
|||
|
u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
|
|||
|
for (row = 0; row < this->row_num; row ++) {
|
|||
|
gpio_direction_input(this->row_pin_list[row]);
|
|||
|
gpio_set_die(this->row_pin_list[row], 1);
|
|||
|
gpio_set_pull_up(this->row_pin_list[row], 1);
|
|||
|
gpio_set_pull_down(this->row_pin_list[row], 0);
|
|||
|
}
|
|||
|
|
|||
|
for (col = 0; col < this->col_num; col ++) {
|
|||
|
gpio_direction_output(this->col_pin_list[col], 0);
|
|||
|
gpio_set_die(this->col_pin_list[col], 1);
|
|||
|
for (row = 0; row < this->row_num; row ++) {
|
|||
|
if (gpio_read(this->row_pin_list[row]) == 0) {
|
|||
|
printf("col:%x row:%x\n", col, row);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
gpio_direction_input(this->col_pin_list[col]);
|
|||
|
gpio_set_pull_up(this->col_pin_list[col], 0);
|
|||
|
gpio_set_pull_up(this->col_pin_list[col], 0);
|
|||
|
gpio_set_die(this->col_pin_list[col], 0);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
void matrix_key_wakeup_timeout_handler(void *arg)
|
|||
|
{
|
|||
|
is_key_active = 1;
|
|||
|
}
|
|||
|
|
|||
|
void matrix_key_wakeup_keep(void)
|
|||
|
{
|
|||
|
is_key_active = 1;
|
|||
|
if (matrix_key_wakeup_hold_timer) {
|
|||
|
sys_s_hi_timeout_del(matrix_key_wakeup_hold_timer);
|
|||
|
}
|
|||
|
matrix_key_wakeup_hold_timer = sys_s_hi_timerout_add(NULL, matrix_key_wakeup_timeout_handler, 10);
|
|||
|
}
|
|||
|
|
|||
|
void matrix_key_wakeup(u8 idx, u32 gpio)
|
|||
|
{
|
|||
|
r_printf("matrix_key wkup!\n");
|
|||
|
matrix_key_wakeup_keep();
|
|||
|
}
|
|||
|
|
|||
|
int matrix_key_init(matrix_key_param *param)
|
|||
|
{
|
|||
|
if (!param) {
|
|||
|
return -1; //参数无效
|
|||
|
}
|
|||
|
this = param;
|
|||
|
u8 row, col;
|
|||
|
for (row = 0; row < this->row_num; row ++) {
|
|||
|
(MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
|
|||
|
for (col = 0; col < this->col_num; col ++) {
|
|||
|
(key_st[row][col]).last_st = MATRIX_NO_KEY;
|
|||
|
(key_st[row][col]).press_cnt = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
printf("key_row:%d rol:%d\n", this->row_num, this->col_num);
|
|||
|
if (matrix_key_timer) {
|
|||
|
sys_s_hi_timer_del(matrix_key_timer);
|
|||
|
}
|
|||
|
|
|||
|
matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, this->col_pin_list, this->col_num);
|
|||
|
matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_INPUT_PULL_UP : IO_STATUS_INPUT_PULL_DOWN, this->row_pin_list, this->row_num);
|
|||
|
|
|||
|
|
|||
|
port_edge_wkup_set_callback(matrix_key_wakeup);
|
|||
|
matrix_key_timer = sys_s_hi_timer_add(NULL, matrix_key_scan, 10);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static u8 matrix_key_idle_query(void)
|
|||
|
{
|
|||
|
return !is_key_active;
|
|||
|
}
|
|||
|
|
|||
|
REGISTER_LP_TARGET(matrix_key_lp_target) = {
|
|||
|
.name = "matrix_key",
|
|||
|
.is_idle = matrix_key_idle_query,
|
|||
|
};
|
|||
|
|
|||
|
#endif
|