matrix_keyboard.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #include "matrix_keyboard.h"
  2. #include "key_driver.h"
  3. #include "gpio.h"
  4. #include "system/event.h"
  5. #include "app_config.h"
  6. #include "timer.h"
  7. #include "asm/power_interface.h"
  8. #include "asm/power/p33.h"
  9. #if TCFG_MATRIX_KEY_ENABLE && !TCFG_EX_MCU_ENABLE
  10. #define MATRIX_NO_KEY 0x1 //没有按键时的IO电平
  11. #define MATRIX_LONG_TIME 35
  12. #define MATRIX_HOLD_TIME 35+10
  13. #define MATRIX_KEY_FILTER_TIME 2
  14. int (*matrix_key_data_send)(u8 report_id, u8 *data, u16 len) = NULL;
  15. static volatile u8 is_key_active = 0;
  16. static volatile u8 keep_wakeup_hold = 0;
  17. static int matrix_key_wakeup_hold_timer = 0;
  18. static int matrix_key_timer = 0;
  19. static matrix_key_st key_st[ROW_MAX][COL_MAX];
  20. static matrix_key_param *this = NULL;
  21. u8 notify_key_array[8] = {0};
  22. u8 key_map[COL_MAX] = {0};
  23. static u16 key_status_array[6] = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
  24. static void full_key_array(u8 row, u8 col, u8 st)
  25. {
  26. u8 offset = 0;
  27. u8 mark = 0, mark_offset = 0;
  28. //最多推6个按键出来,如果需要推多个按键需要自行修改,每个u16 低八位标识row 高八位标识col
  29. u16 key_value = (row | col << 8);
  30. for (offset = 0; offset < sizeof(key_status_array) / sizeof(u16); offset++) {
  31. if (key_status_array[offset] == key_value && st == MATRIX_KEY_UP) { //找到列表中有当前按键且按键状态抬起,则将按键移除列表
  32. mark = 1; //记录相同键值所在位置
  33. mark_offset = offset;
  34. if (mark_offset == sizeof(key_status_array) / sizeof(u16) - 1) {
  35. key_status_array[mark_offset] = 0xffff;
  36. break;
  37. }
  38. } else if (key_status_array[offset] == 0xffff) {
  39. if (mark) {
  40. memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (offset - mark_offset - 1) * 2);
  41. key_status_array[offset - 1] = 0xffff;
  42. } else if (st == MATRIX_KEY_SHORT) { //需要状态为短按才会把键值填充到数组中,防止按键满了之后把抬起也填充进去
  43. key_status_array[offset] = key_value;
  44. }
  45. break;
  46. } else if (mark && (offset == sizeof(key_status_array) / sizeof(u16) - 1)) {
  47. memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (sizeof(key_status_array) / sizeof(u16) - mark_offset - 1) * 2);
  48. key_status_array[sizeof(key_status_array) / sizeof(u16) - 1] = 0xffff;
  49. break;
  50. }
  51. }
  52. }
  53. void full_key_map(u8 row, u8 col, u8 st)
  54. {
  55. if (st) {
  56. key_map[col] |= BIT(row);
  57. } else {
  58. key_map[col] &= ~BIT(row);
  59. }
  60. }
  61. void P33_AND_WKUP_EDGE(u8 data);
  62. void P33_OR_WKUP_EDGE(u8 data);
  63. enum {
  64. IO_STATUS_HIGH_DRIVER = 0,
  65. IO_STATUS_OUTPUT_HIGH,
  66. IO_STATUS_OUTPUT_LOW,
  67. IO_STATUS_INPUT_PULL_DOWN,
  68. IO_STATUS_INPUT_PULL_UP,
  69. };
  70. void matrix_key_set_io_state(u8 state, u32 *io_table, u8 len)
  71. {
  72. u8 i = 0;
  73. u32 porta_value = 0;
  74. u32 portb_value = 0;
  75. u32 portc_value = 0;
  76. u32 portd_value = 0;
  77. for (; i < len; i++) {
  78. switch (io_table[i] / IO_GROUP_NUM) {
  79. case 0: //JL_PORTA
  80. porta_value |= BIT(io_table[i] % IO_GROUP_NUM);
  81. break;
  82. case 1: //JL_PORTB
  83. portb_value |= BIT(io_table[i] % IO_GROUP_NUM);
  84. break;
  85. case 2: //JL_PORTC
  86. portc_value |= BIT(io_table[i] % IO_GROUP_NUM);
  87. break;
  88. case 3: //JL_PORTD
  89. portd_value |= BIT(io_table[i] % IO_GROUP_NUM);
  90. break;
  91. default://USB
  92. break;
  93. }
  94. }
  95. switch (state) {
  96. case IO_STATUS_HIGH_DRIVER:
  97. JL_PORTA->DIR |= porta_value;
  98. JL_PORTA->DIE |= porta_value;
  99. JL_PORTA->PU &= ~porta_value;
  100. JL_PORTA->PD &= ~porta_value;
  101. JL_PORTB->DIR |= portb_value;
  102. JL_PORTB->DIE |= portb_value;
  103. JL_PORTB->PU &= ~portb_value;
  104. JL_PORTB->PD &= ~portb_value;
  105. JL_PORTC->DIR |= portc_value;
  106. JL_PORTC->DIE |= portc_value;
  107. JL_PORTC->PU &= ~portc_value;
  108. JL_PORTC->PD &= ~portc_value;
  109. JL_PORTD->DIR |= portd_value;
  110. JL_PORTD->DIE |= portd_value;
  111. JL_PORTD->PU &= ~portd_value;
  112. JL_PORTD->PD &= ~portd_value;
  113. break;
  114. case IO_STATUS_OUTPUT_HIGH:
  115. JL_PORTA->DIR &= ~porta_value;
  116. JL_PORTA->OUT |= porta_value;
  117. JL_PORTB->DIR &= ~portb_value;
  118. JL_PORTB->OUT |= portb_value;
  119. JL_PORTC->DIR &= ~portc_value;
  120. JL_PORTC->OUT |= portc_value;
  121. JL_PORTD->DIR &= ~portd_value;
  122. JL_PORTD->OUT |= portd_value;
  123. break;
  124. case IO_STATUS_OUTPUT_LOW:
  125. JL_PORTA->DIR &= ~porta_value;
  126. JL_PORTA->OUT &= ~porta_value;
  127. JL_PORTB->DIR &= ~portb_value;
  128. JL_PORTB->OUT &= ~portb_value;
  129. JL_PORTC->DIR &= ~portc_value;
  130. JL_PORTC->OUT &= ~portc_value;
  131. JL_PORTD->DIR &= ~portd_value;
  132. JL_PORTD->OUT &= ~portd_value;
  133. break;
  134. case IO_STATUS_INPUT_PULL_DOWN:
  135. JL_PORTA->DIR |= porta_value;
  136. JL_PORTA->DIE |= porta_value;
  137. JL_PORTA->PU &= ~porta_value;
  138. JL_PORTA->PD |= porta_value;
  139. JL_PORTB->DIR |= portb_value;
  140. JL_PORTB->DIE |= portb_value;
  141. JL_PORTB->PU &= ~portb_value;
  142. JL_PORTB->PD |= portb_value;
  143. JL_PORTC->DIR |= portc_value;
  144. JL_PORTC->DIE |= portc_value;
  145. JL_PORTC->PU &= ~portc_value;
  146. JL_PORTC->PD |= portc_value;
  147. JL_PORTD->DIR |= portd_value;
  148. JL_PORTD->DIE |= portd_value;
  149. JL_PORTD->PU &= ~portd_value;
  150. JL_PORTD->PD |= portd_value;
  151. break;
  152. case IO_STATUS_INPUT_PULL_UP:
  153. JL_PORTA->DIR |= porta_value;
  154. JL_PORTA->DIE |= porta_value;
  155. JL_PORTA->PU |= porta_value;
  156. JL_PORTA->PD &= ~porta_value;
  157. JL_PORTB->DIR |= portb_value;
  158. JL_PORTB->DIE |= portb_value;
  159. JL_PORTB->PU |= portb_value;
  160. JL_PORTB->PD &= ~portb_value;
  161. JL_PORTC->DIR |= portc_value;
  162. JL_PORTC->DIE |= portc_value;
  163. JL_PORTC->PU |= portc_value;
  164. JL_PORTC->PD &= ~portc_value;
  165. JL_PORTD->DIR |= portd_value;
  166. JL_PORTD->DIE |= portd_value;
  167. JL_PORTD->PU |= portd_value;
  168. JL_PORTD->PD &= ~portd_value;
  169. break;
  170. }
  171. }
  172. #if 1
  173. void port_edge_wakeup_control(u16 data);
  174. void matrix_key_scan(void)
  175. {
  176. u8 row, col;
  177. u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
  178. static u8 wk_toggle = 0;
  179. //g_printf("scan...\n");
  180. //P33_LEVEL_WKUP_EN(0);
  181. port_edge_wakeup_control(0);
  182. //p33_tx_1byte(P3_WKUP_EN, 0); //关掉wakeup防止扫描过程一直唤醒
  183. //不直接调用gpio.c的接口主要是由于想控制扫描时间。这样能把时间从1.8ms缩减到800us
  184. matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, this->col_pin_list, this->col_num);
  185. is_key_active = 0;
  186. for (col = 0; col < this->col_num; col ++) {
  187. matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, &(this->col_pin_list[col]), 1);
  188. //gpio_direction_output(this->col_pin_list[col], !MATRIX_NO_KEY);
  189. for (row = 0; row < this->row_num; row ++) {
  190. cur_key_value = gpio_read(this->row_pin_list[row]);
  191. if (cur_key_value != MATRIX_NO_KEY) {
  192. is_key_active = 1;
  193. }
  194. if (cur_key_value != (key_st[row][col]).last_st) {
  195. if (cur_key_value == MATRIX_NO_KEY) { //按键抬起判断
  196. (key_st[row][col]).press_cnt = 0;
  197. //printf("row:%d col:%d [UP]\n", row, col);
  198. (MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
  199. //P33_AND_WKUP_EDGE(row);
  200. full_key_map(row, col, 0);
  201. notify = 1;
  202. } else { //按键初次按下
  203. printf("row:%d col:%d [SHORT]\n", row, col);
  204. full_key_map(row, col, 1);
  205. (MATRIX_NO_KEY) ? P33_AND_WKUP_EDGE(row) : P33_OR_WKUP_EDGE(row);
  206. //P33_OR_WKUP_EDGE(row);
  207. notify = 1;
  208. }
  209. } else { //判断是否按键抬起
  210. if (cur_key_value != MATRIX_NO_KEY) {
  211. (key_st[row][col]).press_cnt ++;
  212. if ((key_st[row][col]).press_cnt == MATRIX_LONG_TIME) {
  213. /* printf("row:%d col:%d [LONG]\n", row, col); */
  214. } else if ((key_st[row][col]).press_cnt == MATRIX_HOLD_TIME) {
  215. /* printf("row:%d col:%d [HOLD]\n", row, col); */
  216. (key_st[row][col]).press_cnt = MATRIX_LONG_TIME;
  217. } else {
  218. //press_cnt还未累加够
  219. }
  220. }
  221. }
  222. (key_st[row][col]).last_st = cur_key_value;
  223. }
  224. //gpio_direction_input(this->col_pin_list[col]);
  225. matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, &(this->col_pin_list[col]), 1);
  226. }
  227. matrix_key_set_io_state((MATRIX_NO_KEY == 1) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, this->col_pin_list, this->col_num);
  228. port_edge_wakeup_control(0xff);
  229. //p33_tx_1byte(P3_WKUP_EN, 0xff);
  230. //P33_LEVEL_WKUP_EN(1);
  231. if (notify) {
  232. struct sys_event e;
  233. e.type = SYS_MATRIX_KEY_EVENT;
  234. e.u.matrix_key.map = key_map;
  235. e.arg = (void *)DEVICE_EVENT_FROM_KEY;
  236. sys_event_notify(&e);
  237. }
  238. }
  239. #else
  240. void matrix_key_scan(void)
  241. {
  242. u8 row, col;
  243. u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
  244. for (row = 0; row < this->row_num; row ++) {
  245. gpio_direction_input(this->row_pin_list[row]);
  246. gpio_set_die(this->row_pin_list[row], 1);
  247. gpio_set_pull_up(this->row_pin_list[row], 1);
  248. gpio_set_pull_down(this->row_pin_list[row], 0);
  249. }
  250. for (col = 0; col < this->col_num; col ++) {
  251. gpio_direction_output(this->col_pin_list[col], 0);
  252. gpio_set_die(this->col_pin_list[col], 1);
  253. for (row = 0; row < this->row_num; row ++) {
  254. if (gpio_read(this->row_pin_list[row]) == 0) {
  255. printf("col:%x row:%x\n", col, row);
  256. }
  257. }
  258. gpio_direction_input(this->col_pin_list[col]);
  259. gpio_set_pull_up(this->col_pin_list[col], 0);
  260. gpio_set_pull_up(this->col_pin_list[col], 0);
  261. gpio_set_die(this->col_pin_list[col], 0);
  262. }
  263. }
  264. #endif
  265. void matrix_key_wakeup_timeout_handler(void *arg)
  266. {
  267. is_key_active = 1;
  268. }
  269. void matrix_key_wakeup_keep(void)
  270. {
  271. is_key_active = 1;
  272. if (matrix_key_wakeup_hold_timer) {
  273. sys_s_hi_timeout_del(matrix_key_wakeup_hold_timer);
  274. }
  275. matrix_key_wakeup_hold_timer = sys_s_hi_timerout_add(NULL, matrix_key_wakeup_timeout_handler, 10);
  276. }
  277. void matrix_key_wakeup(u8 idx, u32 gpio)
  278. {
  279. r_printf("matrix_key wkup!\n");
  280. matrix_key_wakeup_keep();
  281. }
  282. int matrix_key_init(matrix_key_param *param)
  283. {
  284. if (!param) {
  285. return -1; //参数无效
  286. }
  287. this = param;
  288. u8 row, col;
  289. for (row = 0; row < this->row_num; row ++) {
  290. (MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
  291. for (col = 0; col < this->col_num; col ++) {
  292. (key_st[row][col]).last_st = MATRIX_NO_KEY;
  293. (key_st[row][col]).press_cnt = 0;
  294. }
  295. }
  296. printf("key_row:%d rol:%d\n", this->row_num, this->col_num);
  297. if (matrix_key_timer) {
  298. sys_s_hi_timer_del(matrix_key_timer);
  299. }
  300. matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, this->col_pin_list, this->col_num);
  301. 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);
  302. port_edge_wkup_set_callback(matrix_key_wakeup);
  303. matrix_key_timer = sys_s_hi_timer_add(NULL, matrix_key_scan, 10);
  304. return 0;
  305. }
  306. static u8 matrix_key_idle_query(void)
  307. {
  308. return !is_key_active;
  309. }
  310. REGISTER_LP_TARGET(matrix_key_lp_target) = {
  311. .name = "matrix_key",
  312. .is_idle = matrix_key_idle_query,
  313. };
  314. #endif