ZHCT994 November 2025 AWRL1432 , AWRL6432 , IWRL1432 , IWRL6432
低功耗是AWRL6432系列产品的一个重要功能。AWRL6432的软件是基于FreeRTOS操作系统。FreeRTOS操作系统的内核是支持低功耗的,但在不同硬件上的实现会有一些区别。本文结合AWRL6432 MMWAVE_L_SDK驱动以及例程,详细介绍在AWRL6432上的FreeRTOS低功耗底层内核驱动实现和低功耗示例的实现。本文的内容也适用于IWRL6432、AWRL1432和IWRL1432。
操作系统常用的低功耗实现方法是在空闲任务里让微控制器处于低功耗状态。如果使用系统节拍(tick),低功耗省电的效果会受到定期退出并重新进入低功耗状态和处理节拍中断的限制。如果节拍中断的频率太高,则每次节拍进入和退出低功耗状态所消耗的能量和时间可能极大降低潜在的省电收益。FreeRTOS使用无节拍空闲模式,操作系统会在空闲期间(在没有执行的应用任务的期间)停止周期性节拍中断、然后在节拍中断里重新启动时对实时系统节拍计数值进行更正调整。停止节拍中断可以使微控制器保持在深度节能状态、直到发生中断(微控制器内部时钟中断,或者外部信号触发中断)或者实时系统内核应该切换任务时,才将处于低功耗深度节能状态的微控制器转换到ready模式。
在AWRL6432的FreeRTOS里,通过在 FreeRTOSConfig.h中将configUSE_TICKLESS_IDLE定义为2,使能了用户自定义的无节拍空闲功能。使用vPortSuppressTicksAndSleep()函数为相关功能的钩子函数。当软件进入空闲任务后,就会调用vPortSuppressTicksAndSleep()函数。vPortSuppressTicksAndSleep函数中会调用Power_idleFunc函数,而Power_idleFunc()函数需要在enablePolicy标志位置位后,才会真正调用低功耗相关函数Power_enterLPDS()。Power_enterLPDS()函数基于汇编,在power_xwrLx4xx_asm.S(\source\drivers\power\v0)里实现。
FreeRTOSConfig.h(C:\ti\MMWAVE_L_SDK_05_05_02_00\source\kernel\freertos\config\xwrL64xx\m4f)
#define configUSE_TICKLESS_IDLE (2) /* When 2, providing custom implementation for vPortSuppressTicksAndSleep() as a hook function*/
power_xwrLx4xx_freertos.c (c:\ti\mmwave_l_sdk_05_05_02_00\source\kernel\freertos\dpl\common)
/* Tickless Hook */
void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime)
{
#if (configUSE_TICKLESS_IDLE != 0)
unsigned long long time;
idleTicks = xExpectedIdleTime;
// convert ticks to microseconds
time = ((idleTicks / configTICK_RATE_HZ) * 1000000);
Power_idleFunc(time);
#endif
}
power_xwrLx4xx.c (C:\ti\MMWAVE_L_SDK_05_05_02_00\source\drivers\power\v0)
/*
* ======== Power_enablePolicy ========
* Run the configured policy
*/
void Power_enablePolicy(void)
{
Power_module.enablePolicy = TRUE;
DebugP_log("Power: enable policy");
}
…
/*
* ======== Power_idleFunc ========
* Function needs to be plugged into the idle loop.
* It calls the configured policy function if the
* 'enablePolicy' flag is set.
*/
void Power_idleFunc(unsigned long long sleepTimeus)
{
if (Power_module.enablePolicy) {
if (Power_module.policyFxn != NULL) {
DebugP_log("Power: calling policy function (%p)",
(uintptr_t) Power_module.policyFxn);
(*(Power_module.policyFxn))(sleepTimeus);
}
}
}
…
/*
* ======== Power_sleep ========
*/
int_fast16_t Power_sleep(uint_fast16_t sleepState)
{
…
Power_enterLPDS(PRCMSleepEnter);
…
下面用两个MMWAVE_L_SDK里的实例来说明低功耗代码具体实现调用过程。
单任务例程
首先来看一下MMWAVE_L_SDK驱动里的power mode例程(C:\ti\MMWAVE_L_SDK_05_05_02_00\examples\drivers\power\power_modes\xwrL64xx-evm)。
AWRL6432的用户如果要在软件里使能深度睡眠的节电模式,先需要在syscfg里配置相应的power设置。设置后syscfg编译出来的ti_drivers_config.c文件里会有一个power配置的全局变量Power_ConfigV1,这个全局变量会在功耗驱动中被使用。
power_xwrLx4xx.c (c:\ti\mmwave_l_sdk_05_05_02_00\source\drivers\power\v0):extern Power_ConfigV1 Power_config;
power_xwrLx4xx_freertos.c (c:\ti\mmwave_l_sdk_05_05_02_00\source\kernel\freertos\dpl\common):extern Power_ConfigV1 Power_config;
ti_drivers_config.c
const Power_ConfigV1 Power_config = {
.policyInitFxn = Power_initPolicy,
.policyFxn = Power_sleepPolicy,
.enterLPDSHookFxn = NULL,
.resumeLPDSHookFxn = power_LPDSresumehook,
.enteridle3HookFxn = power_idle3entryhook,
.resumeidle3HookFxn = power_idle3resumehook,
.enablePolicy = false,
.enableSleepCounterWakeupLPDS = true,
.enableUARTWakeupLPDS = true,
.enableSPICSWakeupLPDS = true,
.enableRTCWakeupLPDS = true,
.enableFRCWakeupLPDS = false,
.enableGPIOSyncIOWakeupLPDS = true,
.selectGpioSyncIOLpds = POWER_SYNCIN_IO_WAKEUP_LPDS,
.wakeupSyncIOEdgeLPDS = PRCM_LPDS_RISE_EDGE,
.wakeupSpiEdgeLPDS = PRCM_LPDS_FALL_EDGE,
.wakeupUartEdgeLPDS = PRCM_LPDS_FALL_EDGE,
.LPDSThreshold = 30000000,
.totalLatencyForLPDS = 2000,
.sleepThreshold = 999999999,
.totalLatencyForSleep = 1500,
.idleThreshold = 2000,
.totalLatencyForIdle = 1000,
.ramRetentionMaskLPDS = PRCM_APP_PD_SRAM_CLUSTER_1|PRCM_APP_PD_SRAM_CLUSTER_2|PRCM_APP_PD_SRAM_CLUSTER_3|PRCM_FEC_PD_SRAM_CLUSTER_1|PRCM_FEC_PD_SRAM_CLUSTER_2,
.pinParkDefs = parkInfo,
.numPins = 24
};
Power mode 例程如果选择测试深度睡眠功能,会利用信号量获取xSemaphoreTake()函数设置的深度睡眠的时间。在调用xSemaphoreTake()函数前需要先调用Power_enablePolicy()函数,设置enablePolicy标志位为True。xSemaphoreTake()函数的第二个参数是在没有获取到信号量时等待的最大时间。在Power mode例程里xSemaphoreTake()函数第二个参数设置为SLEEP_TIME_TICKS,也就是睡眠时间。这个例程只有一个任务,所以在xSemaphoreTake()函数调用后的等待时候会进入空闲任务,操作系统会调用vPortSuppressTicksAndSleep()让AWRL6432进入深度睡眠。当SLEEP_TIME_TICKS到达之后,AWRL6432会被时钟唤醒。
power_modes.c(C:\ti\MMWAVE_L_SDK_05_05_02_00\examples\drivers\power\power_modes)
if (LPDS_USECASE == sel)
{
DebugP_log("Entering LPDS.... \n\r");
Power_enablePolicy();
xSemaphoreTake(gPowerSem, SLEEP_TIME_TICKS);
Power_disablePolicy();
多任务例程
MMWAVE_L_SDK里的motion_and_presence_detection例程 (\examples\mmw_demo) 使能了低功耗模式,也需要在syscfg里配置power相关选项。但是低功耗的具体实现上和power mode例程有所区别。因为motion_and_presence_detection例程有多个任务,就需要通过调用Power_idleFunc()来实现。Power_enablePolic()仍需要在Power_idleFunc()使用前预先调用。例程里仍然有gPowerSem信号量,但这个信号量主要是用于和串口输出任务做同步使用,设置的等待时间是最大值。
Power_managerment.c
(C:\ti\MMWAVE_L_SDK_05_05_02_00\examples\mmw_demo\motion_and_presence_detection\source\power_management)
if(gMmwMssMCB.lowPowerMode == LOW_PWR_MODE_ENABLE)
{
/* Radar Power Management Framework driver call for getting to Low Power State */
Power_idleFunc(slpTimeus);
Power_disablePolicy();
由于进入低功耗后仿真器会断开,这对于调试低功耗模式代码带来了不便。当低功耗代码出问题时,需要先判断是否时进入低功耗是否正常唤醒。可以在唤醒函数最开设置一个有条件循环,运行代码仿真器断开后,可以再连上仿真器,看是否停在这个循环里。如果是,那说明AWRL6432已经唤醒,排查唤醒后代码。如果不是,那就是没有正常唤醒,需要查看进入休眠的相关代码。下面是一个添加有条件循环的例子。
Power_managerment.c
void loop_forever()
{
volatile uint32_t loop = 1;
while(loop);
}
…
void power_LPDSresumehook(void)
{
static uint8_t ledState = 0;
loop_forever();
…