From 799d8e43b54f68c61c7b63e43d4a3487754dfe60 Mon Sep 17 00:00:00 2001 From: Dien-Nhung Nguyen-Phu Date: Sun, 2 Jun 2024 18:27:36 +0700 Subject: button: add basic button functionalities - Provided a way to set handler for each button one-press/long-press - Debouncing with RC filter and Schmitt trigger --- Makefile | 3 +- src/button.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/button.h | 23 ++++++++++++++++ src/main.c | 74 ++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 173 insertions(+), 16 deletions(-) create mode 100644 src/button.c create mode 100644 src/button.h diff --git a/Makefile b/Makefile index 44a2a17..3d82df9 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,8 @@ CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usb2hostBase.c \ CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_spi1.c \ CH5xx_ble_firmware_library/RVMSIS/core_riscv.c \ src/main.c \ -src/leddrv.c +src/leddrv.c \ +src/button.c # ASM sources diff --git a/src/button.c b/src/button.c new file mode 100644 index 0000000..6adb495 --- /dev/null +++ b/src/button.c @@ -0,0 +1,89 @@ +#include "button.h" + +#define DEBOUNCE_HIGH_THRES (200) // 0-255 +#define DEBOUNCE_LOW_THRES (55) // 0-255 +#define LONGPRESS_THRES (25) // Hz +#define BUTTON_SCAN_FREQ (50) // Hz + +static volatile void (*onePressHandler[KEY_INDEX])(void) = { NULL }; +static volatile void (*longPressHandler[KEY_INDEX])(void) = { NULL }; + +void btn_init() +{ + GPIOA_ModeCfg(KEY1_PIN, GPIO_ModeIN_PD); + GPIOB_ModeCfg(KEY2_PIN, GPIO_ModeIN_PU); + + TMR3_TimerInit(FREQ_SYS/BUTTON_SCAN_FREQ); + TMR3_ITCfg(ENABLE, TMR0_3_IT_CYC_END); + PFIC_EnableIRQ(TMR3_IRQn); +} + +void btn_onOnePress(int key, void (*handler)(void)) +{ + if (key >= KEY_INDEX) return; + onePressHandler[key] = handler; +} + +void btn_onLongPress(int key, void (*handler)(void)) +{ + if (key >= KEY_INDEX) return; + longPressHandler[key] = handler; +} + +__HIGH_CODE +static int debounce(int key, int is_press) +{ + static int y[KEY_INDEX], flag[KEY_INDEX]; + if (key >= KEY_INDEX) return 0; + + // RC filter + y[key] -= y[key] >> 2; + y[key] += is_press ? 0x3F : 0; + + // Schmitt trigger + if ((y[key] > DEBOUNCE_HIGH_THRES) && (flag[key] == 0)) + flag[key] = 1; + if ((y[key] < DEBOUNCE_LOW_THRES) && (flag[key] == 1)) + flag[key] = 0; + + return flag[key]; +} + +__HIGH_CODE +static void check(int k) +{ + static int hold[KEY_INDEX], is_longpress[KEY_INDEX]; + if (k >= KEY_INDEX) return; // TODO: assert instead + + if (debounce(k, isPressed(k))) { + hold[k]++; + if (hold[k] >= LONGPRESS_THRES && is_longpress[k] == 0) { + is_longpress[k] = 1; + if (longPressHandler[k]) longPressHandler[k](); + } + } else { + if (hold[k] > 0 && hold[k] < LONGPRESS_THRES) { + if (onePressHandler[k]) onePressHandler[k](); + } + is_longpress[k] = 0; + hold[k] = 0; + } +} + +__HIGH_CODE +static void check_keys() +{ + for (int k=0; k= (max)) \ + (v) = (min) + +enum MODES { + NORMAL = 0, + DOWNLOAD, + POWER_OFF, + MODES_COUNT, +}; +#define BRIGHTNESS_LEVELS (4) -uint16_t fb[2][FB_WIDTH]; +uint16_t fb[FB_NUM_SPARE][FB_WIDTH]; uint8_t test_font[][11] = { 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xF0, 0x00, // F @@ -31,21 +49,41 @@ void draw2fb(uint16_t *fb, int c, int col) } } -volatile int fb_sel = 0; +volatile int fb_sel, fb_num; +volatile int mode, brightness; +volatile uint64_t tick; + +__HIGH_CODE +static void change_brightness() +{ + NEXT_STATE(brightness, 0, BRIGHTNESS_LEVELS); +} + +__HIGH_CODE +static void change_mode() +{ + NEXT_STATE(mode, 0, MODES_COUNT); +} + +__HIGH_CODE +static void change_fb() +{ + NEXT_STATE(fb_sel, 0, fb_num); +} int main() { SetSysClock(CLK_SOURCE_PLL_60MHz); led_init(); - draw2fb(fb[0], 0, 8*5); - draw2fb(fb[0], 1, 8*6); - draw2fb(fb[0], 2, 8*7); - draw2fb(fb[0], 3, 8*8); - draw2fb(fb[0], 4, 8*9); - draw2fb(fb[0], 5, 8*10); - draw2fb(fb[0], 6, 8*11); - draw2fb(fb[0], 7, 8*12); + draw2fb(fb[0], 0, 8*(5-1)); + draw2fb(fb[0], 1, 8*(6-1)); + draw2fb(fb[0], 2, 8*(7-1)); + draw2fb(fb[0], 3, 8*(8-1)); + draw2fb(fb[0], 4, 8*(9-1)); + draw2fb(fb[0], 5, 8*(10-1)); + draw2fb(fb[0], 6, 8*(11-1)); + draw2fb(fb[0], 7, 8*(12-1)); draw2fb(fb[1], 4, 8*5); draw2fb(fb[1], 5, 8*6); @@ -55,16 +93,23 @@ int main() draw2fb(fb[1], 1, 8*10); draw2fb(fb[1], 2, 8*11); draw2fb(fb[1], 3, 8*12); + fb_num = 2; - TMR0_TimerInit(1500); + TMR0_TimerInit(SCAN_T); TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END); PFIC_EnableIRQ(TMR0_IRQn); + btn_init(); + btn_onOnePress(KEY1, change_mode); + btn_onOnePress(KEY2, change_fb); + btn_onLongPress(KEY1, change_brightness); + while (1) { } } -__attribute__((interrupt)) +__INTERRUPT +__HIGH_CODE void TMR0_IRQHandler(void) { static int i, scroll; @@ -77,7 +122,6 @@ void TMR0_IRQHandler(void) scroll++; if (scroll >= (FB_WIDTH-LED_COLS)*SCROLL_IRATIO) { scroll = 0; - fb_sel = fb_sel == 0; } } // This is a mess -- cgit v1.2.3