Z-Wave 700系列ZGM130 GPIO快速唤醒
经常收听的路由从(FLiRS)设备(如门锁和许多恒温器),其大部分时间工作在能源模式2(EM2)中,以节省电池电量。每秒一次,他们会短暂唤醒,并监听非休眠设备发出的Beam。如果有Beam,FLiRS设备将唤醒并接收Z-Wave命令。这使电池供电的设备可以使用很少的功耗,但仍然能够在一秒钟内响应Z-Wave命令。FLiRS设备比完全休眠的设备(如大多数使用休眠休眠模式(EM4)的传感器)消耗更多的电池电量。要每秒唤醒一次,ZGM130必须快速唤醒并立即回到睡眠状态以最大程度地降低功耗。EM4的问题在于,唤醒整个系统需要花费数十毫秒的时间,因为在关闭电源时必须初始化整个CPU和RAM以节省电量。对于FLiRS设备,保持RAM供电但处于低功耗状态并在没有Beam的情况下快速恢复到睡眠状态会更高效。通常情况下ZGM130 可以从EM2唤醒约500微秒。但是在许多情况下,如果还有其他中断(例如UART或其他传感器),这仍然太长时间无法唤醒。
上面的示波器显示了ZGM130S默认情况下发生的处理。在这种情况下,我正在使用WSTK 驱动另一个运行DoorLockKeyPad示例应用程序的WSTK的SPI引脚。跟踪开始时,芯片位于EM2中。当SPI SEL信号变为低电平时,芯片唤醒。但是它运行在HFRCO振荡器上,该振荡器的精度不足以运行无线电,但它仅在几微秒内即可稳定并可用。因此,使用该时钟在USART中捕获了SPI时钟和数据。但是,默认情况下,中断服务程序被阻止,等待HFXO稳定下来。39MHz HFXO晶体振荡器具有无线电所需的精度。
问题是在这500usec期间发生了什么?答案是CPU只是在等待HFXO稳定下来。我们可以利用这段时间做其他工作吗?幸运的是,答案是肯定的!
解决方案
大部分睡眠处理都具有三个功能。这些是在源代码中提供的,因此您可以阅读代码,但不应更改它。相反,您将提供一个回调函数来在芯片唤醒时进行处理。
简化的睡眠处理代码:
- SLEEP_Sleep在sleep.c中:调用进入睡眠的主要功能
- CORE_ENTER_CRITICAL – PRIMASK = 1屏蔽中断
- DO-WHILE循环
- 调用enterEMx()–这是芯片休眠的地方
- 调用restoreCallback(返回0唤醒,返回1进入睡眠状态)
- 调用EMU_Restore –等待HFXO准备就绪〜500us
- CORE_EXIT_CRITICAL – ISRs现在将运行
- 在sleep.c中输入enterEMx():
- sleepCallback称为
- 调用EMU_EnterEM [1-4]
- 从EMU_EnterEMx返回后的wakeupCallback
- em_emu.c中的EMU_EnterEM2:
- 降低电压
- 调用EMU_EM23PresleepHook()
- __WFI –Wait-For-Interrupt 指令– ZGM130在此处休眠
- 唤醒后调用EMU_EM23PostsleepHook()〜17usec
- 恢复电压标度需要大约20us
该代码位于SDK的sleep.c中,其中有很多详细信息,但从高层次上讲,这是您需要知道的。这里要理解的重要部分是“挂钩”的位置以及如何使用它们。
- 使用Sleep_initEx()分配:
- sleepCallback –在睡觉前被调用
- restoreCallback –返回0唤醒,返回1进入睡眠状态
- akeupCallback –唤醒后调用
- Sleep_initEx()输入是具有三个回调的结构的指针;如果未使用,则为NULL
- 定义功能:
- EMU_EM23PresleepHook()
- EMU_EM23PostsleepHook()
这些都是WEAK函数,没有任何内容,因此,如果您定义它们,则编译器将安装它们
两个EMU_EM23 * 弱 这些函数在等待CPU睡眠的等待中断(WFI)指令之前/之后立即运行。这些是非常底层的函数,尽管您可以使用它们,但我建议使用Sleep_initEx()中的回调。
SLEEP_initEx()函数是我们要使用的函数,尤其是restoreCallback。关于restoreCallback函数的注释谈论恢复时钟,但是如果函数返回0,则芯片将唤醒,如果返回1,则它将立即返回睡眠状态,这正是我们想要的!如果需要,可以使用其他两个钩子,但是restoreCallback是关键之一,因为如果一切闲置,它将立即使芯片进入睡眠状态。
使用这些功能中任何一个的关键是您不能调用任何FreeRTOS功能!您不能发送任何Z-Wave帧或调用任何Z-Wave函数,因为它们都需要RTOS。此时在唤醒处理中,RTOS尚未运行!在这些例程中,您所能做的就是捕获数据并快速确定所有内容是否空闲并重新进入睡眠状态。如果需要更多处理,则返回0并等待RTOS中的事件并在那里处理数据。您也不想在这些例程中花费太多时间,因为它可能会干扰RTOS的时间。一百微秒可能很好,但是您应该等待HFXO更长的时间。
在ApplicationInit()中,您将这样调用Sleep_initEx():
const SLEEP_Init_t sleepinit = {NULL, NULL, CheckSPI};
...
ZW_APPLICATION_STATUS ApplicationIResetReason_t eResetReason) {
...
SLEEP_InitEx(&sleepinit); // call checkSPI() upon wakeup from EM2.
...
}
...
uint32_t CheckSPI(SLEEP_EnergyMode_t emode) {
uint32_t retval=0; // wake up by default
if (GPIO_IntGetEnabled() & 0x0000AAAA) { // Check SPI
GPIO_ODD_IRQHandler(); // service the GPIO interrupt
// wait for all the bytes to come in and compute checksum
NVIC->ICPR[0] = NVIC->ICPR[0]; //clear NVIC pending interrupts
if (!SPIDataError && !IsWakeupCausedByRtccTimeout()) {
retval=1; // go back to sleep!
}
}
return(retval); // 0=wakeup, 1=sleep
}
回想一下,FLiRS设备必须每秒检查一次RTCC计时器触发的Z波Beam。因此,对IsWakeupCausedByRtccTimer的检查可确保发送仍然有效。
该示波器镜头显示了ZGM130S的唤醒过程:
- SPISEL_N SPI芯片选择信号变低,触发GPIO_ODD中断
- 芯片唤醒,HFRCO开始振荡
- HFRCO在几微秒内开始振荡
- 一旦HFRCO运行,外围设备就可以正常工作
- 一旦HFRCO运行,SPI数据就可以开始移位
- 默认HFRCO频率为19MHz,但可以增加
- HFRCO的较高频率还可能需要CPU的更多等待状态,并且将使用更多功率
- 使CPU进入睡眠状态的WFI指令在此处退出
- 如果已定义,则调用EMU_EM23PostSleepHook函数
- 从PostSleepHook返回后,VSCALE返回全功率,大约需要10usec
- 最好等待电压上电,以确保所有逻辑均以最佳速度运行
- 如果已初始化,则退出EMU_EnterEM2并调用restoreCallback
- 这是应调用ISR处理数据的功能
- 如果数据表明事物闲置并且想返回睡眠状态,则返回1
- 如果需要更多分析,则返回0
- 仔细清除中断位
- 首先清除外围中断标志
- 然后清除NVIC中断待处理寄存器
- NVIC-> ICPR [n] = NVIC-> ICPR [n]其中n为0-1,具体取决于您的中断
- 确保没有其他原因可以完全唤醒
- !IsWakeupCausedByRtccTimeout()是1s FLiRS中断
- 可能还有其他原因需要唤醒,具体取决于应用程序
- 在此示例中,在每次GPIO切换时都从USART获取SPI数据
- 最后的切换显示校验和已计算并且数据处于空闲状态,因此返回睡眠状态
- 芯片会在几微秒内返回睡眠状态
- 该中断的总处理时间少于200usec,这只是等待HFXO稳定下来的时间的一小部分
- 大部分时间是在接收和处理SPI数据
- 如果检查闲置速度更快,则可以在50usec以下的时间内入睡
如果您的外围设备处理时间大大少于500usec,则使用HFRCO处理数据而不等待HFXO上电可能会更有效。但是,如果您的应用程序需要更多处理,那么最好等待。每个应用程序必须进行自己的计算以确定最有效的路径。
那么睡眠设备呢?
完全睡眠的设备(EM4也称为RSS –路由睡眠从站)具有完全不同的唤醒/睡眠处理。对于休眠的从机,必须重新初始化处理器和RAM,并且芯片实际上会退出复位状态。所有的初始化过程都需要花费大量时间-几十毫秒。如果您的设备需要经常检查传感器,则可以通过将Power Lock设置为PM_TYPE_PERIPHERAL强制将其保留在EM2中。有关电源锁的更多详细信息,请参见INS14259 第7.6节。确定哪种方法是特定于应用程序的,因此您必须进行计算或测量以找到适合您项目的平衡。