4

I have an ATSAMD21E18A micro that I am using with semi-hosting. In order for the semi-hosting to work, GDB needs to be "attached" before the first bkpt instruction. On the other hand, I have inexplicably found that the SysTick interrupt will not fire if GDB was already attached when I configured it. If I want to the SysTick interrupt to fire, I have to perform a reset (power-off via a button) and tell GDB to continue when it hasn't yet configured the micro (that is, it hasn't sent breakpoints over or anything else), and then hit Ctrl-C to initialize debugging mode after the SysTick configuration but before we get to initialise_monitor_handles.

I have verified that the start function is only copying over the relocatable data segment, zeroing the zero segment, and setting the right initial stack pointer value. We are writing our code without libraries like CMSIS.

Also I can confirm that I have no issues when the debugger is not attached (JLinkGDBServer through an Atmel SAM-ICE), besides needing to remove the semi-hosting stuff.

Also, the SysTick COUNT does still correctly count even when the interrupts themselves don't fire. Also the SysTick pending interrupt bit PENDSTSET in ICSR, is in fact set when this happens.

My code follows:

int main()
{
    // enable system timer interrupt
    SYS_TICK->STATUS = 0; // (CSR)
    SYS_TICK->PERIOD = 48000; // (RVR) fire at 1khz for 48mhz clock
    SYS_TICK->STATUS = 0b111; // use processor clock, w/ interrupt, and enabled
    SYS_TICK->COUNT = 1; // (CVR) avoid high unknown value

    // dumb busy loop
    util_idle_ms(2000); // <<< I hit Ctrl-C to break here!

    initialise_monitor_handles();

    // ... more system initialization and everything else
}

I have seen some similar seeming questions here on StackOverflow, but they seemed to be too vague to get good answers.

Edit: Here are possibly relevant register values taken during the busy loop for the run that doesn't call the SysTick handler (no hard reset, GDB attached before SysTick configured):

SYS_TICK_CSR/STATUS: 0x10007
SYS_TICK_RVR/PERIOD: 48000
SYS_TICK_CVR/COUNT: 5245 (varies of course)
NVC_ISER: 0 (and we expect this since SysTick is considered an exception, and not an interrupt)
DHCSR: 0x30003/0x1030003 (C_MASKINTS is not set; I've seen both values show up)
ICSR: 0x400f00f (it really wants to run the SysTick handler)
PRIMASK: 0
xPSR: 0x2100000f (IPSR is 0x0f/SysTick)

And for the run that calls the SysTick handler just fine (hard reset with GDB attaching after SysTick configuration):

SYS_TICK_CSR/STATUS: 0x10007
SYS_TICK_RVR/PERIOD: 48000
SYS_TICK_CVR/COUNT: 16892 (varies of course)
NVC_ISER: 0
DHCSR: 0x10003/0x1030003 (I've seen both values show up)
ICSR: 0 (SysTick handler already run)
PRIMASK: 0
xPSR: 0x2100000f

So the register values here do not yet seem to reveal anything new to me... Please help inform me of other potentially relevant registers to check!

Just for interest, the reason this is important to me is because I have gotten gprof to work on this chip, based on https://mcuoneclipse.com/2015/08/23/tutorial-using-gnu-profiling-gprof-with-arm-cortex-m/ And although I do have to hit Ctrl-C at just the right time after a hard reset, it does work like this!

Edit I have found that I had a misunderstanding where I thought running load in GDB performed a soft reset. I have since found that although it returns execution to reset vector, various peripherals and other registers are not in fact reset. If I perform a soft reset in GDB with monitor reset then I don't need to Ctrl-C during a delay to attach GDB and both SysTick and SemiHosting will work.

The problem occurs when SysTick is configured and then load is run in GDB, without an explicit hard or soft reset. In this case, SysTick does not fire interrupts. Most of my debugging went like this, loading new code and immediately expecting it to work so I could evaluate it. Just running monitor reset is a better workaround than before, but I still would prefer to know the reason for SysTick's misbehavior!

artless noise
  • 21,212
  • 6
  • 68
  • 105
Akh
  • 632
  • 1
  • 6
  • 15
  • 2
    "I have verified that the start function is only copying over the relocatable data segment, zeroing the zero segment, and setting the right initial stack pointer value." It doesn't call SystemCoreClockUpdate() and the other CMSIS stuff? – Lundin Jan 30 '19 at 07:53
  • @Lundin That is correct, we aren't using CMSIS and clock updates and other peripheral configuration is performed later in the code. – Akh Jan 31 '19 at 18:25

1 Answers1

3

I would visit the ARM® v6-M Architecture Reference Manual and see if you can get some direction from that. https://static.docs.arm.com/ddi0419/d/DDI0419D_armv6m_arm.pdf

Observe that state of the registers related to the Systick that you didn't include in your question. If you can't figure out the problem based on those registers, edit your question and post the register values here (the NVIC ISER, all registers related to systick config, the DHCSR, and any others you think are related). They will be the key to getting more feedback.

The Debug Halting Control and Status Register (DHCSR) has the ability to mask interrupts including the systick. Maybe this is being set by the debugger?

bit 3 of the DHCSR looks relevant

I would also check that the SYST_RVR (Systick reload value register) is being set to something sane.

I don't have the rep to comment on your question, but I'm hoping this can get you going in a productive direction :)

Community
  • 1
  • 1
johnconn
  • 61
  • 5
  • I have added all the register information you requested! Please let me know of any other relevant registers to check – Akh Jan 31 '19 at 18:26
  • 1
    isn't that bit of the DHCSR the S_HALT bit, indicating that the processor is no longer in the debug state after reset? I will look at the arm arm tonight after work, but it seems like either debug mode or how the debugger is interacting with debug mode is disabling your systick – johnconn Jan 31 '19 at 19:47
  • You are right! I was a byte off. (I'll fix it above) I don't doubt it was something to do with the GDB interaction, I'm just sure exactly how. I mean, in both cases I have the micro paused in GDB! – Akh Jan 31 '19 at 20:41
  • can you read the value of the PRIMASK and the IPSR? I want to confirm that something weird isn't happening with the debugger executing your app code in an exception handler of higher prio than the systick. – johnconn Jan 31 '19 at 22:29
  • @jonnconn I have added those values, but noticed first that ISPR had referred to TC3, which was somehow still enabled after having loaded new code. This led me to realize that GDB wasn't performing a soft reset when loading code, and the additional information I just added! – Akh Feb 01 '19 at 19:32
  • okay I'm glad you figured that out, it seems like you have a usable workflow. – johnconn Feb 01 '19 at 21:41
  • 1
    If you want to dig further then I think you'd have to check all of the operations that the debugger is performing (register writes, etc.) The IPSR is supposed to be updated on exception entry and exit, so I'm confused why in both of your regdumps the IPSR indicates you're in the systick exception. Maybe you captured the latter dump in the systick handler, but that doesn't explain the former. You'll be able to figure root cause if you know all the gdb instructions sent...but if you have a workaround.... – johnconn Feb 01 '19 at 21:49