加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

【FreeRTOS操作系统教程】第32章 FreeRTOS低功耗之待机模式

(2016-09-14 17:14:50)
标签:

fatfs

freertos

stemwin

stm32

usb

分类: FreeRTOS

第32章      FreeRTOS低功耗之待机模式



低功耗是MCU的一项重要的指标,本章节为大家讲解STM32F103STM32F407STM32F429的低功耗方式之待机模式在FreeRTOS操作系统上面的实现方法。

本章教程配套的例子含Cortex-M3内核的STM32F103Cortex-M4内核的STM32F407以及F429

32.1 STM32F103待机模式介绍

32.2 STM32F4xx待机模式介绍

32.3 实验例程说明

32.4       总结

 

 

 

32.1  STM32F103待机模式介绍

说明:在FreeRTOS系统上面实现待机方式仅需了解这里讲解的知识基本就够用了,更多待机方式的知识请看STM32F103参考手册和Cortex-M3权威指南。

在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时,用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。

STM32F103有三种低功耗模式:

(1)睡眠模式(Cortex™-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统滴答定时器Systick等仍在运行)

(2)停机模式(所有的时钟都已停止)

(3)待机模式(1.8V电源关闭)

本章节我们主要讲解待机模式,待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLLHSIHSE振荡器也被断电。SRAM和寄存器内容丢失,只有备份的寄存器和待机电路维持供电。

在实际的待机模式编程时需要清楚哪些问题呢? 请继续往下看。

32.1.1  STM32F103如何进入待机模式

FreeRTOS系统中,让STM32进入待机模式比较容易,调用固件库函数PWR_EnterSTANDBYMode即可。

32.1.2 STM32F103如何退出待机模式

STM32从待机模式唤醒可以通过外部复位(NRST引脚)IWDG复位、WKUP引脚上的上升沿或RTC闹钟事件的上升沿。从待机唤醒后,除了电源控制/状寄存器,所有寄存器被复位。

从待机模式唤醒后的代码执行等同于复位后的执行。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出。

在开发板上面是通过K2按键来唤醒,K2按键使用的引脚就是WKUP引脚。

32.1.3 STM32F103使用待机模式注意事项

待机模式要注意以下问题:

在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:

    (1)复位引脚(始终有效)。 

    (2)当被设置为防侵入或校准输出时的TAMPER引脚。

    (3)被使能的唤醒引脚。

32.2STM32F4xx待机模式介绍

说明:本小节的内容含STM32F407STM32F429,在FreeRTOS系统上面实现待机方式仅需了解这里讲解的知识基本就够用了,更多待机方式的知识请看STM32F4xx参考手册和Cortex-M4权威指南。

在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。

STM32F4xx有三种低功耗模式:

(1)睡眠模式(Cortex™-M4F内核停止,所有外设包括Cortex-M4核心的外设,如NVIC、系统滴答定时器Systick等仍在运行)

(2)停机模式(所有的时钟都已停止)

(3)待机模式(1.2V电源关闭)

本章节我们主要讲解待机模式,待机模式下可达到最低功耗。待机模式基于Cortex™-M4F深度睡眠模式,其中调压器被禁止,因此1.2 V域断电。PLLHSI振荡器和HSE 振荡器也将关闭。除备份域RTC寄存器、RTC备份寄存器和备份SRAM和待机电路中的寄存器外,SRAM 和寄存器内容都将丢失。

在实际的待机模式编程时需要清楚哪些问题呢? 请继续往下看。

32.2.1 STM32F4xx如何进入待机模式

FreeRTOS系统中,让STM32进入待机模式比较容易,调用固件库函数PWR_EnterSTANDBYMode即可。

32.2.2STM32F4xx如何退出待机模式

STM32从待机模式唤醒可以通过外WKUP 引脚上升沿、RTC闹钟(闹钟A和闹钟B)、RTC唤醒事件、RTC入侵事件、RTC 时间戳事件、NRST引脚外部复位和IWDG 复位,唤醒后除了电源控制/状寄存器,所有寄存器被复位。

从待机模式唤醒后的代码执行等同于复位后的执行。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出。

早期工程版本是通过K2按键,即引脚PC13检测RTC的入侵事件进行唤醒,实际测试发现问题较多。本实验将其改为复位按键进行唤醒,可以这么做是因为系统进入到待机模式后,被唤醒后系统的执行过程等同于进行复位。

32.2.3STM32F4xx使用待机模式注意事项

待机模式要注意以下问题:

1、将选择的待机模式唤醒源(RTC闹钟ARTC闹钟BRTC唤醒、RTC入侵或RTC时间戳标志)对应的RTC标志清零,防止无法正常进入待机模式。

2、待机模式下的 I/O 状态

    (1)复位引脚(仍可用)。

    (2)RTC_AF1 引脚 (PC13)(如果针对入侵、时间戳、RTC闹钟输出或RTC时钟校准输出进行了配置)。

    (3)WKUP引脚 (PA0)(如果使能)。

32.3实验例程说明

32.3.1STM32F103开发板实验

配套例子:

V4-338_FreeRTOS实验_低功耗(待机模式)

实验目的:

1.     学习FreeRTOS的低功耗(待机模式)

实验内容:

1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。

2.     K2按键按下,系统从待机模式唤醒,即通过WKUP引脚PA0的上升将其唤醒。

3.     K3按键按下,系统进入到待机模式。

4.     关于低功耗的待机模式说明:

(1)  待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLLHSIHSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。

(2)  从待机模式唤醒后的代码执行等同于复位后的执行。

5.     各个任务实现的功能如下:

              vTaskUserIF任务   :按键消息处理。

              vTaskLED任务     LED闪烁。

              vTaskMsgPro任务 :消息处理,这里用作LED闪烁。

              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

6.     设计低功耗主要从以下几方面着手:

(1)  用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。可以使用的低功耗方式有睡眠模式,待机模式,停机模式。

(2)  选择了低功耗方式后就是关闭可以关闭的外设时钟。

(3)  降低系统主频。

(4)  注意I/O的状态。

如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。

如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。

a.     在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。

b.    在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。

c.     在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:

n  复位引脚(始终有效)

n  当被设置为防侵入或校准输出时的TAMPER引脚。

n  被使能的唤醒引脚。

(5)  注意I/O和外设IC的连接。

(6)  测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。

FreeRTOS的配置:

FreeRTOSConfig.h文件中的配置如下:

 

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)

 #include

 extern volatile uint32_t ulHighFrequencyTimerTicks;

#endif

 

#define configUSE_PREEMPTION         1

#define configUSE_IDLE_HOOK          0

#define configUSE_TICK_HOOK          0

#define configCPU_CLOCK_HZ           ( ( unsigned long ) 72000000 )  

#define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )

#define configMAX_PRIORITIES         ( 5 )

#define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )

#define configMAX_TASK_NAME_LEN      ( 16 )

#define configUSE_TRACE_FACILITY      1

#define configUSE_16_BIT_TICKS       0

#define configIDLE_SHOULD_YIELD      1

 

 

#define configGENERATE_RUN_TIME_STATS                1

#define configUSE_STATS_FORMATTING_FUNCTIONS         1

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)

#define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks

//#define portALT_GET_RUN_TIME_COUNTER_VALUE           1

 

 

#define configUSE_CO_ROUTINES            0

#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

 

 

 

#define INCLUDE_vTaskPrioritySet          1

#define INCLUDE_uxTaskPriorityGet         1

#define INCLUDE_vTaskDelete               1

#define INCLUDE_vTaskCleanUpResources      0

#define INCLUDE_vTaskSuspend              1

#define INCLUDE_vTaskDelayUntil           1

#define INCLUDE_vTaskDelay                1

 

 

#ifdef __NVIC_PRIO_BITS

    

     #define configPRIO_BITS              __NVIC_PRIO_BITS

#else

     #define configPRIO_BITS                   

#endif

 

 

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f

 

 

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01

几个重要选项说明:

u  #define configUSE_PREEMPTION        1

使能抢占式调度器

u  #define configCPU_CLOCK_HZ     ( ( unsigned long ) 72000000 )   

系统主频72MHz

u  #define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )

系统时钟节拍1KHz,即1ms

u  #define configMAX_PRIORITIES          ( 5 )

定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4不包含5,对于这一点,初学者要特别的注意。

u  #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )

定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。

u  configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01

定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOSAPI的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:

l  使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。

l  对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。

l  这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。

更多关于这个参数说明请参看第12章。

FreeRTOS任务调试信息(按K1按键,串口打印):

【FreeRTOS操作系统教程】第32章 <wbr>FreeRTOS低功耗之待机模式

 

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:

#define tskBLOCKED_CHAR          ( 'B' )  任务阻塞

#define tskREADY_CHAR           ( 'R' )  任务就绪

#define tskDELETED_CHAR           ( 'D' )  任务删除

#define tskSUSPENDED_CHAR   ( 'S' )  任务挂起

程序设计:

u  任务栈大小分配:

vTaskUserIF任务   2048字节

vTaskLED任务     2048字节

vTaskMsgPro任务 :2048字节

vTaskStart任务    2048字节

任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )

u  系统栈大小分配:

【FreeRTOS操作系统教程】第32章 <wbr>FreeRTOS低功耗之待机模式

 

u  FreeROTS初始化:

 

int main(void)

{

    

     __set_PRIMASK(1); 

    

    

     bsp_Init();

    

    

     vSetupSysInfoTest();

    

    

     AppTaskCreate();

 

    

     AppObjCreate();

    

   

    vTaskStartScheduler();

 

    

     while(1);

}

u  硬件外设初始化

硬件外设的初始化是在bsp.c文件实现:

 

void bsp_Init(void)

{

    

    

          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

 

     bsp_InitUart();   

     bsp_InitLed();    

     bsp_InitKey();    

}

u  FreeRTOS任务创建:

 

static void AppTaskCreate (void)

{

    xTaskCreate( vTaskTaskUserIF,  

                 "vTaskUserIF",    

                 512,              

                 NULL,             

                 1,                

                 &xHandleTaskUserIF );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskLED,          

                 "vTaskLED",        

                 512,               

                 NULL,              

                 2,                 

                 &xHandleTaskLED );

    

     xTaskCreate( vTaskMsgPro,           

                 "vTaskMsgPro",          

                 512,                    

                 NULL,                   

                 3,                      

                 &xHandleTaskMsgPro );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskStart,            

                 "vTaskStart",           

                 512,                    

                 NULL,                   

                 4,                      

                 &xHandleTaskStart );   

}

u  四个FreeRTOS任务的实现:

 

static void vTaskTaskUserIF(void *pvParameters)

{

     uint8_t ucKeyCode;

     uint8_t pcWriteBuffer[500];

    

 

    while(1)

    {

         ucKeyCode = bsp_GetKey();

        

         if (ucKeyCode != KEY_NONE)

         {

              switch (ucKeyCode)

              {

                  

                   case KEY_DOWN_K1:          

                       printf("=================================================\r\n");

                       printf("任务名      任务状态 优先级   剩余栈 任务序号\r\n");

                       vTaskList((char *)&pcWriteBuffer);

                       printf("%s\r\n", pcWriteBuffer);

                  

                       printf("\r\n任务名       运行计数         使用率\r\n");

                       vTaskGetRunTimeStats((char *)&pcWriteBuffer);

                       printf("%s\r\n", pcWriteBuffer);

                       break;

                  

                  

                   case KEY_DOWN_K3:            

                       printf("K3按键按下,系统进入待机模式,按K2按键将唤醒\r\n");

                       PWR_EnterSTANDBYMode();    

                       break;

                  

                  

                   default:                    

                       break;

              }

         }

        

         vTaskDelay(20);

     }

}

 

 

static void vTaskLED(void *pvParameters)

{

     TickType_t xLastWakeTime;

     const TickType_t xFrequency = 200;

 

    

    xLastWakeTime = xTaskGetTickCount();

    

    while(1)

    {

         bsp_LedToggle(2);

         bsp_LedToggle(3);

        

        

        vTaskDelayUntil(&xLastWakeTime, xFrequency);

    }

}

 

 

static void vTaskMsgPro(void *pvParameters)

{

     TickType_t xLastWakeTime;

     const TickType_t xFrequency = 400;

 

    

    xLastWakeTime = xTaskGetTickCount();

    

    while(1)

    {

         bsp_LedToggle(1);

         bsp_LedToggle(4);

        

        

        vTaskDelayUntil(&xLastWakeTime, xFrequency);

    }

}

 

 

static void vTaskStart(void *pvParameters)

{

    while(1)

    {

        

         bsp_KeyScan();

        vTaskDelay(10);

    }

}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有