diff options
| author | Scott Mansell <[email protected]> | 2023-09-23 17:34:47 +1200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-10-07 01:39:29 +0200 |
| commit | 3e054a6f0d3ba018315f7cb7f0a373221e15737a (patch) | |
| tree | 8446ca7d411de6cb18ba2e3bb581ae38857fdf44 | |
| parent | c6d53e7bce9a9f04b2d479a150c4e1aee1bb4ea8 (diff) | |
rp2040: implement BOOTSEL button support
| -rw-r--r-- | embassy-rp/src/bootsel.rs | 81 | ||||
| -rw-r--r-- | embassy-rp/src/lib.rs | 1 |
2 files changed, 82 insertions, 0 deletions
diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs new file mode 100644 index 000000000..69d620e8d --- /dev/null +++ b/embassy-rp/src/bootsel.rs | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | //! Boot Select button | ||
| 2 | //! | ||
| 3 | //! The RP2040 rom supports a BOOTSEL button that is used to enter the USB bootloader | ||
| 4 | //! if held during reset. To avoid wasting GPIO pins, the button is multiplexed onto | ||
| 5 | //! the CS pin of the QSPI flash, but that makes it somewhat expensive and complicated | ||
| 6 | //! to utilize outside of the rom's bootloader. | ||
| 7 | //! | ||
| 8 | //! This module provides functionality to poll BOOTSEL from an embassy application. | ||
| 9 | |||
| 10 | use crate::flash::in_ram; | ||
| 11 | |||
| 12 | /// Polls the BOOTSEL button. Returns true if the button is pressed. | ||
| 13 | /// | ||
| 14 | /// Polling isn't cheap, as this function waits for core 1 to finish it's current | ||
| 15 | /// task and for any DMAs from flash to complete | ||
| 16 | pub fn poll_bootsel() -> bool { | ||
| 17 | let mut cs_status = Default::default(); | ||
| 18 | |||
| 19 | unsafe { in_ram(|| cs_status = ram_helpers::read_cs_status()) }.expect("Must be called from Core 0"); | ||
| 20 | |||
| 21 | // bootsel is active low, so invert | ||
| 22 | !cs_status.infrompad() | ||
| 23 | } | ||
| 24 | |||
| 25 | mod ram_helpers { | ||
| 26 | use rp_pac::io::regs::GpioStatus; | ||
| 27 | |||
| 28 | /// Temporally reconfigures the CS gpio and returns the GpioStatus. | ||
| 29 | |||
| 30 | /// This function runs from RAM so it can disable flash XIP. | ||
| 31 | /// | ||
| 32 | /// # Safety | ||
| 33 | /// | ||
| 34 | /// The caller must ensure flash is idle and will remain idle. | ||
| 35 | /// This function must live in ram. It uses inline asm to avoid any | ||
| 36 | /// potential calls to ABI functions that might be in flash. | ||
| 37 | #[inline(never)] | ||
| 38 | #[link_section = ".data.ram_func"] | ||
| 39 | #[cfg(target_arch = "arm")] | ||
| 40 | pub unsafe fn read_cs_status() -> GpioStatus { | ||
| 41 | let result: u32; | ||
| 42 | |||
| 43 | // Magic value, used as both OEOVER::DISABLE and delay loop counter | ||
| 44 | let magic = 0x2000; | ||
| 45 | |||
| 46 | core::arch::asm!( | ||
| 47 | ".equiv GPIO_STATUS, 0x0", | ||
| 48 | ".equiv GPIO_CTRL, 0x4", | ||
| 49 | |||
| 50 | "ldr {orig_ctrl}, [{cs_gpio}, $GPIO_CTRL]", | ||
| 51 | |||
| 52 | // The BOOTSEL pulls the flash's CS line low though a 1K resistor. | ||
| 53 | // this is weak enough to avoid disrupting normal operation. | ||
| 54 | // But, if we disable CS's output drive and allow it to float... | ||
| 55 | "str {val}, [{cs_gpio}, $GPIO_CTRL]", | ||
| 56 | |||
| 57 | // ...then wait for the state to settle... | ||
| 58 | "1:", // ~4000 cycle delay loop | ||
| 59 | "subs {val}, #8", | ||
| 60 | "bne 1b", | ||
| 61 | |||
| 62 | // ...we can read the current state of bootsel | ||
| 63 | "ldr {val}, [{cs_gpio}, $GPIO_STATUS]", | ||
| 64 | |||
| 65 | // Finally, restore CS to normal operation so XIP can continue | ||
| 66 | "str {orig_ctrl}, [{cs_gpio}, $GPIO_CTRL]", | ||
| 67 | |||
| 68 | cs_gpio = in(reg) rp_pac::IO_QSPI.gpio(1).as_ptr(), | ||
| 69 | orig_ctrl = out(reg) _, | ||
| 70 | val = inout(reg) magic => result, | ||
| 71 | options(nostack), | ||
| 72 | ); | ||
| 73 | |||
| 74 | core::mem::transmute(result) | ||
| 75 | } | ||
| 76 | |||
| 77 | #[cfg(not(target_arch = "arm"))] | ||
| 78 | pub unsafe fn read_cs_status() -> GpioStatus { | ||
| 79 | unimplemented!() | ||
| 80 | } | ||
| 81 | } | ||
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index e8f818bcf..fb9189203 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -10,6 +10,7 @@ mod critical_section_impl; | |||
| 10 | mod intrinsics; | 10 | mod intrinsics; |
| 11 | 11 | ||
| 12 | pub mod adc; | 12 | pub mod adc; |
| 13 | pub mod bootsel; | ||
| 13 | pub mod clocks; | 14 | pub mod clocks; |
| 14 | pub mod dma; | 15 | pub mod dma; |
| 15 | pub mod flash; | 16 | pub mod flash; |
