nRF52832增加BLE外设连接数后无法广播的排查咨询
作为嵌入式系统新手,尝试修改sdk.config中的nrf_sdh_ble_peripheral_link_count来增加nRF52832的BLE外设连接数,但调整后设备完全无法广播。相关代码如下:
static uint16_t m_connection_handle[NRF_SDH_BLE_PERIPHERAL_LINK_COUNT] = {BLE_CONN_HANDLE_INVALID}; static uint8_t m_num_connections = 0; static void on_advertising_events(ble_adv_evt_t advertising_event) { NRF_LOG_DEBUG("on_advertising_events - event: %d", advertising_event); ret_code_t err_code; switch (advertising_event) { case BLE_ADV_EVT_FAST: NRF_LOG_INFO("Fast advertising."); #ifdef BOARD_PCA10040 err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING); APP_ERROR_CHECK(err_code); #endif break; case BLE_ADV_EVT_IDLE: if (m_num_connections < NRF_SDH_BLE_PERIPHERAL_LINK_COUNT) { err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST); APP_ERROR_CHECK(err_code); } break; default: break; } } static void on_ble_events(ble_evt_t const * p_ble_event, void * p_context) { NRF_LOG_DEBUG("on_ble_events - event: %d", p_ble_event->header.evt_id); ret_code_t err_code = NRF_SUCCESS; switch (p_ble_event->header.evt_id) { case BLE_GAP_EVT_DISCONNECTED: NRF_LOG_INFO("Disconnected - Reason: %d", p_ble_event->evt.gap_evt.params.disconnected.reason); m_mtu_exchanged = false; break; case BLE_GAP_EVT_CONNECTED: { NRF_LOG_INFO("Connected."); #if BOARD_PCA10040 err_code = bsp_indication_set(BSP_INDICATE_CONNECTED); APP_ERROR_CHECK(err_code); #endif if (m_num_connections < NRF_SDH_BLE_PERIPHERAL_LINK_COUNT){ m_connection_handle[m_num_connections++] = p_ble_event->evt.gap_evt.conn_handle; } // Trigger the MTU exchange timer NRF_LOG_INFO("Trigger MTU exchange timer."); if (pdPASS != xTimerStart(m_mtu_exchange_timer, OSTIMER_WAIT_FOR_QUEUE)) { NRF_LOG_WARNING("Failed to start MTU exchange timer"); } NRF_LOG_DEBUG("### Configuration:"); NRF_LOG_DEBUG("### Connection Interval: %d (ms)", MAX_CONN_INTERVAL * 1.25); NRF_LOG_DEBUG("### Connection Event Length: %d (ms)", NRF_SDH_BLE_GAP_EVENT_LENGTH * 1.25); NRF_LOG_DEBUG("### Connection Event Length Extension: %d", 0); NRF_LOG_DEBUG("### ATT MTU: %d", NRF_SDH_BLE_GATT_MAX_MTU_SIZE); NRF_LOG_DEBUG("### Data Length: %d", NRF_SDH_BLE_GAP_DATA_LENGTH); } break; case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { NRF_LOG_DEBUG("PHY update request."); ble_gap_phys_t const phys = { .rx_phys = BLE_GAP_PHY_AUTO, .tx_phys = BLE_GAP_PHY_AUTO, }; err_code = sd_ble_gap_phy_update(p_ble_event->evt.gap_evt.conn_handle, &phys); APP_ERROR_CHECK(err_code); } break; case BLE_GATTC_EVT_TIMEOUT: // Disconnect on GATT Client timeout event. NRF_LOG_DEBUG("GATT Client Timeout."); err_code = sd_ble_gap_disconnect(p_ble_event->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); break; case BLE_GATTS_EVT_TIMEOUT: // Disconnect on GATT Server timeout event. NRF_LOG_DEBUG("GATT Server Timeout."); err_code = sd_ble_gap_disconnect(p_ble_event->evt.gatts_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_CONN_PARAM_UPDATE: { NRF_LOG_DEBUG("BLE_GAP_EVT_CONN_PARAM_UPDATE"); ble_gap_conn_params_t const * p_connection = &p_ble_event->evt.gap_evt.params.conn_param_update.conn_params; NRF_LOG_DEBUG("max_conn_interval: %d ms", p_connection->max_conn_interval * 1.25); NRF_LOG_DEBUG("min_conn_interval: %d ms", p_connection->min_conn_interval * 1.25); NRF_LOG_DEBUG("slave_latency: %d", p_connection->slave_latency); NRF_LOG_DEBUG("conn_sup_timeout: %d ms", p_connection->conn_sup_timeout * 10); } break; default: // No implementation needed. break; } } static void disconnect(uint16_t connection_handle, void * p_context) { UNUSED_PARAMETER(p_context); ret_code_t err_code = sd_ble_gap_disconnect(connection_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); if (err_code != NRF_SUCCESS) { NRF_LOG_WARNING("Failed to disconnect connection. Connection handle: %d Error: %d", connection_handle, err_code); } else { NRF_LOG_DEBUG("Disconnected connection handle %d", connection_handle); // Find and remove the connection handle from the array for (int i = 0; i < NRF_SDH_BLE_PERIPHERAL_LINK_COUNT; ++i) { if (m_connection_handle[i] == connection_handle) { m_connection_handle[i] = BLE_CONN_HANDLE_INVALID; m_num_connections--; break; } } // Restart advertising if necessary if (m_num_connections < NRF_SDH_BLE_PERIPHERAL_LINK_COUNT) { start_ble_advertising(NULL); // Adjust parameters as needed } } }
以下是需要检查的关键事项:
同步调整总连接数配置:
只修改nrf_sdh_ble_peripheral_link_count不够,必须同步调整sdk.config中的nrf_sdh_ble_total_link_count,这个参数定义了SoftDevice支持的总连接数(外设+中心角色)。如果总连接数小于外设连接数,SoftDevice初始化会直接失败,导致无法启动广播。检查内存资源是否充足:
nRF52832只有64KB RAM,多连接会占用更多内存:- 增大
HEAP_SIZE配置,每个BLE连接需要1-2KB左右的堆内存存储上下文,堆不足会导致SoftDevice初始化失败或运行时崩溃。 - 查看编译后的内存使用报告,确认剩余RAM是否足够承载目标连接数的需求。
- 降低
NRF_SDH_BLE_GATT_MAX_MTU_SIZE、NRF_SDH_BLE_GAP_DATA_LENGTH等参数,过大的MTU或数据长度会额外占用RAM。
- 增大
验证SoftDevice初始化状态:
在代码中检查sd_ble_enable()和nrf_sdh_enable_request()的返回值,如果返回NRF_ERROR_NO_MEM等错误码,说明资源不足导致初始化失败,无法启动广播。修复连接计数逻辑漏洞:
当前代码仅在自定义disconnect函数中更新m_num_connections,但当远程设备主动断开触发BLE_GAP_EVT_DISCONNECTED事件时,没有处理连接计数的减少,会导致m_num_connections值错误,进而在BLE_ADV_EVT_IDLE时不会重启广播。需要在BLE_GAP_EVT_DISCONNECTED事件中调用disconnect函数,或者手动遍历m_connection_handle数组找到对应的连接句柄并更新计数。调整广播与连接参数:
- 检查广播配置:多连接模式下,广播间隔不能设置过小,否则会占用过多无线资源,导致无法正常处理连接请求或维持现有连接。
- 调整
NRF_SDH_BLE_GAP_EVENT_LENGTH:连接事件长度需要适配多连接场景,确保每个连接都有足够的时间完成通信,否则会导致连接不稳定或广播无法启动。 - 优化连接间隔:如果连接间隔设置过小,会让无线资源被现有连接占满,无法腾出时间进行广播。
内容的提问来源于stack exchange,提问作者newtotech

