前言
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();
}