假日嵌入式藍芽開發工程師:nRF51822 (5)
Introduction of SoftDevice
這一篇我要介紹Nordic SDK的用法,我第一次讀完寫的筆記。自己也都不大會,只好寫下來給社會大眾笑了。
通信系統一般會包括 {Antenna, LNA, RF filter-chain, Digital-front-end, Baseband, BLE protocol}。Baseband/ protocol包括硬體加速器和軟體,這邊的軟體就是SoftDevice,Nordic提供編譯好的binary,燒進指定區域就有BLE protocol可以用。Nordic提供一系列的SoftDevice,我只用過S110,其他的都是照著網頁的寫(心虛)
- S110:BLE Peripheral
- S120:BLE Peripheral or Central
- S130:BLE Central, Observer, Broadcaster
- S210:ANT+
- S310:BLE & ANT+ concurrent
Nordic的SoftDevice燒進去後,memory map如下圖,S110占Flash(96KB),RAM(8KB),這個數量級證明BLE protocol沒辦法自幹。Nordic SDK讓BLE protocol和User code跑在同個space裡,使用MPU(Memory Protection Unit)保護記憶體不互踩,只是debug要花點心思。另外SoftDevice會佔某些MCU的硬體,用戶要知道哪些硬體還可以用。這種做法最優的地方是BLE protocol能無痛升級,怎麼設計SoftDevice也很有趣。用戶的code用SVC(Supervisor Call)呼叫SoftDevice,這部分等有空再寫一下。我在用的S110 SoftDevice這裡有文件可以閱讀。
Basic Program Structure of LBS Example
底下介紹上一篇的程式,Nordic sample code結構都差不多,先把周邊設備都初始化,然後初始化BLE stack,最後進入一個low power的main-loop等待事件。Nordic整份SDK都用了event-driven思維,這部分也很值得學習。
看懂這個範例,免不了要到跨檔案到處讀,我也沒打算寫清楚所有細節(做不到啊...)。底下就盡量用註解的方法,大概描述一下。首先是Device driver initialization的部分:
看懂這個範例,免不了要到跨檔案到處讀,我也沒打算寫清楚所有細節(做不到啊...)。底下就盡量用註解的方法,大概描述一下。首先是Device driver initialization的部分:
- timers_init()
- SoftDevice本體會拿RTC0去用,這裡在配置RTC1。SoftDevice有部分是用source code形式,而且他們假設RTC1也有得用。
- 簡而言之,要用SoftDevice其實RTC0/RTC1就都老實的配置下去,這樣程式才跑得起來,參考資料。
- leds_init()
- 這個function容易一點,配置幾根LED pins而已。
- button_init()
- Nordic的範例程式包括debounce和完整的IRQ handling,有興趣可以追整包code。這個function設定button按下時,對應的event handler。
- Event handler code比較麻煩一點,因為這個範例按下按鈕後,會呼叫BLE framework,通知手機說現在按鈕是按下或放開。
- Nordic把和BLE相關實作放一個獨立的檔案,這個檔案後面還會不斷出現,用力讀吧!
- components/ble/ble_services/ble_lbs/ble_lbs.c
整份程式和底下資料結構強相關,Softdevice回傳的handler都存在裡面。像fopen()回傳FILE*,這個指標要再塞給fwrite()/ fread()。資料結構還包括一個service_handle,和好幾個char_handle。這些Handle的data-type看起來很恐怖,其實只是uint16。使用Debugger連進去看,正好和BLE scanner看到的數值一致。
然後來介紹BLE相關的程式。
然後來介紹BLE相關的程式。
- ble_stack_init()
- SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
- 設定BLE device使用那種crystal
- ble_enable_params_t ble_enable_params = {0};
err_code = sd_ble_enable(&ble_enable_params);- 啟動BLE service
- ble_gap_addr_t addr;
sd_ble_gap_address_get(&addr);
sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr); - 設定BLE的MAC addresss,首先讀取晶片內的FICR裡的address,然後設定到softdevice。Reference
- SoftDevice似乎支援run-time變化MAC address,我在這裡有看到人家在發問。這個範例直接讓ADDR從頭到尾都不變。
- FICR定義:
根據NRF51 manual,Device Address放在0x100000A4/ 0x100000A8,我用Debugger讀出來如下 - 我用Debugger讀到的Device Driver是0xEF77_8B5B7E0C,和上述address MSB不一樣是因為BLE規定bit[47:46]必須是11,所以從AF->EF。
- softdevice_ble_evt_handler_set(ble_evt_dispatch);
- 前面提到SoftDevice是Event-Driven的程式寫法,所以告訴SoftDevice是哪個function負責處理events也是合情合理的。
- 這包程式和前面提到的ble_lbs.c牽連極深,想看懂BLE做什麼,讀吧!
- SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
- gap_params_init()
- 這裡面設定security mode,device-name,以及連線參數。
- 連線參數會大幅影響電池壽命,超級重要;security mode也很重樣;這裡可以故意把device name改掉,看nRF會不會有反應。
- services_init()
- 首先告訴BLE protocol我們現在UUID多少,這裡我承認講不清楚(自己也沒多懂)。欲知詳情,查一下BLE protocol裡的UUID規劃,網路上滿容易找的。
- 然後會呼叫BLE protocol,新增一個service,把回傳的handler填進上述的資料結構。
- 最後是把所有characteristics依序加入上一步的service裡。Nordic有個專門的寫法,裡面還有一堆參數可以填,用力的查文件吧。
- LED characteristic很簡單,就是手機叫他亮就亮,暗就暗。
- Button characteristic就複雜得多,裡面還有一個CCC要設定。
- 我覺得這個function是使用Nordic SDK的精華,要弄清楚要有些BLE底子;但是我們不可能都看完文件再開始寫code,比較合理的做法是邊試邊改
- advertising_init()
- 這個function能設定BLE device要廣播什麼出去。 BLE的多種用法,其中一種是BLE-node只有broadcast,不停送出某些資訊,世界上最有名的iBeacon就是這樣做。
- 放幾個reference以免顯得自己都沒念書(笑)
- conn_params_init()
- 這個function設定BLE在connection mode底下,使用的參數
- advertising_start()
- 上面參數都設定完,呼叫這個function就會開始動
Final Word
寫了很多,又好像什麼都沒寫,我也不是專業藍芽開發者,實在不曉得怎麼寫清楚(好想放棄啊)。但是起碼用這個範例,我們就有個會動的BLE系統,理論上可以拿它來改東改西,做成自己要的東西。
留言