iot-fan

联系: iotfan123#163.com
注意:
1,本博客之内容来源于网上收集以及相关技术人员提供,如果有侵犯到您的权益,请电邮我沟通;
2,本博客之内容乃分享,交流,学习,研究之目的,作者不对内容的真实性,有效性,及时性负责,也不对因本博客的任何内容导致的任何后果负责;
3,本博客之内容禁止转发到CSDN网站,转到别的网站请保留出处.

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

前言

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
  • CH32F208
  • CH32V208

使用

初始化

void RF_Init( void ) {
    uint8 state;
    rfConfig_t rfConfig;
    tmos_memset(&rfConfig,0,sizeof(rfConfig_t));
    //注册一个task,用于用户调度
    taskID = TMOS_ProcessEventRegister( RF_ProcessEvent );
#if defined(CH579) //针对ch59
    rfConfig.TxAccessAddress = 0x8E89BED6;
    rfConfig.RxAccessAddress = 0x8E89BED6;
    rfConfig.TxCRCInit = 0x555555;
    rfConfig.RxCRCInit = 0x555555;
#else
    //这里的 accessAddress 就是preamble后跟的同步字,用于识别一个新包到来,收发设置成一样是是收到包的前提
    //这个accessAddress 的设置要符合蓝牙规范,比如禁止使用0x55555555以及0xAAAAAAAA ( 建议不超过24次位反转,且不超过连续的6个0或1 )
    rfConfig.accessAddress = 0x8E89BED6;
    //crc24_ble 的初值,这个收发也要相同,否则一定会在接收完成后产生crc24 错误
    rfConfig.CRCInit = 0x555555;
#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 系列不支持)
    //在ch58x平台,通过这里的对应bit来设置不同的PHY 速率,如1M/2M/500K/125K
    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 ); 注册的
//对于ch59x,ch32x208 系列,该回掉为LLE中断回掉, 对于之气那的ch58x,ch57x 系列芯片,该回掉为tmos回掉
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 ) {
                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;
            }
            if( crc & 0x01 ) {
                 PRINT("crc error\n");
            }
            if( crc & 0x02 )
                PRINT("match type error\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 ) {
                uint8 i;
                //rxBuf[0] 默认情况下是rssi,如果 在LLEMode初始化时同时开启了LLE_MODE_NON_RSSI,那这里将会变为PKT_TYPE
                PRINT("rx recv, rssi: %d\n",(s8)rxBuf[0]);
                //针对ch573/571我们还可以通过下面方式获取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;
            }
            if( crc & 0x01 ) {
                 PRINT("crc error\n");
            }
            if( crc & 0x02 )
                PRINT("match type error\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;
    tmos_memset(&rfConfig,0,sizeof(rfConfig_t));
    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广播

这里我们只是对单个channel进行被动扫描(不发scan_request,自然也拿不到scan_rspone)

//init
//根模拟蓝牙广播一样初始化,只是接下来是进接收模式

//接收处理
        case RX_MODE_RX_DATA:
            if(!crc) {
                uint8_t pkt_length = rxBuf[1];
                int8_t rssi = (int8_t)rxBuf[0];
                uint8_t *mac_addr = &rxBuf[2];
                uint8_t *adv_data = &rxBuf[2+6];
                uint8_t adv_length = pkt_length - 6;

                PRINT("adv_len:%u,rssi:%3d\n",adv_length,rssi);
                PRINT("mac_addr:");
                hex_dump(mac_addr, 6);
                PRINT("adv_data:");
                hex_dump(adv_data, adv_length);
            }
            tmos_set_event(taskID, SBP_RF_RF_RX_EVT);

与BLE工程一起跑

BLE的工作特点是间歇性工作,依据广播间隔/连接间隔协议栈进行定时调用收发器工作,其他时间收发器资源都是释放的,这也是为什么的BLE可以和WIFI,zigbee,thread等协议共用部分射频资源动态共存的原因
鉴于BLE的这种工作特点,wch也把RF_PHY 这种模式与ble可以共存运行.
下面在wch 提供的ble的工程里面加入RF_PHY 工作的初始方式,实际上就是把RF_PHY的初始化函数放在BLE初始化完成后调用即可,但是由于BLE 的存在,所以丢包可能是非常普遍, 如,这边在发射,接收端的射频被BLE短暂占用,就会导致接收不到这一包数据,所以一定差错控制(如ack机制,数据包冗余机制)在实际的应用中,往往是必要的.

  • 注意蓝牙的堆开销,建议额外增加1K的蓝牙的RAM空间
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( );
    RF_RoleInit();      //使能私有2.4G角色
    Peripheral_Init( );
    RF_Init();          //初始化私有2.4G角色
    Main_Circulation();
}
posted on 2021-01-24 11:45  iot-fan  阅读(4658)  评论(0编辑  收藏  举报