Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Buttonless DFU works on dev kits but not on custom board

Hello,

I’m using the secure bootloader for serial DFU (UART, not USB). To enter bootloader mode from the application, I write 0xB1 to GPREGRET, then call NVIC_SystemReset(). On the dev boards I have (PCA10056 and Particle Boron), this works to reboot into DFU mode. However, on my custom board, it doesn’t work. The device appears to boot immediately into the application code.

I have made a custom board file that looks like this

#define LEDS_NUMBER    2

#define LED_1          NRF_GPIO_PIN_MAP(0,15)
#define LED_2          NRF_GPIO_PIN_MAP(0,18)
#define LED_START      LED_1
#define LED_STOP       LED_2

#define LEDS_ACTIVE_STATE 1

#define LEDS_LIST { LED_1, LED_2 }

#define LEDS_INV_MASK  LEDS_MASK

#define BSP_LED_0      NRF_GPIO_PIN_MAP(0,15)
#define BSP_LED_1      NRF_GPIO_PIN_MAP(0,18)

#define BUTTONS_NUMBER 0

#define RX_PIN_NUMBER  NRF_GPIO_PIN_MAP(0,23)
#define TX_PIN_NUMBER  NRF_GPIO_PIN_MAP(0,24)
#define CTS_PIN_NUMBER NRF_GPIO_PIN_MAP(0,30)
#define RTS_PIN_NUMBER NRF_GPIO_PIN_MAP(0,31) 
#define HWFC           false

I’ve already read some advice including checking the LF crystal, and checking the UART pins. These don’t appear to be causing my problem, so I’m not really sure what to try next. I am open to debugging the bootloader, but I’m not sure how that will help since the device just enters the application code. Any guidance would be greatly appreciated

Thank you,

Carlos

  • I put a 10 second delay in the beginning of main() so that I would have time to attach the debugger after sending the command to boot into DFU mode. In this way I have discovered that the bootloader does make it into the main() function. I will see tomorrow if I can find out more

  • Well, I have discovered something interesting.

    After I send the reset into DFU command to my device, I can verify that GPREGRET has the correct contents in the following way

    (gdb) p/x *0x4000051c
    $1 = 0xb1

    However, when my device then resets into the bootloader, I run the same command to check the contents of GPREGRET, right at the beginning of main(), and it appears the value has been erased or overwritten

    (gdb) p/x *0x4000051c
    $1 = 0x0

    The documentation states that retained registers will only be overwritten on power cycle or brownout. I've also discovered that the RESETREAS register is set to 0 after the reset, which suggests that the device might be browning out or power cycling?

    (gdb) p/x *0x40000400
    $3 = 0x0

    However, I'm seeing that NVIC_SystemReset() doesn't actually write anything to RESETREAS, so it makes sense that value would be 0 as far as I can tell. So I'm not really sure why GPREGRET is being overwritten, especially since it doesn't seem to happen on the other boards

  • The dfu flag in GPREGRET gets cleared by the bootloader when it reaches the dfu_enter_flags_clear() function in nrf_bootloader.c after entering DFU mode, so this is probably to be expected.

    Based on your findings thus far, I suspect the problem must be an error occurring in the bootloader after entering DFU mode that leads to the device being reset again. Maybe something related to the UART pinout considering the problem only happens with your board. Could you try to place a breakpoint in nrf_dfu_serial_uart.c::uart_event_handler()::NRF_DRV_UART_EVT_ERROR and see if it gets hit?

  • I tried what you've suggested, and the breakpoint was never hit. Also, in my application code I use UART to send the command to switch to DFU mode. I have that set up as the same pins as what I designate in the custom.h board file I wrote for my board.

    Also, I don't believe that the bootloader is code is running, then resetting, then running again. I have inserted in the first line of the bootloader's main function: nrf_delay_ms(5000);

    When I power cycle my device, the application code loads after about 5 seconds (indicated by an LED). If it was resetting from the bootloader (so bootloader code is essentially running twice), I would expect that when I reset the device using the ENTER_DFU command I send to my application code, I would have to wait 10 seconds for the application code to start running. But the application code will load after 5 seconds, even when I am using the serial command.

    Is there some minimum hardware requirements in terms of how many LEDs must be designated in the board file for the bootloader to work? My board only has 2 LEDs and implementations on the dev kits I have seen use more LEDs than that (I have done this with PCA10056 and the particle boron which has more than 4 LEDs

  • cwmoreiras said:

    Also, I don't believe that the bootloader is code is running, then resetting, then running again. I have inserted in the first line of the bootloader's main function: nrf_delay_ms(5000);

    When I power cycle my device, the application code loads after about 5 seconds (indicated by an LED). If it was resetting from the bootloader (so bootloader code is essentially running twice), I would expect that when I reset the device using the ENTER_DFU command I send to my application code, I would have to wait 10 seconds for the application code to start running. But the application code will load after 5 seconds, even when I am using the serial command.

    Yes, I agree. It sounds like the startup delay should have been 10 seconds and not 5 if an assert was raised after entering DFU mode.

    If you haven't done it already, please try to debug the Bootloader project while sending the ENTER_DFU command to the main app and then check if the dfu_enter_check() function sets the 'dfu_enter' to true or false.

    Also, this should not be board specific, but have you verified that the GPREGRET register is set correctly in the application before it resets into the bootloader? A common mistake is to access the GPREGRET register directly while the Softdevice is enabled instead of going through the SD API sd_power_gpregret_set(). Writing directly to POWER registers will trigger the Softdevice's Memory isolation and runtime protection mechanism.

    Bootloader enters DFU mode when 'dfu_enter' flag is 'true'

    cwmoreiras said:
    Is there some minimum hardware requirements in terms of how many LEDs must be designated in the board file for the bootloader to work? My board only has 2 LEDs and implementations on the dev kits I have seen use more LEDs than that (I have done this with PCA10056 and the particle boron which has more than 4 LEDs

    There are not really any minimum requirements. But in addition to creating the custom board header file, you should comment the  bsp_board_led_off(BSP_BOARD_LED_2); and the bsp_board_led_on(BSP_BOARD_LED_2); line in main.c to make the project use 2 instead of 3 LEDs for state indication.

    The NRF_BL_DFU_ENTER_METHOD_BUTTON setting in sdk_config.h must be disabled if you don't have a dedicated button for entering DFU mode.

Related