This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Interrupt Vectors REMAP

How can I relocate or manage the transition between the bootloaders interrupt vector map and the applications interrupt vector map which will be at different addresses in FLASH. On the M3/M4, you can remap this but presumably on the M0, you cant. Is there a method I could use on the NRF51822?

Edit: We are not using soft devices (we are using proprietary software and protocols).

Ive written the bootloader software running on the NRF51822 which accepts and programs an image sent from a C++ application, and then using some assembler, loads the main image @ 0x8000. The only issue is how to tackle the problem of a non-relocatable vector table (unless I am mistaken) of the Cortex M0.

NXP and ST's Cortex M0 dont have a VTOR (vector table offset register) but they do have a remap register to set the vector table in SRAM. The vector table could then jump to the correct bootloader vector table (@ 0) or main application vector table (@ 0x8000).

If you could investigate if the NRF51822 offers any features/registers to enable relocation of the vector table I would be grateful, thanks.

  • There is no direct HW support for this, but you could solve this in software.

    You could write a block of code on the lowest address (0x00) where the interrupt vectors reside, that point all interrupt vectors to some code that reads the wanted offset from RAM or a register (UICR registers are non-volatile and could be useful for this), and branches to the original interrupt vector address + the offset. This would of course add a few CPU clock cycles of latency, but would be very flexible.

    Edit: The reply to your first comment below was too long to post as a comment, so I expand my answer here.

    The easiest way to point all interrupt vectors to the same place, is to modify the vector table in the startup assembly source code. This would be arm_startup_nrf51.s (for armcc with the Nordic MDK, but the other compilers have similar files that work in a similar way). In arm_startup_nrf51.s, find the __Vectors label, there you see the vector table. Change all entrys except the first one (top of stack) to name your custom forwarder function, so that it looks something like this (for armcc):

    __Vectors       DCD     __initial_sp              ; Top of Stack
                    DCD     irq_forwarder
                    DCD     irq_forwarder
                    DCD     irq_forwarder
                    DCD     irq_forwarder
                    DCD     irq_forwarder
                    ; et cetera
    

    This will lead to a function called irq_forwarder being called on reset and every interrupt.

    Then implement the function irq_forwarder something like this (note that I haven't tested this, but it should give you an idea):

    //Typedef'ing an interrupt handler function pointer
    typedef void (*irq_handler_t)(void);
    
    void irq_forwarder(void)
    {
      uint32_t irq_handler_offset = //Read your offset here, from RAM or flash or wherever you
      //have it stored. Make sure it is valid at all times (or add some kind of check for it, e.g.
      //also add a "valid" flag somewhere.)
    
      //Read the number of the currently executing interrupt handler (if any) from ICSR. See the
      //Cortex-M0 user guide for details.
      uint32_t irq_interrupt_number = (*(uint32_t *)0xE000ED04) & 0x3F;
    
      //Find the address offset in the vector table for the currently running interrupt
      uint32_t vector_table_offset = (irq_interrupt_number * 4)
    
      //Get the address of the vector in the offset vector table
      uint32_t offset_vector_address = vector_table_offset + irq_handler_offset;
    
      //Read the address of the IRQ handler to branch to from the offset vector
      irq_handler_t irq_handler = (irq_handler_t)(*(uint32_t *)offset_vector_address);
    
      //Branch to the irq_handler
      irq_handler();
    }
    
  • thanks a lot! May you provide a example? I'm not good enough in english,I don't understand how to point all interrupt vectors to some code that reads the wanted offset from RAM or a register can you show me the source code?It will help me undestand it. thanks!

Related