完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
`简介 随着物联网(IoT)的兴起,产品对功耗的需求越来越强烈。作为数据采集的传感器节点通常需要在电池供电时长期工作,而作为联网的SOC也需要有快速的响应功能和较低的功耗。IoT 产品的功耗来源可以分成2部分,一部分是 MCU 内部的功耗,一部分是板载其他外设的功耗。而在 MCU 内的功耗又可以分成CPU 的功耗和片内外设的功耗。为了实现低功耗的功能,我们需要对它们进行合适的管理。 在该文档中,基于MM32 MCU 特性,适配RT-Thread 强大的应用调度功能,对功耗做优良的管理。 MM32 Series MCU 低功耗有三种模式,分别为:Sleep/Stop/Standby,其中Sleep可以被任意中断唤醒,故在进入Sleep前需要关闭Systick。Stop/Standby则不需要考虑这种问题。程序的移植 Low-power modes有三种,Sleep mode、Stop mode、Standby mode,实现如下 :void pwr_control(rt_uint8_t NewState) { /* Check the parameters */ assert_param(IS_POWERMODE_STATE(NewState)); if(PM_SLEEP_MODE_STANDBY == NewState) { // PWR CLOCK RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // RCC->APB2RSTR|=0X01FC;//REAST IO //Enable to wake up pin function PWR_WakeUpPinCmd(ENABLE); //Enter standby mode PWR_EnterSTANDBYMode(); } else if(PM_SLEEP_MODE_DEEP == NewState) { /* enter Stop mode */ sysTick_Cmd(DISABLE); RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWREN, ENABLE); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); /* exit Sleep mode */ /* HSE和HSI已关闭需重启开启 */ sysTick_init(); SYSCLKConfig_START(); } else { /* enter Sleep mode */ /* SysTick_Handler() 会自增rt_tick,需要DISABLE。否则无法进入睡眠 */ sysTick_Cmd(DISABLE); __WFI(); /* exit Sleep mode */ /* 单纯使用sysTick_Cmd(ENABLE)不能正常,rt_thread_delay()也会有影响 */ sysTick_init(); } } 在RT-Thread任务运行中使MCU进入低功耗状态,由于系统有个默认的工作模式,是IDLE空闲模式,这个模式下会一直调用sleep这个函数,导致无法进入低功耗模式,故需要修改成NONE模式,同时在进入前使系统进入临界状态。进入睡眠后使用K1(外部中断PA0)唤醒,在EXTI0中断中使任务退出临界状态,执行正常的任务。因为RT-Thread使用到systick,在Sleep mode模式时,是无法进入低功耗状态的,因此需要临时关闭Systick,唤醒后再次启用。在实验中我们使用外部中断模式唤醒,故进行如下配置: // This function is EXTI0 1 Handler void EXTI0_1_IRQHandler(void) { EXTI_ClearFlag(EXTI_Line0); rt_exit_critical(); } // NVIC EXTI Config static void EXTI_NVIC_Init(void) { NVIC_InitTypeDef NVIC_InitStructure; //ENABLE External interrupt NVIC_InitStructure.NVIC_IRQChannel = EXTI0_1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 0x01; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } // EXTI Config static void EXTI_Config(void) { EXTI_InitTypeDef EXTI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //PA.0 use EXTI line 0 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); EXTI_StructInit(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); } // EXTI Config static void EXTI_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //set as pull down input GPIO_Init(GPIOA, &GPIO_InitStructure); } // External interrupt wake-up standby initialization void WKUP_STOP_Init(void) { // EXTI SYSTEM CLOLK ENABLE EXTI_NVIC_Init(); EXTI_Config(); EXTI_GPIO_Config(); } 为了便于观察,我们建立两个线程,线程中进行LED闪烁,用来判断任务是否正常运行,代码如下:/* 线程1入口函数 */ static void thread1_entry(void *param) { while (1) { LED2_TOGGLE(); LED1_TOGGLE(); rt_thread_delay(1000); } } unsigned char flash_buff[40]; /* 线程2入口函数 */ static void thread2_entry(void *param) { while (1) { LED4_TOGGLE(); LED3_TOGGLE(); rt_thread_delay(1000); } } int event_simple_init() { /* 创建线程1 */ tid1 = rt_thread_create("t1", thread1_entry, RT_NULL, /* 线程入口是thread1_entry, 入口参数是RT_NULL */ THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid1 != RT_NULL) rt_thread_startup(tid1); else tc_stat(TC_STAT_END | TC_STAT_FAILED); /* 创建线程2 */ tid2 = rt_thread_create("t2", thread2_entry, RT_NULL, /* 线程入口是thread2_entry, 入口参数是RT_NULL */ THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid2 != RT_NULL) rt_thread_startup(tid2); else tc_stat(TC_STAT_END | TC_STAT_FAILED); return 0; } int rt_application_init() { u16 i; LED_Init(); for(i = 0; i < 10; i++) { LED1_TOGGLE(); LED2_TOGGLE(); LED3_TOGGLE(); LED4_TOGGLE(); deleyNop(1000); } rt_enter_critical(); WKUP_STOP_Init(); pwr_control(PM_SLEEP_MODE_STANDBY); event_simple_init(); } 考虑到芯片进入低功耗模式时,有些时候不易擦除,故在进入低功耗之前最好做一个比较大的延时。同时在进入之前,先使系统进入临界区。进入临界区后调度器将被上锁。在系统锁住调度器的期间,系统依然响应中断,如果中断唤醒了的更高优先级线程,调度器并不会立刻执行它,直到调用解锁调度器函数才尝试进行下一次调度。需要注意的是在唤醒后需要先执行退出临界区操作,当系统退出临界区的时候,系统会计算当前是否有更高优先级的线程就绪,如果有比当前线程更高优先级的线程就绪,将切换到这个高优先级线程中执行;如果无更高优先级线程就绪,将继续执行当前任务。 实验 按下Miniboard的K1键后工程开始运行,可以看到LED闪烁,表示唤醒开始工作。 ` |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2249个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11703 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5930 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10965 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4577 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4302 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
981浏览 1评论
806浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-27 22:18 , Processed in 0.470073 second(s), Total 37, Slave 29 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号