KE04Z Relocated Vector Table and Lockup after ISR

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

KE04Z Relocated Vector Table and Lockup after ISR

ソリューションへジャンプ
1,321件の閲覧回数
kevincuzner
Contributor II

I've been writing a small program for my 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 PIT 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_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

str r1,[r0]

__interrupt_vector_table points to the beginning of the RAM section where I have placed my interrupt vector table (0x1fffff00 for the record) (link to code here: swd-kinetis/startup.S at master · kcuzner/swd-kinetis · GitHub ).

In my main method I have the following:

SIM->SCGC |= SIM_SCGC_PIT_MASK;

PIT->MCR = 0;

PIT->CHANNEL[0].LDVAL = 1.2e6;

PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK;

PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK;

NVIC->ISER[0] = 1 << 22;

__enable_irq();

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:

void PIT_CH0_IRQHandler(void)

{

    PIT->CHANNEL[0].TFLG = 0x1;

}

Whch compiles to:

2000001c <PIT_CH0_IRQHandler>:

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 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.

ラベル(1)
タグ(5)
0 件の賞賛
返信
1 解決策
925件の閲覧回数
kevincuzner
Contributor II

The full source can be found here: https://github.com/kcuzner/swd-kinetis/tree/master/firmware/KE04

However, I managed to fix the problem!

I was thinking about how exactly the NVIC stores the context since that seems to be the moment that causes things to go nuts and I realized that it likely uses the stack.

I execute the following sequence in SWD when loading my program (its likely not the best way to do it, but its a work in progress):

  1. Enable debug in DHCSR
  2. Enable reset catch in DEMCR
  3. Clear any reset flag in DHCSR
  4. Use AIRCE to request a reset and wait for it to occur by olling DHCSR. The processor is now halted just after a reset occurs.
  5. Use the AHB-AP to load the program into RAM
  6. Set VTOR to point to my table in RAM and set register 15 (DebugReturnAddress) to the start of the reset routine in my code (whose address is found at VTOR+4)
  7. Unhalt the processor and let it run.

The processor would then run until the first interrupt. My realization was that since I had neglected to set the stack pointer during step 6 it was probably pointing to the reset value, which would be 0xffffffff. The NVIC likely had nowhere to save the context when the interrupt occurred and probably caused a fault. This would eventually let the WDT go off since it just loops endlessly in those routines which would cause the VTOR to reset back to 0x0, then attempting to execute 0xffffffff (since that's what is at address 0x4 in the unprogrammed state of the device) which would result in a LOCKUP.

By simply setting the stack pointer (register 14) to the top of my stack during step 6 above I fixed my problem.

元の投稿で解決策を見る

0 件の賞賛
返信
2 返答(返信)
925件の閲覧回数
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Kevin,

Can you attach your project so that we can review even test your code on our FRDM board?

BR

Xiangjun Rong

0 件の賞賛
返信
926件の閲覧回数
kevincuzner
Contributor II

The full source can be found here: https://github.com/kcuzner/swd-kinetis/tree/master/firmware/KE04

However, I managed to fix the problem!

I was thinking about how exactly the NVIC stores the context since that seems to be the moment that causes things to go nuts and I realized that it likely uses the stack.

I execute the following sequence in SWD when loading my program (its likely not the best way to do it, but its a work in progress):

  1. Enable debug in DHCSR
  2. Enable reset catch in DEMCR
  3. Clear any reset flag in DHCSR
  4. Use AIRCE to request a reset and wait for it to occur by olling DHCSR. The processor is now halted just after a reset occurs.
  5. Use the AHB-AP to load the program into RAM
  6. Set VTOR to point to my table in RAM and set register 15 (DebugReturnAddress) to the start of the reset routine in my code (whose address is found at VTOR+4)
  7. Unhalt the processor and let it run.

The processor would then run until the first interrupt. My realization was that since I had neglected to set the stack pointer during step 6 it was probably pointing to the reset value, which would be 0xffffffff. The NVIC likely had nowhere to save the context when the interrupt occurred and probably caused a fault. This would eventually let the WDT go off since it just loops endlessly in those routines which would cause the VTOR to reset back to 0x0, then attempting to execute 0xffffffff (since that's what is at address 0x4 in the unprogrammed state of the device) which would result in a LOCKUP.

By simply setting the stack pointer (register 14) to the top of my stack during step 6 above I fixed my problem.

0 件の賞賛
返信