在ThreadX中使用low_power低功耗(ARM)

在单片机系统运行过程中,大部分时间均处于空闲状态,为了减小功耗,可以让ThreadX管理在空闲时进入低功耗模式。在utility\low_power文件夹有关于这个模块使用的详细说明。

移植说明

这个工具位于utility\low_power文件夹下,使用时将这个文件夹下的源文件添加进工程,C/C++的包含路径也添加这个文件夹。ThreadX可用的配置有TX_LOW_POWER_TIMER_SETUPTX_LOW_POWER_TICKLESS,这两个选项组合能产生三种配置(不使能TX_LOW_POWER_TIMER_SETUP、使能TX_LOW_POWER_TICKLESS无效),第一种是TX_LOW_POWER_TIMER_SETUP不被宏定义(无论是否宏定义TX_LOW_POWER_TICKLESS),这种情况下退出低功耗时与进入低功耗的所有时刻均相同。第二种是TX_LOW_POWER_TIMER_SETUP被宏定义,TX_LOW_POWER_TICKLESS不被宏定义,这种情况下时刻正常增加。第三种是TX_LOW_POWER_TIMER_SETUPTX_LOW_POWER_TICKLESS都被宏定义,这种情况下在若有激活的定时器则与第二种情况相同,若没有激活的定时器则与第一种情况相同。

使能low_power

tx_user.h中添加宏定义TX_LOW_POWER以使能low_power工具。

函数实现(使能TX_ENABLE_WFI)

使用该模块还需要实现TX_LOW_POWER_TIMER_SETUPTX_LOW_POWER_USER_ENTERTX_LOW_POWER_USER_EXITTX_LOW_POWER_USER_TIMER_ADJUST四个函数中的若干个。对于ARM,可以使用低功耗指令WFI(Wait For Interrupt)进入低功耗模式,WFI指令可以让CPU进入standby模式,即低功耗模式,此时内核会暂停其他活动,一直等待中断事件的发生,检测到中断发生后,WFI指令执行完成,CPU退出standby模式。ThreadX给出的样例port文件中已经帮我们写好了这一部分代码,因此也不需要实现TX_LOW_POWER_USER_ENTERTX_LOW_POWER_USER_EXIT函数,在第一种情况下也不需要实现TX_LOW_POWER_TIMER_SETUPTX_LOW_POWER_USER_TIMER_ADJUST。因此只需要在tx_user.h中添加宏定义TX_ENABLE_WFI来使能进入WFI的代码。

#ifdef TX_LOW_POWER
    PUSH    {r0-r3}
    BL      tx_low_power_enter                      // Possibly enter low power mode
    POP     {r0-r3}
#endif

#ifdef TX_ENABLE_WFI
    DSB                                             // Ensure no outstanding memory transactions
    WFI                                             // Wait for interrupt
    ISB                                             // Ensure pipeline is flushed
#endif

#ifdef TX_LOW_POWER
    PUSH    {r0-r3}
    BL      tx_low_power_exit                       // Exit low power mode
    POP     {r0-r3}
#endif

结果

我们采用第一种配置,当ThreadX空闲时则进入低功耗模式,通常SysTick中断会使内核从低功耗模式中退出(当然也可能是其他的中断),ThreadX内部时钟运行也是正常的。当然,这样做并不完美,因为SysTick引起的中断可能并不会引起有新的线程就绪,更高级的用法还需要配置TX_LOW_POWER_TIMER_SETUPTX_LOW_POWER_TICKLESS

一点小问题:使用BASEPRI来屏蔽中断时,较低优先级的中断无法使单片机退出低功耗模式

若ThreadX使用的是BASEPRI来屏蔽中断,且屏蔽中断的优先级比SysTick大(SysTick默认的优先级为6,见ARM单片机中断的各类问题),会导致SysTick中断不能使内核退出低功耗模式,关键代码如下:

__tx_ts_wait
#ifdef TX_PORT_USE_BASEPRI
    LDR     r1, =TX_PORT_BASEPRI                    // Mask interrupt priorities =< TX_PORT_BASEPRI
    MSR     BASEPRI, r1
#else
    CPSID   i                                       // Disable interrupts
#endif
    LDR     r1, [r2]                                // Pickup the next thread to execute pointer
    STR     r1, [r0]                                // Store it in the current pointer
    CBNZ    r1, __tx_ts_ready                       // If non-NULL, a new thread is ready!

#ifdef TX_LOW_POWER
    PUSH    {r0-r3}
    BL      tx_low_power_enter                      // Possibly enter low power mode
    POP     {r0-r3}
#endif

#ifdef TX_ENABLE_WFI
    DSB                                             // Ensure no outstanding memory transactions
    WFI                                             // Wait for interrupt
    ISB                                             // Ensure pipeline is flushed
#endif

#ifdef TX_LOW_POWER
    PUSH    {r0-r3}
    BL      tx_low_power_exit                       // Exit low power mode
    POP     {r0-r3}
#endif

#ifdef TX_PORT_USE_BASEPRI
    MOV     r4, #0                                  // Disable BASEPRI masking (enable interrupts)
    MSR     BASEPRI, r4
#else
    CPSIE   i                                       // Enable interrupts
#endif
    B       __tx_ts_wait                            // Loop to continue waiting

__tx_ts_wait是空闲时的循环,它会一直查看是否有新的线程就绪(一般由中断引起),在循环的开头会屏蔽所有中断,并在循环的结束才使能中断,而WFI等待的中断也会被BASEPRI屏蔽掉,导致了WFI无法正常退出,需要在使用WFI之前关闭BASEPRI,或者使用PRIMASK(CPSID i)屏蔽中断(WFI不受PRIMASK的影响),或者修改SysTick的优先级使之不会被BASEPRI屏蔽掉。
(注:在tx_low_power_enter(如下)函数中虽然看起来使能了中断,但实际并没有,TX_DISABLE会将当前的BASEPRI值储存起来,而使用TX_RESTORE恢复到原来的状态,在调用这个函数之前BASEPRI已经禁止中断,因此tx_low_power_enterTX_RESTORE函数也会恢复到禁用中断的状态,导致并没有实际打开中断)

VOID  tx_low_power_enter(VOID)
{

...

    /* Disable interrupts while we prepare for low power mode.  */
    TX_DISABLE
...

    /* Re-enable interrupts before low power mode is entered.  */
    TX_RESTORE

    /* User code to enter low power mode. This allows the application to power down
       peripherals and put the processor in sleep mode.
    */
#ifdef TX_LOW_POWER_USER_ENTER
    TX_LOW_POWER_USER_ENTER;
#endif

    /* If the low power code returns, this routine returns to the tx_thread_schedule loop.  */
}

这个问题已经向ThreadX仓库提交azure-rtos/threadx Issues #279,官方也给出来一种变通方法,在进入低功耗前后使用BASEPRI来屏蔽中断解决,但是感觉这样做不够好,WFI本就是等待中断,应该在进入低功耗前打开中断。按照一般处理方法和原代码的注释来看,在调用tx_low_power_enter之前应该使能中断,而不是在退出低功耗时使能中断,即修改__tx_ts_wait循环如下:

__tx_ts_wait:
#ifdef TX_PORT_USE_BASEPRI
    LDR     r1, =TX_PORT_BASEPRI                    // Mask interrupt priorities =< TX_PORT_BASEPRI
    MSR     BASEPRI, r1
#else
    CPSID   i                                       // Disable interrupts
#endif
    LDR     r1, [r2]                                // Pickup the next thread to execute pointer
    STR     r1, [r0]                                // Store it in the current pointer
    CBNZ    r1, __tx_ts_ready                       // If non-NULL, a new thread is ready!

#ifdef TX_PORT_USE_BASEPRI
    MOV     r4, #0                                  // Disable BASEPRI masking (enable interrupts)
    MSR     BASEPRI, r4
#else
    CPSIE   i                                       // Enable interrupts
#endif

#ifdef TX_LOW_POWER
    PUSH    {r0-r3}
    BL      tx_low_power_enter                      // Possibly enter low power mode
    POP     {r0-r3}
#endif

#ifdef TX_ENABLE_WFI
    DSB                                             // Ensure no outstanding memory transactions
    WFI                                             // Wait for interrupt
    ISB                                             // Ensure pipeline is flushed
#endif

#ifdef TX_LOW_POWER
    PUSH    {r0-r3}
    BL      tx_low_power_exit                       // Exit low power mode
    POP     {r0-r3}
#endif

    B       __tx_ts_wait                            // Loop to continue waiting

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇