DFU Bootloader using BLE + UART: I need to selectively not initialise UART

I have a customised bootloader using uart + BL, built from the SDK examples and modified using articles found here. It works - most of the time. The product is a cusom board which provides connections to the outside world either by uart or by gpio signalling. Both are provided - it's up tto the customer which method they use.

My issue is thus: If the uart is initialised without an interface physical connection, the system hangs (and in my case the watchdog resets it). I discovered this when developing my application and I got around it by checking the gpio line first as the "idle" state of a logic-level uart is high, and only initialising the uart if there is a signal present.

For this same reason, the BLE+UART Bootloader crashes if there is no physical interface connected. So I want to prevent the uart service from running in the same way. But I'm finding it difficult to follow the SDK code, especailly as documentation is scant.

So can you advise the best way for me to skip the uart listener at runtime?

  • From memory, it just hangs without a physical connection.

    I have a reliable way to detect the connection.This is my mechanism:

    • Set pin as input with pulldown
    • Check for input (with timeout), set no_uart flag
    • Set pin to default
    • If no_uart is false initialise uart
    • All functions with printf() check no_uart flag

    ..this works 100% with my application

    So again my question isn't about the uart detection, it's how I select which transport is used.

    It seems to be here in nrf_dfu_transport.c

    uint32_t nrf_dfu_transports_init(nrf_dfu_observer_t observer)
    {
        uint32_t const num_transports = DFU_TRANS_SECTION_ITEM_COUNT;
        uint32_t ret_val = NRF_SUCCESS;
    
        NRF_LOG_DEBUG("Initializing transports (found: %d)", num_transports);
    
        for (uint32_t i = 0; i < num_transports; i++)
        {
            nrf_dfu_transport_t * const trans = DFU_TRANS_SECTION_ITEM_GET(i);
            ret_val = trans->init_func(observer);
            if (ret_val != NRF_SUCCESS)
            {
                NRF_LOG_DEBUG("Failed to initialize transport %d, error %d", i, ret_val);
                break;
            }
        }
    
        return ret_val;
    }

    ...but I can't see how this works

  • It executes the init functions registered with the DFU_TRANSPORT_REGISTER() macro. These will be placed in the .dfu_trans linker section. If you want to select which transport to initialize, I suggest exposing the init functions from the transports and calling them directly.

Related