From e301949335a1b8f14177d7696d1fd65548d6d667 Mon Sep 17 00:00:00 2001 From: 3djc <5167938+3djc@users.noreply.github.com> Date: Sun, 22 Feb 2026 01:16:49 +0100 Subject: [PATCH] fix(gx12): periodically read IO expander in mixer (#7105) --- radio/src/mixer.cpp | 8 +++ radio/src/targets/simu/switch_driver.cpp | 4 ++ radio/src/targets/taranis/gx12/bsp_io.cpp | 88 +++++++++-------------- radio/src/targets/taranis/gx12/bsp_io.h | 24 +++++++ 4 files changed, 70 insertions(+), 54 deletions(-) create mode 100644 radio/src/targets/taranis/gx12/bsp_io.h diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index cd9125f88..70661b93b 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -35,6 +35,9 @@ #include "luminosity_sensor.h" #endif +#if defined(RADIO_GX12) +#include "targets/taranis/gx12/bsp_io.h" +#endif #define DELAY_POS_MARGIN 3 uint8_t s_mixer_first_run_done = false; @@ -1144,6 +1147,11 @@ void evalMixes(uint8_t tick10ms) static uint16_t delta = 0; static uint16_t flightModesFade = 0; +#if defined(RADIO_GX12) + // see #6159 + _poll_switches(); +#endif + uint8_t fm = getFlightMode(); if (lastFlightMode != fm) { diff --git a/radio/src/targets/simu/switch_driver.cpp b/radio/src/targets/simu/switch_driver.cpp index 73b08842c..a6900a8cd 100644 --- a/radio/src/targets/simu/switch_driver.cpp +++ b/radio/src/targets/simu/switch_driver.cpp @@ -42,6 +42,10 @@ struct hw_switch_def { int8_t switchesStates[MAX_SWITCHES]; +#if defined(RADIO_GX12) +void _poll_switches() {} +#endif + void simuSetSwitch(uint8_t swtch, int8_t state) { assert(swtch < switchGetMaxAllSwitches()); diff --git a/radio/src/targets/taranis/gx12/bsp_io.cpp b/radio/src/targets/taranis/gx12/bsp_io.cpp index 77d3b4ba4..db9885834 100644 --- a/radio/src/targets/taranis/gx12/bsp_io.cpp +++ b/radio/src/targets/taranis/gx12/bsp_io.cpp @@ -19,24 +19,16 @@ * GNU General Public License for more details. */ -#include "hal/switch_driver.h" #include "drivers/pca95xx.h" +#include "hal/switch_driver.h" +#include "myeeprom.h" #include "stm32_i2c_driver.h" -#include "timers_driver.h" -#include "delays_driver.h" -#include "stm32_ws2812.h" #include "stm32_switch_driver.h" -#include "os/async.h" -#include "os/timer.h" - -#include "myeeprom.h" - +constexpr uint8_t MAX_UNREAD_CYCLE = 100; // Force a read every 100 cycles even if no interrupt was triggered #define IO_INT_GPIO GPIO_PIN(GPIOE, 14) #define IO_RESET_GPIO GPIO_PIN(GPIOE, 15) - extern const stm32_switch_t* boardGetSwitchDef(uint8_t idx); -extern bool suspendI2CTasks; struct bsp_io_expander { pca95xx_t exp; @@ -44,17 +36,19 @@ struct bsp_io_expander { uint32_t state; }; -static volatile bool _poll_switches_in_queue = false; - +static volatile uint8_t _poll_switches_cnt = 0; static bsp_io_expander _io_switches; static bsp_io_expander _io_fs_switches; -static timer_handle_t _poll_timer = TIMER_INITIALIZER; +static void _io_int_handler() +{ + _poll_switches_cnt = 0; +} static void _init_io_expander(bsp_io_expander* io, uint32_t mask) { io->mask = mask; - io->state = 0; + io->state = 0; } static uint32_t _read_io_expander(bsp_io_expander* io) @@ -68,46 +62,28 @@ static uint32_t _read_io_expander(bsp_io_expander* io) delay_us(1); // Only 6ns are needed according to PCA datasheet, but lets be safe gpio_set(IO_RESET_GPIO); } - return io->state; + return io->state; } -typedef enum { - TRIGGERED_BY_TIMER = 0, - TRIGGERED_BY_IRQ, -} trigger_source_t; - -static void _poll_switches(void *param1, uint32_t trigger_source) +void _poll_switches() { - (void)param1; - - if (trigger_source == TRIGGERED_BY_IRQ) { - _poll_switches_in_queue = false; - timer_reset(&_poll_timer); + if ( _poll_switches_cnt == 0) { + _read_io_expander(&_io_switches); + _read_io_expander(&_io_fs_switches); + _poll_switches_cnt = MAX_UNREAD_CYCLE; + } else { + _poll_switches_cnt--; } - - // Suspend hardware reads when required - if (suspendI2CTasks) return; - - _read_io_expander(&_io_switches); - _read_io_expander(&_io_fs_switches); } -static void _io_int_handler() +uint32_t bsp_io_read_switches() { - async_call_isr(_poll_switches, &_poll_switches_in_queue, nullptr, - TRIGGERED_BY_IRQ); + return _read_io_expander(&_io_switches); } -static void _poll_cb(timer_handle_t* timer) +uint32_t bsp_io_read_fs_switches() { - (void)timer; - _poll_switches(nullptr, TRIGGERED_BY_TIMER); -} - -static void start_poll_timer() -{ - timer_create(&_poll_timer, _poll_cb, "portex", 100, true); - timer_start(&_poll_timer); + return _read_io_expander(&_io_fs_switches); } int bsp_io_init() @@ -135,10 +111,8 @@ int bsp_io_init() gpio_init(IO_RESET_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); gpio_set(IO_RESET_GPIO); - _read_io_expander(&_io_switches); - _read_io_expander(&_io_fs_switches); - - start_poll_timer(); + bsp_io_read_switches(); + bsp_io_read_fs_switches(); return 0; } @@ -148,6 +122,14 @@ void boardInitSwitches() bsp_io_init(); } +struct bsp_io_sw_def { + uint32_t pin_high; + uint32_t pin_low; +}; + +static constexpr uint32_t RGB_OFFSET = (1 << 16); // first after bspio pins +static uint16_t soft2POSLogicalState = 0xFFFF; + static SwitchHwPos _get_switch_pos(uint8_t idx) { SwitchHwPos pos = SWITCH_HW_UP; @@ -161,8 +143,7 @@ static SwitchHwPos _get_switch_pos(uint8_t idx) } else { return SWITCH_HW_UP; } - } - else if (!def->Pin_low) { + } else if (!def->Pin_low) { // 2POS switch if ((state & def->Pin_high) == 0) { pos = SWITCH_HW_DOWN; @@ -194,7 +175,6 @@ static SwitchHwPos _get_fs_switch_pos(uint8_t idx) SwitchHwPos boardSwitchGetPosition(uint8_t idx) { - if (idx < 8) - return _get_switch_pos(idx); + if (idx < 8) return _get_switch_pos(idx); return _get_fs_switch_pos(idx); -} +} \ No newline at end of file diff --git a/radio/src/targets/taranis/gx12/bsp_io.h b/radio/src/targets/taranis/gx12/bsp_io.h new file mode 100644 index 000000000..ad5eb63a5 --- /dev/null +++ b/radio/src/targets/taranis/gx12/bsp_io.h @@ -0,0 +1,24 @@ +/* +* Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#pragma once + +void _poll_switches(); \ No newline at end of file