-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
I have some RP2040 code which used to work fine in pico-sdk 1.4.0.
Now, I've upgraded to pico-sdk 2.1.0, and after making all the changes so the project builds again, I've stumbled upon quite a surprising problem - namely, somewhat randomly, the code fails to run after being flashed on the RP2040 MCU, because it hits an assert in gpio_set_irq_enabled.
I say that I hit the condition "somewhat randomly", because the first time I noticed this problem with the Debug .elf, I think I just reflashed the same .elf (or maybe I rebuilt the code, however without any code changes, can't really remember exactly), and then it started working. But then I rebuilt and reflashed Debug .elf again, and it started hitting the assert again; ever since, I cannot build a Debug .elf which works (does not hit the assert). However, I have built a Release .elf that does work.
I have seen gpio_set_irq_enabled() will not enable GPIO interrupt handling · Issue #1594 · raspberrypi/pico-sdk and tried to reorganize my setup code according to #1594 (comment) .
My main() function in this project calls this function somewhere at start:
void prestart_irq_setup( void )
{
irq_set_exclusive_handler( IO_IRQ_BANK0, on_gpio_edge_isr );
irq_set_enabled( IO_IRQ_BANK0, true );
gpio_set_irq_enabled( iopins.PIN_RX, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true );
// disable the interrupt until it's needed
irq_set_enabled( IO_IRQ_BANK0, false );
}... where the function prototype for on_gpio_edge_isr is
__attribute__( ( interrupt( "IRQ" ) ) ) void __time_critical_func( on_gpio_edge_isr )( void );I compile in a MINGW64 bash shell on Windows 10, with:
$ arm-none-eabi-gcc --version | head -1
arm-none-eabi-gcc.exe (GCC) 13.3.0
Here is a transcript of gdb-multiarch session, where the assert has been hit after flashing, and then (after program restart) stepping through the first three lines of prestart_irq_setup (some spacing added, and removed "target halted due ..." lines after p commands, for readability):
__breakpoint () at C:/src/pico-sdk/src/rp2040/pico_platform/include/pico/platform.h:126
126 pico_default_asm_volatile ("bkpt #0" : : : "memory");
(gdb) bt
#0 __breakpoint () at C:/src/pico-sdk/src/rp2040/pico_platform/include/pico/platform.h:126
#1 _exit (status=status@entry=1) at C:/src/pico-sdk/src/rp2_common/pico_clib_interface/newlib_interface.c:45
#2 0x1000c894 in __assert_func (file=file@entry=0x10056dd8 "C:/src/pico-sdk/src/rp2_common/hardware_gpio/gpio.c",
line=line@entry=190, func=func@entry=0x1005dc24 <__func__.4> "gpio_set_irq_enabled",
failedexpr=failedexpr@entry=0x10056e18 "!enabled || (raw_irq_mask[get_core_num()] & (1ull<<gpio)) || callbacks[get_core_num()]")
at C:/src/pico-sdk/src/rp2_common/pico_clib_interface/newlib_interface.c:168
#3 0x10009a84 in gpio_set_irq_enabled (gpio=<optimized out>, events=events@entry=12, enabled=enabled@entry=true)
at C:/src/pico-sdk/src/rp2_common/hardware_gpio/gpio.c:190
#4 0x1000f110 in prestart_irq_setup () at C:/src/myproject/my_setup.c:430
#5 0x100008ea in main () at C:/src/myproject/main.c:607
(gdb) b prestart_irq_setup
Breakpoint 1 at 0x1000f0f0: file C:/src/myproject/my_setup.c, line 408.
Note: automatically using hardware breakpoints for read-only addresses.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: C:\src\myproject\build\Debug\myproject.elf
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000184 msp: 0x20041f00
[New Thread 1]
[Switching to Thread 1]
Thread 2 hit Breakpoint 1, prestart_irq_setup () at C:/src/myproject/my_setup.c:408
427 {
(gdb) n
428 irq_set_exclusive_handler( IO_IRQ_BANK0, on_gpio_edge_isr );
(gdb) p raw_irq_mask[get_core_num()]
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000184 msp: 0x20041f00
$1 = 0
(gdb) p callbacks[get_core_num()]
$2 = (gpio_irq_callback_t) 0x0
(gdb) n
429 irq_set_enabled( IO_IRQ_BANK0, true );
(gdb) p raw_irq_mask[get_core_num()]
$3 = 0
(gdb) p callbacks[get_core_num()]
$4 = (gpio_irq_callback_t) 0x0
(gdb) n
430 gpio_set_irq_enabled( iopins.PIN_RX, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true );
(gdb) p raw_irq_mask[get_core_num()]
$5 = 0
(gdb) p callbacks[get_core_num()]
$6 = (gpio_irq_callback_t) 0x0
(gdb) p get_core_num()
$7 = 0
(gdb) n
Thread 2 received signal SIGTRAP, Trace/breakpoint trap.
_exit (status=status@entry=1) at C:/src/pico-sdk/src/rp2_common/pico_clib_interface/newlib_interface.c:45
45 __breakpoint();
(gdb) bt
#0 _exit (status=status@entry=1) at C:/src/pico-sdk/src/rp2_common/pico_clib_interface/newlib_interface.c:45
#1 0x1000c894 in __assert_func (file=file@entry=0x10056dd8 "C:/src/pico-sdk/src/rp2_common/hardware_gpio/gpio.c",
line=line@entry=190, func=func@entry=0x1005dc24 <__func__.4> "gpio_set_irq_enabled",
failedexpr=failedexpr@entry=0x10056e18 "!enabled || (raw_irq_mask[get_core_num()] & (1ull<<gpio)) || callbacks[get_core_num()]")
at C:/src/pico-sdk/src/rp2_common/pico_clib_interface/newlib_interface.c:168
#2 0x10009a84 in gpio_set_irq_enabled (gpio=<optimized out>, events=events@entry=12, enabled=enabled@entry=true)
at C:/src/pico-sdk/src/rp2_common/hardware_gpio/gpio.c:190
#3 0x1000f110 in prestart_irq_setup () at C:/src/myproject/my_setup.c:430
#4 0x100008ea in main () at C:/src/myproject/main.c:607
So, I guess, neither of irq_set_exclusive_handler or irq_set_enabled changes neither callbacks nor raw_irq_mask from their starting value of 0 for that core, which ends up triggering the assert in gpio_set_irq_enabled.
I've also tried using gpio_set_irq_callback( &on_gpio_edge_isr ); instead of irq_set_exclusive_handler, but it generates compiler warnings:
warning: passing argument 1 of 'gpio_set_irq_callback' from incompatible pointer type [-Wincompatible-pointer-types]
note: expected 'gpio_irq_callback_t' {aka 'void (*)(unsigned int, long unsigned int)'} but argument is of type 'void (*)(void)'
,,, as it apparently expects a function with two int arguments instead of no (void) arguments; this skips the assert and allows the rest of my code to run, but on_gpio_edge_isr never fires (so overall, it does not work for me). Apparently I'm using gpio_set_irq_callback incorrectly, as I'd need a different prototype for on_gpio_edge_isr, but I haven't been able to find a proper example for that so far. But at least, it confirms that gpio_set_irq_callback does set either callbacks or raw_irq_mask, as the assert in gpio_set_irq_enabled is not hit.
What can I do, to have my code running again?