返回列表 发新帖我要提问本帖赏金: 70.00元(功能说明)

[APM32F1] 基于APM32F103 Stop模式关于WFE内核命令问题分析及解决

[复制链接]
 楼主| lzh12a3nf 发表于 2023-10-7 22:27 | 显示全部楼层 |阅读模式
<
本帖最后由 lzh12a3nf 于 2023-10-8 13:42 编辑

#申请原创#@21小跑堂
1、前言
     近日,在学习APM32开发板关于PMU模块的内容,看到很多内容都是调用WFI内核指令进入低功耗模式,于是自己想尝试调用WFE内核指令进入低功耗模式,但在APM32F10xx中,我运用按键中断,在中断调用PMU_EnterSTOPMode库函数,用WFE内核指令进入STOP模式是存在问题的,后经查验解决了问题,于是在此进行了内容记录。

2、相关知识介绍
2.1、低功耗模式概述
         当APM32在系统或者电源复位后,芯片处于运行状态,此时HCLK为CPU提供时钟,内核执行程序代码,当CPU不需要运行时,可以采用低功耗模式来降低芯片运行的电流。

2.2、低功耗模式
        低功耗模式可分为睡眠模式和深度睡眠模式,其中深度睡眠模式分别停止模式和待机模式。而本文的重点则在于讲解进入停止模式。

2.3、进入停止模式配置
PMU_Stop WFE 1.png

        如上,进入停止模式需要将SCB->SCR->SLEEPDEEP置为1,同时PMU->CTRL->PDDSCFG置为0,同时要执行WFI/WFE指令进入停止模式。其中,两个内核指令的区别如下:

PMU_Stop WFE 2.png

        如上,当调用WFI内核指令时,会直接进入睡眠/深度睡眠模式。当调用WFE指令时,会根据事件锁存器的值来判断能否直接进入睡眠/深度睡眠模式。如下,我做了一个流程图:

PMU_Stop WFE 3.png


3、问题分析及解决
3.1、配置的关键代码
  1. int main(void)
  2. {
  3.     RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));

  4.     APM_MINI_LEDInit(LED2);
  5.     APM_MINI_LEDInit(LED3);
  6.         
  7.     /* KEY1 \ KEY2 Set */
  8.                 //APM_MINI_PBInit(BUTTON_KEY1, BUTTON_MODE_GPIO);
  9.     APM_MINI_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT);
  10.     APM_MINI_PBInit(BUTTON_KEY2, BUTTON_MODE_EINT);

  11.     /* NVIC Priority Set */
  12.     NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_1);
  13.     NVIC_EnableIRQRequest(EINT0_IRQn, 0, 1);
  14.     NVIC_EnableIRQRequest(EINT1_IRQn, 1, 1);

  15.     APM_MINI_LEDOn(LED2);
  16.     APM_MINI_LEDOff(LED3);

  17.     /* Enable PMU Periph Clock */
  18.     RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
  19.     PMU_Reset();

  20.     while (1)
  21.     {
  22.         Delay(0x7FFFFF);

  23.         APM_MINI_LEDToggle(LED2);
  24.     }
  25. }
  1. void Eint1_Isr(void)
  2. {
  3.     if (EINT_ReadIntFlag(KEY1_BUTTON_EINT_LINE) != RESET)
  4.     {
  5.         APM_MINI_LEDOn(LED3);
  6.         APM_MINI_LEDOff(LED2);

  7.         /* Enter STOP Mode */
  8.         PMU_EnterSTOPMode(PMU_REGULATOR_LOWPOWER, PMU_STOP_ENTRY_WFE);
  9.         EINT_ClearIntFlag(KEY1_BUTTON_EINT_LINE);
  10.     }
  11. }

  12. void Eint0_Isr(void)
  13. {
  14.     if (EINT_ReadIntFlag(KEY2_BUTTON_EINT_LINE) != RESET)
  15.     {
  16.         SystemInit();
  17.         APM_MINI_LEDOff(LED3);
  18.         /* Wait for system init */
  19.         Delay(0xfffff);
  20.         EINT_ClearIntFlag(KEY2_BUTTON_EINT_LINE);
  21.     }
  22. }
           如上代码,按下按键1后会进入睡眠模式,LED2灯灭,LED3常亮。按下按键2后会从睡眠模式中唤醒,LED2跳灯,LED3灯灭。但真实的现象便是按下按键1后,LED2仍处于跳灯状态,但LED3常亮,因此我初步判断第一次运用WFE指令时没有进入停止模式,但我从而验证我的判断?

3.2、PMU_EnterSTOPMode 函数
  1. void PMU_EnterSTOPMode(PMU_REGULATOR_T regulator, PMU_STOP_ENTRY_T entry)
  2. {
  3.     /* Clear PDDSCFG and LPDSCFG bits */
  4.     PMU->CTRL_B.PDDSCFG = 0x00;
  5.     PMU->CTRL_B.LPDSCFG = 0x00;
  6.     /* Set LPDSCFG bit according to regulator value */
  7.     PMU->CTRL_B.LPDSCFG = regulator;
  8.     /* Set Cortex System Control Register */
  9.     SCB->SCR |= (uint32_t)0x04;
  10.     /* Select STOP mode entry*/
  11.     if (entry == PMU_STOP_ENTRY_WFI)
  12.     {
  13.         /* Request Wait For Interrupt */
  14.         __WFI();
  15.     }
  16.     else
  17.     {
  18.         /* Request Wait For Event */
  19.         __WFE();
  20.     }

  21.     /* Reset SLEEPDEEP bit of Cortex System Control Register */
  22.     SCB->SCR &= (uint32_t)~((uint32_t)0x04);
  23. }
           如下库API函数中,运用一次WFE内核指令,当我第一次看到这个函数时,并没有发现什么问题,于是,我照着手册深入我的问题探究。于是,我在《Cortex M3与M4权威指南》中找到如下内容:
PMU_Stop WFE 4.png

             当我们运用WFE内核指令进入停止模式时,一般调用两次WFE内核指令,因为事件寄存器会因为中断事件的产生而置位。这时,在结合2.3中内容,我便知晓了问题的答案。因为在初始化的按键配置中,按键1和按键2连接了外部中断线,当我调用该库函数中,运用WFE指令进入停止模式时,第一次会因为有中断事件的产生,WFE的作用是运用于清除事件锁存器的值,而第二次才用于进入睡眠模式,因此在后面的Demo例程中,我给出了一种解决方法。

注:

1、在解决问题的过程中,我给出了第二种解决方法,便是不通过按键中断调用WFE内核指令进入停止模式,而是在主函数中直接对按键进行一个是否按键的判断,按下即进入睡眠模式。(这两种方法均已通过实验)。




4、基于APM32F103 PMU_Stop Demo - 运用WFE内核指令

PMU_Stop Demo.rar (264.08 KB, 下载次数: 9)


本次分享到此结束,如有问题大家一起在评论区讨论,谢谢

打赏榜单

21小跑堂 打赏了 70.00 元 2023-10-19
理由:恭喜通过原创审核!期待您更多的原创作品~

评论

解决APM32F103使用WFE指令进入停止模式失败的问题,从发现问题要猜测问题原因,再到解决问题,整个流程完整详细。其实二姨这里也可以给出一个关键技术点,或许可以与你一同验证猜想:为了顺利进入深度睡眠模式,所有 EXTI 线上的挂起状态和相关外设标志位必须被复位。否则,程序将直接跳过深度睡眠模式进入过程而继续执行下面的程序。  发表于 2023-10-19 18:23
赞,来学习一下!  发表于 2023-10-12 11:46
修改部分内容表述  发表于 2023-10-8 10:21
 楼主| lzh12a3nf 发表于 2023-10-8 10:21 | 显示全部楼层
修改部分内容表述
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

37

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部