-
Hi! I have an application that requires a certain pin driven high while the rp2040 performs a watchdog reset. For this purpose, I'm setting the Now on boot, within the pico-sdk, When I do this in a plain pico-sdk program, I get the expected result: the IO_BANK0 registers remain unchanged and the output remains overridden until I call However, when I port this code to Arduino-pico, Any ideas? #include "hardware/gpio.h"
#include "hardware/resets.h"
#include "hardware/structs/psm.h"
static uint32_t old_ctrl, old_wdsel;
static uint32_t old_reset_ctrl_reset = 0;
static uint32_t old_reset_ctrl_reset_done = 0;
static uint32_t mask = 0;
extern "C" {
void runtime_init_early_resets(void) {
// copied from https://github.com/raspberrypi/pico-sdk/blob/2.1.0/src/rp2_common/pico_runtime_init/runtime_init.c#L56
// changed to read out post-reboot register state and to skip resetting IO_BANK0
// changed: read out some post-reboot state
old_ctrl = io_bank0_hw->io[11u].ctrl;
old_wdsel = resets_hw->wdsel;
old_reset_ctrl_reset = resets_hw->reset;
old_reset_ctrl_reset_done = resets_hw->reset_done;
// end change
static_assert(NUM_RESETS <= 32, "");
// Reset all peripherals to put system into a known state,
// - except for QSPI pads and the XIP IO bank, as this is fatal if running from flash
// - and the PLLs, as this is fatal if clock muxing has not been reset on this boot
// - and USB, syscfg, as this disturbs USB-to-SWD on core 1
mask = ((1u << RESET_IO_QSPI) | (1u << RESET_PADS_QSPI) | (1u << RESET_PLL_USB) | (1u << RESET_USBCTRL) | (1u << RESET_SYSCFG) | (1u << RESET_PLL_SYS));
// changed: don't reset GPIO pins if watchdog caused the reboot
if (watchdog_caused_reboot())
mask |= (1u << RESET_IO_BANK0);
// end change
reset_block_mask(~mask);
// Remove reset from peripherals which are clocked only by clk_sys and
// clk_ref. Other peripherals stay in reset until we've configured clocks.
unreset_block_mask_wait_blocking(RESETS_RESET_BITS & ~(
#if !PICO_RP2040
(1u << RESET_HSTX) |
#endif
(1u << RESET_ADC) |
#if PICO_RP2040
(1u << RESET_RTC) |
#endif
(1u << RESET_SPI0) | (1u << RESET_SPI1) | (1u << RESET_UART0) | (1u << RESET_UART1) | (1u << RESET_USBCTRL)));
}
}
void setup() {
Serial1.setRX(1);
Serial1.setTX(0);
Serial1.begin(115200);
// set two pins to output: 11 will be set to override-high before watchdog reboot, 2 will be normal
gpio_put(11u, true);
gpio_set_function(11u, GPIO_FUNC_SIO);
gpio_set_dir(11u, GPIO_OUT);
gpio_put(2u, true);
gpio_set_function(2u, GPIO_FUNC_SIO);
gpio_set_dir(2u, GPIO_OUT);
Serial1.println("setup() done");
sendStatus();
}
void fire() {
// force pin 11 to high through IO_BANK0
// hw_set_bits only works for GPIO_OVERRIDE_HIGH = 0b11
hw_set_bits(&io_bank0_hw->io[11u].ctrl,
(GPIO_OVERRIDE_HIGH << IO_BANK0_GPIO0_CTRL_OUTOVER_LSB)
| (GPIO_OVERRIDE_HIGH << IO_BANK0_GPIO0_CTRL_OEOVER_LSB));
watchdog_reboot(0, 0, 10);
// watchdog_reboot() calls watchdog_enable(), it will set psm's wdsel to reset the peripheral reset controller and clocks controller.
// remove CLOCKS and RESETS before watchdog fires to prevent reset controller from resetting all peripherals.
hw_clear_bits(&psm_hw->wdsel, PSM_WDSEL_RESETS_BITS | PSM_WDSEL_CLOCKS_BITS | PSM_WDSEL_XOSC_BITS | PSM_WDSEL_ROSC_BITS);
while (1) {
tight_loop_contents();
}
}
void sendStatus() {
auto gpio = sio_hw->gpio_in;
auto pad = pads_bank0_hw->io[11u];
auto now_ctrl = io_bank0_hw->io[11u].ctrl;
Serial1.printf("\nmask was %08x at boot\n", mask);
Serial1.printf("ctrl was %08x at boot\n", old_ctrl);
Serial1.printf("reset was %08x at boot\n", old_reset_ctrl_reset);
Serial1.printf("rdone was %08x at boot\n", old_reset_ctrl_reset_done);
Serial1.printf("wdsel was %08x at boot\n", old_wdsel);
Serial1.printf("ctrl is %08x now\n", now_ctrl);
Serial1.printf("gpio is %08x now\n", gpio);
Serial1.printf(" pad is %08x now\n", pad);
Serial1.printf("wdsel is %08x now\n", resets_hw->wdsel);
}
void resetGpio() {
Serial1.println("resetting IO");
uint32_t mask = (1u << RESET_IO_BANK0);
reset_block_mask(mask);
unreset_block_mask_wait_blocking(mask);
Serial1.setRX(1);
Serial1.setTX(0);
Serial1.begin(115200);
Serial1.println("resetting IO done");
}
void loop() {
switch (Serial1.read()) {
case -1:
break;
case 'H':
case 'h':
digitalWrite(11u, HIGH);
digitalWrite(2u, HIGH);
digitalWrite(PIN_LED, HIGH);
Serial1.println("H");
break;
case 'L':
case 'l':
digitalWrite(11u, LOW);
digitalWrite(2u, LOW);
digitalWrite(PIN_LED, LOW);
Serial1.println("L");
break;
case '?':
sendStatus();
break;
case 'x':
case 'X':
Serial1.println("X");
fire();
break;
case 'r':
case 'R':
resetGpio();
break;
}
delay(50);
} Example output:
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
So the OTA handler also runs its own copy of The quickest fix I see for this would be to to add an earlier runtime_init_func that checks if we are in OTA, and if not, continue with this Lines 181 to 196 in dc0dc50 @earlephilhower what are your thoughts on this? |
Beta Was this translation helpful? Give feedback.
So the OTA handler also runs its own copy of
runtime_init_early_resets()
, and this will still reset IO_BANK0.The quickest fix I see for this would be to to add an earlier runtime_init_func that checks if we are in OTA, and if not, continue with this
arduino-pico/ota/ota.c
Lines 181 to 196 in dc0dc50