设计说明
PM 驱动源码位于 bsp/artinchip/drv/pm/。
PM 框架和功耗模式
Luban-Lite 的 PM 驱动完全遵循 RT-Thread 的 PM 框架。PM 框架将系统的功耗分为多个等级,每个等级对应一个功耗模式,实现对不同功耗模式的管理。
以下是 Luban-Lite 中各功耗模式的详细描述及其在 Luban-Lite 中的实现功能:
功耗模式 | 级别 | 描述 | Luban-Lite 是否支持 | Luban-Lite 实现功能的区别 |
---|---|---|---|---|
PM_SLEEP_MODE_NONE | 0 | 系统处于活跃状态 | 是 |
未做任何低功耗处理,系统处于全速运行状态。 |
PM_SLEEP_MODE_IDLE | 1 | 空闲模式 | 是 |
执行 |
PM_SLEEP_MODE_LIGHT | 2 | 轻睡眠模式 | 是 |
执行 |
PM_SLEEP_MODE_DEEP | 3 | 深睡眠模式 | 是 | 执行 WFI 指令,同时将 CPU 及总线时钟切换到 24 MHz,并关闭 PLL 时钟,将
PSRAM 时钟降频。 |
PM_SLEEP_MODE_STANDBY | 4 | 待机模式 | 否 | - |
PM_SLEEP_MODE_SHUTDOWN | 5 | 关机模式 | 否 | - |
申请和释放功耗模式
-
PM 框架提供的申请休眠模式的接口有:
rt_pm_release(rt_uint8_t mode) rt_pm_module_request(uint8_t module_id, rt_uint8_t sleep_mode) rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode) rt_pm_sleep_none_request(rt_uint16_t module_id) rt_pm_sleep_idle_request(rt_uint16_t module_id) rt_pm_sleep_light_request(rt_uint16_t module_id)
-
释放休眠模式的接口有:
rt_pm_release(rt_uint8_t sleep_mode) rt_pm_module_release(uint8_t module_id, rt_uint8_t sleep_mode) rt_pm_module_release_all(uint8_t module_id, rt_uint8_t sleep_mode) rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode) rt_pm_sleep_none_release(rt_uint16_t module_id) rt_pm_sleep_idle_release(rt_uint16_t module_id) rt_pm_sleep_light_release(rt_uint16_t module_id)
-
module_id
RT-Thread 官方推荐使用基于module_id
的 API 接口,用于申请和释放功耗模式。使用这些接口可以查看申请功耗的模块,也方便调试。rt_pm_module_request(uint8_t module_id, rt_uint8_t sleep_mode) // 申请进入指定的功耗模式 rt_pm_module_release(uint8_t module_id, rt_uint8_t sleep_mode) // 释放指定的功耗模式
module_id
是在 pm_cfg.h 文件中定义的,用于表示不同的模块。开发者可以根据实际需求自行定义module_id
,以便更好地管理和调试功耗模式。
- 最高优先级的模式优先:如果某个线程申请了
PM_SLEEP_MODE_NONE
模式,而另一个线程申请了PM_SLEEP_MODE_DEEP
模式,则系统会以PM_SLEEP_MODE_NONE
模式运行,直到所有申请PM_SLEEP_MODE_NONE
模式的任务都释放了这个模式,系统才会切换到PM_SLEEP_MODE_DEEP
模式,进入 deep sleep mode。RT-Thread 的功耗模式需要在代码中主动申请和释放,为了保证系统的正常运行,功耗越大的模式优先级越高。
- 默认休眠模式:在 PM 框架初始化时,将
PM_SLEEP_MODE_DEEP
设置为默认休眠模式。如果没有比PM_SLEEP_MODE_DEEP
更高优先级的请求,系统会立刻进入 deep sleep mode。 - 初始化时的默认模式:PM 框架初始化时会申请
PM_SLEEP_MODE_NONE
模式,以确保在 PM 初始化完成后,系统可以正常运行,而不会立即进入 deep sleep mode。因此,在应用代码中,想要进入低功耗模式,需要主动调用 release 相关的 API 接口释放PM_SLEEP_MODE_NONE
模式。
休眠唤醒流程
如上图所示,PM 框架及驱动使能后,RT-Thread 会在 idle 线程进入休眠唤醒流程。在休眠唤醒流程中,PM
框架会检查所有正在运行的任务和线程,确定当前系统中申请的最高优先级的功耗模式,并以最高优先级的功耗模式运行。例如,如果最高优先级是
PM_SLEEP_MODE_DEEP
,系统将进入 deep sleep mode。
在低功耗模式 ( deep sleep mode) 下,系统会等待外部中断或特定事件来触发唤醒。当外部中断或事件触发时,系统会退出低功耗模式,恢复到工作状态,继续执行被中断的任务或线程。
代码段保护
- 通过 rt_pm_module_request
函数申请不进入任何低功耗模式。
rt_pm_module_request(PM_MAIN_ID, PM_SLEEP_MODE_NONE);
- 等待执行读取数据的操作。
- 通过 rt_pm_module_release
函数释放不进入任何低功耗模式的请求。
rt_pm_module_release(PM_MAIN_ID, PM_SLEEP_MODE_NONE);
设置唤醒源
- rt_device_wakeup_enable(rt_device_t dev, rt_bool_t
enable):用来设置普通外设作为唤醒源,包括 RTC、I2C 和 SPI 等。这类设备在 RR-Thread 中采用
rt_device
描述设备。 - rt_pm_set_pin_wakeup_source(rt_base_t pin):用来设置某个 GPIO
引脚作为唤醒源。
在 RT-Thread 中,采用
rt_base_t
描述一个具体的 GPIO 口,而没有采用 rt_device 描述,因此需要一个单独的接口来设置 GPIO 的唤醒源。
低功耗定时器
系统中没有专用的低功耗定时器,Luban-Lite SDK 通过利用 CPU 的计时器 MTIME 来实现低功耗定时器。详细的实现原理和步骤如下所示:
-
修改 MTIME 的比较值寄存器,减少中断的周期性触发,从而实现 tickless 的目的。
-
获取低功耗定时器的下一次超时时间,然后加上当前的 MTIME 的计数值,再将结果写入 MTIME 的比较值寄存器。
-
当系统从低功耗模式唤醒时,需要计算 MTIME 当前计数值和休眠前计数值的差值,并将该差值补偿到 rt_tick 中。
-
在系统唤醒后,需要恢复 MTIME 的周期性触发计数。