Custom MCUboot DFU bootloader nrf Connect

Hi,

We want to modify the bootloader process on MCUboot. To avoid someone having to press and hold a button the entire time on our custom boards we want as a minimum to set a pin high to ensure it doesn't turn off.

I was successfully able to try this using SYS_INIT and a custom board.c file by following this ticket  Modify the MCUboot's booting process however, the problem I've found with this method is it sets the pin high regardless of whether the unit goes through the bootloader or not - which makes sense. In some instances we want to indicate the bootloader is running by switching on an LED just as user feedback something's going on. So a potential flicker of the LED (e.g. switching it off ASAP in the main app) would be inappropriate for our devices. 

It looks therefore that the best way to achieve what we want is by modifying the bootloader and I've gone down a ticket rabbit hole through here  How to create custom MCUBOOT for DFU which ends up leading to this blog archive:  nRF Connect SDK Tutorial - Part 2 | NCS v1.3.0 

is there a more up to date and recommended way of customising the mcuboot? Our aim would be to have a file within the main project directory that handles the main functions of the boot but adds in our own "switch on this pin" code.

Thanks.

BR,
Richard

Parents
  • Hi,

    To avoid someone having to press and hold a button the entire time on our custom boards

    Could you explain this some more? Why does a use need to press and hold a button?

  • Hi Sigurd,

    On most of our boards we have a soft power on that maintains the power after being physically switched on via a button. The board is therefore either on by pressing and holding the button, or on if a pin is held high.

    BR,
    Richard

  • Richard said:
    Using the CONFIG_OS_MGMT_RESET_HOOK happens too late as well unfortunately. Seems to occur after the image has been sent, and when it's verifying.

    Ah, okay. If you want a callback when the image is being transferred OTA, then you can do it like this:

    Snippet 1:

    #include <zephyr/mgmt/mcumgr/smp_bt.h>
    #include "os_mgmt/os_mgmt.h"
    #include "img_mgmt/img_mgmt.h"
    
    
    void dfu_started_cb(void)
    {
    
    		printk("Starting DFU image upload\n");
    
    }
    
    
    const struct img_mgmt_dfu_callbacks_t dfu_callbacks = {
    	.dfu_started_cb = dfu_started_cb,
    	.dfu_stopped_cb = NULL,
    	.dfu_pending_cb = NULL,
    	.dfu_confirmed_cb = NULL
    };

    Snippet 2:

    void main(void)
    {
    	int blink_status = 0;
    	int err;
    
    	printk("Starting Bluetooth Peripheral LBS example\n");
    
    	err = dk_leds_init();
    	if (err) {
    		printk("LEDs init failed (err %d)\n", err);
    		return;
    	}
    
    	err = init_button();
    	if (err) {
    		printk("Button init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("build time: " __DATE__ " " __TIME__ "\n");
    	os_mgmt_register_group();
    	
    	img_mgmt_register_group();
    	img_mgmt_register_callbacks(&dfu_callbacks);
    	smp_bt_register();
    
    	if (IS_ENABLED(CONFIG_BT_LBS_SECURITY_ENABLED)) {
    		err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    		if (err) {
    			printk("Failed to register authorization callbacks.\n");
    			return;
    		}
    
    		err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    		if (err) {
    			printk("Failed to register authorization info callbacks.\n");
    			return;
    		}
    	}
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Bluetooth initialized\n");
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
    		settings_load();
    	}
    
    	err = bt_lbs_init(&lbs_callbacs);
    	if (err) {
    		printk("Failed to init LBS (err:%d)\n", err);
    		return;
    	}
    
    	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad),
    			      sd, ARRAY_SIZE(sd));
    	if (err) {
    		printk("Advertising failed to start (err %d)\n", err);
    		return;
    	}
    
    	printk("Advertising successfully started\n");
    
    	for (;;) {
    		dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
    		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
    	}
    }
    

  • Hi,

    I am also an engineer at the same company as Richard and am looking at this as well.

    Is the gap in asserting the pin due to the startup time of the nRFConnect SDK (or perhaps the RTOS part of it)? 

    In my tests the fastest I can get a pin set on the nrf52840 after a reset using nRFConnect is 250mS. Using SDK 3.2 for thread and zigbee it is instantaneous. I have tried using 

    SYS_INIT(_init_fn, PRE_KERNEL_2, 1);
    to set it as early as possible. This test did not involve a bootloader.
    So if during a DFU the 52840 resets then the pin will not get asserted for the 250ms because nothing can run? Could this be what is happening?
    kind regards
    Liam
  • Liam said:
    SYS_INIT(_init_fn, PRE_KERNEL_2, 1);
    to set it as early as possible.

    You are here waiting until all PRE_KERNEL_1 init is done. So use PRE_KERNEL_1 instead here if you want it to happen earlier. 

    Snippet:

    #include <hal/nrf_gpio.h>
    
    #define MY_PIN 3
    
    static int early_init(const struct device *dev)
    {
    nrf_gpio_cfg_output(MY_PIN);
    nrf_gpio_pin_set(MY_PIN);
    return 0;
    }
    
    SYS_INIT(early_init, PRE_KERNEL_1, 0);

  • I should have mentioned I could not get PRE_KERNEL_1 to work.

    void _init_fn( void )
    {
        int ret;

        if (!device_is_ready(led.port)) {
            return;
        }

        ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
        if (ret < 0) {
            return;
        }

        gpio_pin_set_dt(&led, 0);
    }
    SYS_INIT(_init_fn, PRE_KERNEL_1, 1);

    void main(void)
    {
        int ret;

    I found it would not ever set the pin.

    regards

  • I found it would not ever set the pin.

    AFAIR, the Zephyr GPIO API is initialized at PRE_KERNEL_1 , priority 40 or 60 ... So if you want to set the pin before this, then you need to use the HAL functions(hal/nrf_gpio.h , nrf_gpio_cfg_output , nrf_gpio_pin_set).

Reply Children
No Data
Related