Crash on bt_le_adv_stop() and bt_le_update_data() when updating advertising data (nRF5340)

Hi Nordic team,

I'm encountering a crash when attempting to stop BLE advertising using bt_le_adv_update_data() and bt_le_adv_stop() on the nRF5340. Below are the details:
Environment:
SoC: nRF5340
SDK: nrf connect SDK v2.6.1
Role: Peripheral
Toolchain: nRF Connect SDK v2.7.0
Issue Summary:
BLE advertising starts successfully via bt_le_adv_start().
However, when I attempt to update advertising with bt_le_adv_update_data() or bt_le_adv_stop()+bt_le_adv_start(), a hard fault occurs inside bt_hci_cmd_send_sync().
Minimal Reproduction Code:
#if defined(CONFIG_BT)



/*
 * Static variables
 */
static struct bt_conn *s_p_conn;
static struct bt_gatt_exchange_params s_exchange_params;    /* Variable that holds callback for MTU negotiation */
static uint32_t s_adv_update_timer;
static uint8_t s_adv_packet_raw[ADV_PACKET_LEN];
static uint8_t s_scan_rsp_raw[SCAN_RSP_LEN];
static bool s_is_advertising = false;

/* Advertise Packet */
static struct bt_data s_adv_data[] =
{
    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    BT_DATA(BT_DATA_MANUFACTURER_DATA, s_adv_packet_raw, ADV_PACKET_LEN),
};
static struct bt_data s_scan_rsp_data[] =
{
    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    BT_DATA(BT_DATA_MANUFACTURER_DATA, s_scan_rsp_raw, SCAN_RSP_LEN)
};

/* Advertise Parameters */
static struct bt_le_adv_param *s_p_adv_param =
    BT_LE_ADV_PARAM(
        BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_IDENTITY,
        BLE_MIN_ADV_INTERVAL, BLE_MAX_ADV_INTERVAL, NULL);


/*
  * @fn          blep_nrf_start_adv
  * @brief       set advertise data from saved data
 */
static void blep_nrf_start_adv(void){
    int err = 0;

    uint8_t adv_format = STANDARD_ADVERTISING;
    DBG_PRINT_INFO("BLE advertise start\n");
    blep_nrf_set_adv_packet(adv_format);
    blep_nrf_set_scan_rsp_packet();

    s_adv_update_timer = util_timer_create(false, blep_nrf_update_adv_packet);
    uint32_t adv_interval = 10000;//unit ms
    int rc = util_timer_start(s_adv_update_timer, adv_interval);
    if( rc < 0 ){
        DBG_PRINT_FATAL("  - !! Fail to start timer\n");
    }

    switch(adv_format){
        case STANDARD_ADVERTISING:
            err = bt_le_adv_start(s_p_adv_param, s_adv_data, ARRAY_SIZE(s_adv_data), NULL, 0);
            DBG_PRINT_INFO("STANDARD ADV start\n");
            break;
        case EXTENDED_ADVERTISING:
            
            break;
        case SENSOR_BROADCAST:
            
            //
            break;
        default:
            //
            break;
    }

    if(err < 0)
    {
        blep_nrf_print_error_no(BLEP_NRF_ERR_ADV_START, err);
        return;
    }
    s_is_advertising = true;
}

/**
 * @fn          blep_nrf_set_adv_packet
 * @brief       set advertise data
 * @param       advertise_format         advertise format
 */
static void blep_nrf_set_adv_packet(uint8_t advertise_format)
{
    uint16_t param_len;
    rb_param_union_t *p_saved_param;

    memset(s_adv_packet_raw, 0x00, sizeof(s_adv_packet_raw));

    s_adv_packet_raw[COMPANY_ID_OFFSET]     = BLE_COMPANY_ID_CODE & 0xFF;
    s_adv_packet_raw[COMPANY_ID_OFFSET + 1] = (BLE_COMPANY_ID_CODE >> 8) & 0xFF;
    s_adv_packet_raw[FRAME_TYPE_OFFSET]     = 0x01;//frame type

    switch(advertise_format){
        case STANDARD_ADVERTISING:
            s_adv_packet_raw[ST_PRODUCT_ID_OFFSET] = 0xA1;
            s_adv_packet_raw[ST_FW_VER_OFFSET] = 0x00;
            util_byteorder_put_le16(v_bat, &s_adv_packet_raw[ST_BATTEY_OFFSET]);
            s_adv_packet_raw[ST_UPDATE_FLAG_OFFSET] = 0x01;
            s_adv_packet_raw[ST_TEMPERATURE_OFFSET] = 0x01;//get temp
            s_adv_packet_raw[ST_DEV_STATUS_OFFSET] = 0x01;//TODO need fix specification and RAM partetion
            s_adv_packet_raw[ST_ERR_STATUS_OFFSET] = 0x01;
            break;
        case EXTENDED_ADVERTISING:
            //
            break;
        case SENSOR_BROADCAST:
            //
            break;
        default:
            //
            break;
    }
}
/**
 * @fn          blep_nrf_set_scan_rsp_packet
 * @brief       set scan response data
 */
static void blep_nrf_set_scan_rsp_packet(void)
{
    memset(s_scan_rsp_raw, 0x00, sizeof(s_scan_rsp_raw));
    s_scan_rsp_raw[SR_LENGTH_OFFSET] = BLE_SCAN_RSP_LEN;
    s_scan_rsp_raw[SR_AD_TYPE_OFFSET] = BLE_SCAN_RSP_AD_TYPE;
    s_scan_rsp_raw[SR_COMPANY_ID_OFFSET]     = (uint8_t)(BLE_COMPANY_ID_CODE & 0xFF);
    s_scan_rsp_raw[SR_COMPANY_ID_OFFSET + 1] = (uint8_t)((BLE_COMPANY_ID_CODE >> 8) & 0xFF);//util_byteorder_put_le16(BLE_COMPANY_ID_CODE, &s_scan_rsp_raw[SR_COMPANY_ID_OFFSET]);
}

/**
 * @fn          blep_nrf_update_adv_packet
 * @brief       set advertisement data and scan response data at advertise setting command
 *              or timer.
 * @param       advertise_format         advertise format
 */
void blep_nrf_update_adv_packet(void)
{
    uint16_t param_len;
    rb_param_adv_t *p_saved_param;
    int err = 0;

    err = bt_le_adv_stop();
    if(err < 0)
    {
        blep_nrf_print_error_no(BLEP_NRF_ERR_ADV_START, err);
        return;
    }

    uint8_t adv_format = STANDARD_ADVERTISING;
    DBG_PRINT_INFO("update advertise packet\n");
    blep_nrf_set_adv_packet(adv_format);
    blep_nrf_set_scan_rsp_packet();

    if(!s_is_advertising) return;

    switch(adv_format){
        case STANDARD_ADVERTISING:
            //err = bt_le_adv_update_data(s_adv_data, ARRAY_SIZE(s_adv_data), NULL, 0);
            err = bt_le_adv_start(s_p_adv_param, s_adv_data, ARRAY_SIZE(s_adv_data), NULL, 0);
            DBG_PRINT_INFO("STANDARD ADV re-start\n");
            break;
        case EXTENDED_ADVERTISING:

            break;
        case SENSOR_BROADCAST:

            break;
        default:
            //
            break;
    }

    if(err < 0)
    {
        blep_nrf_print_error_no(BLEP_NRF_ERR_ADV_START, err);
        return;
    }
}

/**
 * @fn          blep_nrf_print_error_no
 * @brief       Print error number
 * @param       err_num         Error number
 * @param       err_code        Error code from API
 */
static void blep_nrf_print_error_no(uint16_t err_num, int err_code)
{
    DBG_PRINT_ERROR("[blep_nrf] 0x%04x(%d)\n", err_num, err_code);
}

/**
 * @fn          blep_nrf_init
 * @brief       BLE stack initialization
 */
static void blep_nrf_init(void)
{
    bt_addr_t   addr;
    int         err;

    bt_conn_cb_register(&s_conn_cb);
    err = bt_enable(NULL);
    if(err < 0)
    {
        blep_nrf_print_error_no(BLEP_NRF_ERR_BT_EN, err);
        return;
    }

    if(blep_nrf_get_addr(&addr))
    {
        blep_nrf_set_addr(&addr);
    }

    err = bt_set_name(BLE_DEV_NAME);
    if(err < 0)
    {
        blep_nrf_print_error_no(BLEP_NRF_ERR_DEV_NAME, err);
        return;
    }

    blep_nrf_start_adv();
}

#endif
What I Have Tried:
  • Verified that advertising is active (s_is_advertising = true) before calling bt_le_adv_stop()&bt_le_adv_update_data()
  • Checked that no connection exists (bt_conn_lookup_state_le() returns NULL)
  • Used both bt_le_adv_update_data() and bt_le_adv_stop()+bt_le_adv_start() pattern
  • Ensured bt_enable() completes successfully
 Questions:
Am I using bt_le_adv_update_data() or bt_le_adv_stop() incorrectly?
Any guidance or similar experience would be greatly appreciated.
Thank you in advance!
  • The issue in this question has been resolved.
    I realized that the cause was directly calling functions like bt_le_adv_stop from a timer.
    While investigating the communication between the app core and net core, I found that semaphores were being used.
    Since the BLE stack also uses semaphores in its processing, calling such functions from a timer likely prevents them from operating in blocking mode, which seems to be the cause of the problem.

    By having the timer issue a message and handling the processing in a thread instead, the system now works correctly.

Related