2022-06-27 03:28 PM
update (a week later, after a vacation to clear head):
This was solved by changing the entry in the vector table from ".word timer7"
to ".word timer7+1". The +1 is to set bit 1 of the handler address to signal that it is a 16 bit
thumb instruction. (obviously the same must be done for the fault handler address....)
What clued me in was that the CFSR was showing an invalid ESPR fault, which implies mixing up 16 and 32 bit instructions. I am AMAZED that several days of searching online for examples of interrupt handler code in assembly, and appealing to experts on several sites did not reveal this. Doesn't anybody do bare metal assembly anymore???
----------original post below---------------
I am migrating NXP ARM7 to STM32. I've played with G031 and F423 so far. I've got a F423 on my own testboard now, clocked to 100 MHz (w/ 3 flash wait states, boosted from 20 MHz crystal), using J-Link Plus on SWD port. It works great as I fill my toolbox with cool tricks, until I try to implement interrupts. It always halts on the interrupt. (Free running timers continue spinning, but code stops executing.)
Only interrupt enabled is TIM7 reload, enabled on timer configure and on NVIC #55. The vector points to code that increments a location in SRAM that I can watch on mem probe. If I understand, all context saving is done by syscode, I don't need to push on entry (if only using R0, R1), and exit is only "BX LR".
Examination of the stack shows two frames pushed. First frame pushed was from one or two lines in the 4 line main loop, with an 0xFFFFFFFF LR. Second frame pushed was from the first line of the timer handler with an 0xFFFFFFF9 LR. Examination of status register shows a UFSR=0002, implying an illegal instruction. I should be in privileged mode - I can write to the NVIC registers, and I haven't touched the modes since reset. I've added ".align" to make sure we are aligned, I've tried bypassing the clock boosts, I've got all sorts of telltale sram pokes scattered to let me know if it is bouncing anywhere. Plain vanilla code in the handler, accessing only the SRAM (0x200000xx), the GPIO (40021418), and clearing the UIF bit on the timer and the pending interrupt bit on the NVIC (E000E284)...don't know if I need that last one since it hasn't worked yet.
The entire rest of the vector table points to a single handler that just goes infinite loop spinning one sram counter as a telltale -- no evidence it was called.
(edit: i've tried with and without "cpsie f" or "cpsie i" in the setup. i've tried with and without changing the NVIC priority reset at 0xE000E434 to FF (lowest possible). no effect .)
Clearly I'm missing some crucial setup. Help? Don't tell me to program in C, it is irrelevant and doesn't help. I need to understand what is going on here.
Thanks! Jeff
2022-06-27 03:39 PM
If you don't service the interrupt source it will re-enter.
Have a Hard-Fault Handler.
Watch what you push on the stack, does the FPU need enabling?
0xFFFFFFF9 is a call-gate to pull context from the stack
You have a minimal .HEX demonstrating this, might be easier than unpacking your description?
2022-06-27 04:06 PM
Thanks! Not sure it helps though, but good to check it all off.
I do have a handler, and in it it clears the timer flag and also the NVIC pending flag, as I said above. However, it doesn't get there -- the stack shows that it loaded the 2nd frame on the first line of the handler code. This means that the hard fault was generated before the handler could service anything.
There is nothing on the stack but the two frames I mentioned, the call is from top level in the code. The stack pointer is initialized midway through SRAM, so I would see under/overflow.
I've done nothing with the FPU yet.
The hard fault vector points to a handler as I mentioned above, that just does a telltale increment of one sram location.
So - no help yet. But thanks. What else you got?
2022-06-27 04:52 PM
code minimal presentation:
.syntax unified
.cpu cortex-m4
.thumb
.word 0x20001000
.word init
.word faults <<<--repeated to fill all of vector table except 1 handler
.word timer7 <<<-- at code word 11C, vector for timer7
.word faults <<<--repeated more, entire vector table
faults: <<code to increment 0x20000000 in infinite loop, never to return, as telltale to mem probe>>
timer7: // *** this is the handler
<<checks flag in 0x20000010, either 0 or 1, and toggles it>> **** the second frame, pushed on the stack comes from here. lockup.
write 0x40021418, <<either 1 or 1<<16, to turn LED on or off, depending on flag>>
write 0x40001410,0 // clear UIF bit on timer7
write 0xE000E284,1<<23 // clear pending NVIC interrupt bit, not sure if this is necessary
bx lr
init: <<code to set 3 flash wait states, activate 20 MHz xtal, activate PLL for 98 MHz, set APB2=98, APB1=49>>
<<about 20 lines>>
write 0x40023830,0xFF // RCC_AHB1ENR -- I/O port clock enable register <<< setup I/O port clock enable register, TIM7 enable>>>
write 0x40023840,1<<5 // RCC_APB1ENR -- TIM7 clock enable <<< write is an obvious macro >>>
write 0x40001428,48999 // TIM7_PSC -- prescaler, 49MHz base, 1kHz clock ticks << code to setup timer 7>>
write 0x4000142C,249 // TIM7_ARR -- auto-reload - 4 Hz
write 0x40001424,0 // TIM7_CNT -- clear
write 0x4000140C,1 // TIM7_DIER -- enable UIE interrupts << note that interrupt enabled in timer>>
write 0x40001400,1 // TIM7_CR1 -- start
write 0xE000E104,1<<23 // NVIC_ISER1 -- enable interrupt #55 (TIMER7) << note that interrupt bit in NVIC enabled>>
main_loop:
<<3-lines to increment 0x20000020>> *** the first frame in the stack comes from here
b main_loop
2022-06-27 05:11 PM
I'd like to see what the processor actually has to execute..