From 09f8710eb320f37f20dda8c635497c2b505d25e2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 19:30:57 -0700 Subject: [PATCH] altos: add button matrix driver Scans the matrix once per clock tick queuing events for changed keys. Signed-off-by: Keith Packard --- src/drivers/ao_event.h | 1 + src/drivers/ao_matrix.c | 201 ++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_matrix.h | 24 +++++ src/stm/ao_arch_funcs.h | 8 +- 4 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 src/drivers/ao_matrix.c create mode 100644 src/drivers/ao_matrix.h diff --git a/src/drivers/ao_event.h b/src/drivers/ao_event.h index d1c69d81..d1df6eac 100644 --- a/src/drivers/ao_event.h +++ b/src/drivers/ao_event.h @@ -22,6 +22,7 @@ #define AO_EVENT_NONE 0 #define AO_EVENT_QUADRATURE 1 #define AO_EVENT_BUTTON 2 +#define AO_EVENT_KEY 3 struct ao_event { uint8_t type; diff --git a/src/drivers/ao_matrix.c b/src/drivers/ao_matrix.c new file mode 100644 index 00000000..e0f8ba75 --- /dev/null +++ b/src/drivers/ao_matrix.c @@ -0,0 +1,201 @@ +/* + * Copyright © 2017 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include + +#define row_port(q) AO_MATRIX_ROW_ ## q ## _PORT +#define row_bit(q) AO_MATRIX_ROW_ ## q ## _PIN +#define row_pin(q) AO_MATRIX_ROW_ ## q ## _PIN + +#define col_port(q) AO_MATRIX_COL_ ## q ## _PORT +#define col_bit(q) AO_MATRIX_COL_ ## q ## _PIN +#define col_pin(q) AO_MATRIX_COL_ ## q ## _PIN + +static void +_ao_matrix_drive_row(uint8_t row, uint8_t val) +{ + switch (row) { +#define drive(n) case n: ao_gpio_set(row_port(n), row_bit(n), row_pin(n), val); break + drive(0); +#if AO_MATRIX_ROWS > 1 + drive(1); +#endif +#if AO_MATRIX_ROWS > 2 + drive(2); +#endif +#if AO_MATRIX_ROWS > 3 + drive(3); +#endif +#if AO_MATRIX_ROWS > 4 + drive(4); +#endif +#if AO_MATRIX_ROWS > 5 + drive(5); +#endif +#if AO_MATRIX_ROWS > 6 + drive(6); +#endif +#if AO_MATRIX_ROWS > 7 + drive(7); +#endif + } +} + +static uint8_t +_ao_matrix_read_cols(void) +{ + uint8_t v = 0; +#define read(n) (v |= ao_gpio_get(col_port(n), col_bit(n), col_pin(n)) << n) + + read(0); +#if AO_MATRIX_ROWS > 1 + read(1); +#endif +#if AO_MATRIX_ROWS > 2 + read(2); +#endif +#if AO_MATRIX_ROWS > 3 + read(3); +#endif +#if AO_MATRIX_ROWS > 4 + read(4); +#endif +#if AO_MATRIX_ROWS > 5 + read(5); +#endif +#if AO_MATRIX_ROWS > 6 + read(6); +#endif +#if AO_MATRIX_ROWS > 7 + read(7); +#endif + return v; +} + +static uint8_t +_ao_matrix_read(uint8_t row) { + uint8_t state; + _ao_matrix_drive_row(row, 1); + state = _ao_matrix_read_cols(); + _ao_matrix_drive_row(row, 0); + return state; +} + +#define AO_MATRIX_DEBOUNCE_INTERVAL AO_MS_TO_TICKS(50) + +static uint8_t ao_matrix_keymap[AO_MATRIX_ROWS][AO_MATRIX_COLS] = AO_MATRIX_KEYCODES; + +static uint8_t ao_matrix_state[AO_MATRIX_ROWS]; +static AO_TICK_TYPE ao_matrix_tick[AO_MATRIX_ROWS]; + +static void +_ao_matrix_poll_one(uint8_t row) { + uint8_t state = _ao_matrix_read(row); + + if (state != ao_matrix_state[row]) { + AO_TICK_TYPE now = ao_time(); + + if ((now - ao_matrix_tick[row]) >= AO_MATRIX_DEBOUNCE_INTERVAL) { + uint8_t col; + uint8_t changes = state ^ ao_matrix_state[row]; + + for (col = 0; col < AO_MATRIX_COLS; col++) { + if (changes & (1 << col)) { + ao_event_put_isr(AO_EVENT_KEY, + ao_matrix_keymap[row][col], + ((state >> col) & 1) == 0); + } + } + ao_matrix_state[row] = state; + } + ao_matrix_tick[row] = now; + } +} + +void +ao_matrix_poll(void) +{ + uint8_t row; + + for (row = 0; row < AO_MATRIX_ROWS; row++) + _ao_matrix_poll_one(row); +} + +#define init_row(b) do { \ + ao_enable_output(row_port(b), row_bit(b), row_pin(v), 1); \ + ao_gpio_set_output_mode(row_port(b), row_bit(b), row_pin(b), AO_OUTPUT_OPEN_DRAIN); \ + } while (0) + +#define init_col(b) do { \ + ao_enable_input(col_port(b), col_bit(b), AO_EXTI_MODE_PULL_UP); \ + } while(0) + +void +ao_matrix_init(void) +{ + uint8_t row; + + init_row(0); +#if AO_MATRIX_ROWS > 1 + init_row(1); +#endif +#if AO_MATRIX_ROWS > 2 + init_row(2); +#endif +#if AO_MATRIX_ROWS > 3 + init_row(3); +#endif +#if AO_MATRIX_ROWS > 4 + init_row(4); +#endif +#if AO_MATRIX_ROWS > 5 + init_row(5); +#endif +#if AO_MATRIX_ROWS > 6 + init_row(6); +#endif +#if AO_MATRIX_ROWS > 7 + init_row(7); +#endif + + init_col(0); +#if AO_MATRIX_COLS > 1 + init_col(1); +#endif +#if AO_MATRIX_COLS > 2 + init_col(2); +#endif +#if AO_MATRIX_COLS > 3 + init_col(3); +#endif +#if AO_MATRIX_COLS > 4 + init_col(4); +#endif +#if AO_MATRIX_COLS > 5 + init_col(5); +#endif +#if AO_MATRIX_COLS > 6 + init_col(6); +#endif +#if AO_MATRIX_COLS > 7 + init_col(7); +#endif + for (row = 0; row < AO_MATRIX_ROWS; row++) { + ao_matrix_state[row] = _ao_matrix_read(row); + ao_matrix_tick[row] = ao_time(); + } +} diff --git a/src/drivers/ao_matrix.h b/src/drivers/ao_matrix.h new file mode 100644 index 00000000..ab5a1c51 --- /dev/null +++ b/src/drivers/ao_matrix.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2017 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_MATRIX_H_ +#define _AO_MATRIX_H_ + +void +ao_matrix_poll(void); + +void +ao_matrix_init(void); + +#endif /* _AO_MATRIX_H_ */ diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 88097406..b294c379 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -211,6 +211,12 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s stm_moder_set(port, bit, STM_MODER_OUTPUT);\ } while (0) +#define AO_OUTPUT_PUSH_PULL STM_OTYPER_PUSH_PULL +#define AO_OUTPUT_OPEN_DRAIN STM_OTYPER_OPEN_DRAIN + +#define ao_gpio_set_output_mode(port,bit,pin,mode) \ + stm_otyper_set(port, pin, mode) + #define ao_gpio_set_mode(port,bit,mode) do { \ if (mode == AO_EXTI_MODE_PULL_UP) \ stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP); \ @@ -219,7 +225,7 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s else \ stm_pupdr_set(port, bit, STM_PUPDR_NONE); \ } while (0) - + #define ao_enable_input(port,bit,mode) do { \ ao_enable_port(port); \ stm_moder_set(port, bit, STM_MODER_INPUT); \ -- 2.30.2