NRF51-SDK的低功耗藍牙廣播包的單通道掃描實現

一,前言

 

    半導體生產商NORDIC SEMICONDUCTOR爲低功耗藍牙芯片NRF51提供了開發工具包NRF51-SDK,該SDK中包含了與型號爲NRF51的藍牙芯片提供了大量的例程代碼,同時也包含了幾種不同的藍牙協議棧(SOFTDEVICE)。但這些藍牙協議棧是以二進制形式提供的(以Intel HEX文本格式),沒有源代碼。在工作中遇到掃描低功耗藍牙廣播包的需求,要求只在BLE三個廣播信道中的一個來實現掃描功能。而SOFTDEVICE在掃描BLE廣播時不會固定在一個廣播信道上掃描,且早期版本的SOFTDEVCE未提供單信道掃描的接口(以後可能會有),那麼要實現這個功能,必須使用非常規的手段。因此在這裏記錄一下這裏用到的“非常規”方法,以便日後遇到此類問題時可以參考——但在工作中不推薦使用此類方法。

 

二,實現方案

 

    根據NRF51芯片手冊(nRF51_Series_Reference_manual v3.0)的信息,我們知道,芯片的射頻模塊有一個寄存器,用於設置當前接收或發送的藍牙數據的頻率:

 

 

 

    那麼我們需要找到NORDIC的藍牙協議棧中寫該寄存器的二進制機器碼,將其對應的SOFTDEVICE IHEX文件修改成我們需要設置的BLE藍牙信道頻率,然後重新燒寫SOFTDEVICE即可。但也要注意其可操作性,我們要避免將掃描的藍牙信道修改成固定的值,而是可以容易修改的,也可以動態地取消增加的強制修改信道的代碼。

    我們使用的硬件設備是在https://ohtcom.taobao.com/購買的藍牙開發板,其中搭載了一顆型號爲NRF51822_QFAC的藍牙芯片,有256KB的FLASH存儲空間和32KB的RAM空間,使用的NRF51 SDK版本爲nRF5_SDK_12.0.0_12f24da,官方下載地址爲

https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v12.x.x/nRF5_SDK_12.0.0_12f24da.zip

 

三,實現步驟

 

    1, 找到寫入NRF51射頻模塊的FREQUENCY寄存器的代碼地址。上圖中寄存器地址爲0x40001508。將SOFTDEVICE(s130_nrf51_2.0.1_softdevice.hex)和掃描的代碼燒寫到NRF51芯片中,打開SEGGER提供的GDB調試工具,加載gdb調試工具:

    由上面的操作可知,地址爲0x11da0的指今處會對寄存器進行操作,下面就需要進一步驗證一下。

    2, 使用IDA反彙編工具加載SOFTDEVICE並對之反彙編,找到0x11da0處並確認此處的指今對藍牙射頻的頻率寄存器執行寫入操作:

    可以看到,是0x11DA2處的指令會寫入射頻頻率寄存器。現在的問題來了:會不會有其它的地方也會對該寄存器操作呢?這樣的想法不無道理,但經過多次繼續執行,可以認爲在SOFTDEVICE掃描BLE廣播時,它只是在這裏操作了頻率寄存器。

    從上圖也可以看到,在寫入0x40001508的寄存器後面的三個指令,會操作另一個寄存器,這裏我們暫時不要關心。之後回有一條BX LR的指令,該指令告訴我們這裏是一個類似於C語言的函數調用返回。下面就找到調用該函數的返回地址:

 

    這樣我們得到在地址爲0x133b9的指令之前會調用這個函數:

 

    這樣,我們就進一步知道寫入頻率寄存器的函數地址了,爲0x11d76,用IDA看一下此函數的大致執行流程:

    從中基本上可以確定該函數只有一個參數。其中0x25/0x26/0x27分別爲BLE廣播信道的信道編號,該函數於其進行特殊處理後就開始寫藍牙射頻頻率寄存器了:

    到這一步,我們就需要考慮如何修改此SOFTDEVICE,讓它能夠配置頻率寄存器以我們想要的值呢?修改這個函數嗎?這似乎是一個方案,但我們要知道,這樣的修改是比較死板的,沒有靈活性和可擴展性。我們可以考慮修改其調用代碼指令,指向我們新增的代碼,修改一下函數參數後,我們自己再調用此函數。

    3, 我們知道SOFTDEVICE和自己編譯的固件是獨立的,而自己編譯的固件需要燒寫在NRF51芯片指定地址上,這樣SOFTDEVICE才能正確地執行它。從下圖可以看到,自己編譯的固件nrf51822_xxac.hex的中斷向量表確實在固定的地址:

 

     該地址爲0x1b000。實際上,這個地址是在鏈接腳本中指定的。於是我們考慮在向量表的最後面加入一個函數地址,這個函數是在nrf51822_xxac固件中實現的,這就要求在SOFTDEVICE中注入一段代碼,在調用SOFTDEVCE的操作頻率寄存器函數之前調用我們自己的函數。

    4, 下圖即爲在SOFTDEVICE中注入的代碼,可以看到該代碼會讀取NRF51822_XXAC固件的中斷向量表0x30偏移處,調用之並調用之前反彙編得到的函數。

 

    之後需要對其編譯、鏈接並寫入到新的SOFTDEVICE IHEX文件中:

 

 

    這樣我們就得到了四行的IHEX形式的注入代碼,代碼中函數地址爲0x1AFE0,編譯之前的C代碼需要注意,得到的機器碼長度不能太長,否則就可能與我們自己編譯的固件在FLASH中燒寫的位置重合了。上圖中我們只需中間的兩行,複製到新的SOFTDEVICE中:

    5, 修改0x133b4處的四字節指令,使其調用我們注入的函數。這需要手動來計算,根據ARM官方文檔DDI0419C_arm_architecture_v6m_reference_manual對BL指令編碼的介紹:

 

    經計算,我們要將0x133b4處的四個字節FE F7 DF FC修改爲07 F0 14 FE,之後重新計算行尾的較驗值,並保存。

    6, 之後我們在自己編譯的固件中加入注入的函數:

    可以看到,我們在中斷向量表之後加入了一個符號_injected_freq_code,其相應的C函數實現在右邊。編譯後重新燒寫SOFTDEVICE和NRF51822_XXAC的固件,可以在串口上得到調試結果:

 

    可以看到,函數_injected_freq_code函數被調用了,由於我們在代碼中沒有調此函數,可以確定,它是由我們在SOFTDEVICE中增加的代碼調用的,也就是說,是SOFTDEVICE調用的。

    7, 爲進一步確認,我們修改藍牙的廣播通道頻率對掃描過程沒什麼影響,只是改變掃描信道,可以將掃描的信道都改變一下,看是否仍能掃描到BLE的廣播:

 

    由上圖可以看到,確實仍然能夠掃描到BLE的廣播數據。

    8, 之後,修改函數_inject_freq_code()函數,固定在38通道上掃描,也可以掃描到BLE廣播數據:

至此,我們就實現了基於NRF51 SDK的藍牙協議棧的BLE廣播單通道掃描的功能。

 

四,總結

    這是一個非常規的解決方案,沒有得到具體的應用,但這仍有一定的意義,以後遇到類似的問題,在沒有其他可選的方法時可以參考一下。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章