
33.6
实验3:贪睡模式
在软件待机模式下,大部分时钟是关闭的,只有RTC,AGT,IWGT这些低功耗时钟可以运行。但贪睡模式下,所有时钟都能运行,这也包括了GPT,因此本次实验为了体现贪睡模式的特点,并使用GPT产生的PWM来控制开发板的LED亮度。
33.6.1
硬件设计
33.6.1.1
软件待机模式与贪睡模式的转变框图

进入贪睡模式前需要进入软件待机模式,在SNZCR(Snooze Control Register)寄存器的SNZE(Snooze Mode Enable)位为1的时候,再通过贪睡请求(Snooze requests)进入贪睡模式。同时也
能通过贪睡结束(Snooze end)下再次进入软件待机模式,这两个模式共用唤醒源(Wake Source)
进行唤醒。
33.6.2
软件设计
33.6.2.1
新建工程
对于e2 studio开发环境:拷贝一份我们刚刚的e2s工程“38_LPM_Sleep_Mode”,然后将工程文件夹重命名为“38_LPM_Snooze_Mode”,最后再将它导入到我们的e2 studio工作空间中。
对于Keil开发环境:拷贝一份我们刚刚的Keil工程“38_LPM_Sleep_Mode”,然后将工程文件夹重命名为“38_LPM_Snooze_Mode”,并进入该文件夹里面双击Keil工程文件,打开该工程。
工程新建好之后,我们还需要添加GPT用来进行实验,在例程中为了方便我们不再额外添加GPT模块函数,而是直接放到LED中使用,只需要让PWM占空比大一些,能通过视觉看出差异即可。
33.6.2.2
FSP配置
如图,将Low Power Mode修改为Snooze mode,名字按自己需求取即可。Wake Sources与实验2相同,选择IRQ9。Snooze Request Source选择 IRQ10,其他按照默认设置即可。

33.6.2.3
LED_Task流水灯任务
列表6:代码清单38-4:LED_Task流水灯任务
左右滑动查看完整内容
voidLED_Task(){/* 流水灯任务 */LED2_ON;R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);LED3_ON;R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);LED2_OFF;R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);LED3_OFF;/* 贪睡前打印 */printf("MCU 进入贪睡模式状态\r\n");/* 执行完流水灯任务,进入贪睡模式 */R_LPM_LowPowerModeEnter(snooze.p_ctrl);/* 被唤醒后打印 */printf("MCU 被唤醒成功\r\n");}
与实验1和2不同,LED_R,即红色LED需要用于表现PWM输出,因此这里的流水灯只有蓝色LED和绿色LED。注意,在任务流水灯结束后进入的是软件待机模式,需要通过贪睡请求(Snooze Request)才能进入贪睡模式,也就是我们刚刚设置的的Key2按键。
33.6.2.4
hal_entry函数
列表7:代码清单38-5:hal_entry函数
左右滑动查看完整内容
voidhal_entry(void){/* TODO: add your own code here */Debug_UART4_Init(); //初始化 debug 串口Key_Init(); //初始化按键R_BSP_PinAccessEnable(); //启用对 PFS 寄存器的访问, 因为后面写 IO 口都用 BSP内联函数R_LPM_Open(snooze.p_ctrl, snooze.p_cfg); //打开 LPMR_GPT_Open(gpt_pwm.p_ctrl, gpt_pwm.p_cfg); //打开 GPT 计时器R_GPT_Start(gpt_pwm.p_ctrl); //启动 GPT 计时器while(1){GPT_LED1_PWM_ON_Snooze_Mode(); //LED1 呼吸灯任务LED_Task(); //led 任务}#if BSP_TZ_SECURE_BUILD/* Enter non-secure code */R_BSP_NonSecureEnter();#endif}
hal_entry函数中初始化外设并打开LPM后,在while(1)中执行LED任务。
33.6.3
下载验证
下载程序后,需要断电再供电重启,程序即可正常运行。正确连接硬件并供电后,可以看见,流水灯任务执行完毕后,用于表现PWM输出的红色LED熄灭或者和开发板的红色电源LED灯一样亮(这取决与进入低功耗模式时红色LED的亮灭状态),这是因为此时处于软件待机模式,GPT时钟是停止工作的,自然也不会产生PWM。按下按键2后,MCU收到贪睡请求,进入贪睡模式,此时GPT恢复工作,因此红色LED也恢复运行状态时的原本亮度。

注:
贪睡模式下也无法对MCU进行烧写,如果发现无法烧写程序,可以试着按一下复位键或者将MCU唤醒后再进行烧写。
33.7
实验4:深度软件待机模式
最后我们来学习深度软件待机模式,这个模式的耗电是四种低功耗模式中最低的,能工作的外设和时钟也是最少的。
33.7.1
硬件设计
所需硬件较少,两个按键,一个LED和一个串口即可。
33.7.2
软件设计
33.7.2.1
普通模式与深度软件待机模式的转换框图

如上图,进入深度软件待机模式前会先进入软件待机模式,若DPSBYCR(Deep Standby Control Register)寄存器的DPSBY(Deep Software Standby)位为1,则进入深度软件待机模式。在深度软件待机模式下,CPU,不在备份域的寄存器和SRAM的数据都会丢失,因此无法在进入该模式的地方唤醒,只能通过内部复位让程序从头开始运行。
33.7.2.2
新建工程
对于e2studio开发环境:拷贝一份我们刚刚的e2s工程“38_LPM_Sleep_Mode”,然后将工程文件夹重命名为“38_LPM_Deep_SW_Standby_Mode”,最后再将它导入到我们的e2studio工作空间中。
对于Keil开发环境:拷贝一份我们刚刚的Keil工程“38_LPM_Sleep_Mode”,然后将工程文件夹重命名为“38_LPM_Deep_SW_Standby_Mode”,并进入该文件夹里面双击Keil工程文件,打开该工程。
33.7.2.3
FSP配置
将Low Power Mode配置为Deep Software Standby mode,在Deep Standby Options中配置唤醒源,因为我们开发板的按钮是按下后接地,默认唤醒边沿就是下降沿,故不需要配置唤醒边沿,其他
配置按默认即可。

下表为Deep Standby Options的属性描述。

表5:Deep Standby Options属性描述
33.7.2.4
hal_entry函数
列表8:代码清单38-6:hal_entry函数
左右滑动查看完整内容
voidhal_entry(void){/* TODO: add your own code here */Debug_UART4_Init (); //初始化 debug 串口IRQ_Init (); //按键中断初始化R_BSP_PinAccessEnable (); //启用对 PFS 寄存器的访问, 因为后面写 IO 口都用 BSP内联函数/* 判断是否在深度软件待机模式下被唤醒 */if (1U == R_SYSTEM->RSTSR0_b.DPSRSTF){/* 从深度软件待机模式唤醒后清除 IOkeep 位,以允许使用 IO 端口 */R_LPM_IoKeepClear (NULL);/* 清除唤醒标志位 */R_SYSTEM->RSTSR0_b.DPSRSTF = 0;/* 判断唤醒源是 IRQ-9 还是 IRQ-10,并将判断结果打印出来 */if (R_SYSTEM->DPSIFR1 >> 1 & 0x01U){printf("MCU 唤醒源为 IRQ-9\r\n");}elseif (R_SYSTEM->DPSIFR1 >> 2 & 0x01U){printf("MCU 唤醒源为 IRQ-10\r\n");}}LED_Flicker (10); //LED 闪烁 10 次while (1){if (key_flag == true){/* 标志位置 0,防止程序不断进入 if 的代码块里面 */key_flag = false;/*LED 闪烁 2 次 */LED_Flicker (2);/* 进入低功耗模式前打印 */printf("MCU 进入深度软件待机状态\r\n");/* 打开 LPM, 进入深度软件待机状态 */R_LPM_Open (deep_sw_standby.p_ctrl, deep_sw_standby.p_cfg);R_LPM_LowPowerModeEnter (deep_sw_standby.p_ctrl);/* 唤醒后打印,但是在进入深度软件待机模式后不能保存上下文,故这里正常来说无法被执行, 如果执行了则说明进入的是睡眠模式,也就是程序出现了问题,一般刚烧写程序会导致这个问题,重新上电即可恢复正常 */printf("MCU 被唤醒(出现本消息说明程序出错)\r\n");}}#if BSP_TZ_SECURE_BUILD/* Enter non-secure code */R_BSP_NonSecureEnter();#endif}
hal_entry函数首先初始化外设,并检测RSTSR0(Reset Status Register)寄存器的DPSRSTF(Deep Software Standby Reset Flag)位,判断MCU是否从深度软件待机模式中唤醒,若该位为1,则清除IOkeep位和DPSRSTF位,允许使用IO口,并通过串口打印唤醒源。在进入while(1)循环前再次让LED闪烁。注意,LED闪烁和打印前必须清除IOkeep位,否则IO口无法工作。在while(1)中,通过key_flag标志位判断按钮是否按下,按下后,LED闪烁两次,通过串口打印信息并进入深度软件待机模式。
33.7.2.5
按键外部中断回调函数
列表9:代码清单38-7:按键外部中断回调函数
左右滑动查看完整内容
volatile_Bool key_flag = false; //设置标志位/* 按键 1 中断回调,用于进入深度睡眠或唤醒 */voidkey1_irq_callback(external_irq_callback_args_t *p_args){/* 防止编译器产生没有使用形参的警告 */FSP_PARAMETER_NOT_USED(p_args);key_flag = true;}/* 按键 2 中断回调,用于唤醒 */voidkey2_irq_callback(external_irq_callback_args_t *p_args){/* 防止编译器产生没有使用形参的警告 */FSP_PARAMETER_NOT_USED(p_args);}
key_flag是一个volatile修饰的全局变量,用于hal_entry函数判断按键是否被按下。
33.7.2.6
LED闪烁函数
列表10:代码清单38-8:LED闪烁函数
左右滑动查看完整内容
voidLED_Flicker(int num){/*LED1 闪烁‘num’次 */for (int i = 0; i < num*2; i++){LED1_TOGGLE;R_BSP_SoftwareDelay (50, BSP_DELAY_UNITS_MILLISECONDS);}}
33.7.3
下载验证
用Type-C线连接开发板“USB TO UART”接口跟电脑,烧写代码后,给开发板重新供电,并打开串口调试助手。红色LED连续闪烁10次后,按下按键1,LED闪烁两次,并进入深度软件待机模式。然后再按下按钮2或1,红色LED再次连续10次闪烁,并在串口调试助手中看见唤醒信息,说明唤醒成功。

注:
深度软件待机模式下也是无法烧写代码的,可以参考上述方法烧写。
需要技术支持?
如您在使用瑞萨MCU/MPU产品中有任何问题,可识别下方二维码或复制网址到浏览器中打开,进入瑞萨MCU/MPU官方技术论坛寻找答案或获取在线技术支持。

https://bbs.21ic.com/renesas
未完待续
推荐阅读





夜雨聆风