Gate controller pairing behind BOOTSEL
This commit is contained in:
parent
fac919a798
commit
4a73680bd2
24 changed files with 934 additions and 145 deletions
99
bootsel_pairing_button.cpp
Normal file
99
bootsel_pairing_button.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#include "bootsel_pairing_button.h"
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
#include "pico/flash.h"
|
||||
#include "pico/time.h"
|
||||
#if PICO_RP2350
|
||||
#include "hardware/regs/sio.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kPollIntervalMs = 100;
|
||||
constexpr uint32_t kFlashSafeTimeoutMs = 100;
|
||||
constexpr uint32_t kQspiCsPinIndex = 1;
|
||||
|
||||
BootselPairingButtonHoldFsm g_hold_fsm;
|
||||
uint32_t g_last_sample_ms = 0;
|
||||
|
||||
// QSPI CSn sampling adapted from awalol/DS5Dongle's button_functions.cpp:
|
||||
// https://github.com/awalol/DS5Dongle/blob/master/src/button_functions.cpp
|
||||
// Copyright (c) 2026 awalol; used under the MIT License.
|
||||
//
|
||||
// This callback and everything it executes while CSn is floated must remain in
|
||||
// SRAM or be an inlined hardware-register operation. In particular, do not add
|
||||
// logging or ordinary flash-backed data access here.
|
||||
void __no_inline_not_in_flash_func(read_bootsel_callback)(void* parameter) {
|
||||
auto* pressed = static_cast<bool*>(parameter);
|
||||
|
||||
hw_write_masked(
|
||||
&ioqspi_hw->io[kQspiCsPinIndex].ctrl,
|
||||
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
for (volatile uint32_t delay = 0; delay < 1000; ++delay) {
|
||||
}
|
||||
|
||||
#if PICO_RP2350
|
||||
*pressed =
|
||||
(sio_hw->gpio_hi_in & SIO_GPIO_HI_IN_QSPI_CSN_BITS) == 0;
|
||||
#else
|
||||
*pressed = (sio_hw->gpio_hi_in & (1u << kQspiCsPinIndex)) == 0;
|
||||
#endif
|
||||
|
||||
hw_write_masked(
|
||||
&ioqspi_hw->io[kQspiCsPinIndex].ctrl,
|
||||
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
}
|
||||
|
||||
BootselPairingButtonSample sample_bootsel() {
|
||||
bool pressed = false;
|
||||
const int result = flash_safe_execute(read_bootsel_callback, &pressed,
|
||||
kFlashSafeTimeoutMs);
|
||||
if (result != PICO_OK) {
|
||||
return BootselPairingButtonSample::kUnread;
|
||||
}
|
||||
return pressed ? BootselPairingButtonSample::kPressed
|
||||
: BootselPairingButtonSample::kReleased;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool BootselPairingButtonHoldFsm::update(
|
||||
BootselPairingButtonSample sample) {
|
||||
if (sample == BootselPairingButtonSample::kUnread) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sample == BootselPairingButtonSample::kReleased) {
|
||||
pressed_samples_ = 0;
|
||||
hold_reported_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hold_reported_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++pressed_samples_;
|
||||
if (pressed_samples_ < kHoldSamples) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hold_reported_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bootsel_pairing_button_task() {
|
||||
const uint32_t now_ms =
|
||||
static_cast<uint32_t>(to_ms_since_boot(get_absolute_time()));
|
||||
if (now_ms - g_last_sample_ms < kPollIntervalMs) {
|
||||
return false;
|
||||
}
|
||||
g_last_sample_ms = now_ms;
|
||||
|
||||
return g_hold_fsm.update(sample_bootsel());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue