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