BLE和2.4G同時執行
阿新 • • 發佈:2022-04-15
前言
RF_PHY 是wch提供的一個呼叫底層2.4g收發器的一個介面,可以通過此介面實現更為靈活的通訊方式
這種底層,僅僅是BLE的收發器基礎上,這意味著,收發器調製解調引數,包括frequency,deviation,symbol_rate,以及packet_handler(preamble,syncword,length,crc,whitening)都是符合藍芽的底層規範的.
具體的工程可參考官方SDK對應路徑下的工程,如:CH579EVT_2.3\EXAM\BLE\RF_PHY
適用晶片
- CH577/CH578/CH579
- CH571/CH573
使用
初始化
void RF_Init( void) { uint8 state; rfConfig_t rfConfig; //註冊一個task,用於使用者排程 taskID = TMOS_ProcessEventRegister( RF_ProcessEvent ); #if defined(CH573) //針對ch573 //這裡的 accessAddress 就是preamble後跟的同步字,用於識別一個新包到來,收發設定成一樣是是收到包的前提 //這個accessAddress 的設定要符合藍芽規範,比如禁止使用0x55555555以及0xAAAAAAAA ( 建議不超過24次位反轉,且不超過連續的6個0或1 )rfConfig.accessAddress = 0x8E89BED6; //crc24_ble 的初值,這個收發也要相同,否則一定會在接收完成後產生crc24 錯誤 rfConfig.CRCInit = 0x555555; #elif defined(CH579) //針對ch579 rfConfig.TxAccessAddress = 0x8E89BED6; rfConfig.RxAccessAddress = 0x8E89BED6; rfConfig.TxCRCInit = 0x555555; rfConfig.RxCRCInit = 0x555555; #else #error "You must define CH573 or CH579 first!" #endif //The channel is mapped to ble channel, ble4.x adv at channel 37/38/39 //這裡的通道對映是BLE的通道,如37通道對應2402Mhz,這個值在收發也要相同 rfConfig.Channel = 37; //這裡的工作模式有兩種LLE_MODE_BASIC和LLE_MODE_AUTO //其中LLE_MODE_BASIC 是基本的收發,而LLE_MODE_AUTO 是帶自動回覆的,根據實際場景來選擇 //另外在最近更新的庫裡面 增加了兩個可配置選項LLE_MODE_NON_RSSI和LLE_MODE_EX_CHANNEL(ch57x m0 系列不支援) rfConfig.LLEMode = LLE_MODE_BASIC; //註冊狀態回撥函式,這裡主要是傳送完成,接收到資料之類的會進入這個回撥函式 rfConfig.rfStatusCB = RF_2G4StatusCallBack; state = RF_Config( &rfConfig ); PRINT("rf 2.4g init state for ble adv test: %x\n",state); }
狀態回撥
/這裡的回撥函式是在state = RF_Config( &rfConfig ); 註冊的 void RF_2G4StatusCallBack( uint8 sta, uint8 crc, uint8 *rxBuf ) { switch( sta ) { case TX_MODE_TX_FINISH://傳送完成,LLE_MODE_BASIC,LLE_MODE_AUTO模式都會產生 break; case TX_MODE_TX_FAIL: //傳送失敗,LLE_MODE_BASIC,LLE_MODE_AUTO模式都會產生 break; case TX_MODE_RX_DATA: //LLE_MODE_AUTO模式下,傳送完資料後,接收到了ack訊號 if( crc == 1 ) { PRINT("crc error\n"); } else if( crc == 2 ) { PRINT("match type error\n"); //這裡的match type 就是再發射接收的時候 傳入的match type跟當前接收配置的type對比的結果 } else { uint8 i; PRINT("tx recv,rssi:%d\n",(s8)rxBuf[0]); PRINT("len:%d-",rxBuf[1]); for(i=0; i<rxBuf[1]; i++) PRINT("%x ",rxBuf[i+2]); PRINT("\n"); } break; case TX_MODE_RX_TIMEOUT: //LLE_MODE_AUTO模式下,傳送完資料後,沒有接收到ack訊號,預設超時是 3 ms break; case RX_MODE_RX_DATA: //接收到資料,LLE_MODE_BASIC,LLE_MODE_AUTO模式都會產生 if( crc == 1 ) { PRINT("crc error\n"); } else if( crc == 2 ) { PRINT("match type error\n"); } else { uint8 i; //rxBuf[0] 預設情況下是rssi,如果 在LLEMode初始化時同時開啟了LLE_MODE_NON_RSSI,那這裡將會變為PKT_TYPE PRINT("rx recv, rssi: %d\n",(s8)rxBuf[0]); //我們還可以通過下面方式獲取RSSI,這個不受LLE_MODE_NON_RSSI配置影響: PRINT("rssi:%d\r\n",(int8_t)rxBuf[2+((rxBuf[1]+5)&0xffc)]); //資料部分 PRINT("length: %d:",rxBuf[1]); for(i=0; i<rxBuf[1]; i++) { PRINT("%02x ",rxBuf[i+2]); } PRINT("\n"); } break; case RX_MODE_TX_FINISH: //LLE_MODE_AUTO模式下,接收到資料後,自動ack完成 break; case RX_MODE_TX_FAIL: //LLE_MODE_AUTO模式下,接收到資料後,ack失敗,僅僅只是傳送失敗 break; } PRINT("STA: %x\n",sta); }
API說明
//RF_PHY內部初始化必須先執行這個再執行後面的RF_Config //這個也可以 在ble初始化以後再加入這個,這樣就可以做到2.4g跟ble 同時執行 bStatus_t RF_RoleInit( void ); //初始化,按照上面給你的示例說明 bStatus_t RF_Config( rfConfig_t *pConfig ); /******************************************************************************* * @fn RF_Rx * * @brief rx mode. * * input parameters * * @param txBuf - rx mode tx data * @param txLen - rx mode tx length(0-251) * @param pktRxType - rx mode rx package type * broadcast type(0xFF):receive all matching types, * others:receive match type or broadcast type * @param pktTxType - rx mode tx package type(auto mode) * broadcast type(0xFF):received by all matching types; * others:only received by matching type * * output parameters * * @param None. * * @return 0 - success. */ extern bStatus_t RF_Rx( u8 *txBuf, u8 txLen, u8 pktRxType, u8 pktTxType ); /******************************************************************************* * @fn RF_Tx * * @brief tx mode. * * input parameters * * @param txBuf - tx mode tx data * @param txLen - tx mode tx length(0-251) * @param pktTxType - tx mode tx package type * broadcast type(0xFF):received by all matching types; * others:only received by matching type * @param pktRxType - tx mode rx package type(auto mode) * broadcast type(0xFF):receive all matching types, * others:receive match type or broadcast type * * output parameters * * @param None. * * @return 0 - success. */ extern bStatus_t RF_Tx( u8 *txBuf, u8 txLen, u8 pktTxType, u8 pktRxType ); //關閉TX/RX模式,不建議在狀態回撥裡呼叫,而是在外面呼叫 bStatus_t RF_Shut( void ); //設定RF的通道,這裡的通道對應的是ble的通道,比如37對應2402Mhz void RF_SetChannel( u8 channel );
應用
模擬BLE廣播
說明
- 有時候,我們的應用很簡單,並不需要建立BLE連線,只需要廣播,比如各種beacon應用,而ble的協議棧是比較龐大的,而用2.4G的方式直接寫,則可以做到非常的輕量.
- 本文只實現不可連線的廣播,不支援scan_respone的回覆包
初始化
void RF_Init( void ) { uint8 state; rfConfig_t rfConfig; taskID = TMOS_ProcessEventRegister( RF_ProcessEvent ); #if defined(CH573) //依據BLE的核心規範,填寫Access Address 和 CRC24 的入值. rfConfig.accessAddress = 0x8E89BED6; rfConfig.CRCInit = 0x555555; #elif defined(CH579) rfConfig.TxAccessAddress = 0x8E89BED6; rfConfig.RxAccessAddress = 0x8E89BED6; rfConfig.TxCRCInit = 0x555555; rfConfig.RxCRCInit = 0x555555; #else #error "You must define CH573 or CH579 first!" #endif //The channel is mapped to ble channel, ble4.x adv at channel 37/38/39 rfConfig.Channel = 37; rfConfig.LLEMode = LLE_MODE_BASIC; rfConfig.rfStatusCB = RF_2G4StatusCallBack; state = RF_Config( &rfConfig ); PRINT("rf 2.4g init state for ble adv test: %x\n",state); }
構造資料
//ble adv data for RF-PHY test static uint8_t ble_adv_test_data[] = { 0x3c,0x10,0x2D, 0xE4, 0xC2, 0x84, //MAC ADDR 9,0x09,'A','D','V','-','T','E','S','T' //ADV data };
傳送
uint8_t ble_adv_tx(void) { RF_Shut( ); //tx type :0X02 for no connected adv return RF_Tx( ble_adv_test_data,sizeof(ble_adv_test_data), 0x02, 0xFF ); }
接收BLE廣播
與BLE工程一起跑
BLE的工作特點是間歇性工作,依據廣播間隔/連線間隔協議棧進行定時呼叫收發器工作,其他時間收發器資源都是釋放的,這也是為什麼的BLE可以和WIFI,zigbee,thread等協議共用部分射頻資源動態共存的原因
鑑於BLE的這種工作特點,wch也把RF_PHY 這種模式與ble可以共存執行.
下面在wch 提供的ble的工程裡面加入RF_PHY 工作的初始方式,實際上就是把RF_PHY的初始化函式放在BLE初始化完成後呼叫即可,但是由於BLE 的存在,所以丟包可能是非常普遍, 如,這邊在發射,接收端的射頻被BLE短暫佔用,就會導致接收不到這一包資料,所以一定差錯控制(如ack機制,資料包冗餘機制)在實際的應用中,往往是必要的.
int main( void ) { #if (defined (DCDC_ENABLE)) && (DCDC_ENABLE == TRUE) PWR_DCDCCfg( ENABLE ); #endif SetSysClock( CLK_SOURCE_PLL_60MHz ); GPIOA_ModeCfg( GPIO_Pin_All, GPIO_ModeIN_PU ); GPIOB_ModeCfg( GPIO_Pin_All, GPIO_ModeIN_PU ); #ifdef DEBUG GPIOA_SetBits(bTXD1); GPIOA_ModeCfg(bTXD1, GPIO_ModeOut_PP_5mA); UART1_DefInit( ); #endif PRINT("%s\n",VER_LIB); CH57X_BLEInit( ); HAL_Init( ); GAPRole_PeripheralInit( ); Peripheral_Init( ); //RF_PHY 例程初始化函式 RF_Init(); Main_Circulation(); }