藍(lán)牙BLE芯片Ti CC2541 Notify最大吞吐量解析

關(guān)于CC2541吞吐量的最權(quán)威測試來自Ti官方的wiki:http://processors.wiki.ti.com/index.php/CC2540_Data_Throughput

這篇文章里面其實(shí)一共也沒幾句話,然后配了一個(gè)圖和一個(gè)源碼包。。但信息量還是蠻大的。。

首先解釋一下為數(shù)不多的這幾句話:

This is example modification of CC2540 SimpleBLEPeripheral application to measure user data throughput. Initial testing shows we can reach 5.9K bytes per second. 

This is using a 10ms connection interval and 20 user data bytes sent in GATT notifications. 4 notifications are sent every 7ms, based on an OSAL timer. When sending the notifications, a check is made to see if a buffer is available. 

In all, 1000 notifications are sent. This is 20K bytes, which are sent over 3.35 seconds. 

首先,這個(gè)測試吞吐量的例子是用SimpleBLEPeripheral項(xiàng)目修改得到的,從源碼來看確實(shí)也沒做什么大的改動(dòng),主要是調(diào)小了連接間隔,并添加了定時(shí)器來規(guī)律的通過Notify發(fā)送數(shù)據(jù)。

測量結(jié)果聲稱達(dá)到了5.9K/s,但按照理論計(jì)算,10ms的連接間隔說明1秒內(nèi)觸發(fā)100次連接事件,而每個(gè)連接事件內(nèi)觸發(fā)4次射頻發(fā)送(Tx),每個(gè)Tx攜帶最大的20字節(jié)數(shù)據(jù),那么這個(gè)理論值應(yīng)該是8K/s,也就是說實(shí)測數(shù)值低于理論數(shù)值。

再看一下代碼實(shí)現(xiàn),主要有這么幾個(gè)步驟:

  1. 主機(jī)端將連接間隔設(shè)置到主從設(shè)備雙方可接收的最小限度,在外設(shè)初始化的回調(diào)里有如下代碼:
GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &enable_update_request );
GAPRole_SetParameter( GAPROLE_MIN_CONN_INTERVAL, sizeof( uint16 ), &desired_min_interval );
GAPRole_SetParameter( GAPROLE_MAX_CONN_INTERVAL, sizeof( uint16 ), &desired_max_interval );
GAPRole_SetParameter( GAPROLE_SLAVE_LATENCY, sizeof( uint16 ), &desired_slave_latency );
GAPRole_SetParameter( GAPROLE_TIMEOUT_MULTIPLIER, sizeof( uint16 ), &desired_conn_timeout );

其中GAPROLE_PARAM_UPDATE_ENABLE是要求外設(shè)向主設(shè)備發(fā)起更新連接參數(shù)申請,并提交自己期望的連接參數(shù)配置。
之后主設(shè)備會(huì)根據(jù)自己的情況決定采納該配置或拒絕。若采納該配置,則主設(shè)備會(huì)調(diào)用GAPCentralRole_UpdateLink()函數(shù)來通過GAP協(xié)議更新連接參數(shù)。

  1. 在全局的消息處理回調(diào)函數(shù)中SimpleBLEPeripheral_ProcessEvent()中,負(fù)責(zé)處理所有的任務(wù)事件,包括計(jì)時(shí)器、消息以及各種用戶定義事件。
if ( events & SYS_EVENT_MSG )
  {
    uint8 *pMsg;

    if ( (pMsg = osal_msg_receive( simpleBLEPeripheral_TaskID )) != NULL )
    {
      simpleBLEPeripheral_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );

      // Release the OSAL message
      VOID osal_msg_deallocate( pMsg );
    }

    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }

static void simpleBLEPeripheral_ProcessOSALMsg( osal_event_hdr_t *pMsg )
{
  switch ( pMsg->event )
  {
  #if defined( CC2540_MINIDK )
    case KEY_CHANGE:
      simpleBLEPeripheral_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys );
      break;
  #endif // #if defined( CC2540_MINIDK )
   .....
  }
}

static void simpleBLEPeripheral_HandleKeys( uint8 shift, uint8 keys )
{
  uint8 SK_Keys = 0;

  (void)shift;  // Intentionally unreferenced parameter

  if ( keys & HAL_KEY_SW_1 )
  {
    SK_Keys |= SK_KEY_LEFT;

  
  osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_BURST_EVT, SBP_BURST_EVT_PERIOD );
  }
  ...
}

如果接收到SYS_EVENT_MSG消息,則檢查該消息中的事件是否是KEY_CHANGE事件,如果是則檢查被按下的是否是左鍵(HAL_KEY_SW_1),如果是則開啟數(shù)據(jù)發(fā)送定時(shí)器。事件名稱為SBP_BURST_EVT,定時(shí)器延時(shí)為SBP_BURST_EVT_PERIOD=7,也就是說7ms后發(fā)起事件。

  1. 接收到SBP_BURST_EVT事件后,連續(xù)發(fā)送四次sendData,其中每次通過GATT_Notification來發(fā)送20個(gè)字節(jié),根據(jù)函數(shù)返回狀態(tài)來決定索引指針是否向前移動(dòng)。
if ( events & SBP_BURST_EVT )
  {
    // Restart timer
    if ( SBP_BURST_EVT_PERIOD )
    {
      osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_BURST_EVT, SBP_BURST_EVT_PERIOD );
    }

     sendData();
     sendData();
     sendData();
     sendData();

    //burstData[0] = !burstData[0];
    return (events ^ SBP_BURST_EVT);
  }  
  1. SBP_BURST_EVT_PERIOD設(shè)置為7ms是因?yàn)槠湫枰冗B接間隔稍小一點(diǎn)保證每次連接事件發(fā)生的時(shí)候,緩沖區(qū)里都有足夠的數(shù)據(jù)可以發(fā)送。連續(xù)調(diào)用四次是因?yàn)镃C2541的發(fā)射緩沖區(qū)只能存4個(gè)數(shù)據(jù)包的內(nèi)容長度(4*20=80字節(jié))。這樣的話實(shí)際上sendData的頻率大于GATT_Notification的頻率,也就是說生產(chǎn)者速度大于消費(fèi)者,而緩沖區(qū)又極其有限,必然會(huì)經(jīng)常觸發(fā)緩沖區(qū)滿的錯(cuò)誤,也就是說GATT_Notification返回錯(cuò)誤碼,因?yàn)镚ATT_Notification的該錯(cuò)誤碼是標(biāo)示數(shù)據(jù)并沒有從上位機(jī)通過HCI發(fā)送到下位機(jī)的發(fā)送緩沖區(qū),則上位機(jī)的應(yīng)用層必須控制其重發(fā)機(jī)制。對這個(gè)問題在e2e論壇上Ti開發(fā)者解釋如下:
7ms is just a OSAL timer which is suppose to be less than the connection interval, so we always keep the output buffer full and thereby maximizing the throughput. since the minimum connection we usually recommend is 10ms you could just as well test 9ms OSAL timer. But if you'd like to test minimum possible connection interval of 7.5ms, you'd like to push as many packets (maximum allowed is currently 4) you can between every connection event, so they might be sent during the actual connection interval.

Again, the OSAL timer is just used to put packets in the output buffer, and the buffer is emptied upon the connection event.

這里說明了為什么定時(shí)器設(shè)置為7ms,也說明了GATT_Notification只是把數(shù)據(jù)轉(zhuǎn)移到下位機(jī)的發(fā)射緩沖當(dāng)中(output buffer)。另外還隱含了一個(gè)信息,buffer is emptied upon the connection event。也就是說每個(gè)連接事件都會(huì)清空緩沖區(qū),所以因?yàn)榫彌_區(qū)最大容納4個(gè)20字節(jié)數(shù)據(jù)包,那么最多對傳4次數(shù)據(jù),如果緩沖區(qū)不滿應(yīng)該就不會(huì)傳夠4次。并且在發(fā)射緩沖區(qū)數(shù)據(jù)的過程中應(yīng)該是對緩沖區(qū)加鎖的(互斥資源),應(yīng)用層在這個(gè)時(shí)候不能往緩沖區(qū)里繼續(xù)添加數(shù)據(jù)(GATT_Notification返回錯(cuò)誤,這個(gè)是我猜的,隱約記得在哪里看到過這個(gè)說法)。
另外我覺得這里還忽略了一個(gè)問題,一次連接事件并不一定能清空緩沖區(qū),因?yàn)檫€涉及到鏈路層未收到數(shù)據(jù)或者收到了以后CRC校驗(yàn)失敗的情況下的重傳問題,應(yīng)該是確認(rèn)傳輸成功再清空一個(gè)數(shù)據(jù)包的字節(jié),那么如果連續(xù)傳輸不成功,很可能在一個(gè)連接事件里并不能完成清空緩沖區(qū),雖然是個(gè)很小的緩沖區(qū)。另外連接事件的window size和window offset是怎么確定的?主機(jī)決定并告知從機(jī)的?但從機(jī)的時(shí)鐘準(zhǔn)確度決定其采用的windows offset的大小,這個(gè)是否是固件程序中可設(shè)置的?又如何能讓主從設(shè)備做到該參數(shù)互相知曉?

  1. iOS限制每個(gè)連接間隔的最大數(shù)據(jù)對傳次數(shù)是4,而CC2541恰好也是4,這就正好是可采用的最大發(fā)送次數(shù)。Android允許發(fā)送次數(shù)1-11,大部分手機(jī)允許最大穩(wěn)定到7,但受制于CC2541的緩沖區(qū)限制,也只能用到4。另外一點(diǎn)不太明確的問題就是,主從設(shè)備的連接參數(shù)協(xié)商里面并沒有包含對傳次數(shù)的參數(shù),那么雙方是怎么確認(rèn)在一個(gè)連接間隔里已經(jīng)達(dá)到了最大的傳輸次數(shù)而避免繼續(xù)開射頻發(fā)射和接收來做無效的能量消耗??

最后再分析一下那個(gè)FTS的截圖來解釋一下為什么傳輸速率沒有達(dá)到理論的10K/s的速率。


FTS的截圖

如圖2的位置,side1代表主機(jī),side2代表從機(jī)?;疑砜瞻{(lán)色代表數(shù)據(jù)開始包,深灰色代表數(shù)據(jù)延續(xù)包。而只有writeLongValue才會(huì)產(chǎn)生延續(xù)包,所以sendData里面單次調(diào)用GATT_Notification都是數(shù)據(jù)開始包。這就解釋了下面圖中一個(gè)side1中包含空包的M->S后面緊跟的是side2中包含數(shù)據(jù)開始包的S->M。

如圖3的位置,說明這個(gè)數(shù)據(jù)包sniffer沒有捕獲到,雖然漏掉了但他知道這里應(yīng)該有一個(gè)包,所以留出來了空白。另外豎向的每一行代表一個(gè)連接事件的時(shí)間軸,但橫向是為什么把每個(gè)連接事件錯(cuò)開的原因我還沒想明白。

然后說下結(jié)論,我認(rèn)為wiki中目前版本的代碼,跟跑出來這個(gè)sniffer截圖的代碼根本不一致。代碼只發(fā)了1000個(gè)包一共20K字節(jié),但sniffer在3.5秒的范圍內(nèi)673-2523是1850個(gè)包。

如圖1的位置,可以看到藍(lán)色的先在選中那個(gè)區(qū)域的平均值大概是120000Bits/s,這個(gè)值怎么來的呢?懶得查BPA的軟件參考手冊,這里我推理一下。
看其下方的select packets顯示的是673-2523,一共1850個(gè)packets,顯示的消耗時(shí)間是3.35s。那么計(jì)算可知552packets/s,而552個(gè)包要達(dá)到120000Bits,那么一個(gè)包被統(tǒng)計(jì)的字節(jié)數(shù)應(yīng)該是120000 / 8 / 552 = 27.17,那么說明這里記錄的是LL層數(shù)據(jù)包的payload = 27字節(jié)。而實(shí)際GATT層單個(gè)包20字節(jié)的有效數(shù)據(jù),所以有效數(shù)據(jù)傳輸速率應(yīng)該是552包/秒 * 20字/包 = 11KB/秒,而不是聲稱的5.9K/s。

若每個(gè)連接事件發(fā)4個(gè)包,則連接事件數(shù)量為552/4=138,而想達(dá)到該數(shù)值的連接間隔應(yīng)該是1000/138 = 7.25ms。這里肯定是4個(gè)包而不是3個(gè)包,因?yàn)槿绻?,計(jì)算出來的連接間隔是5.4ms,是低于BLE規(guī)范要求的最小值7.5ms的。但是從另外從下方的抓包圖來看,其每個(gè)連接事件只有3次數(shù)據(jù)包對傳,懷疑可能截圖的這部分正好連接不是很穩(wěn)定所以只發(fā)了3個(gè)包,具體如何還要看cfa文件。

也就是說,我懷疑sniffer截圖里的配置,其采用的是6的連接間隔6*1.25=7.5ms(這里又有一個(gè)疑問,最小的連接間隔6來計(jì)算,應(yīng)該是7.5ms,為什么上段中算出來的是7.25ms),而不是wiki上所說的10ms。

這樣基本就能解釋通了,這個(gè)配置的理論傳輸速率應(yīng)該是1000/7.5 * 4 * 20 = 10.66K/s,而看sniffer的截圖也應(yīng)該是這個(gè)速率,所以5.9K/s這個(gè)結(jié)論不知道是從哪里來的。如果按照wiki文檔里說的10ms連接間隔,每次4個(gè)包,其速度也應(yīng)該是1000 / 10 * 4 * 20 = 8K/s。

參考https://e2e.ti.com/support/wireless_connectivity/bluetooth_low_energy/f/538/t/169928
這個(gè)帖子后面有大量有價(jià)值的回復(fù)
另外http://processors.wiki.ti.com/index.php/Category:BluetoothLE 有海量的值得研究的資源。。

最新修改

已經(jīng)可以確認(rèn),Ti在這個(gè)帖子里對CC2541的吞吐量測試,是基于1.3的協(xié)議棧進(jìn)行的。
而在1.4協(xié)議棧以后增加了OverlappedProcessing,從而顯著的增加了吞吐量,但在Ti的wiki上并沒有新的throughput測試內(nèi)容。
并且OverlappedProcessing的wiki頁現(xiàn)在也打不開了,在這里放兩個(gè)能用時(shí)候截的圖。

OverlappedProcessing_1.png
OverlappedProcessing_2.png

根據(jù)以上的內(nèi)容可以看出來,其實(shí)1.4協(xié)議棧引入OverlappedProcessing以后,傳輸速率已經(jīng)大幅提升。
用截圖上的指標(biāo)來計(jì)算最高傳輸速率:
脈沖的數(shù)量有28個(gè),橙色范圍的時(shí)間是9ms,看起來整個(gè)連接事件的時(shí)間是18ms左右,那么連接間隔至少要大于連接事件假設(shè)為20ms
max throughput = 1000ms / 20ms * 28packets * 20Byte = 28000Byte/s
也就是說理論可以達(dá)到28K/S,當(dāng)然這是只考慮兩個(gè)2541對傳的情況,如果對端設(shè)備是手機(jī),那瓶頸很可能在手機(jī)藍(lán)牙芯片的協(xié)議棧一端。

另外TI論壇帖子里,言之鑿鑿的說CC2541 BT4.0最大到305kbps,要做到1Mbps建議采用CC2652R或者CC2640R2F能到1.4mbps。

經(jīng)實(shí)測,iPhone7/iPhoneX采用15ms連接間隔(iOS11以上允許15ms)的情況下,每個(gè)連接間隔往packet queue里填充的包數(shù)超過8個(gè)的話,會(huì)導(dǎo)致iPhone端藍(lán)牙連接斷開。也就是說與iPhone連接傳輸?shù)淖畲髤⒖妓俾蚀蟾旁?1000/15 * 8 * 20 = 10.6KB/S左右。

而安卓機(jī)型之間的差異比較大,華為mate的機(jī)型測試可以穩(wěn)定達(dá)到7KB/S以上,OPPO的某些機(jī)型只能4KB/S左右,連接間隔設(shè)置的過小就會(huì)在傳輸過程中出現(xiàn)各種詭異現(xiàn)象。

為了達(dá)到最高速率,需要監(jiān)聽每個(gè)連接事件結(jié)束的通知,并且在這個(gè)時(shí)間去重新填滿packets queue,見下圖的策略和鏈接地址。
http://e2e.ti.com/support/wireless-connectivity/bluetooth/f/538/p/353327/1244676#1244676

藍(lán)牙包數(shù)據(jù)填充方案.png

藍(lán)牙包填充策略.png

但這也不能達(dá)到最大,因?yàn)閜ackets queue=12+Tx buffer=4,一共也只有16個(gè)packet的空間,達(dá)不到上面wiki demo中示波器截圖的28個(gè)packets,所以不能只是一次性填滿就不管了,而是在連接事件結(jié)束的通知里再加一個(gè)低于連接間隔的定時(shí)器,定時(shí)器觸發(fā)后再用很短的時(shí)間間隔周期性的執(zhí)行一個(gè)填充任務(wù)。

再放兩個(gè)鏈接,第一個(gè)是2540最大5.9K那個(gè)wiki的地址。
http://processors.wiki.ti.com/index.php/CC2540_Data_Throughput
第二個(gè)是2640號稱最高可以超過100KB/S的github文檔。
https://github.com/ti-simplelink/ble_examples/blob/ble_examples-2.2/docs/throughput_example.md

其他參考資料:
https://blog.csdn.net/Wendell_Gong/article/details/50386849
https://www.cnblogs.com/jeffkuang/category/1009458.html
下面是LightBlue的官網(wǎng)關(guān)于BLE速率的知識庫文章,總體來說寫的很好,但其中對包數(shù)上限的言之鑿鑿不知道是哪里來的信心
https://punchthrough.com/pt-blog-post/maximizing-ble-throughput-on-ios-and-android/
https://punchthrough.com/pt-blog-post/maximizing-ble-throughput-part-2-use-larger-att-mtu/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 12,298評論 6 13
  • 藍(lán)牙 藍(lán)牙的波段為2400-2483.5MHz(包括防護(hù)頻帶)。這是全球范圍內(nèi)無需取得執(zhí)照(但定不是無管制的)的工...
    蘇永茂閱讀 6,575評論 0 11
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,502評論 19 139
  • 翻翻手機(jī),在網(wǎng)易云音樂上,偶然看到了一個(gè)專訪 對于很少涉略日本音樂的我,點(diǎn)開這個(gè)專訪欄目,實(shí)屬偶然。原想點(diǎn)開瞄上幾...
    時(shí)尚鏟屎官閱讀 1,046評論 1 0
  • 我雖然不知道別人是怎么樣的。 但是我想世界上沒有比我更糟糕的人了。
    入夢安眠閱讀 123評論 0 0

友情鏈接更多精彩內(nèi)容