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

Custom bootloader: Can't reach interrupt handler

Hello,

We're trying to create a custom bootloader from scratch and we're struggling with a weird behavior. This is for the nRF52840 and the bootloader doesn't use the softdevice. 

The bootloader is located at address 0xF8000 which is written in UICR.NRFFW[0]. Right now, we are able to execute code from the bootloader, including successfully jumping to the application (normally located after the softdevice). The problem is that we want to use some interrupts, but whenever we'd expect to jump to an interrupt handler, instead our debugger stops at address 0x00. At this point it seems we're in hardfault (ICSR->VECTATIVE is 3) but for some reason we never reach a breakpoint placed in our Hardfault_Handler.  

The only SDK files we're building are: gcc_startup_nrf52840.S, nrfx_gpiote.c and system_nrf52840.c. We also have a linker script very similar to the one of the secure_dfu_uart example. 

The bootloader's main'code looks like this, and its goal is simply to jump to the app when we toggle the GPIO 16:

#include <stdbool.h>
#include "nrfx_gpiote.h"

static volatile bool jump_to_app = false;

void HardFault_Handler(void) __attribute__((naked));
void HardFault_Handler(void)
{
    NVIC_SystemReset();
}

void pin_handler(uint32_t pin, nrf_gpiote_polarity_t action)
{
    if ((action == NRF_GPIOTE_POLARITY_TOGGLE) && (pin == 16))
    {
        jump_to_app = true;
    }
}

int main(void)
{
    // Some code to set GPIO as input/output
    
    nrfx_gpiote_in_config_t nrfx_gpiote_cfg = {.sense           = NRF_GPIOTE_POLARITY_TOGGLE,
                                               .pull            = NRF_GPIO_PIN_PULLUP,
                                               .is_watcher      = false,
                                               .hi_accuracy     = false,
                                               .skip_gpio_setup = true};
    nrfx_gpiote_init();
    nrfx_gpiote_in_init(HWP_P1, &nrfx_gpiote_cfg, pin_handler);
    nrfx_gpiote_in_event_enable(16, true);
    
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    while (1)
    {
        __SEV(); // Set the internal event register
        __WFE(); // Clear event register
        __WFE(); // Enter sleep

        if (jump_to_app)
        {
            // Boot the application
            bootloader_start_app();
        }

}

I checked the MAP file and I can see that isr_vector is correctly located at address 0xF8000. I can also see from my debug session that at address 0xF8058 (isr_vector + 0x58 is the GPIOTE Handler address) there is 0xFA7D9, which is the address of the GPIOTE_Handler (in my MAP file it's 0xFA7D8). If I put a breakpoint at this address, it's never reached. 

I also checked if interrupts were enabled or blocked. BASEPRI is 0, PRIMASK is 0, NVIC_ICER0.SETENA_6 is 1 (should be GPIOTE) and GPIOTE.INTENSET.PORT is 1, 

Do you have any idea what could cause this behavior ? I have the feeling that this could be simple, or that my analysis is wrong somewhere, but I'm really stuck on that one. 

Work environment details:

Windows 10 64-bit, build with arm gcc  7.2.1 20170904, based on SDK 15.1 and using SD s140. The nRF52840 are engineering C. 

Parents Reply Children
  • Hi Bjørn, no problem, this is not a blocking point for us. 

    We actually found a way to fix this, but I'm really curious to know if this is just a workaround or if this is the correct way to do it. What we do now is that at the beginning of our bootloader's main, we perform a MBR command (SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET) to forward IRQ to the bootloader. After we do this, we correctly enter the GPIOTE handler when toggling our GPIO. 

    What makes me think it could not be the correct way is that the s140 SDS states this:

    Else if a bootloader is present:
    Forward interrupts to the bootloader.
    Run Bootloader Reset Handler (defined in bootloader Vector Table at BOOTLOADERADDR).

    So I was thinking we wouldn't need to tell the MBR to forward interrupts to the bootloader since it's already part of the procedure. Also, the MBR already knows the address of the bootloader ISR vector since it's where it jumps to at the beginning. 

    Best regards,

    Timothée

  • HI Timothée, 

    the MBR should already have set the IRQ forwarding address to the bootloader's vectortable address prior to passing execution to the bootloader. If you look at our Secure Bootloader we only call nrf_dfu_mbr_irq_forward_address_set( which in turn calls sd_mbr_command with SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET as a parameter) when we jump to the application. 

    Would it be possible for you to share the project so that I could try running this on a NRF52840 DK ?

    Best regards
    Bjørn

  • Hi Bjørn,

    Thanks, then this is what I thought. .I suspect we have another issue then, I will continue searching for it, but it's probably not linked to ISRs in general because it seems the SPI handler is called correctly. I can't share the code, but your answer is enough for me.

    Best regards and thanks for your time,

    Tim

Related