I've been writing a small program for my Freescale Kinetis KE04Z which runs in RAM in order to program the flash of the device. I've been using SWD to place the program in RAM and run it. All was going well (blinking LEDs as a test, etc) until I tried to start the periodic interrupt timer (PIT module) in order to confirm the speed of the microcontroller by flashing an LED with some specific timing (the flash controller manual says that if the speed is wrong then it could destroy the flash). I don't have an oscilloscope available at the moment, otherwise I would just ditch the PIT, write the gpio pin toggle register (PTOR) over and over again, and measure the period of the resulting square wave.
I have in my startup section the following assembly which moves the VTOR to my interrupt vector table:
ldr r0, =0xE000ED08
ldr r1, =__interrupt_vector_table
__interrupt_vector_table points to the beginning of the RAM section where I have placed my interrupt vector table (0x1fffff00 for the record). The code can be found here. The interrupt table and startup code listing is here.
In my main method I have the following:
SIM->SCGC |= SIM_SCGC_PIT_MASK; //turn on PIT clock
PIT->MCR = 0; //activate PIT
PIT->CHANNEL.LDVAL = 1.2e6; //100mS tick
PIT->CHANNEL.TCTRL = PIT_TCTRL_TEN_MASK; //enable the timer
PIT->CHANNEL.TCTRL |= PIT_TCTRL_TIE_MASK; //enable the interrupt
NVIC->ISER = 1 << 22; //enable interrupt in NVIC
__enable_irq(); //cpsie i
It was at this point where I started to run into problems. Once the PIT would go off, a lockup would occur according to the SIM_SRSID register when I read it via SWD. I have a couple thoughts on why this could happen:
- The ISR runs, but never returns, causing the WDT to go off an initiate a reset, causing the VTOR to be reset to 0x0. Since the device is unprogrammed, the reset vector is 0xffffffff, which causes a lockup.
- The ISR runs, smashes the registers, and prevents the main method from properly resetting the WDT, causing the same situation as above.
- The interrupt goes off, but for some reason the NVIC is unable to run my ISR and initiates a HardFault. My hard fault code just loops forever, which would eventually cause the WDT to go off and etc.
- My hand-written interrupt table is off-by-one and one of the default ISRs is getting executing and causing a WDT timeout (or I'm not enabling the correct ISR and the same thing is happening). The thing is, I've never been able to show that my default ISR code was running instead of my actual IRQ handler. I've done a few tests using writing memory locations to specific values and then reading them after the reset and the code to set those values has never executed.
I'm pretty sure it has to do with my ISR or the interrupt in general because once I comment out the line of code that sets PIT_TCTRL0.TIE the program works fine and doesn't lock up.
My ISR is really simple right now:
PIT->CHANNEL.TFLG = 0x1; //reset flags
Which compiles to:
2000001c: 2201 movs r2, #1
2000001e: 4b01 ldr r3, [pc, #4] ; (20000024 <PIT_CH0_IRQHandler+0x8>)
20000020: 611a str r2, [r3, #16]
20000022: 4770 bx lr
20000024: 400370fc strdmi r7, [r3], -ip
I honestly don't know if this is right. There is no context saving going on or anything else that I've seen in other ISRs, but I've never looked in detail at ARM Cortext M0+ ISRs so for all I know the NVIC takes care of context saving.
My question is:
- Is my ISR code, NVIC code, or VTOR relocating code the problem here?
- Or perhaps is locating the VTOR to a location in RAM a bad thing and won't work properly?
This is my first time writing a program that runs in RAM and also my first time relocating the VTOR, so I don't have a lot of experience in these matters. I've done lots of interrupt code for a K20 before, but the VTOR was always at 0x0. If I've left anything out or need to supply additional information, just let me know.