当前位置:   article > 正文

LoRa学习<三>:CAD模式实验_lora cad

lora cad

平台:两台NUCLEO-WL55JC1开发板,即STM32WL55方案,内置LoRa射频SX1261的SOC。

内容:两台设备上电后都启动2s的软定时器,timerout后监听CAD,若有IRQ_CAD_DETECTED中段,则Radio.Rx(3000);   操作其中一台设备按键发送数据"LoRa_CAD",接收段回复“ACK”。然后双方都再次进入CAD监听模式;

一、CAD监听(Channel Activity Detection

       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模式,参考如下

         

         

二、CAD参数设定

        2.1 SX126x数据手册,CAD监听消耗数据如下(SF7,BW125KHz)

        2.2 CAD设定,Best settings更具官方手册设定(BW = 125KHz)

 

        2.3 CAD模式下前导码时长设定,由《LoRa学习<一>:基本参数和数据格式》可知:

                                                T_{symbol} = \frac{2^{SF}}{BW} = 1.024ms 

                                                T_{preamble} = (N_{preamble} + 4.5) * T_{symbol}

              加入设定每隔2s, MCU设定RF执行一次CAD监听,SF=7, BW = 125KHz,根据手册设定

        cadSymbolNum = 2,Cad Time Measure = 2.6641ms。则T_{preamble} > (2s + 2.6641ms),可

        以设定N_{preamble} = 2000,

                            ​​​​T_{preamble} = (2000+ 4.5)* 1.024ms = 2,052.608ms > 2002.6641ms

三、参考代码如下

        3.1 初始化函数

  1. //#define SUPPORT_RX_DUTY_MODE
  2. #define SUPPORT_CAD_MODE
  3. #ifdef SUPPORT_CAD_MODE
  4. #define SUPPORT_CAD_ONLY
  5. #endif
  6. typedef enum
  7. {
  8. LOWPOWER = 0,
  9. RX,
  10. RX_TIMEOUT,
  11. RX_ERROR,
  12. TX,
  13. TX_TIMEOUT,
  14. PREAMBLE_DETECT,
  15. START_CAD,
  16. CAD_DONE,
  17. } States_t;
  18. #ifdef SUPPORT_CAD_MODE
  19. CadRx_t CadRx = CAD_FAIL;
  20. static UTIL_TIMER_Object_t CADTimeoutTimer;
  21. #define CAD_TIMER_TIMEOUT 2000 //Define de CAD timer's timeout here
  22. #endif
  23. #ifdef SUPPORT_CAD_MODE
  24. static
  25. void OnCadDone( bool channelActivityDetected);
  26. static void CADTimeoutTimeoutIrq(void *context);
  27. #endif
  28. /* Exported functions ---------------------------------------------------------*/
  29. void SubghzApp_Init(void)
  30. {
  31. /* USER CODE BEGIN SubghzApp_Init_1 */
  32. #ifdef SUPPORT_CAD_MODE
  33. APP_LOG(TS_OFF, VLEVEL_M, "\n\rCAD Mode Test\n\r");
  34. #elif defined(SUPPORT_RX_DUTY_MODE)
  35. APP_LOG(TS_OFF, VLEVEL_M, "\n\rRx Duty Cycle Test\n\r");
  36. #endif
  37. /* Print APP version*/
  38. APP_LOG(TS_OFF, VLEVEL_M, "APP_VERSION= V%X.%X.%X\r\n",
  39. (uint8_t)(__APP_VERSION >> __APP_VERSION_MAIN_SHIFT),
  40. (uint8_t)(__APP_VERSION >> __APP_VERSION_SUB1_SHIFT),
  41. (uint8_t)(__APP_VERSION >> __APP_VERSION_SUB2_SHIFT));
  42. /* Led Timers*/
  43. //UTIL_TIMER_Create(&timerLed, 0xFFFFFFFFU, UTIL_TIMER_ONESHOT, OnledEvent, NULL);
  44. //UTIL_TIMER_SetPeriod(&timerLed, LED_PERIOD_MS);
  45. //UTIL_TIMER_Start(&timerLed);
  46. #ifdef SUPPORT_CAD_MODE
  47. UTIL_TIMER_Create(&CADTimeoutTimer, 0xFFFFFFFFU, UTIL_TIMER_ONESHOT, CADTimeoutTimeoutIrq, NULL);
  48. UTIL_TIMER_SetPeriod(&CADTimeoutTimer, CAD_TIMER_TIMEOUT);
  49. #endif
  50. //UTIL_TIMER_Start(&CADTimeoutTimer);
  51. /* USER CODE END SubghzApp_Init_1 */
  52. /* Radio initialization */
  53. RadioEvents.TxDone = OnTxDone;
  54. RadioEvents.RxDone = OnRxDone;
  55. RadioEvents.TxTimeout = OnTxTimeout;
  56. RadioEvents.RxTimeout = OnRxTimeout;
  57. RadioEvents.RxError = OnRxError;
  58. RadioEvents.PreambleDetect = PreambleDectect;
  59. #ifdef SUPPORT_CAD_MODE
  60. RadioEvents.CadDone = OnCadDone;
  61. #endif
  62. Radio.Init(&RadioEvents);
  63. /* USER CODE BEGIN SubghzApp_Init_2 */
  64. /* Radio Set frequency */
  65. Radio.SetChannel(RF_FREQUENCY);
  66. /* Radio configuration */
  67. #if ((USE_MODEM_LORA == 1) && (USE_MODEM_FSK == 0))
  68. APP_LOG(TS_OFF, VLEVEL_M, "---------------\n\r");
  69. APP_LOG(TS_OFF, VLEVEL_M, "LORA_MODULATION\n\r");
  70. APP_LOG(TS_OFF, VLEVEL_M, "LORA_BW=%d kHz\n\r", (1 << LORA_BANDWIDTH) * 125);
  71. APP_LOG(TS_OFF, VLEVEL_M, "LORA_SF=%d\n\r", LORA_SPREADING_FACTOR);
  72. #ifdef SUPPORT_CAD_MODE
  73. //BW = 0, 125K
  74. //Tsymbol = 1.024ms
  75. //Preamble Lenght = 2000; //2004.5*1.024 = 2,052.608
  76. Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, 0,
  77. LORA_SPREADING_FACTOR, LORA_CODINGRATE,
  78. 2000, LORA_FIX_LENGTH_PAYLOAD_ON,
  79. true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE);
  80. Radio.SetRxConfig(MODEM_LORA, 0, LORA_SPREADING_FACTOR,
  81. LORA_CODINGRATE, 0, 2000,
  82. LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
  83. 0, true, 0, 0, LORA_IQ_INVERSION_ON, true);
  84. #elif defined(SUPPORT_RX_DUTY_MODE)
  85. //BW = 1, 250K
  86. //Tsymbol = 0.512ms
  87. //Preamble Lenght = 2000; //2004.5*5.012 = 1,026.304
  88. Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, 1,
  89. LORA_SPREADING_FACTOR, LORA_CODINGRATE,
  90. 2000, LORA_FIX_LENGTH_PAYLOAD_ON,
  91. true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE);
  92. Radio.SetRxConfig(MODEM_LORA, 1, LORA_SPREADING_FACTOR,
  93. LORA_CODINGRATE, 0, 2000,
  94. LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
  95. 0, true, 0, 0, LORA_IQ_INVERSION_ON, true);
  96. #else
  97. Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
  98. LORA_SPREADING_FACTOR, LORA_CODINGRATE,
  99. LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
  100. true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE);
  101. Radio.SetRxConfig(MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
  102. LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
  103. LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
  104. 0, true, 0, 0, LORA_IQ_INVERSION_ON, true);
  105. #endif
  106. Radio.SetMaxPayloadLength(MODEM_LORA, MAX_APP_BUFFER_SIZE);
  107. #elif ((USE_MODEM_LORA == 0) && (USE_MODEM_FSK == 1))
  108. APP_LOG(TS_OFF, VLEVEL_M, "---------------\n\r");
  109. APP_LOG(TS_OFF, VLEVEL_M, "FSK_MODULATION\n\r");
  110. APP_LOG(TS_OFF, VLEVEL_M, "FSK_BW=%d Hz\n\r", FSK_BANDWIDTH);
  111. APP_LOG(TS_OFF, VLEVEL_M, "FSK_DR=%d bits/s\n\r", FSK_DATARATE);
  112. Radio.SetTxConfig(MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0,
  113. FSK_DATARATE, 0,
  114. FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON,
  115. true, 0, 0, 0, TX_TIMEOUT_VALUE);
  116. Radio.SetRxConfig(MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE,
  117. 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH,
  118. 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true,
  119. 0, 0, false, true);
  120. Radio.SetMaxPayloadLength(MODEM_FSK, MAX_APP_BUFFER_SIZE);
  121. #else
  122. #error "Please define a modulation in the subghz_phy_app.h file."
  123. #endif /* USE_MODEM_LORA | USE_MODEM_FSK */
  124. /* LED initialization*/
  125. BSP_LED_Init(LED_GREEN);
  126. BSP_LED_Init(LED_RED);
  127. BSP_LED_Init(LED_BLUE);
  128. BSP_LED_On(LED_GREEN);
  129. /* KEY initialization*/
  130. APP_LOG(TS_ON, VLEVEL_L, "Key Init\r\n");
  131. BSP_PB_Init(BUTTON_SW1, BUTTON_MODE_EXTI);
  132. BSP_PB_Init(BUTTON_SW2, BUTTON_MODE_EXTI);
  133. BSP_PB_Init(BUTTON_SW3, BUTTON_MODE_EXTI);
  134. /*calculate random delay for synchronization*/
  135. random_delay = (Radio.Random()) >> 22; /*10bits random e.g. from 0 to 1023 ms*/
  136. /*fills tx buffer*/
  137. memset(BufferTx, 0x0, MAX_APP_BUFFER_SIZE);
  138. APP_LOG(TS_ON, VLEVEL_L, "rand=%d\n\r", random_delay);
  139. /*starts reception*/
  140. #ifdef SUPPORT_RX_DUTY_MODE
  141. Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
  142. #elif defined(SUPPORT_CAD_MODE)
  143. Radio.StartCad();
  144. #else
  145. Radio.Rx(RX_TIMEOUT_VALUE);
  146. #endif
  147. /*register task to to be run in while(1) after Radio IT*/
  148. UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_SubGHz_Phy_App_Process), UTIL_SEQ_RFU, CadTest_Process);
  149. /* USER CODE END SubghzApp_Init_2 */
  150. }

         3.2 设定CAD,使能CAD_DETECT,设定 CAD_ONLY,即监测到CAD信道信息后,由MCU

切换到Rx模式;

  1. static void RadioStartCad( void )
  2. {
  3. /* RF switch configuration */
  4. //SUBGRF_SetSwitch(SubgRf.AntSwitchPaSelect, RFSWITCH_RX);
  5. SUBGRF_SetDioIrqParams( IRQ_CAD_CLEAR | IRQ_CAD_DETECTED,
  6. IRQ_CAD_CLEAR | IRQ_CAD_DETECTED,
  7. IRQ_RADIO_NONE,
  8. IRQ_RADIO_NONE );
  9. SUBGRF_SetCadParams(LORA_CAD_02_SYMBOL, 22, 10, LORA_CAD_ONLY, 0);
  10. //SUBGRF_SetCadParams(LORA_CAD_02_SYMBOL, 22, 10, LORA_CAD_RX, 192000);
  11. //SUBGRF_SetCadParams(LORA_CAD_04_SYMBOL, 21, 10, LORA_CAD_RX, 192000);
  12. SUBGRF_SetCad( );
  13. }

         3.3 CAD Done和CAD Detect中断处理函数,如果是CAD Detect,则进入Rx模式,否则继续

启动Timer,并再次启动CAD Start。

  1. static void RadioIrqProcess( void )
  2. {
  3. uint8_t size = 0;
  4. int32_t cfo = 0;
  5. MW_LOG( TS_OFF, VLEVEL_M, "IRQ = %d\r\n", SubgRf.RadioIrq);
  6. switch ( SubgRf.RadioIrq )
  7. {
  8. //省略部分
  9. 。。。。。。
  10. case IRQ_CAD_CLEAR:
  11. //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
  12. //SUBGRF_SetStandby( STDBY_RC );
  13. if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) )
  14. {
  15. RadioEvents->CadDone( false );
  16. }
  17. break;
  18. case IRQ_CAD_DETECTED:
  19. //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
  20. //SUBGRF_SetStandby( STDBY_RC );
  21. if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) )
  22. {
  23. RadioEvents->CadDone( true );
  24. }
  25. break;
  26. 。。。。。。
  27. //省略部分
  28. default:
  29. break;
  30. }
  31. }
  1. #ifdef SUPPORT_CAD_MODE
  2. static void OnCadDone( bool channelActivityDetected)
  3. {
  4. if( channelActivityDetected == true )
  5. {
  6. CadRx = CAD_SUCCESS;
  7. #ifdef SUPPORT_CAD_ONLY
  8. State = CAD_DONE;
  9. UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_SubGHz_Phy_App_Process), CFG_SEQ_Prio_0);
  10. #endif
  11. }
  12. else
  13. {
  14. CadRx = CAD_FAIL;
  15. UTIL_TIMER_Start(&CADTimeoutTimer);
  16. }
  17. }
  18. #endif

         3.4  CAD timer中断函数

  1. #ifdef SUPPORT_CAD_MODE
  2. static void CADTimeoutTimeoutIrq(void *context)
  3. {
  4. Radio.Standby( );
  5. State = START_CAD;
  6. UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_SubGHz_Phy_App_Process), CFG_SEQ_Prio_0);
  7. }
  8. #endif

         3.5  CadTest_Process状态处理函数

  1. /* USER CODE BEGIN PrFD */
  2. static void CadTest_Process(void)
  3. {
  4. static bool TxAckFlag = false;
  5. uint8_t i = 0;
  6. APP_LOG(TS_OFF, VLEVEL_L, "State=%d\n\r", State);
  7. switch (State)
  8. {
  9. case RX:
  10. if (RxBufferSize > 0) //Received is True;
  11. {
  12. APP_LOG(TS_OFF, VLEVEL_L, "Rx:");
  13. for(i=0; i<RxBufferSize; i++)
  14. {
  15. APP_LOG(TS_OFF, VLEVEL_L, "%02x ", BufferRx[i]);
  16. }
  17. APP_LOG(TS_OFF, VLEVEL_L, "len(%d)\n\r", RxBufferSize);
  18. if (strncmp((const char *)BufferRx, ACKMSG, sizeof(ACKMSG) - 1) == 0)
  19. {
  20. BSP_LED_On(LED_RED);
  21. HAL_Delay(Radio.GetWakeupTime() + RX_TIME_MARGIN);
  22. BSP_LED_Off(LED_RED);
  23. #ifdef SUPPORT_RX_DUTY_MODE
  24. APP_LOG(TS_OFF, VLEVEL_L, "Rx Ack success, Go Duty Cycle\n\r");
  25. Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
  26. #elif defined(SUPPORT_CAD_MODE)
  27. APP_LOG(TS_OFF, VLEVEL_L, "Rx Ack success, Go CAD Mode\n\r");
  28. UTIL_TIMER_Start(&CADTimeoutTimer);
  29. #else
  30. Radio.Rx(3000);
  31. #endif
  32. }
  33. else if (strncmp((const char *)BufferRx, TXMSG, sizeof(TXMSG) - 1) == 0)
  34. {
  35. BSP_LED_On(LED_GREEN);
  36. HAL_Delay(Radio.GetWakeupTime() + RX_TIME_MARGIN);
  37. BSP_LED_Off(LED_GREEN);
  38. APP_LOG(TS_OFF, VLEVEL_L, "Rx success, Send Ack\n\r");
  39. memcpy(BufferTx, ACKMSG, sizeof(ACKMSG) - 1);
  40. Radio.Send(BufferTx, PAYLOAD_LEN);
  41. TxAckFlag = true;
  42. //APP_LOG(TS_OFF, VLEVEL_L, "Go Duty Cycle\n\r");
  43. //Radio.SetRxDutyCycle(1000, 5000);
  44. }
  45. }
  46. #ifdef SUPPORT_CAD_MODE
  47. else
  48. {
  49. if (CadRx == CAD_SUCCESS)
  50. {
  51. APP_LOG(TS_ON, VLEVEL_L, "CAD_SUCCESS, Go Rx\n\r");
  52. Radio.Rx( RX_TIMEOUT_VALUE );
  53. }
  54. else
  55. {
  56. APP_LOG(TS_ON, VLEVEL_L, "Restart Cad timer\n\r");
  57. UTIL_TIMER_Start(&CADTimeoutTimer);
  58. }
  59. }
  60. #endif
  61. break;
  62. case TX:
  63. if(TxAckFlag == false)
  64. {
  65. APP_LOG(TS_OFF, VLEVEL_L, "Tx Msg Done, wait Ack\n\r");
  66. Radio.Rx(1000);
  67. }
  68. else
  69. {
  70. TxAckFlag = false;
  71. #ifdef SUPPORT_RX_DUTY_MODE
  72. APP_LOG(TS_OFF, VLEVEL_L, "Tx Timeout, Go Duty Cycle\n\r");
  73. Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
  74. #elif defined(SUPPORT_CAD_MODE)
  75. UTIL_TIMER_Start(&CADTimeoutTimer);
  76. #else
  77. Radio.Rx(3000);
  78. #endif
  79. }
  80. break;
  81. case RX_TIMEOUT:
  82. APP_LOG(TS_OFF, VLEVEL_L, "Rx Timeout, ");
  83. case RX_ERROR:
  84. #ifdef SUPPORT_RX_DUTY_MODE
  85. APP_LOG(TS_OFF, VLEVEL_L, "Rx Err, Go Duty Cycle\n\r");
  86. Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
  87. #elif defined(SUPPORT_CAD_MODE)
  88. APP_LOG(TS_OFF, VLEVEL_L, "Rx Err, Go Cad\n\r");
  89. UTIL_TIMER_Start(&CADTimeoutTimer);
  90. #else
  91. Radio.Rx(3000);
  92. #endif
  93. break;
  94. case TX_TIMEOUT:
  95. #ifdef SUPPORT_RX_DUTY_MODE
  96. APP_LOG(TS_OFF, VLEVEL_L, "Tx Timeout, Go Duty Cycle\n\r");
  97. Radio.SetRxDutyCycle(RC_RX_TIIME, RC_SLEEP_TIIME);
  98. #elif defined(SUPPORT_CAD_MODE)
  99. APP_LOG(TS_OFF, VLEVEL_L, "Tx Timeout, Go Cad\n\r");
  100. UTIL_TIMER_Start(&CADTimeoutTimer);
  101. #else
  102. Radio.Rx(3000);
  103. #endif
  104. break;
  105. case PREAMBLE_DETECT:
  106. APP_LOG(TS_ON, VLEVEL_L, "Preamble Dectect, Go Rx\n\r");
  107. break;
  108. case START_CAD:
  109. Radio.StartCad();
  110. break;
  111. case CAD_DONE
  112. :
  113. APP_LOG(TS_ON, VLEVEL_L, "CAD Dectect, Go Rx\n\r");
  114. Radio.Rx(3000);
  115. break;
  116. case LOWPOWER:
  117. default:
  118. break;
  119. }
  120. }

四、实验结果

 测试软件下载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;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/714223
推荐阅读
相关标签
  

闽ICP备14008679号