谷动谷力

 找回密码
 立即注册
查看: 2551|回复: 0
打印 上一主题 下一主题
收起左侧

【ZigBee 系列】NXP JN516x 低功耗睡眠唤醒流程

[复制链接]
跳转到指定楼层
楼主
发表于 2022-11-25 23:51:11 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
【ZigBee 系列】 NXP JN516x 低功耗睡眠唤醒流程

NXP JN516x 无线微控制器系列包括超低功耗、高性能 MCU,带有符合 IEEE802.15.4 标准的 2.4GHz 无线电收发器。集成了超低功耗睡眠模式,深度睡眠模式功耗仅 100nA ,开启定时器唤醒功耗仅 0.64 μA 。

NXP 提供了运行在 JN516x 芯片上满足各种物联网应用的无线组网协议栈,例如 ZigBee Pro Home Automation、ZigBee Pro Light Link、 ZigBee 3.0 等协议栈极大地简化了使用 JN516x 开发 ZigBee 应用的难度,加快了开发进度。




为了实现低功耗睡眠唤醒功能, JN516x 硬件集成两个专用于唤醒 CPU 的 41 位递减定时器,由 32kHz 时钟驱动,在唤醒定时器启动后从设定值开始递减,到计数值为零时触发中断。唤醒定时器默认使用片内 32kHz RC 振荡器, 也可以选择外部 32kHz 晶振作为时钟源。 片内 32kHz RC 时钟可能有高达 18% 的计时误差,不过这个误差可以利用 32MHz 的外设时钟校正从而大大减小。
ZigBee 协议栈 SDK 的 Power Manager (PWRM) 模块实现低功耗睡眠 、唤醒功能提供了下面的一系列 PWRM API 函数,并有完整的低功耗睡眠 End Device 设备参考设计源代码。





下图是 JN 516x 低功耗睡眠设备的冷启动和睡眠唤醒启动流程图。





本文以 NXP JN5169 ZigBee 参考设计 JN AN 1189 ZigBee HA Demo 中的 LightSensor 应用代码为例,分析 JN516x低功耗睡眠唤醒设备的代码结构。 为了便于理解代码的主要脉络, 相关函数只保留关键的代码片段。 请参照完整的源代码了解更多细节。

JN516x复位启动 后将 运行 vApp Main() 这是整个程序初始化入口。 系统初始化函数调用顺序:




调用 PWRM_vInit 初始化 Power Manager (PWRM) 模块。一般情况下,使能 OSC Wake T imer 并保持 RAM 数据 。这个函数将会调用 vAppRegisterPWRMCallbacks注册回调函数注册二个应用层睡眠前、唤醒后的处理函数。



PreSleep 和 Wakeup 是二个非常重要的回调函数。开发人员往往需要根据产品应用的需求,修改这二个函数的具体实现 。例如在 CPU 进入睡眠之前调用 PreSleep 函数,设置 GPIO 状态,设定唤醒源(唤醒 GPIO 管脚, 触发边沿),关闭芯片的外设节省功耗。

应用代码调用 PWRM_eScheduleActivity(pwrm_tsWakeTimerEvent *psWake,uint32 u32Ticks,void (*prCallbackfn)(void)) 函数设置 Wake Event 。 可以设置多个 Wake Event 建议一般情况设置一个唤醒 Wake Event 事件 ),多个 Wake Event 按照唤醒时间由小到大组成一个链表,其中 u32TickDelta 保存各个 Wake Event 之间的差值,例如 Wake Event1 设置 5 秒后唤醒, Wake Event2 设置 10 秒后唤醒,则 二个 Wake Event 的 u32TickDelta 都是 5 。u32TickDelta 的数组值由 SDK 根据链表计算获得差值,用户不能修改这个数据结构的值。

函数 PWRM_eScheduleActivity 是实现睡眠的一个重要函数。PWRM_eScheduleActivit 将会启动 Wake Timer1 唤醒定时器, 并设置 Wake Timer1 为激活状态。
用户程序尝试进入休眠的调用流程







函数 PWRM_vManagePower 在 CPU 空闲时运行, 不停地检查系统是否满足进入休眠条件。



下面是 PWRM_vManagePower 函数的 pseudocode 展示了 JN516x 如何进入休眠。如果满足没有更高优先级的任务并且没有其他活跃的定时器的条件时将会调用 PreSleep 然后 CPU 进入休眠状态。


函数的调用关系





与 PreSleep 相对应,当 CPU 唤醒后将调用 Wakeup 回调函数,恢复 CPU 正常运行环境。例如重新初始化 UART 串口,使能 GPIO 状态,重新使能 JenOS 的 任务调度。请特别注意,由于 PreSleep 已经关闭了 UART 串口输出,在 Wakeup 重新初始化串口之前,不能调用 DBG _vPrintf 串口调试输出,否则 JN516x 会出现 crash dump 错误。



当 CPU 的 Wake Timer0 或 者 Wake Timer1 计数为 0 时 CPU 将会被唤醒,并触发 vISR_SystemController 硬件中断 ISR 服务函数。在 PWRM_vWakeInterruptCallback 中将会调用 PWRM_eScheduleActivity 注册的 Wake Event 回调函数。如果 Wake Event 链表中仍有其他未超时的事件,则继续启动 Wake Timer1 定时器准备休眠。



JN516x 的 GPIO 和 Wake Timer0/1 硬件中断服务函数都是 vISR_SystemController。在中断 ISR 函数中,建议不要进行耗时的操作。由于在休眠前 UART 已经被关闭,在 vISR_SystemController 中不要进行 UART 操作。



系统中断重入问题:
当频繁产生 GPIO 中断时,vISR_SystemController 中断服务函数将会抢占休眠函数 PreSleep 的执行中断 ISR 的优先级别高于函数代码。在 OS_ISR vISR_SystemController) 中将会 Disable GPIO interrupt 中断,并影响 PWRM 休眠管理模块。另外,PreSleep 函数 Disable UART 串口,因此,不能在 vISR_SystemController 中断服务函数中调用串口打印输出,否则会 watchdog 复位。
解决方法:
在 PreSleep 函数中禁止系统中断,从而避免中断抢占的问题。请参照下面代码,调用 MICRO_DISABLE_AND_SAVE_INTERRUPTS 在休眠前禁止系统中断。



在实际开发阶段,需要特别注意 PWRM_eScheduleActivity 函数调用时机,否则将无法使 J N 516x 进入低功耗休眠状态:
A. 在调用 PWRM_eScheduleActivity 函数之前应该保证没有激活的软件定时器。否则将不会调用 PreSleep 函数,无法进入睡眠状态。当调用 PWRM_u16GetActivityCount 函数返回当前活跃的个数为 0 时,表示系统允许进入低功耗睡眠。

B. 不能重复调度同一个 Wake Event,否则 PWRM_eScheduleActivity 将返回 PWRM_E_TIMER_RUNNING 错误。即使 PWRM_eScheduleActivity 返回成功后 JN516x 并不会马上休眠。只有当 PWRM_vManagePower 判断满足休眠条件后 JN516x 才会进入休眠。

C. 当 Wake Timer 启动后,将在 32 kHz 时钟驱动下自动递减计数器。需要通过特殊步骤才能修改 Wake Timer 计数器。例如,应用设定 10 s 的 Wake Timer 当在第 9 秒时由于 GPIO 唤醒了 CPU 后 重新进入休眠,则 1 s 后 Wake Timer 将会唤醒 CPU。如果需要在当前时刻点起重新设定 Wake Timer1 唤醒时间,可以调用 vAHI_WakeTimerStartLarge 函数重新设置计数器。

D. 即使 PWRM_eScheduleActivity 函数返回成功后,ZigBee 协议栈内部某些软件定时器例如 MAC 重传定时器、APS 重传定时器等将会阻止 PWRM_vManagePower 使 CPU 进入休眠状态。在 vISR_SystemController 中断服务函数不要遗漏执行 PWRM_vWakeInterruptCallback 函数,否则 Wake Event 事件不会被被触发,下 一次 PWRM_eScheduleActivity 函数将返回 PWRM_E_TIMER_RUNNING 错误错误,导致系统无法进入休眠。

E. 如果在执行某些重要代码过程中不希望 CPU 进入休眠,可以使用 PWRM_eStartActivity 禁止休眠,执行完毕后需要使用 PWRM_eFinishActivity 允许休眠,这个二个函数改变 s_u16ActivityCounter 计数值。

F. ZigBee SDK 默认使用 Wake Timer1 作为唤醒定时器。用户可以使用 Wake Timer0 作为睡眠计时器。在设备进入睡眠前启动 Wake Timer0 并设置计数值,当唤醒时通过 u64AHI_WakeTimerReadLarge 函数读取 Wake Timer0 的当前计数值,即可获得睡眠时间。Wake Timer 的详细使用方法请参考 <>文档。

本文作者 shaozhong



+10

本帖被以下淘专辑推荐:

  • · zigbee|主题: 38, 订阅: 0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-11-24 16:00 , Processed in 0.294629 second(s), 44 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表