Can NMI pre-empt the Reset Handler on the Kinetis K24FN1M0?

cancel
Showing results for 
Search instead for 
Did you mean: 

Can NMI pre-empt the Reset Handler on the Kinetis K24FN1M0?

Jump to solution
645 Views
DaveTonyCook
Contributor IV

Hi

Its my understanding that the Reset vector is at a higher priority than NMI and that the NMI should pend to be executed on return from the reset handler. [Sec 7.4 p247,248 Definitive Guide to ARM cortex..]

However when I run in debug starting at the reset vector (i.e. not from main) and I force the NMI line low in hardware before running the code. The NMI handler interrupts immediately.  This has left me confused.... is this behaviour because the code is running from the debugger or is my understanding of the interrupt priority scheme incorrect?

Background:- 

I have a hardware problem that asserts NMI at power-up.  Whilst waiting for the hardware fix I thought I could fix this in software by controlling the code that runs in the NMI Handler using the variable NMI_armed

The problem with this approach is that it relies on the ROM COPY function to execute without being pre-empted. The rom

copy is performed by the DLIB function   __iar_data_init3 and is called from within the reset handler.  It was my assumption, that because this code is in the reset handler that the NMI couldn't pre-empt it.

Code snippet from the IAR supplied startup_MK24F12.s

__vector_table

        DCD     sfe(CSTACK)

        DCD     Reset_Handler                                   ;Reset Handler             (priority -3)

        DCD     NMI_Handler                                      ;NMI Handler                (priority -2)

        DCD     HardFault_Handler                             ;Hard Fault Handler     (priority -1)

        DCD     MemManage_Handler                        ;MPU Fault Handler     (programmable)

        DCD     BusFault_Handler                               ;Bus Fault Handler      (programmable)

        DCD     UsageFault_Handler                           ;Usage Fault Handler  (programmable)

 

        THUMB

        PUBWEAK Reset_Handler

        SECTION .text:CODE:REORDER:NOROOT(2)

Reset_Handler

        CPSID   I               ; Mask interrupts PRIMASK

        LDR R0, =_NVIC_ICER0    ; Disable interrupts and clear pending flags

        LDR R1, =_NVIC_ICPR0

        LDR R2, =0xFFFFFFFF

        MOV R3, #8

_irq_clear

        CBZ R3, _irq_clear_end

        STR R2, [R0], #4        ; NVIC_ICERx - clear enable IRQ register

        STR R2, [R1], #4        ; NVIC_ICPRx - clear pending IRQ register

        SUB R3, R3, #1

        B _irq_clear

_irq_clear_end

        LDR     R0, =SystemInit

        BLX     R0

        LDR     R0, =init_data_bss

        BLX     R0

        CPSIE   I               ; Unmask interrupts

        LDR     R0, =__iar_program_start        ; calls __iar_data_init3 before entering main()

        BX      R0

        PUBWEAK NMI_Handler

        SECTION .text:CODE:REORDER:NOROOT(1)

NMI_Handler      ;Implemented in 'C' in prw_fail.c

        B .

In my module prw_fail.c

EXPORT VOID NMI_Handler(VOID)

{

        if(NMI_armed)        // NMI_armed controlled in main() as I only want to be true on power down

        {

                //do stuff

        }

}

Thanks

1 Solution
122 Views
mjbcswitzerland
Specialist V

Hi Dave

I think that the confusion is that the reset context terminates on the very first instruction of code that is executed. That means that the system reset will cause the stack pointer to be loaded with the value at address 0x00000000 (sfe(CSTACK) in your case) and then will cause the program counter to be loaded with the address of the first instruction to be executed (Reset_Handler in your case). Now code start executing the processor is no longer in the reset context but the supervisor state and NMI can occur.

Since NMI cannot be masked you will get its vector (NMI_Handler in your case) taken, when the NMI line is asserted, before any code is executed - the line

CPSID   I           ; Mask interrupts PRIMASK

WILL NOT be executed until the NMI vector has been handled in this case so it is importent that:

1) The stack pointer has a valid address so that the interrupt vector can push the NMI interrupt context to the stack

2) The NMI handler is in Flash so that it can execute without further configuration

3) The NMI handler code does anything necessary to remove the pending NMI so that the code can continue after the return

Summary:

Reset_Handler in your code is not a 'reset vector' in the sense of an interrupt vector that is operating in a "reset context". It is the first instruction of code operating in the 'normal' supervisor context, which is not an interrupt based context. This context can be interrupted by NMI. Normally the global interrupt mask is set so that no 'normal' interrupt can occur yet (the CPSID I should be superfluous).

Regards

Mark

View solution in original post

1 Reply
123 Views
mjbcswitzerland
Specialist V

Hi Dave

I think that the confusion is that the reset context terminates on the very first instruction of code that is executed. That means that the system reset will cause the stack pointer to be loaded with the value at address 0x00000000 (sfe(CSTACK) in your case) and then will cause the program counter to be loaded with the address of the first instruction to be executed (Reset_Handler in your case). Now code start executing the processor is no longer in the reset context but the supervisor state and NMI can occur.

Since NMI cannot be masked you will get its vector (NMI_Handler in your case) taken, when the NMI line is asserted, before any code is executed - the line

CPSID   I           ; Mask interrupts PRIMASK

WILL NOT be executed until the NMI vector has been handled in this case so it is importent that:

1) The stack pointer has a valid address so that the interrupt vector can push the NMI interrupt context to the stack

2) The NMI handler is in Flash so that it can execute without further configuration

3) The NMI handler code does anything necessary to remove the pending NMI so that the code can continue after the return

Summary:

Reset_Handler in your code is not a 'reset vector' in the sense of an interrupt vector that is operating in a "reset context". It is the first instruction of code operating in the 'normal' supervisor context, which is not an interrupt based context. This context can be interrupted by NMI. Normally the global interrupt mask is set so that no 'normal' interrupt can occur yet (the CPSID I should be superfluous).

Regards

Mark

View solution in original post