0

I'm running on a Raspberry Pi Pico (RP2040, Cortex-M0+ core, debugging via VSCode cortex-debug using JLink SWD), and I'm seeing strange behaviour regarding PendSV.

Immediately prior, the SVCall exception handler requested PendSV via the ICSR register. But on exception return, rather than tail-chaining the PendSV, execution instead returns to the calling code and continues non-exception execution.

All the while the ICSR register shows the pending PendSV, even while thread code instructions are repeatedly stepped. System handler priorities are all zero, IRQ priorities are lower.

enter image description here

According to the ARMv6-M reference manual, PendSV cannot be disabled.

So, what am I missing that would cause this behaviour?

Edited to add:

Perhaps it's a debugger interaction? The JLink software (v4.95d) is still in Beta...

I see that the debugger can actually disable PendSV and Systick - C1.5.1 Debug Stepping: "Optionally, the debugger can set DHCSR.C_MASKINTS to 1 to prevent PendSV, SysTick, and external configurable interrupts from occurring. This is described as masking these interrupts. Table C1-7 on page C1-326 summarizes instruction stepping control."

Jeremy
  • 5,055
  • 1
  • 28
  • 44
  • 1
    You mention stepping - are you also seeing this behaviour when the code is running normally? Bear in mind that interrupts are disabled while stepping. This is logical for ordinary asynchronous hardware interrupts, but the behaviour extends to semi-synchronous software-triggered interrupts such as PendSV and SVC. – cooperised Feb 17 '21 at 11:05
  • @cooperised - I suspect you might be right. According to the reference manual, stepping can occur with or without interrupts disabled. I'm pretty sure I've successfully stepped through identical code on another Cortex-M0+ platform (Atmel SAMD21) - but maybe I'm mistaken, so I'll definitely double check on both platforms. – Jeremy Feb 17 '21 at 11:31
  • Stepping with interrupts enabled is rarely useful because (by their nature) interrupt requests will usually queue up between steps and you'll find that nothing happens sequentially anymore - or at least that ISRs run and change stuff between one line and the next. Disabling interrupts while stepping is therefore the default on every debugger I've ever used. That said, it would often be useful to see SVC and PendSV excluded from that because they're software triggered. – cooperised Feb 17 '21 at 11:45

2 Answers2

0

It turns out that the problem is caused by single-stepping the instruction that writes to the PENDSVSET bit in the ICSR: the bit is set, and the VECTPENDING field shows 0xe, but the PendSV never fires.

Free-running over that instruction to a later breakpoint sees the PendSV fire correctly.

So it is indeed a debugger interaction.

Whether that's to do with interrupts being inhibited as @cooperised suggests isn't clear - the DHCSR's C_MASKINTS bit reads as zero throughout, but how that bit is manipulated during the actual step operation isn't visible at this level.

Which makes me wonder whether the way the JLink is performing the step induces unpredictable/indeterminate behaviour - e.g. as per the warning in the C_MASKINTS description. Or perhaps this is simply what happens in an M0+ under these circumstances, and I've never single-stepped this instruction before.

In any case, the workaround is simply to not single-step the instruction that sets PENDSVSET.

Edited to add:

Finally, @cooperised was correct.

On taking more care to distinguish exactly between stepping (including stepping over function calls) and running (including running to the very next instruction), it's clear that stepping disables interrupts including PendSV.

Jeremy
  • 5,055
  • 1
  • 28
  • 44
  • Not in this exact way (I have no use for single stepping nor breakpoints) but I have seen some strange behavior with the pico and openocd that I have never seen before with openocd and cortex-m's so if they are not done with this work or have some holes or if this is some security thing, then it would explain what I am seeing too. I guess we have to wait for them to finish the openocd implementation or of this is a security thing then we cant do everything we want (there are some new stm32 chips that you cant do things from the debugger and have to execute code to have it happen for example) – old_timer Feb 18 '21 at 10:17
  • I already have seen this kind of thing with the pico as well when trying to figure out the second stage bootloader, my guess is the debugger comes through a different ahb bus than the example code connects to the spi flash, so had to execute code not simply read/write things through openocd. – old_timer Feb 18 '21 at 10:19
0

The same thing happened to me but I found that the reason was that I was not closing the previous PensSV interrupt by returning through LR containing 0xFFFFFFF9. Instead I was returning via the PC to a previous routine's return address.

Since I did not return via 0xFFFFFFF9 it was not properly closing the previous PendSV and did not recognize subsequent ones.

Babaluis
  • 101