CC1101: WOR间隔出现WOR Timing Error,配置为1s实际为300s

Part Number: CC1101


image.png我想要关于WOR实现的示例代码。因为勘误手册中有多处关于WOR的bug,我复现了多种bug。同时我也复现了唤醒处于WOR模式下,唤醒失败的情况。当存在一次正常数据交互后会概率出现唤醒成功,一段时间之后又唤醒失败了。希望提供可靠稳定的实现WOR的示例代码,以及实现唤醒处于WOR模式下的示例代码。

  • 已经收到了您的案例,调查需要些时间,感谢您的耐心等待。

  • 我现在的问题还包括执行了WOR命令,但是有概率停留在IDLE状态,但是从EVENT0查看的话依然是按照设置的间隔有一个脉冲。但是无法被唤醒,从功耗监控的话是1.8mA,接近IDLE状态的功耗。最核心的问题是我无法保证WOR执行完肯定进入了。再执行SPI指令验证肯定会让cc1101退出sleep返回IDLE状态。这个如何实现稳定性的进入WOR呢。

  • 我遇到处于WOR模式的cc1101会突然进RX,此时GDO0为EVENT0 GDO2为CRC_OK,引脚并没有变化。唯一有变化的是WOR间隔从996ms变化为988ms.有些时候RX会进入idle有时候不会。帮我分析这是什么造成的,如何修复

    我仿真GDO0和GDO2引脚中断,始终没有进入。事实上逻辑分析仪也没有监控到变化。但是模组的功耗突然上升17mA左右,然后变化为1.7mA左右。有时候可能会维持17mA。很接近RX和IDLE的功耗。此时我并没有对cc1101进行配置。

  •  我找到了问题点。事实上和GDO0配置为EVENT0 ,GDO2配置为CRC_OK有关。当接收到干扰的假唤醒信号后,CC1101会进入RX模式维持到超时进入IDLE模式。上述两个配置均不会触发导致MCU没有响应异常的信号。我把GDO2改为0x06,end of the packet之后。对异常信号进行识别排查后正常返回WOR就可以了。

  • 上面那个帖子其实就是我咨询的。但是那个方案有概率还是会复现WOR间隔异常。我已经按照勘误手册进行处理了,依旧还会复现。主要是进入WOR之后无法验证这个间隔是否对。我需要一个经过验证可靠的实现方案。

    void CC1101_Write_Cmd_SWOR()
    {
      // Step1: 进入IDLE并清FIFO
      CC1101_SET_CSN_LOW();
      Delay_Us(300);
      CC1101_Write_Cmd(CC1101_SIDLE);
      Delay_Us(1000);
      
      CC1101_Write_Reg(CC1101_IOCFG0, 0x29); // CHIP_RDYn
      (void)CC1101_Wait_ChipReady(2000);
      CC1101_Write_Cmd(CC1101_SFRX);
    
      //多次校准避免触发 WOR timing error on short timing intervals bug
      // Step2: 频综SCAL校准,最多3次,确保回到IDLE
      bool scal_ok = false;
      for (uint8_t attempt = 0; attempt < 3 && !scal_ok; ++attempt) {
          CC1101_Write_Cmd(CC1101_SCAL);
          uint32_t guard = 5000;
          while (guard) {
              uint8_t marc = (uint8_t)(CC1101_Read_Status(CC1101_MARCSTATE) & 0x1F);
              if (marc == 0x01) { scal_ok = true; break; }
              Delay_Us(50); guard = (guard > 50) ? (guard - 50) : 0;
          }
          if (!scal_ok) {
              CC1101_Write_Cmd(CC1101_SIDLE);
              CC1101_Write_Cmd(CC1101_SFRX);
              Delay_Us(500);
          }
      }
      if (!scal_ok) { extern uint8_t RF_reset; RF_reset = 2; return; }
    
       CC1101_Write_Reg(CC1101_MCSM0, 0x38);//PO_TIMEOUT = 2 155us
      // Step3: 配置WOR相关寄存器
      if (WOR_short) {
          CC1101_Write_Reg(CC1101_MCSM2, 0x37);
          CC1101_Write_Reg(CC1101_WOREVT1, 0x06);
          CC1101_Write_Reg(CC1101_WOREVT0, 0xC5);
      } else {
          CC1101_Write_Reg(CC1101_MCSM2, 0x37);
          CC1101_Write_Reg(CC1101_WOREVT1, 0x87);
          CC1101_Write_Reg(CC1101_WOREVT0, 0x6A);
      }
      
      DisableInterruptsAndSaveState();
      CC1101_Write_Reg(CC1101_IOCFG0, 0x26); // CLK_256 间隔1.84ms电平翻转
      
      CC1101_Write_Reg(CC1101_WORCTRL, 0x58); // EVENT1=5, RC_CAL=1 Enables RC oscillator calibration.
      Delay_Ms(3); //等待校准完成
    
      // 在 RC_CAL=1 的情况下,尽量先读取并缓存 RCCTRL 状态值,
      // 以便在捕获 GDO0 边沿并清除 RC_CAL 后能马上写回,
      // 避免在 1.84ms 窗口内执行过多 SPI 操作导致 WOR timer 变慢。
      uint8_t cached_c1 = 0, cached_c0 = 0; bool cached_ok = false;
      for (uint8_t i = 0; i < 3 && !cached_ok; ++i) {
        uint8_t r1 = CC1101_Read_Status(RCCTRL1_STATUS);
        uint8_t r0 = CC1101_Read_Status(RCCTRL0_STATUS);
        if (r1 != 0) cached_c1 = r1; else if (g_wor_last_calib1) cached_c1 = g_wor_last_calib1;
        if (r0 != 0) cached_c0 = r0; else if (g_wor_last_calib0) cached_c0 = g_wor_last_calib0;
        cached_ok = (cached_c1 != 0 && cached_c0 != 0);
      }
    
      // 等待 GDO0 边沿,一旦捕获立即清除 RC_CAL,并尽快写回 RCCTRL 寄存器,随后进入 SWOR
      while(1)
      {
        if(GDO0_IN == 0)
          break;
      }
      CC1101_Write_Reg(CC1101_WORCTRL, 0x50); // EVENT1=5(667us >PO_TIMEOUT155us + startup 150us), RC_CAL=0
    
      // 立即写回缓存的 RCCTRL 值(如果有),以尽量缩短从清除 RC_CAL 到进入 SWOR 的时间窗口
      if (cached_ok) {
        CC1101_Write_Reg(CC1101_RCCTRL1, cached_c1);
        CC1101_Write_Reg(CC1101_RCCTRL0, cached_c0);
        if (cached_c1) g_wor_last_calib1 = cached_c1; if (cached_c0) g_wor_last_calib0 = cached_c0;
      }else {
         extern uint8_t RF_reset; RF_reset = 2; return;
      }
    
      CC1101_Write_Reg(CC1101_IOCFG2, 0x25); // WOR_EVENT0/WOR_EVENT1
      CC1101_Write_Reg(CC1101_IOCFG0, 0x06); // end of the packet
      
      // Step6: 进入WOR(临界区,避免中断干扰)
      CC1101_Write_Cmd(CC1101_SWORRST);
      CC1101_Write_Cmd(CC1101_SWOR);
      // 进入WOR后保持SPI静默,避免触发进入失败或假WOR
      Delay_Ms(3);
      RestoreInterrupts();
    }