radio 事件_nRF52832/51822系列RADIO外设介绍/使用
nRF52/51系列
以nRF52832的RADIO外設(下文簡稱RADIO)為例,操作寄存器的方式介紹和使用該外設;
目的在于充分認識RADIO外設,和記錄自己走過的坑;
全為自己理解,可能有不對的地方感謝指正。
1.空中無線協議
這是RADIO從天線發出的數據。順序固定但是內容可以配置。
*【PREAMBLE】為前導碼/前同步碼:根據地址自動設置,我們無需關心,但是它是8bit還是16bit可以通過PCNF0寄存器的PLEN配置。(除2Mb/s BLE模式外,前導碼長度都為1字節。 如果【ADDRESS】的第一位為0,則前導碼將設置為0xAA,否則0x55)PS:Ble_1Mbit為帶寬250 kHz,NRF_1Mbit帶寬160 kHz。
*【ADDRESS】是“接入地址”,由我們的代碼設置,這個地址由 BASE和PREFIX兩部分組成,BASE分為BASE0(4Bytes)、BASE1(4Bytes); PREFIX分為PREFIX0(4Bytes)、PREFIX1(4Bytes),BASEn 和 PREFIXn 的值可以在RADIO的寄存器中設置。
BASEn 和 PREFIXn要怎么組合成“接入地址”呢?見下表:
地址共有8種組合方式,啟用哪幾種方式可以在RADIO的寄存器中設置。(下面代碼啟用0方案)
NRF_RADIO->TXADDRESS = 0 << RADIO_TXADDRESS_TXADDRESS_Pos; //TX使用的某一個地址 NRF_RADIO->RXADDRESSES = RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos; //RX使用的某些地址,可以是多個其中PREFIXn固定貢獻1字節,BASEn可以貢獻2~4字節(NRF_RADIO->PCNF1中的BALEN設置)一起組成“接入地址”,所以“接入地址”長度范圍為 3~5字節。(PS:BLE廣播時“接入地址”為0x8E89BED6)
*【S0、LENGTH、S1、PAYLOAD】這些數據都是我們自己要傳輸的數據,NRF_RADIO->PACKETPTR寄存器保存這些數據的起始地址(指針);
S0、LENGTH、S1、PAYLOAD可以通過NRF_RADIO->PCNFn 寄存器配置 有無、bit大小、大小端。例如NRF_RADIO->PCNF0 = 0即沒有S0、LENGTH、S1,那么PACKETPTR指向的地址就全是PAYLOAD數據。
PCNF1寄存器中的STATLEN暫時不清楚是做什么的,可能是被一幀數據的固定長度,但是好像跟分組有關。
PCNF1寄存器中的MAXLEN可以設置PAYLOAD最大長度(最大255),如果過長會直接丟棄,防止RAM越界;所以S0+LENGTH+S1+PAYLOAD最大長度=258
*【CRC】CRC是硬件自動計算并加入的,可以配置其 有無、位數、多項式。
*數據白化:防止空中數據連續多0或1bit出現,可以進行數據白化,白化功能可以通過寄存器配置。配置之后,RADIO會自動進行白化和去白化。
2.RADIO狀態與發送數據
RADIO可以進入多個狀態,見下圖,圖中:圓角矩形為各個狀態、線上名稱為執行某種動作、帶 / 符號的為RADIO產生的事件
以發送一幀數據為例,分析要執行的操作 和 RADIO的狀態:
要讓RADIO發出數據,RADIO必須要進入 [ TX ] 狀態(圖中右上角)。
第一步:初始化各個參數后(還要使能使用外部32M時鐘),此時RADIO處于[DISABLED]狀態,執行下面的代碼
NRF_RADIO->EVENTS_READY = 0; //清除標志位 NRF_RADIO->TASKS_TXEN = 1; //使能TX while(NRF_RADIO->EVENTS_READY == 0); //等待READY事件:就緒RADIO將會啟動TXRU,成功后將產生READY事件,此時RADIO處于[TXIDLE]狀態,可以進行 數據傳輸。
第二步:處于處于[TXIDLE]狀態后,通過START任務啟動RADIO,注:RADIO的EasyDMA使用相同的PACKETPTR來接收和發送數據包。 每次通過START任務啟動RADIO之前,CPU都應重新配置此指針。
NRF_RADIO->EVENTS_END = 0; //清除標志位 NRF_RADIO->TASKS_START = 1; //開始發送數據 while(NRF_RADIO->EVENTS_END == 0); //等待產生END事件:發送完成這時RADIO將會處于[TX]狀態并自動發送數據。發送完成后將產生END事件,RADIO回到[TXIDLE]狀態。這時可以再次更新要發送的數據,然后再次執行第二步發送、或可以執行下面的代碼結束發送狀態。
NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while(NRF_RADIO->EVENTS_DISABLED == 0);//等待停止等待生成DISABLED事件,RADIO將會回到[DISABLED]狀態。
PS:發送過程其他狀態也會產生相應的事件:發送完ADDEESS、發送完PAYLOAD;所有事件可以啟用對應的中斷。。。上面的過程可以見下面的時序圖:
優化:
上面的過程中,執行第一步需要等到產生READY事件后,才能執行第二步的TASKS_START = 1,這個過程會有一定的延時,那么RADIO可不可以自動執行這個過程呢?就是:產生READY事件后,自動執行START,答案是可以的,詳見NRF_RADIO->SHORTS寄存器,里面有各種自動執行的配置,優化后的發送過程,見下圖
上圖中READY--START、END--DISABLE(第二次END)就是使用了這個功能,配置代碼如下:
NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos; //READY后自動開始執行START| RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos; //END后,自動讓DISABLE所以此時發送代碼就可以精簡為:
void RADIO_SendStart(void) { NRF_RADIO->PACKETPTR = (uint32_t)&TxBuff; //每次通過START任務啟動RADIO之前,CPU都應重新配置此指針//此時RADIO要處于DISABLE或 TXIDLE狀態 (RXIDLE應該也可以未測試)NRF_RADIO->EVENTS_DISABLED = 0; //清除標志位NRF_RADIO->TASKS_TXEN = 1; //開始后會內部自己操作 while(NRF_RADIO->EVENTS_DISABLED == 0); //等待事件,RADIO回到DISABLE狀態***開啟END事件中斷后可以不用死循環等待 }3.RADIO狀態與接收數據
RADIO能夠接收數據包之前,它必須處在[RX]模式下
進入[RX]狀態方式和TX類似,見下面的時序圖:
代碼如下(沒有使能NRF_RADIO->SHORTS相關功能):
void RADIO_ReceiveStart(void) {NRF_RADIO->EVENTS_READY = 0; //清除標志位NRF_RADIO->TASKS_RXEN = 1; //使能RXwhile(NRF_RADIO->EVENTS_READY == 0); //等待READY事件:就緒NRF_RADIO->EVENTS_END = 0; //清除標志位NRF_RADIO->TASKS_START = 1; //開始發送數據while(NRF_RADIO->EVENTS_END == 0); //等待產生END事件:接收完成NRF_RADIO->EVENTS_DISABLED = 0;NRF_RADIO->TASKS_DISABLE = 1;while(NRF_RADIO->EVENTS_DISABLED == 0);//等待停止 }時序圖中的 ‘X’表示從START開始,直到RADIO收到帶有有效前同步碼(P)的數據包;
直到收到并校驗CRC為止,RADIO產生END事件,表示RX接收一幀完成。
優化:
和TX過程一樣,可以讓RADIO自動完成一些狀態的切換,比如READY--START、END--DISABLE
所以此時接收代碼就可以精簡為:
void RADIO_ReceiveStart(void) {NRF_RADIO->PACKETPTR = (uint32_t)&RxBuff; //每次通過START任務啟動RADIO之前,CPU都應重新配置此指針NRF_RADIO->EVENTS_END = 0U;NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_END == 0U);//等待事件,RADIO回到DISABLE狀態 }進一步優化:
由于接收有效前同步碼(P)的數據包時間不定,可能會等待很久,所以代碼可能會阻塞很長時間,因此可以用END事件的中斷,就不用阻塞代碼了。
同樣的:TX也可以使用該中斷,來指示發送完成,所以發送也不需要等待END事件,TX功能被進一步優化。
void NRF_RADIO_init(void) {... ...... ...NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos; //TXEN(RXEN) 后如果EVENTS_READY=1(處于TXIDLE(RXIDLE)狀態)后自動開始執行START=1(進行TX(RX))NRF_RADIO->INTENSET = RADIO_INTENSET_END_Enabled << RADIO_INTENSET_END_Pos;NVIC_SetPriority(RADIO_IRQn, 1);NVIC_ClearPendingIRQ(RADIO_IRQn);NVIC_EnableIRQ(RADIO_IRQn); } void RADIO_IRQHandler(void) {if(NRF_RADIO->EVENTS_END) //接收 或 發送 完成{NRF_RADIO->EVENTS_END = 0;//-----接收 或 發送 完成 相關代碼------------ } } void RADIO_ReceiveStart(void) {NRF_RADIO->PACKETPTR = (uint32_t)&RxBuff; //每次通過START任務啟動RADIO之前,CPU都應重新配置此指針NRF_RADIO->EVENTS_END = 0;NRF_RADIO->TASKS_RXEN = 1; } void RADIO_SendStart(void) { NRF_RADIO->PACKETPTR = (uint32_t)&TxBuff; //每次通過START任務啟動RADIO之前,CPU都應重新配置此指針//此時RADIO要處于DISABLE或 TXIDLE狀態 (RXIDLE應該也可以未測試)NRF_RADIO->EVENTS_END = 0; //清除標志位NRF_RADIO->TASKS_TXEN = 1; //開始后會內部自己操作 }4.其他遺留問題
4.1 RX過程的如果CRC校驗不通過,會不會也產生END中斷?
4.2 RX要怎么實現地址自動過濾?也就是自動進行地址匹配?如果地址不正確則放棄本次數據。
可能是用DACNF選擇,但是 DAB與DAP又有啥用呢?
5.其他選擇
當然也可以直接使用Nordic SDK中的外設庫進行上面的設置,這樣就無需關心寄存器的事情。也可以是使用SDK中的esb庫,可以有更多實用的功能,但是代價就是要額外使用別的外設,比如 PPI、NRF_TIMER、SWI
總結
以上是生活随笔為你收集整理的radio 事件_nRF52832/51822系列RADIO外设介绍/使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: poi获取段落位置_Apache POI
- 下一篇: hbuilder怎么做登录界面_hbui