From 1d3f150dfb19fd11a2ff865ad925356e9ff50f1d Mon Sep 17 00:00:00 2001 From: Nicholas G Date: Sun, 7 Nov 2021 21:55:49 -0500 Subject: [PATCH] Encoder debouncing and minor cleanup --- README.md | 4 +- build_uf2/Pico_Game_Controller.uf2 | Bin 74752 -> 74240 bytes src/controller_config.h | 1 + src/pico_game_controller.c | 67 +++++++++++++++-------------- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index dc3a59b..a209486 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Pico-Game-Controller -Code for a keyboard or game controller using a Raspberry Pi Pico. Capable of handling 11 buttons, 10 LEDs, 1 WS2812B RGB strip, and 2 encoders. Developed with SDVX and IIDX in mind - see branches release/pocket-sdvx-pico and release/pocket-iidx for preconfigured versions. +Code for a keyboard or game controller using a Raspberry Pi Pico. Capable of handling 11 buttons, 10 LEDs, 1 WS2812B RGB strip, and 2 encoders. Developed with SDVX and IIDX in mind - see branches release/pocket-sdvx-pico and release/pocket-iidx for preconfigured versions. Demo of this firmware running on Pocket SDVX Pico, purchasable at https://discord.gg/MmuKd73XbY @@ -16,6 +16,7 @@ Currently working/fixed: - sdvx/iidx spoof - Tested on EAC - checkout branches release/pocket-sdvx-pico or release/pocket-iidx - 1000hz polling - Reversable Encoders with debouncing +- Switch debouncing - Switch and LED pins are now staggered for easier wiring - Fix 0-~71% encoder rollover in gamepad mode, uint32 max val isn't divisible evenly by ppr\*4 for joystick - thanks friends - HID LEDs now have labels, thanks CrazyRedMachine @@ -25,7 +26,6 @@ TODO: - refactor ws2812b into a seperate file for cleaner code & implement more RGB modes - store configuration settings in a text file? consider implementing littlefs https://github.com/littlefs-project/littlefs https://www.raspberrypi.org/forums/viewtopic.php?t=313009 https://www.raspberrypi.org/forums/viewtopic.php?p=1894014#p1894014 - Store last mode in flash memory (probably implement into above TODO if possible) https://www.raspberrypi.org/forums/viewtopic.php?t=305570 -- debounce on switches How to Use: diff --git a/build_uf2/Pico_Game_Controller.uf2 b/build_uf2/Pico_Game_Controller.uf2 index de2ee7293ba721faaf123ba217cb236655450762..c95ea122bd3ed281b1222377a5e843902a7942b3 100644 GIT binary patch delta 20281 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 B7D503 delta 20642 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 diff --git a/src/controller_config.h b/src/controller_config.h index 45bfdd3..478a74e 100644 --- a/src/controller_config.h +++ b/src/controller_config.h @@ -6,6 +6,7 @@ #define ENC_GPIO_SIZE 2 // Number of encoders #define ENC_PPR 600 // Encoder PPR #define ENC_DEBOUNCE true // Encoder Debouncing +#define SW_DEBOUNCE_TIME_US 4000 // Switch debounce delay in us #define ENC_PULSE (ENC_PPR * 4) // 4 pulses per PPR #define REACTIVE_TIMEOUT_MAX 500000 // Cycles before HID falls back to reactive #define WS2812B_LED_SIZE 10 // Number of WS2812B LEDs diff --git a/src/pico_game_controller.c b/src/pico_game_controller.c index c18305a..adb91a5 100644 --- a/src/pico_game_controller.c +++ b/src/pico_game_controller.c @@ -26,11 +26,11 @@ uint32_t enc_val[ENC_GPIO_SIZE]; uint32_t prev_enc_val[ENC_GPIO_SIZE]; int cur_enc_val[ENC_GPIO_SIZE]; -bool sw_val[SW_GPIO_SIZE]; +bool prev_sw_val[SW_GPIO_SIZE]; +uint64_t sw_timestamp[SW_GPIO_SIZE]; bool kbm_report; -bool leds_changed; unsigned long reactive_timeout_count = REACTIVE_TIMEOUT_MAX; void (*loop_mode)(); @@ -114,23 +114,20 @@ void update_lights() { if (reactive_timeout_count < REACTIVE_TIMEOUT_MAX) { reactive_timeout_count++; } - if (leds_changed) { - for (int i = 0; i < LED_GPIO_SIZE; i++) { - if (reactive_timeout_count >= REACTIVE_TIMEOUT_MAX) { - if (sw_val[i]) { - gpio_put(LED_GPIO[i], 1); - } else { - gpio_put(LED_GPIO[i], 0); - } + for (int i = 0; i < LED_GPIO_SIZE; i++) { + if (reactive_timeout_count >= REACTIVE_TIMEOUT_MAX) { + if (!gpio_get(SW_GPIO[i])) { + gpio_put(LED_GPIO[i], 1); } else { - if (lights_report.lights.buttons[i] == 0) { - gpio_put(LED_GPIO[i], 0); - } else { - gpio_put(LED_GPIO[i], 1); - } + gpio_put(LED_GPIO[i], 0); + } + } else { + if (lights_report.lights.buttons[i] == 0) { + gpio_put(LED_GPIO[i], 0); + } else { + gpio_put(LED_GPIO[i], 1); } } - leds_changed = false; } } @@ -147,7 +144,13 @@ void joy_mode() { if (tud_hid_ready()) { uint16_t translate_buttons = 0; for (int i = SW_GPIO_SIZE - 1; i >= 0; i--) { - translate_buttons = (translate_buttons << 1) | (sw_val[i] ? 1 : 0); + if (!gpio_get(SW_GPIO[i]) && + time_us_64() - sw_timestamp[i] >= SW_DEBOUNCE_TIME_US) { + translate_buttons = + (translate_buttons << 1) | (!gpio_get(SW_GPIO[i]) ? 1 : 0); + } else { + translate_buttons <<= 1; + } } report.buttons = translate_buttons; @@ -177,7 +180,8 @@ void key_mode() { /*------------- Keyboard -------------*/ uint8_t nkro_report[32] = {0}; for (int i = 0; i < SW_GPIO_SIZE; i++) { - if (sw_val[i]) { + if (!gpio_get(SW_GPIO[i]) && + time_us_64() - sw_timestamp[i] >= SW_DEBOUNCE_TIME_US) { uint8_t bit = SW_KEYCODE[i] % 8; uint8_t byte = (SW_KEYCODE[i] / 8) + 1; if (SW_KEYCODE[i] >= 240 && SW_KEYCODE[i] <= 247) { @@ -209,14 +213,16 @@ void key_mode() { /** * Update Input States + * Note: Switches are pull up, negate value **/ void update_inputs() { for (int i = 0; i < SW_GPIO_SIZE; i++) { - sw_val[i] = !gpio_get(SW_GPIO[i]); // Switches are pull up, negate value + // If switch gets pressed, record timestamp + if (prev_sw_val[i] == false && !gpio_get(SW_GPIO[i]) == true) { + sw_timestamp[i] = time_us_64(); + } + prev_sw_val[i] = !gpio_get(SW_GPIO[i]); } - - // Update LEDs if input changed while in reactive mode - if (reactive_timeout_count >= REACTIVE_TIMEOUT_MAX) leds_changed = true; } /** @@ -251,9 +257,7 @@ void init() { // Setup Encoders for (int i = 0; i < ENC_GPIO_SIZE; i++) { - enc_val[i] = 0; - prev_enc_val[i] = 0; - cur_enc_val[i] = 0; + enc_val[i], prev_enc_val[i], cur_enc_val[i] = 0; encoders_program_init(pio, i, offset, ENC_GPIO[i], ENC_DEBOUNCE); dma_channel_config c = dma_channel_get_default_config(i); @@ -280,7 +284,8 @@ void init() { // Setup Button GPIO for (int i = 0; i < SW_GPIO_SIZE; i++) { - sw_val[i] = false; + prev_sw_val[i] = false; + sw_timestamp[i] = 0; gpio_init(SW_GPIO[i]); gpio_set_function(SW_GPIO[i], GPIO_FUNC_SIO); gpio_set_dir(SW_GPIO[i], GPIO_IN); @@ -294,16 +299,15 @@ void init() { } // Set listener bools - leds_changed = false; kbm_report = false; // Joy/KB Mode Switching - if (gpio_get(SW_GPIO[0])) { - loop_mode = &joy_mode; - joy_mode_check = true; - } else { + if (!gpio_get(SW_GPIO[0])) { loop_mode = &key_mode; joy_mode_check = false; + } else { + loop_mode = &joy_mode; + joy_mode_check = true; } } @@ -368,6 +372,5 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, lights_report.raw[i] = buffer[i + 1]; } reactive_timeout_count = 0; - leds_changed = true; } }