如何实现BLE 最大数据吞吐率并满足设计功耗要求?
文章目錄
- 一、如何提高BLE 數據傳輸速率?
- 1.1 Nordic BLE 最大數據吞吐率是多少?
- 1.2 如何獲知BLE 當前數據吞吐率?
- 1.3 如何提高BLE 數據傳輸速率?
- 1.3.1 LE 1M PHY 最大數據吞吐率
- 1.3.2 LE 2M PHY 最大數據吞吐率
- 1.4 如何同步數據的生產與發送?
- 二、如何設置廣播連接參數以滿足低功耗需求?
- 更多文章:
我們開發的BLE 設備多數都有兩點要求:一是低功耗,電池供電需要持續工作數周甚至數個月;二是將BLE peripheral產生的數據快速傳送給central,傳輸數據功耗較高,提高傳輸速率縮短傳輸時間也有利于降低平均功耗。我們該如何設置廣播參數與連接參數以達到我們要求的功耗呢?該如何設置連接參數與報文長度(PDU / MTU)以盡可能達到最大傳輸速率呢?
一、如何提高BLE 數據傳輸速率?
BLE 數據傳輸相關的服務中有一個比較基礎的串口透傳服務,本文以nRF5_SDK_17.0.2 中的ble_app_uart 工程為例,展示如何提高BLE 的數據傳輸速率。
在嘗試提高BLE 數據傳輸速率前,需要先獲得兩個信息:
1.1 Nordic BLE 最大數據吞吐率是多少?
對于第一個問題,我們可以從Nordic 協議棧規格說明書中獲知,比如使用s132 softdevice 可以參考文檔:S132 SoftDevice SoftDevice Specification v7.1,查閱Bluetooth Low Energy data throughput 章節,數據傳輸速率使用下面的公式:
#define OPCODE_LENGTH 1 #define HANDLE_LENGTH 2Throughput_bps = num_packets * (ATT_MTU - OPCODE_LENGTH - HANDLE_LENGTH) * 8 / seconds這里統計的傳輸數據指的是應用數據,ATT_MTU 減去Attribute protocol PDU Opcode 和Attribute Handle 字段長度,剩下的就是Attribute Value 字段(也即有效的應用數據)。每個字節占8 比特,下表中的傳輸速率單位是kbps(如果要換算成 KB/s 需要除以8),下表Connection interval 與Connection Event Length 相等:
從上表可知,跟傳輸速率相關的因素主要有ATT MTU size、Connection interval、Connection Event Length、Communication Mode、LE PHY speed 等。比如ATT MTU size 為23、Connection interval 與Connection Event Length 取7.5 ms、Communication Mode 為Send Notification、LE 1M PHY 的最大速率為24 KB/s;ATT MTU size 為247、Connection interval 與Connection Event Length 取50 ms、Communication Mode 為Send Notification、LE 2M PHY 的最大速率為165.94 KB/s。
1.2 如何獲知BLE 當前數據吞吐率?
一般BLE peripheral 作為GATT Server 向BLE central 也即GATT Client 傳輸數據,想獲得BLE 當前的數據吞吐率,一般有三種方式:
Nordic 手機端的應用并沒有提供顯示當前數據吞吐率的功能,我們開發GATT Server 應用再去修改BLE central 代碼比較麻煩。BLE sniffer 抓包分析倒是比較方便,wireshark + nRF sniffer 抓包方案容易丟包也沒有直接統計數據吞吐率指標,專業的藍牙分析儀Ellisys Bluetooth Explorer 倒是可以直接統計數據吞吐率,藍牙分析儀成本太高。因此,本文選擇第一種方案,在BLE peripheral 代碼中添加統計數據發送量的功能,并通過RTT Log 打印出來。
我們在.\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart 示例工程的基礎上添加統計單位時間內數據發送量的代碼,Nordic UART Service 我們在博文:如何實現掃碼連接BLE 設備的功能? 中已經介紹過了,二者主要的代碼邏輯差不多,主要有兩點不同:
- ble_app_uart 工程在GAP 階段作為Advertiser,在函數advertising_init 中初始化廣播包內容、廣播間隔、廣播超時時間等,然后在函數advertising_start 中開始廣播;ble_app_uart_c 工程在GAP 階段作為Scanner 和Initiator,在函數scan_init 中設置掃描過濾條件、注冊scan_evt_handler 等,然后在函數scan_start 中開始掃描周圍的廣播設備;
- ble_app_uart 工程在GATT 階段作為GATT Server,在函數services_init --> ble_nus_init 中添加NUS service(包括RX Characteristic、TX Characteristic)、注冊nus_data_handler 等,其中NUS 為Primary Service 對外提供串口透傳服務;ble_app_uart_c 工程在GATT 階段作為GATT Client,在函數db_discovery_init 和nus_c_init 中發現對端設備提供了哪些services(特別是NUS 服務)、注冊db_disc_handler 和ble_nus_c_evt_handler 等,發現NUS 服務后就可以訪問該服務了。
本文就不展開介紹ble_app_uart 工程代碼邏輯了,我們重點關心的是GATT Server 如何使用NUS 服務向GATT Client 發送數據。從函數uart_event_handle 代碼可以看出,使用函數ble_nus_data_send 可以通過NUS 服務向對端設備發送數據,該函數的聲明如下:
// .\nRF5_SDK_17.0.2_d674dde\components\ble\ble_services\ble_nus\ble_nus.h/**@brief Function for sending a data to the peer.** @details This function sends the input string as an RX characteristic notification to the* peer.** @param[in] p_nus Pointer to the Nordic UART Service structure.* @param[in] p_data String to be sent.* @param[in,out] p_length Pointer Length of the string. Amount of sent bytes.* @param[in] conn_handle Connection Handle of the destination client.** @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.*/ uint32_t ble_nus_data_send(ble_nus_t * p_nus,uint8_t * p_data,uint16_t * p_length,uint16_t conn_handle);既然是統計單位時間內GATT Server 發送出去的數據量,自然需要一個定時器資源,我們選用低功耗的app_timer。為了提高數據發送速率,我們選擇Send Notification 模式。為了少做無用功,我們在NUS Notification enable 的情況下再開始發送數據,當連接斷開后便停止發送數據。新增用于統計BLE data throughput 的代碼如下:
// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c/**@brief Resources related to throughput testing.*/ #define DATA_THROUGHPUT_INTERVAL APP_TIMER_TICKS(5) /**< data throughput interval (ticks). */ APP_TIMER_DEF(m_timer_throughput_id);uint32_t m_data_sent_length = 0; uint8_t m_data_array[BLE_NUS_MAX_DATA_LEN] = {0};/**@brief Data generation timer timeout handler function.*/ static void data_throughput_timeout_handler(void * p_context) {UNUSED_PARAMETER(p_context);static uint32_t timeout_count = 0;ret_code_t err_code;timeout_count++;do{uint16_t length = BLE_NUS_MAX_DATA_LEN;err_code = ble_nus_data_send(&m_nus, m_data_array, &length, m_conn_handle);if ((err_code != NRF_ERROR_INVALID_STATE) &&(err_code != NRF_ERROR_RESOURCES) &&(err_code != NRF_ERROR_NOT_FOUND)){APP_ERROR_CHECK(err_code);}if(err_code == NRF_SUCCESS){m_data_sent_length += length;m_data_array[0]++;m_data_array[length-1]++;}} while (err_code == NRF_SUCCESS);// Timer interval 5 ms, when the timer reaches 1 second if(timeout_count == 200){// Send m_data_sent_length bytes of data within 1 second, which is equal to m_data_sent_length * 8 / 1024 kilobits of dataNRF_LOG_INFO("****** BLE data throughput: %d kbps ******", m_data_sent_length >> 7);m_data_sent_length = 0;timeout_count = 0;} }/**@brief Function for initializing the timer module.*/ static void timers_init(void) {......// Create a data generation timer for testing throughput.err_code = app_timer_create(&m_timer_throughput_id, APP_TIMER_MODE_REPEATED, data_throughput_timeout_handler);APP_ERROR_CHECK(err_code); }/**@brief Function for handling the data from the Nordic UART Service.*/ static void nus_data_handler(ble_nus_evt_t * p_evt) {if (p_evt->type == BLE_NUS_EVT_RX_DATA) {......} else if(p_evt->type == BLE_NUS_EVT_COMM_STARTED) {// Start data throughput timers.ret_code_t err_code;err_code = app_timer_start(m_timer_throughput_id, DATA_THROUGHPUT_INTERVAL,NULL);APP_ERROR_CHECK(err_code);} }/**@brief Function for handling BLE events.*/ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) {uint32_t err_code;switch (p_ble_evt->header.evt_id){case BLE_GAP_EVT_CONNECTED:......case BLE_GAP_EVT_DISCONNECTED:......// Stop data throughput timers.err_code = app_timer_stop(m_timer_throughput_id);APP_ERROR_CHECK(err_code);break;case BLE_GAP_EVT_PHY_UPDATE_REQUEST:......} }上述代碼主要包含兩部分:
值得一提的是,每個定時周期可以發送不止一個數據包,博文鏈路層空口報文設計 中提到LE 1M PHY 發送最大PDU 約需2.3 ms,上面的代碼設置的定時周期為5 ms,因此每個定時周期可以發送多個數據包,我們將ble_nus_data_send 放到循環體內,當返回值為NRF_SUCCESS 時繼續循環發送下一個數據包。
通過RTT Log 打印當前BLE 數據吞吐量的代碼已經實現了,編譯工程 --> 將代碼燒錄到nRF52 DK 內,PC 端打開J-Link RTT Viewer,手機端打開nRF Connect for mobile。點擊Enable CCCDs 或者Tx Characteristic 右邊的圖標使能NUS Notification,nRF52 DK 開始通過BLE 向手機端發送數據,nRF Connect --> Show log 可以查看接收到的數據,J-Link RTT Viewer 開始打印當前的BLE 數據吞吐率:
1.3 如何提高BLE 數據傳輸速率?
上圖展示的BLE 數據吞吐率只有41 kbps,遠低于nordic softdevice 支持的最大數據吞吐率,這是怎么回事呢?
BLE 數據吞吐率的計算公式:
Throughput_kbps = num_packets * (ATT_MTU - 3) * 8 / 1000 // num_packets 為單位時間也即 1 秒內發送的數據包個數= (num_packets_interval / CONN_INTERVAL) * (ATT_MTU - 3) * 8 / 1000 // num_packets_interval 為單個連接間隔內發送的數據包個數,CONN_INTERVAL 為連接間隔,單位是秒1.3.1 LE 1M PHY 最大數據吞吐率
上述工程默認的ATT_MTU 值為247,CONN_INTERVAL 為20 ~ 75 ms,由Throughput_kbps 等于41 kbps 可反推出num_packets_interval 等于1(CONN_INTERVAL 取中間值47.5 ms)。一個連接間隔只發送出去一個數據包,這大概是BLE 數據吞吐率這么低的主要原因吧,該如何提高BLE Throughput_kbps 呢?
前面也談到,影響BLE Throughput_kbps 的因素主要有ATT MTU size、Connection interval、Connection Event Length、Communication Mode、LE PHY speed 等,ATT MTU size 已經設置為BLE 支持的最大值247,Connection Event 值為7.5 ms,也即一個連接周期最多只有Connection Event 時間傳輸數據,這個值遠小于Connection interval,我們需要讓Connection Event 占滿Connection interval。為便于跟nordic softdevice 規格說明書中的值對比,這里設置連接參數如下:
編譯工程 --> 燒錄到nRF52 DK,J-Link RTT Viewer 打印RTT Log 信息如下:
在執行函數sd_ble_enable 時返回NRF_ERROR_NO_MEM,也即分配給softdevice 的RAM 空間不足,需要為softdevice 預留更多的空間(也即縮減application 可用RAM 空間)。我們按照RTT Log 調整RAM_Start 和RAM_Size 如下:
重新編譯工程并燒錄代碼,nRF Connect for mobile 使能notification 或CCCDs,J-Link RTT Viewer 打印的BLE 數據吞吐率如下:
BLE 最大數據吞吐率已經達到697 kbps了,很接近nordic softdevice 規格說明書中的702.8 kbps(也即87.85 KB/s),多打印會兒是可以看到BLE data throughput 達到七百以上的,BLE 數據傳輸速率達到了softdevice 支持的最大值。
如果已知Throughput_kbps 值為702.8 kbps,ATT_MTU 值為247,CONN_INTERVAL 值為50 ms,可以通過公式反求出單個連接間隔內發送出去的數據包個數為18,也即每個數據包以send notification 模式發送出去所需的平均時間為2.78 ms(包括radio 啟動和切換時間、協議棧調度時間等)。
1.3.2 LE 2M PHY 最大數據吞吐率
從nordic softdevice 規格說明書可知,還可以使用BLE 5.0 新增的LE 2M PHY 特性進一步提高數據吞吐率。鏈路層使用LE 2M PHY,可以在更短的時間發送完等長度的數據包,也即在一個連接間隔可以發送更多的數據包,實現更大的傳輸速率。
當Connection interval 與Connection event 均為50 ms,ATT_MTU size 為247,采用Send Notification 通信模式和LE 2M PHY 物理鏈路,可以達到的Throughput_kbps 值為1327.5 kbps,通過公式可反求出單個連接間隔內發送出去的數據包個數為34,也即每個數據包以send notification 模式發送出去所需的平均時間為1.47 ms(由于radio 啟動與切換時間、協議棧調度時間基本固定,因此發送單個數據包使用LE 2M PHY 比LE 1M PHY 所需時間的一半略多)。如何啟用LE 2M PHY 呢?
前面通過修改宏變量值就可以更新Data Length 和Connection Parameters,這些更新過程在鏈路層有相應的控制報文交互(參閱博文:Link Layer Control Protocol),對于PHY Update 也有對應的鏈路層控制報文交互。
上述工程ble_app_uart 代碼中跟PHY Update 相關的主要代碼如下:
上面的代碼是處理BLE_GAP_EVT_PHY_UPDATE_REQUEST 事件的,從BLE_GAP_PHYS_SUPPORTED 可以看出nRF52 DK 是支持BLE_GAP_PHY_2MBPS 的,變量phys 的值如果設置為BLE_GAP_PHY_1MBPS 或BLE_GAP_PHY_2MBPS 則強制選擇相應的PHY,上述代碼phys 設置為BLE_GAP_PHY_AUTO 則會自動選擇當前最合適的PHY。如果在BLE central 端請求使用LE 2M PHY,BLE peripheral 端也會更新到LE 2M PHY(前提是BLE central 端與peripheral 端均支持LE 2M PHY,且peripheral 端未強制指定PHY)。
手機端是否支持LE 2M PHY,可以從nRF connect for mobile --> Device information 界面查看“High speed(PHY 2M) supported” 項為“YES” 表示支持LE 2M PHY。nRF connect for mobile 連接到nRF52 DK 廣播名NORDIC_UART 后,點擊“Enable CCCDs”使能NUS Notification,點擊"Set preferred PHY" Tx/Rx PHY 均選擇“LE 2M(Double speed)”。PC 端J-Link RTT Viewer 打印的BLE 數據吞吐率如下:
我們看到了很奇怪的現象,理論上切換到LE 2M PHY,BLE 數據吞吐率應該提高近一倍的,實際情況卻是大幅下降,這是怎么回事呢?
我們也是在每個定時周期循環發送數據包,直到函數ble_nus_data_send 的返回值不為NRF_SUCCESS 或者函數data_throughput_timeout_handler 被更高優先級的中斷搶占(協議棧softdevice 事件的優先級高于application 中斷的優先級)。同樣的代碼LE 1M PHY 可以接近最大數據吞吐率,切換到LE 2M PHY 數據吞吐率反而下降了,我們可以合理猜測循環發送數據包的過程出問題了,也即函數ble_nus_data_send 的返回值不是NRF_SUCCESS 而過早的退出了循環。該如何驗證并解決該問題呢?
這里選用的Send Notification 通信模式,server 可以連續向Client 發送多個數據包而不需要等待response 或Confirmation 報文(Client 可能來不及處理數據包而直接丟棄),因此可以達到較高的數據吞吐率:
調用函數ble_nus_data_send,實際上是將應用層待發送數據指針傳給softdevice 協議棧,放入到radio FIFO 中,當radio 將數據包成功發送出去后,softdevice 協議棧會返回BLE_GATTS_EVT_HVN_TX_COMPLETE 事件通知應用層數據包已成功發送出去。NUS 服務則會返回BLE_NUS_EVT_TX_RDY 事件通知應用層數據包已通過NUS 服務成功發送出去。
前面的問題既然猜測是由函數ble_nus_data_send 返回值非NRF_SUCCESS 而過早退出循環導致每個定時周期發送的數據包太少引起的,我們可以在每次觸發BLE_NUS_EVT_TX_RDY 事件時再次循環調用函數ble_nus_data_send 發送下一個數據包。每成功發送一個數據包觸發一次BLE_NUS_EVT_TX_RDY 事件,調用一次函數ble_nus_data_send,理論上應該能解決上述問題,我們添加如下代碼:
// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c/**@brief Function for handling the data from the Nordic UART Service.*/ static void nus_data_handler(ble_nus_evt_t * p_evt) {if (p_evt->type == BLE_NUS_EVT_RX_DATA) {......} else if(p_evt->type == BLE_NUS_EVT_COMM_STARTED) {// Start data throughput timers.......} else if (p_evt->type == BLE_NUS_EVT_TX_RDY) {ret_code_t err_code;do {uint16_t length = BLE_NUS_MAX_DATA_LEN;err_code = ble_nus_data_send(&m_nus, m_data_array, &length, m_conn_handle);if ((err_code != NRF_ERROR_INVALID_STATE) &&(err_code != NRF_ERROR_RESOURCES) &&(err_code != NRF_ERROR_NOT_FOUND)){APP_ERROR_CHECK(err_code);}if(err_code == NRF_SUCCESS){m_data_sent_length += length;m_data_array[0]++;m_data_array[length-1]++;}} while (err_code == NRF_SUCCESS);} }重新編譯工程并燒錄代碼,nRF Connect for mobile 點擊“Enable CCCDs”使能NUS Notification,點擊"Set preferred PHY" Tx/Rx PHY 均選擇“LE 2M(Double speed)”,J-Link RTT Viewer 打印的BLE 數據吞吐率如下:
切換到LE 2M PHY 后,BLE 數據吞吐率果然大幅提升,上圖顯示吞吐率可以達到1220 kbps (也即152.5 KB/s),已經比較接近nordic softdevice 支持的最大吞吐率1327.5 kbps 了,多打印會兒是可以看到BLE data throughput 達到一千三以上的,BLE 數據傳輸速率達到了softdevice 支持的最大值。
1.4 如何同步數據的生產與發送?
前面的代碼直接對數組首尾字節自增后發送,實際應用場景中都是將斷開連接期間暫時保存在本設備的數據或者sensor 實時產生的數據,在BLE 建立連接后分包發送給BLE Central 設備。如何保證數據包的有序發送呢?
我們很容易想到,可以借助FIFO 緩沖隊列實現數據包的有序發送,這里使用nordic 提供的queue 庫,生產出來的待發送數據有序入隊,要發送的數據從隊列中取用即可。
我們將上述持續發送BLE 數據包的代碼修改為使用queue 的形式,首先需要將目錄 .\nRF5_SDK_17.0.2_d674dde\components\libraries\queue 下的源文件和頭文件路徑添加進工程中,再在main.c 文件中包含"nrf_queue.h" 頭文件,在main.c 中添加或修改如下代碼:
// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c ...... #include "nrf_queue.h" ...... #define QUEUE_ELEMENT_NUMBERS 32 #define PKGS_PER_TIMER_PERIOD 8uint8_t m_data_array[QUEUE_ELEMENT_NUMBERS][BLE_NUS_MAX_DATA_LEN] = {0}; typedef struct {uint8_t * p_data;uint16_t length; } m_element_t;NRF_QUEUE_DEF(m_element_t, m_buf_queue, QUEUE_ELEMENT_NUMBERS, NRF_QUEUE_MODE_NO_OVERFLOW); ...... /**@brief Use queue to send ble data.*/ void ble_data_send_with_queue(void) {ret_code_t err_code;m_element_t data_item;uint16_t length = BLE_NUS_MAX_DATA_LEN;while(!nrf_queue_is_empty(&m_buf_queue)){err_code = nrf_queue_pop(&m_buf_queue, &data_item);APP_ERROR_CHECK(err_code);length = MIN(length, data_item.length);err_code = ble_nus_data_send(&m_nus, data_item.p_data, &length, m_conn_handle);if ((err_code != NRF_ERROR_INVALID_STATE) &&(err_code != NRF_ERROR_RESOURCES) &&(err_code != NRF_ERROR_NOT_FOUND)){APP_ERROR_CHECK(err_code);}if(err_code == NRF_SUCCESS)m_data_sent_length += length;elsebreak;} }/**@brief Data generation timer timeout handler function.*/ static void data_throughput_timeout_handler(void * p_context) {UNUSED_PARAMETER(p_context);static uint32_t timeout_count = 0;ret_code_t err_code;static uint8_t value = 0;m_element_t data_item;uint16_t length = BLE_NUS_MAX_DATA_LEN;uint8_t pkgs = PKGS_PER_TIMER_PERIOD;timeout_count++;while (!nrf_queue_is_full(&m_buf_queue) && pkgs--){m_data_array[value % QUEUE_ELEMENT_NUMBERS][0] = value;m_data_array[value % QUEUE_ELEMENT_NUMBERS][length-1] = value;data_item.p_data = &m_data_array[value % QUEUE_ELEMENT_NUMBERS][0];data_item.length = length;err_code = nrf_queue_push(&m_buf_queue, &data_item);APP_ERROR_CHECK(err_code);value++;}ble_data_send_with_queue();// Timer interval 5 ms, when the timer reaches 1 second if(timeout_count == 200){// Send m_data_sent_length bytes of data within 1 second, which is equal to m_data_sent_length * 8 / 1024 kilobits of dataNRF_LOG_INFO("****** BLE data throughput: %d kbps ******", m_data_sent_length >> 7);m_data_sent_length = 0;timeout_count = 0;value = 0;} } ...... /**@brief Function for handling the data from the Nordic UART Service.*/ static void nus_data_handler(ble_nus_evt_t * p_evt) {if (p_evt->type == BLE_NUS_EVT_RX_DATA) {......} else if(p_evt->type == BLE_NUS_EVT_COMM_STARTED) {......} else if(p_evt->type == BLE_NUS_EVT_TX_RDY) {ble_data_send_with_queue();} }使用queue 同步數據的產生與發送,隊列未滿時將生產的數據入隊,隊列非空時從隊列中取出下一個元素通過調用函數ble_nus_data_send 將其發送出去。
編譯工程報錯,提示nrf_queue 函數未定義,我們需要在sdk_config.h 文件中啟用NRF_QUEUE 模塊相關的宏變量如下:
// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\pca10040\s132\config\sdk_config.h#define NRF_QUEUE_ENABLED 1重新編譯工程并燒錄代碼,nRF Connect for mobile 點擊“Enable CCCDs”使能NUS Notification,點擊"Set preferred PHY" Tx/Rx PHY 均選擇“LE 2M(Double speed)”,J-Link RTT Viewer 打印的BLE 數據吞吐率如下:
使用queue 同步數據產生與發送,PHY 使用LE 1M 時最大數據吞吐率為726 kbps,PHY 切換到LE 2M 時最大數據吞吐率為1334 kbps,均略高于nordic softdevice 支持的最大值,達到了我們預期的效果。
二、如何設置廣播連接參數以滿足低功耗需求?
我們開發的BLE peripheral 多數都有低功耗要求,由電池供電,如何滿足電池續航需求呢?
Nordic 提供了nRF 芯片理論功耗計算網頁Online Power Profiler for BLE,我們可以在該頁面修改參數,看理論功耗是否滿足我們的設計要求。如果已經試產出產品了,也可以借助Power Profiler Kit 或Power Profiler Kit II 測量產品的真實功耗。
假設我們使用CR2032 紐扣電池(額定容量為220 mAh,額定電壓3.0 V)供電,使用壽命一年,每天平均連接兩個小時,其余時間處于idle 空閑狀態,我們該如何設置廣播參數與連接參數,以滿足我們的設計續航要求呢?
假設我們選用nRF52832 芯片,Idle current 為2 uA,全年待機共消耗電量 = 365 * 24 * 2 uAh = 17.52 mAh。在產品壽命期間,BLE 連接通信時間約730 小時,可供BLE 連接消耗的電量約200 mAh,BLE 連接的平均功耗為274 uA。電池并不僅僅為BLE 通信供電,還為必要的傳感器與外設工作供電,考慮到傳感器與外設工作的時間比BLE 連接通信的時間更長,我們假設僅電池電量的1/3 供BLE 廣播連接通信使用,其余2/3 為傳感器和芯片外設工作供電,因此BLE 廣播連接通信的平均功耗應控制在90 uA 左右。我們在Online Power Profiler for BLE 頁面配置如下參數:
芯片選擇nRF52832、CR2032 的額定電壓為3.0 V、穿戴設備Radio Tx Power 選擇 0 dBm 可以滿足傳輸距離需求(可根據BLE 在空氣中的路徑損耗公式,結合通訊距離要求選擇合適的Tx Power)。
DC/DC regulator 是一種效率很高的穩壓器,原理是DC->AC->DC,既可以升壓也可以降壓。與之相比,還有一種低成本的LDO (Low Dropout regulator) 穩壓器,效率比DC/DC 低些,只能降壓使用且對輸入輸出電壓差有限制。如果想達到更低的功耗,可以選擇DC/DC,如果想進一步降低成本,可以選擇LDO。這里我們選擇更高效率的DC/DC regulator。
BLE 芯片通常需要兩個時鐘信號,比如nRF52 DK 上高頻晶振頻率為32 MHz、低頻晶振頻率為32.768 KHz,高頻晶振驅動MCU 和高速外設工作,低頻晶振可以大幅降低芯片的待機功耗(idle 或sleep 狀態耗電的高頻時鐘關閉,僅保留低頻時鐘方便計時和喚醒)。高頻時鐘信號都需要外部晶振提供,低頻時鐘信號既可以外部晶振提供也可以使用MCU 內部的RC 振蕩器獲得。如果使用MCU 內部的RC 振蕩器作為低頻時鐘則需要定期對其進行校準,需要大概 1.0 uA 的校準電流,且時鐘精度略低些(較低的時鐘精度也會增加BLE 通訊功耗)。
配置低頻時鐘信號的代碼如下(工程ble_app_uart 默認選擇的外部晶振作為低頻時鐘信號,若想選擇MCU 內部振蕩器作為低頻時鐘,修改sdk_config.h 中如下的四個宏變量值即可,本文選擇默認的外部晶振):
// .\nRF5_SDK_17.0.2_d674dde\components\softdevice\common\nrf_sdh.c/**@brief Function for requesting to enable the SoftDevice, is called in the function ble_stack_init.*/ ret_code_t nrf_sdh_enable_request(void) {......nrf_clock_lf_cfg_t const clock_lf_cfg ={.source = NRF_SDH_CLOCK_LF_SRC,.rc_ctiv = NRF_SDH_CLOCK_LF_RC_CTIV,.rc_temp_ctiv = NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,.accuracy = NRF_SDH_CLOCK_LF_ACCURACY};...... }// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\pca10040\s132\config\sdk_config.h ...... // <h> Clock - SoftDevice clock configuration //========================================================== // <o> NRF_SDH_CLOCK_LF_SRC - SoftDevice clock source.// <0=> NRF_CLOCK_LF_SRC_RC // <1=> NRF_CLOCK_LF_SRC_XTAL // <2=> NRF_CLOCK_LF_SRC_SYNTH #ifndef NRF_SDH_CLOCK_LF_SRC #define NRF_SDH_CLOCK_LF_SRC 1 #endif// <o> NRF_SDH_CLOCK_LF_RC_CTIV - SoftDevice calibration timer interval. #ifndef NRF_SDH_CLOCK_LF_RC_CTIV #define NRF_SDH_CLOCK_LF_RC_CTIV 0 #endif// <o> NRF_SDH_CLOCK_LF_RC_TEMP_CTIV - SoftDevice calibration timer interval under constant temperature. // <i> How often (in number of calibration intervals) the RC oscillator shall be calibrated // <i> if the temperature has not changed.#ifndef NRF_SDH_CLOCK_LF_RC_TEMP_CTIV #define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 0 #endif// <o> NRF_SDH_CLOCK_LF_ACCURACY - External clock accuracy used in the LL to compute timing.// <0=> NRF_CLOCK_LF_ACCURACY_250_PPM // <1=> NRF_CLOCK_LF_ACCURACY_500_PPM // <2=> NRF_CLOCK_LF_ACCURACY_150_PPM // <3=> NRF_CLOCK_LF_ACCURACY_100_PPM // <4=> NRF_CLOCK_LF_ACCURACY_75_PPM // <5=> NRF_CLOCK_LF_ACCURACY_50_PPM // <6=> NRF_CLOCK_LF_ACCURACY_30_PPM // <7=> NRF_CLOCK_LF_ACCURACY_20_PPM // <8=> NRF_CLOCK_LF_ACCURACY_10_PPM // <9=> NRF_CLOCK_LF_ACCURACY_5_PPM // <10=> NRF_CLOCK_LF_ACCURACY_2_PPM // <11=> NRF_CLOCK_LF_ACCURACY_1_PPM #ifndef NRF_SDH_CLOCK_LF_ACCURACY #define NRF_SDH_CLOCK_LF_ACCURACY 7 #endifBLE 廣播通信階段作為Advertising(connectable) role,假設TX payload 為31 bytes,當設置Advertising interval 為160 ms 時,Total average current 為87 uA,可滿足我們的功耗需求,我們可以設置如下的宏變量(將Advertising interval 設置為160 ms):
// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c ...... #define APP_ADV_INTERVAL 256 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 160 ms). */ #define APP_ADV_DURATION 18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */ ......BLE 連接通信階段作為Connection(peripheral) role,啟用Data Packet Length Extension 和Connection Event Length Extension,假設TX payload per event 和RX payload per event 均為251 bytes,選擇LE 1M PHY,我們在Online Power Profiler for BLE 頁面配置如下參數:
我們配置較小的Connection interval 可以在BLE peripheral 有數據傳輸需求時及時通知BLE central,配置較大的Slave latency 可以讓BLE peripheral 在沒有數據傳輸需求時跳過一定的連接事件以降低功耗。我們配置Connection interval 為25 ms、Slave latency 為 14 時,Total average current 為89 uA,可滿足我們的功耗需求,我們可以設置如下的宏變量:
本工程源碼下載地址:https://github.com/StreamAI/Nordic_nRF5_Project/tree/main/examples/ble_peripheral\ble_app_uart。
更多文章:
- 《如何抓包分析BLE 空口報文(GAP + GATT + LESC procedure)?》
- 《如何實現掃碼連接BLE 設備的功能?》
- 《Nordic_nRF5_Project》
- 《Nordic nRF5 SDK documentation》
- 《BLE 技術(三)— Link Layer Packet format 》
- 《BLE 技術(四)— Link Layer communication protocol 》
- 《BLE 技術(五)— Generic Access Profile》
- 《BLE 技術(六)— GATT Profile + ATT protocol》
- 《Bluetooth Core Specification_v5.2》
總結
以上是生活随笔為你收集整理的如何实现BLE 最大数据吞吐率并满足设计功耗要求?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑端“一键“获得一个手机端截屏
- 下一篇: 计算机组装功耗,浅谈组装电脑之电脑功耗电