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?

Parents
  • Hello,

    The way it normally works is that the bootloader initializes both the serial and BLE transport, and the bootloader will thenwait for DFU to be initiated on either transport. The first transport that receives the DFU start command will 'close' the other transport.

    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.

    Since the UART bus may be physically disconnected, I recommend enabling the internal pull-up resistor on the RX line to prevent this input from floating. You can do it by adding this line after UART init but before RX enable:

    NRF_GPIO->PIN_CNF[RX_PIN_NUMBER] |= GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos;

    If the RX input is left floating, it will often lead to an NRF_DRV_UART_EVT_ERROR error event.

    Best regards,

    Vidar

  • Hi Vidar,

    Sorry if this sounds rude, but is this a known solution, or your educated guess? For example I would expect that the uart initialisation code sets up the gpio itself so I would expect the pullup to be disabled in that case.

    Irerspective, I would still like to know how I can selectively skip the uart transport if possible.

  • It's common practice to enable the pull-up on the RX line if the bus may become disconnected. You are correct that the UART configures the GPIO without the pull-up enabled.

    You may connect a debugger to your board to check if the NRF_DRV_UART_EVT_ERROR event is raised as I suspect, or if the bootloader hangs due to something else.

    Nick_RA said:
    Irerspective, I would still like to know how I can selectively skip the uart transport if possible.

    You can't reliably read the signal level if the input is floating, so you would need another way to determine if the UART is connected.

  • 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

Reply
  • 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

Children
Related