開發環境:
nRF5_SDK_14.2.0_17b948a
KEIL 5.27
Windows 10 x64
芯片:nRF51822/nRF52832/nRF52840
新版本SDK做了很多改弄,下面來分析一下兩個比較有意思的模塊,nrf_setion和nrf_section_iter
這個兩位模塊基本都是用宏定義的
nrf_setion
NRF_SECTION_START_ADDR
NRF_SECTION_END_ADDR
NRF_SECTION_LENGTH
NRF_SECTION_DEF
NRF_SECTION_ITEM_REGISTER
NRF_SECTION_ITEM_GET
NRF_SECTION_ITEM_COUNT
nrf_section_iter
NRF_SECTION_SET_DEF
NRF_SECTION_SET_ITEM_REGISTER
nrf_section_iter_init、nrf_section_iter_get、nrf_section_iter_next
1、NRF_SECTION_START_ADDR、NRF_SECTION_END_ADDR、
NRF_SECTION_LENGTH

剛看這個宏定義有點蒙,這是什么鬼,查閱一下資料仔細看看
CONCAT_2表示將兩個參數合並,使用的是C語言的##操作符
$$Base表示起始地址
$$Limit表示結束地址
NRF_SECTION_START_ADDR 表示獲取SECTION起始地址
NRF_SECTION_END_ADDR 表示獲取SECTION起始地址
NRF_SECTION_LENGTH 表示獲取SECTION大小
2、NRF_SECTION_DEF

例如:
/* Create the section "fs_data". */
NRF_SECTION_DEF(fs_data, nrf_fstorage_t);
宏替換完之后最終就是
extern nrf_fstorage_t * fs_data$$Base;
extern void * fs_data$$Limit;
聲明兩個變量fs_data$$Base和fs_data$$Limit,變量的值為fs_data section段的起始地址和結束地址
現在明白了,實際上NRF_SECTION_DEF表示聲明兩個變量,變量值分別為section段的起始地址和結束地址
3、NRF_SECTION_ITEM_REGISTER

STRINGIFY 表示將將宏參數轉換為字符串,使用使用的是C語言的#操作符
還是找個實例看一看:
#define NRF_FSTORAGE_DEF(inst) NRF_SECTION_ITEM_REGISTER(fs_data, inst)
NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs) =
{
// The flash area boundaries are set in fds_init().
.evt_handler = fs_event_handler,
};
宏替換完之后最終就是
nrf_fstorage_t m_fs __attribute__ ((section(‘fs_data’))) __attribute__((used)) = {
// The flash area boundaries are set in fds_init().
.evt_handler = fs_event_handler,
};
那么NRF_SECTION_ITEM_REGISTER 就表示定義一個變量,並且指定這個變量在哪個section段,可以將多個變量指定到同一個section段


4、NRF_SECTION_ITEM_GET

還是找個實例看一看:
/**@brief Macro for retrieving an fstorage instance. */
#define NRF_FSTORAGE_INSTANCE_GET(i) NRF_SECTION_ITEM_GET(fs_data, nrf_fstorage_t, (i))
宏替換完之后最終就是
((nrf_fstorage_t*)fs_data$$Base + (i))
那么NRF_SECTION_ITEM_GET就表示獲取section段中的一個實例,i表示索引
結合上面的NRF_SECTION_ITEM_REGISTER來看,NRF_FSTORAGE_INSTANCE_GET(0)就是變量m_fs。

5、NRF_SECTION_ITEM_COUNT

NRF_SECTION_ITEM_COUNT 就表示獲取section段中有多少個變量實例,獲取到數量之后就可以通過NRF_SECTION_ITEM_GET遍歷整個section段全部變量實例
6、NRF_SECTION_SET_DEF
迭代器定義

7、NRF_SECTION_SET_ITEM_REGISTER
觀察者注冊到迭代器中


8、nrf_section_iter_init、
nrf_section_iter_get、
nrf_section_iter_next
遍歷迭代器

9、總結:
使用C語言和編譯器的一些功能實現 迭代器的效果,這樣的寫執行回調函數的時候就不用管有多少個回調函數,具體的回調函數是什么,只需要定義好section段,需要執行的回調函數注冊到這個section段中,這樣在需要執行回調函數的時候遍歷這個section段所以回調函數即可,實現解耦,代碼分離。例如藍牙連接這個事件,不需要知道有多少個service需要這個藍牙連接消息,只需要注冊一個藍牙的section段,誰需要誰就注冊回調函數到這個section中,在藍牙連接這個消息到來是只需要遍歷這個藍牙的section段,就可以通知所有需要該消息的觀察者
$$Base和$$Limit 非常有用,在SDK中很多地址都有用到,熟練掌握使用對代碼有很大的幫助


參考:
關於__attribute__中section部分的一些了解:
https://blog.csdn.net/sadshen/article/details/9419267