123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- #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
|