Feature request: Early GPIO startup control & state latching #959
Labels
No labels
bazel
bluetooth
board settings
boot_stage2
bug
build
c++
can't reproduce
clang
clib-interface
cmsis
code cleanliness
code size
compiler version issues
cyw43_driver
debug
discussion
documentation
duplicate
dynamic_clock
elf2uf2
enhancement
errata
filesystem
flash layout
floating point
FreeRTOS
hardware_adc
hardware_claim
hardware_clocks
hardware_dma
hardware_exception
hardware_flash
hardware_gpio
hardware_i2c
hardware_irq
hardware_pio
hardware_pwm
hardware_rcp
hardware_rtc
hardware_spi
hardware_sync
hardware_uart
hardware_vreg
hardware_watchdog
hardware_xosc
help wanted
host
IAR
installation
invalid
linker scripts
lto
lwip
mbedtls
missing API
needs reporter detail
networking
newlib
newlib-multicore
non-c
non-cmake
non-gcc
openocd
orphan PR
OS integration
pico_async_context
pico_base
pico_binary_info
pico_flash
picolibc
pico_lwip
pico_malloc
pico_multicore
pico_printf
pico_runtime
pico_stdio
pico_stdio_usb
pico_sync
pico_time
pico_util
pioasm
port
question
review
review2
rtos interop
runtime init
static library
svd
test
tinyusb
vscode
wifi integration
wontfix
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-raspberrypi/pico-sdk#959
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
We have a few applications of the RP2040 chip and Pico W-as-a-SOM where it's important for us to:
When writing a basic program in C++ it's possible to assert a pin and get the startup GPIO state some 15ms after a cold boot, simply by doing it in the top of
main, but this depends on there being absolutely no preinit/init happening beforemainis reached.In real-world scenarios there could be large quantities of zero init BSS (MicroPython for Pico W's 166k
gc_heap) or initialized SRAM which - in our tests - can move any existing methods of hooking into early startup to some 150ms after the rising edge of RESET. This is enough to miss even a user button press, much less a transient pulse from a hardware peripheral.We can do better by modifying
crt0.Sto init the RP2040 peripherals before SRAM load and zeroing the BSS. This is achieved by splittingruntime_initintoruntime_initandruntime_reset_peripheralsthe latter of which is called before BSS and SRAM init, immediately followed byruntime_user_init(this is a very rough proof of concept) which latches ourVSYS_EN.This takes a (MicroPython PicoW) 150ms time from rising edge of RESET to VSYS_EN_PIN HIGH right down to about 8ms, beating even a vanilla C++ example with code in
main.Why? In our application
VSYS_ENmust be held high for the Pico W to be powered. We're shutting the chip fully down and powering it back on with a mix of external events. We'd like to know what event "woke" the chip, even if it's transient. Down to a limit, of course. And bearing in mind the chip is off so interrupts et al are no go.To summarize:
I imagine this being configured with something like
-DPICO_STARTUP_PIN_STATEand-DPICO_STARTUP_PIN_MASKso a build can be configured with any permutation of (not system essential) pins set to a desired state. This may include pulls but should probably only focus on SIO.For the programming minded (or those who want to deploy this themselves) here's a diff showing my changes to
runtime.candcrt0.S:relates to #748
@Gadgetoid There's no reason that MicroPython's gc heap needs to be zero initialised at boot (in fact, the gc doesn't assume that it has been initialised, because on other platforms it comes from malloc).
It should be pretty straightforward to put it in a different section (e.g.
.noinit), or better do what we do on stm32 where it's just defined entirely in the linker config as a start and end symbol used directly by gc_init().@jimmo the zero fill only accounted for something like 20ms of the startup delay, with the remaining ~120 being the initialised SRAM copy. Definitely worth the gains, but not the full picture.
I didn’t try to figure out what portion of the SRAM copy was our C++ modules versus MicroPython itself but we’re extremely cautious with RAM usage so I’d hope not much!
I need to improve my objdump/nm skills so I can figure out where the main thrust of the delay is coming from since - as you imply - fixing it downstream is also an option!
8ms from cold boot to pin toggle low level is hard to pass up though- even if we can get full MicroPython started in 50ms now.
Edit: Note I tested the affect noinit might have on
gc_heapby building a version with a smallergc_heap(around 16K IIRC) and that's how I measured the 20ms speedup..noinitmight gain slightly over 20ms.In fact we have a patch in our build (excuse the patch of a patch here) to set the ROSC early and this dramatically speeds up the BSS/Zero init steps- https://github.com/pimoroni/pimoroni-pico/pull/480/commits/69493e5af76d6196beac30ad2592f6605244486c
Just these lines alone in
crt0.Swill take a full startup from rising edge of reset to MicroPython toggling a pin from ~200ms to ~50ms.So some way to set the ROSC would be another great addition to Pico SDK if a mode configurable startup is on the table.
Using the ROSC is mentioned briefly in #745 ?
Some more data for the finer-control-over-runtime case- https://github.com/pimoroni/badger2040/issues/10
Just having some weak ref empty functions that are called at various stages of boot would be handy as hooks to avoid having to replace entire portions of the runtime.