赞
踩
平台:两台NUCLEO-WL55JC1开发板,即STM32WL55方案,内置LoRa射频SX1261的SOC。
内容:两台设备上电后都启动2s的软定时器,timerout后监听CAD,若有IRQ_CAD_DETECTED中段,则Radio.Rx(3000); 操作其中一台设备按键发送数据"LoRa_CAD",接收段回复“ACK”。然后双方都再次进入CAD监听模式;
1.1 SX126x之前的产品,只提供对Preamble检测的功能,SX126X系统提供了对CAD检测的功能,芯片设定为进入CAD模式后,SX1261/2将在用户可选择的持续时间内(以数量定义)对频带进行扫描,如果在CAD过程中检测到LoRa®信号,则将返回检测到的通道活动IRQ。
1.2 不同于Rx Duty Cycle模式,在没有LoRa信号的情况下,MCU需要周期性的设定芯片Start CAD。而Rx Duty Cycle模式整个过程无需MCU参与,直到IRQ_PREAMBLE_DETECTED中断触发MCU。CAD模式工作时序图如下:
1.2 SetCadParams()函数原型
CAD_ONLY:
芯片在LoRa®中执行CAD操作。一旦做了什么在通道上活动时,芯片返回STBY_RC模式。
CAD_RX:
芯片执行CAD操作,如果检测到活动,则它将保持在RX状态,直到检测到数据包或计时器达
到cadTimeout*15.625us。
这里再介绍下STBY模式,参考如下
2.1 SX126x数据手册,CAD监听消耗数据如下(SF7,BW125KHz)
2.2 CAD设定,Best settings更具官方手册设定(BW = 125KHz)
2.3 CAD模式下前导码时长设定,由《LoRa学习<一>:基本参数和数据格式》可知:
加入设定每隔2s, MCU设定RF执行一次CAD监听,SF=7, BW = 125KHz,根据手册设定
cadSymbolNum = 2,Cad Time Measure = 2.6641ms。则 > (2s + 2.6641ms),可
以设定 = 2000,
= (2000+ 4.5)* 1.024ms = 2,052.608ms > 2002.6641ms
3.1 初始化函数
- //#define SUPPORT_RX_DUTY_MODE
- #define SUPPORT_CAD_MODE
-
- #ifdef SUPPORT_CAD_MODE
- #define SUPPORT_CAD_ONLY
- #endif
-
- typedef enum
- {
- LOWPOWER = 0,
- RX,
- RX_TIMEOUT,
- RX_ERROR,
- TX,
- TX_TIMEOUT,
- PREAMBLE_DETECT,
- START_CAD,
- CAD_DONE,
- } States_t;
-
- #ifdef SUPPORT_CAD_MODE
- CadRx_t CadRx = CAD_FAIL;
- static UTIL_TIMER_Object_t CADTimeoutTimer;
- #define CAD_TIMER_TIMEOUT 2000 //Define de CAD timer's timeout here
- #endif
-
- #ifdef SUPPORT_CAD_MODE
- static
- void OnCadDone( bool channelActivityDetected);
- static void CADTimeoutTimeoutIrq(void *context);
- #endif
-
-
- /* Exported functions ---------------------------------------------------------*/
- void SubghzApp_Init(void)
- {
- /* USER CODE BEGIN SubghzApp_Init_1 */
- #ifdef SUPPORT_CAD_MODE
- APP_LOG(TS_OFF, VLEVEL_M, "\n\rCAD Mode Test\n\r");
- #elif defined(SUPPORT_RX_DUTY_MODE)
- APP_LOG(TS_OFF, VLEVEL_M, "\n\rRx Duty Cycle Test\n\r");
- #endif
-
- /* Print APP version*/
- APP_LOG(TS_OFF, VLEVEL_M, "APP_VERSION= V%X.%X.%X\r\n",
- (uint8_t)(__APP_VERSION >> __APP_VERSION_MAIN_SHIFT),
- (uint8_t)(__APP_VERSION >> __APP_VERSION_SUB1_SHIFT),
- (uint8_t)(__APP_VERSION >> __APP_VERSION_SUB2_SHIFT));
-
- /* Led Timers*/
- //UTIL_TIMER_Create(&timerLed, 0xFFFFFFFFU, UTIL_TIMER_ONESHOT, OnledEvent, NULL);
- //UTIL_TIMER_SetPeriod(&timerLed, LED_PERIOD_MS);
- //UTIL_TIMER_Start(&timerLed);
- #ifdef SUPPORT_CAD_MODE
- UTIL_TIMER_Create(&CADTimeoutTimer, 0xFFFFFFFFU, UTIL_TIMER_ONESHOT, CADTimeoutTimeoutIrq, NULL);
- UTIL_TIMER_SetPeriod(&CADTimeoutTimer, CAD_TIMER_TIMEOUT);
- #endif
- //UTIL_TIMER_Start(&CADTimeoutTimer);
- /* USER CODE END SubghzApp_Init_1 */
-
- /* Radio initialization */
- RadioEvents.TxDone = OnTxDone;
- RadioEvents.RxDone = OnRxDone;
- RadioEvents.TxTimeout = OnTxTimeout;
- RadioEvents.RxTimeout = OnRxTimeout;
- RadioEvents.RxError = OnRxError;
- RadioEvents.PreambleDetect = PreambleDectect;
-
- #ifdef SUPPORT_CAD_MODE
- RadioEvents.CadDone = OnCadDone;
- #endif
-
- Radio.Init(&RadioEvents);
-
- /* USER CODE BEGIN SubghzApp_Init_2 */
- /* Radio Set frequency */
- Radio.SetChannel(RF_FREQUENCY);
-
- /* Radio configuration */
- #if ((USE_MODEM_LORA == 1) && (USE_MODEM_FSK == 0))
- APP_LOG(TS_OFF, VLEVEL_M, "---------------\n\r");
- APP_LOG(TS_OFF, VLEVEL_M, "LORA_MODULATION\n\r");
- APP_LOG(TS_OFF, VLEVEL_M, "LORA_BW=%d kHz\n\r", (1 << LORA_BANDWIDTH) * 125);
- APP_LOG(TS_OFF, VLEVEL_M, "LORA_SF=%d\n\r", LORA_SPREADING_FACTOR);
-
- #ifdef SUPPORT_CAD_MODE
- //BW = 0, 125K
- //Tsymbol = 1.024ms
- //Preamble Lenght = 2000; //2004.5*1.024 = 2,052.608
- Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, 0,
- LORA_SPREADING_FACTOR, LORA_CODINGRATE,
- 2000, LORA_FIX_LENGTH_PAYLOAD_ON,
- true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE);
-
- Radio.SetRxConfig(MODEM_LORA, 0, LORA_SPREADING_FACTOR,
- LORA_CODINGRATE, 0, 2000,
- LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
- 0, true, 0, 0, LORA_IQ_INVERSION_ON, true);
- #elif defined(SUPPORT_RX_DUTY_MODE)
- //BW = 1, 250K
- //Tsymbol = 0.512ms
- //Preamble Lenght = 2000; //2004.5*5.012 = 1,026.304
- Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, 1,
- LORA_SPREADING_FACTOR, LORA_CODINGRATE,
- 2000, LORA_FIX_LENGTH_PAYLOAD_ON,
- true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE);
-
- Radio.SetRxConfig(MODEM_LORA, 1, LORA_SPREADING_FACTOR,
- LORA_CODINGRATE, 0, 2000,
- LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
- 0, true, 0, 0, LORA_IQ_INVERSION_ON, true);
- #else
- Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
- LORA_SPREADING_FACTOR, LORA_CODINGRATE,
- LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
- true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE);
-
- Radio.SetRxConfig(MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
- LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
- LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
- 0, true, 0, 0, LORA_IQ_INVERSION_ON, true);
- #endif
-
-
- Radio.SetMaxPayloadLength(MODEM_LORA, MAX_APP_BUFFER_SIZE);
-
- #elif ((USE_MODEM_LORA == 0) && (USE_MODEM_FSK == 1))
- APP_LOG(TS_OFF, VLEVEL_M, "---------------\n\r");
- APP_LOG(TS_OFF, VLEVEL_M, "FSK_MODULATION\n\r");
- APP_LOG(TS_OFF, VLEVEL_M, "FSK_BW=%d Hz\n\r", FSK_BANDWIDTH);
- APP_LOG(TS_OFF, VLEVEL_M, "FSK_DR=%d bits/s\n\r", FSK_DATARATE);
-
- Radio.SetTxConfig(MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0,
- FSK_DATARATE, 0,
- FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON,
- true, 0, 0, 0, TX_TIMEOUT_VALUE);
-
- Radio.SetRxConfig(MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE,
- 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH,
- 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true,
- 0, 0, false, true);
-
- Radio.SetMaxPayloadLength(MODEM_FSK, MAX_APP_BUFFER_SIZE);
-
- #else
- #error "Please define a modulation in the subghz_phy_app.h file."
- #endif /* USE_MODEM_LORA | USE_MODEM_FSK */
-
-
- /* LED initialization*/
- BSP_LED_Init(LED_GREEN);
- BSP_LED_Init(LED_RED);
- BSP_LED_Init(LED_BLUE);
-
- BSP_LED_On(LED_GREEN);
-
-
- /* KEY initialization*/
- APP_LOG(TS_ON, VLEVEL_L, "Key Init\r\n");
- BSP_PB_Init(BUTTON_SW1, BUTTON_MODE_EXTI);
- BSP_PB_Init(BUTTON_SW2, BUTTON_MODE_EXTI);
- BSP_PB_Init(BUTTON_SW3, BUTTON_MODE_EXTI);
-
- /*calculate random delay for synchronization*/
- random_delay = (Radio.Random()) >> 22; /*10bits random e.g. from 0 to 1023 ms*/
- /*fills tx buffer*/
- memset(BufferTx, 0x0, MAX_APP_BUFFER_SIZE);
-
- APP_LOG(TS_ON, VLEVEL_L, "rand=%d\n\r", random_delay);
- /*starts reception*/
-
- #ifdef SUPPORT_RX_DUTY_MODE
- Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
- #elif defined(SUPPORT_CAD_MODE)
- Radio.StartCad();
- #else
- Radio.Rx(RX_TIMEOUT_VALUE);
- #endif
-
- /*register task to to be run in while(1) after Radio IT*/
- UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_SubGHz_Phy_App_Process), UTIL_SEQ_RFU, CadTest_Process);
- /* USER CODE END SubghzApp_Init_2 */
- }

3.2 设定CAD,使能CAD_DETECT,设定 CAD_ONLY,即监测到CAD信道信息后,由MCU
切换到Rx模式;
- static void RadioStartCad( void )
- {
- /* RF switch configuration */
- //SUBGRF_SetSwitch(SubgRf.AntSwitchPaSelect, RFSWITCH_RX);
-
- SUBGRF_SetDioIrqParams( IRQ_CAD_CLEAR | IRQ_CAD_DETECTED,
- IRQ_CAD_CLEAR | IRQ_CAD_DETECTED,
- IRQ_RADIO_NONE,
- IRQ_RADIO_NONE );
-
- SUBGRF_SetCadParams(LORA_CAD_02_SYMBOL, 22, 10, LORA_CAD_ONLY, 0);
- //SUBGRF_SetCadParams(LORA_CAD_02_SYMBOL, 22, 10, LORA_CAD_RX, 192000);
-
- //SUBGRF_SetCadParams(LORA_CAD_04_SYMBOL, 21, 10, LORA_CAD_RX, 192000);
-
- SUBGRF_SetCad( );
- }

3.3 CAD Done和CAD Detect中断处理函数,如果是CAD Detect,则进入Rx模式,否则继续
启动Timer,并再次启动CAD Start。
-
- static void RadioIrqProcess( void )
- {
- uint8_t size = 0;
- int32_t cfo = 0;
-
- MW_LOG( TS_OFF, VLEVEL_M, "IRQ = %d\r\n", SubgRf.RadioIrq);
- switch ( SubgRf.RadioIrq )
- {
- //省略部分
- 。。。。。。
-
- case IRQ_CAD_CLEAR:
- //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
- //SUBGRF_SetStandby( STDBY_RC );
- if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) )
- {
- RadioEvents->CadDone( false );
- }
- break;
-
- case IRQ_CAD_DETECTED:
- //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
- //SUBGRF_SetStandby( STDBY_RC );
- if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) )
- {
- RadioEvents->CadDone( true );
- }
- break;
-
- 。。。。。。
- //省略部分
- default:
- break;
- }
- }

- #ifdef SUPPORT_CAD_MODE
- static void OnCadDone( bool channelActivityDetected)
- {
- if( channelActivityDetected == true )
- {
- CadRx = CAD_SUCCESS;
- #ifdef SUPPORT_CAD_ONLY
- State = CAD_DONE;
- UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_SubGHz_Phy_App_Process), CFG_SEQ_Prio_0);
- #endif
- }
- else
- {
- CadRx = CAD_FAIL;
- UTIL_TIMER_Start(&CADTimeoutTimer);
- }
- }
- #endif

3.4 CAD timer中断函数
- #ifdef SUPPORT_CAD_MODE
- static void CADTimeoutTimeoutIrq(void *context)
- {
- Radio.Standby( );
- State = START_CAD;
- UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_SubGHz_Phy_App_Process), CFG_SEQ_Prio_0);
- }
- #endif
3.5 CadTest_Process状态处理函数
-
- /* USER CODE BEGIN PrFD */
- static void CadTest_Process(void)
- {
- static bool TxAckFlag = false;
- uint8_t i = 0;
-
- APP_LOG(TS_OFF, VLEVEL_L, "State=%d\n\r", State);
- switch (State)
- {
- case RX:
- if (RxBufferSize > 0) //Received is True;
- {
- APP_LOG(TS_OFF, VLEVEL_L, "Rx:");
- for(i=0; i<RxBufferSize; i++)
- {
- APP_LOG(TS_OFF, VLEVEL_L, "%02x ", BufferRx[i]);
- }
- APP_LOG(TS_OFF, VLEVEL_L, "len(%d)\n\r", RxBufferSize);
-
- if (strncmp((const char *)BufferRx, ACKMSG, sizeof(ACKMSG) - 1) == 0)
- {
- BSP_LED_On(LED_RED);
- HAL_Delay(Radio.GetWakeupTime() + RX_TIME_MARGIN);
- BSP_LED_Off(LED_RED);
-
- #ifdef SUPPORT_RX_DUTY_MODE
- APP_LOG(TS_OFF, VLEVEL_L, "Rx Ack success, Go Duty Cycle\n\r");
- Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
- #elif defined(SUPPORT_CAD_MODE)
- APP_LOG(TS_OFF, VLEVEL_L, "Rx Ack success, Go CAD Mode\n\r");
- UTIL_TIMER_Start(&CADTimeoutTimer);
- #else
- Radio.Rx(3000);
- #endif
- }
- else if (strncmp((const char *)BufferRx, TXMSG, sizeof(TXMSG) - 1) == 0)
- {
- BSP_LED_On(LED_GREEN);
- HAL_Delay(Radio.GetWakeupTime() + RX_TIME_MARGIN);
- BSP_LED_Off(LED_GREEN);
- APP_LOG(TS_OFF, VLEVEL_L, "Rx success, Send Ack\n\r");
- memcpy(BufferTx, ACKMSG, sizeof(ACKMSG) - 1);
- Radio.Send(BufferTx, PAYLOAD_LEN);
- TxAckFlag = true;
-
- //APP_LOG(TS_OFF, VLEVEL_L, "Go Duty Cycle\n\r");
- //Radio.SetRxDutyCycle(1000, 5000);
- }
- }
- #ifdef SUPPORT_CAD_MODE
- else
- {
- if (CadRx == CAD_SUCCESS)
- {
- APP_LOG(TS_ON, VLEVEL_L, "CAD_SUCCESS, Go Rx\n\r");
- Radio.Rx( RX_TIMEOUT_VALUE );
- }
- else
- {
- APP_LOG(TS_ON, VLEVEL_L, "Restart Cad timer\n\r");
- UTIL_TIMER_Start(&CADTimeoutTimer);
- }
- }
- #endif
- break;
-
- case TX:
- if(TxAckFlag == false)
- {
- APP_LOG(TS_OFF, VLEVEL_L, "Tx Msg Done, wait Ack\n\r");
- Radio.Rx(1000);
- }
- else
- {
- TxAckFlag = false;
- #ifdef SUPPORT_RX_DUTY_MODE
- APP_LOG(TS_OFF, VLEVEL_L, "Tx Timeout, Go Duty Cycle\n\r");
- Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
- #elif defined(SUPPORT_CAD_MODE)
- UTIL_TIMER_Start(&CADTimeoutTimer);
- #else
- Radio.Rx(3000);
- #endif
- }
- break;
-
- case RX_TIMEOUT:
- APP_LOG(TS_OFF, VLEVEL_L, "Rx Timeout, ");
- case RX_ERROR:
- #ifdef SUPPORT_RX_DUTY_MODE
- APP_LOG(TS_OFF, VLEVEL_L, "Rx Err, Go Duty Cycle\n\r");
- Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
- #elif defined(SUPPORT_CAD_MODE)
- APP_LOG(TS_OFF, VLEVEL_L, "Rx Err, Go Cad\n\r");
- UTIL_TIMER_Start(&CADTimeoutTimer);
- #else
- Radio.Rx(3000);
- #endif
- break;
-
- case TX_TIMEOUT:
- #ifdef SUPPORT_RX_DUTY_MODE
- APP_LOG(TS_OFF, VLEVEL_L, "Tx Timeout, Go Duty Cycle\n\r");
- Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
- #elif defined(SUPPORT_CAD_MODE)
- APP_LOG(TS_OFF, VLEVEL_L, "Tx Timeout, Go Cad\n\r");
- UTIL_TIMER_Start(&CADTimeoutTimer);
- #else
- Radio.Rx(3000);
- #endif
- break;
-
- case PREAMBLE_DETECT:
- APP_LOG(TS_ON, VLEVEL_L, "Preamble Dectect, Go Rx\n\r");
- break;
-
- case START_CAD:
- Radio.StartCad();
- break;
-
- case CAD_DONE
- :
- APP_LOG(TS_ON, VLEVEL_L, "CAD Dectect, Go Rx\n\r");
- Radio.Rx(3000);
- break;
-
- case LOWPOWER:
- default:
- break;
- }
- }

测试软件下载STM32Cube_FW_WL_V1.1.0_Test.rar-嵌入式文档类资源-CSDN文库
工程路径:STM32Cube_FW_WL_V1.1.0_Test\Projects\NUCLEO-WL55JC\Applications\SubGHz_Phy\SubGHz_Phy_PingPong
其中Keil MDK和STM32CubeIDE编译测试都有测试OK;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。