硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5718|回复: 7
收起左侧

[FreeRTOS教程] 第33章 FreeRTOS低功耗之tickless模式

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2016-9-17 16:55:51 | 显示全部楼层 |阅读模式
第33章    FreeRTOS低功耗之tickless模式



        本章节为大家讲解FreeRTOS本身支持的低功耗模式tickless实现方法,tickless低功耗机制是当前小型RTOS所采用的通用低功耗方法,比如embOS,RTX和uCOS-III(类似方法)都有这种机制。
        本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
33.1 tickless低功耗模式介绍
33.2 FreeRTOS的低功耗模式介绍
33.3 FreeRTOS的低功耗模式配置
33.4 FreeRTOS实现tickless模式的框架
33.5 实验例程说明
33.6      总结



33.1  tickless低功耗模式介绍


        tickless低功耗机制是当前小型RTOS所采用的通用低功耗方法,比如embOS,RTX和uCOS-III(类似方法)都有这种机制。
        FreeRTOS的低功耗也是采用的这种方式,那么tickless又是怎样一种模式呢?仅从字母上看tick是滴答时钟的意思,less是tick的后缀,表示较少的,这里的含义可以表示为无滴答时钟。整体看这个字母就是表示滴答时钟节拍停止运行的情况。
        反映在FreeRTOS上,tickless又是怎样一种情况呢?我们都知道,当用户任务都被挂起或者阻塞时,最低优先级的空闲任务会得到执行。那么STM32支持的睡眠模式,停机模式就可以放在空闲任务里面实现。为了实现低功耗最优设计,我们还不能直接把睡眠或者停机模式直接放在空闲任务就可以了。进入空闲任务后,首先要计算可以执行低功耗的最大时间,也就是求出下一个要执行的高优先级任务还剩多少时间。然后就是把低功耗的唤醒时间设置为这个求出的时间,到时间后系统会从低功耗模式被唤醒,继续执行多任务。这个就是所谓的tickless模式。从上面的讲解中可以看出,实现tickless模式最麻烦是低功耗可以执行的时间如何获取。关于这个问题,FreeRTOS已经为我们做好了。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-17 16:58:50 | 显示全部楼层
33.2 FreeRTOS的低功耗模式介绍


      对于Cortex-M3和M4内核来说,FreeRTOS已经提供了tickless低功耗代码的实现,通过调用指令WFI实现睡眠模式,具体代码的实现就在port.c文件中,用户只需在FreeRTOSConfig.h文件中配置宏定义configUSE_TICKLESS_IDLE1即可。如果配置此参数为2,那么用户可以自定义tickless低功耗模式的实现。当用户将宏定义configUSE_TICKLESS_IDLE配置为1且系统运行满足以下两个条件时,系统内核会自动的调用低功耗宏定义函数portSUPPRESS_TICKS_AND_SLEEP()
-------------------------------
    (1)当前空闲任务正在运行,所有其它的任务处在挂起状态或者阻塞状态。
    (2)根据用户配置configEXPECTED_IDLE_TIME_BEFORE_SLEEP的大小,只有当系统可运行于低功耗模式的时钟节拍数大于等于这个参数时,系统才可以进入到低功耗模式。此参数默认已经在FreeRTOS.h文件进行定义了,下面是具体的定义内容,当然,用户也可以在FreeRTOSConfig.h文件中重新定义:
  1. #ifndef configEXPECTED_IDLE_TIME_BEFORE_SLEEP
  2.      #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
  3. #endif
  4. #if configEXPECTED_IDLE_TIME_BEFORE_SLEEP < 2
  5. #error configEXPECTED_IDLE_TIME_BEFORE_SLEEP must not be less than 2
  6. #endif
复制代码
        默认定义的大小是2个系统时钟节拍,且用户自定义的话,不可以小于2个系统时钟节拍。
                               ---------------------------------
        函数portSUPPRESS_TICKS_AND_SLEEP是FreeRTOS实现tickles模式的关键,此函数被空闲任务调用,其定义是在portmacro.h文件中:
  1. /* Tickless idle/low power functionality. */
  2. #ifndef portSUPPRESS_TICKS_AND_SLEEP
  3.      extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
  4.      #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
  5. #endif
复制代码
其中函数vPortSuppressTicksAndSleep是实际的低功耗执行代码,在port.c文件中定义,参数xExpectedIdleTime就是系统可以处于低功耗模式的系统时钟节拍数。
        FreeRTOS在线电子手册低功耗的说明http://www.freertos.org/low-power-tickless-rtos.html
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-17 17:02:02 | 显示全部楼层
33.3 FreeRTOS的低功耗模式配置


        关于FreeRTOS低功耗方面的配置主要涉及到以下几个问题。

33.3.1 滴答定时器频率与系统主频的关系


        对于Cortex-M3和M4内核的微控制器来说,实时操作系统一般都是采用滴答定时器做系统时钟,FreeRTOS也不例外。SysTick滴答定时器是一个24bit的递减计数器,有两种时钟源可选择,一个是系统主频,另一个是系统主频的八分频,默认的port.c移植文件中是用的系统主频。这里我们就根据这两种时钟源来说一说配置上的不同。
(1)SysTick滴答定时器时钟源选择系统主频
如果滴答定时器选择系统主频的话,那么需要配置configSYSTICK_CLOCK_HZ等于configCPU_CLOCK_HZ,这种关系已经在port.c文件中进行默认配置了:
  1. #ifndef configSYSTICK_CLOCK_HZ
  2.      #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
  3.      /* Ensure the SysTick is clocked at the same frequency as the core. */
  4.      #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
  5. #else
  6.      /* The way the SysTick is clocked is not modified in case it is not the same
  7.      as the core. */
  8.      #define portNVIC_SYSTICK_CLK_BIT ( 0 )
  9. #endif
复制代码
其中系统主频configCPU_CLOCK_HZ是在FreeRTOSConfig.h文件中进行定义的。
(2)SysTick滴答定时器时钟源选择系统主频的八分频
       这种情况的话,需要用户在FreeRTOSConfig.h文件中专门配置configSYSTICK_CLOCK_HZ为实际的频率,即系统主频的八分频大小。

33.3.2 系统时钟节拍不使用滴答定时器


        这种情况我们这里不做讨论,用户看FreeRTOS官网此处的说明即可:http://www.freertos.org/low-power-ARM-cortex-rtos.html

33.3.3 如何使用微控制器其它低功耗模式


        前面我们说了,对Cortex-M3和M4内核来说,FreeRTOS自带的低功耗模式是通过指令WFI让系统进入睡眠模式,如果想让系统进入停机模式,又该怎么修改呢?FreeRTOS为我们提供了两个函数:
                 configPRE_SLEEP_PROCESSING( xExpectedIdleTime )
                 configPOST_SLEEP_PROCESSING( xExpectedIdleTime )
这两个函数的定义是在FreeRTOS.h文件中定义的,什么都没有执行:
  1. #ifndef configPRE_SLEEP_PROCESSING
  2.      #define configPRE_SLEEP_PROCESSING( x )
  3. #endif
  4. #ifndef configPOST_SLEEP_PROCESSING
  5.      #define configPOST_SLEEP_PROCESSING( x )
  6. #endif
复制代码
如果需要实际执行代码需要用户在FreeRTOSConfig.h文件中重新进行宏定义,将其映射到一个实际的函数中。另外,这两个函数是在port.C文件中被函数vPortSuppressTicksAndSleep调用,具体位置如下:
  1. /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
  2.               set its parameter to 0 to indicate that its implementation contains
  3.               its own wait for interrupt or wait for event instruction, and so wfi
  4.               should not be executed again.  However, the original expected idle
  5.               time variable must remain unmodified, so a copy is taken. */
  6.               xModifiableIdleTime = xExpectedIdleTime;
  7.               configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
  8.               if( xModifiableIdleTime > 0 )
  9.               {
  10.                    __dsb( portSY_FULL_READ_WRITE );
  11.                    __wfi();
  12.                    __isb( portSY_FULL_READ_WRITE );
  13.               }
  14.               configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
复制代码
这两个函数位于指令wfi的前面和后面,用户想实现其它低功耗方式的关键就在这两个函数里面:
(1)configPRE_SLEEP_PROCESSING( xExpectedIdleTime )
      执行低功耗模式前,用户可以在这个函数里面关闭外设时钟来进一步降低系统功耗。设置其它低功耗方式也是在这个函数里面,用户只需设置参数xExpectedIdleTime=0即可屏蔽掉默认的wfi指令执行方式,因为退出这个函数后会通过if语句检测此参数是否大于0,即上面的代码所示。因此,如果用户想实现其它低功耗模式还是比较方便的,配置好其它低功耗模式后,设置参数 xExpectedIdleTime = 0即可,但切不可将此参数随意设置为0以外的其它数值。
(2)configPOST_SLEEP_PROCESSING ( xExpectedIdleTime )
      退出低功耗模式后,此函数会得到调用,之前在configPRE_SLEEP_PROCESSING里面关闭的外设时钟,可以在此函数里面重新打开,让系统恢复到正常运行状态。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-17 17:05:26 | 显示全部楼层
33.4 FreeRTOS实现tickless模式的框架


        对Cortex-M3和M4内核的微控制器来说,FreeRTOS已经提供了tickless低功耗模式的代码,对于没有支持的微控制器,用户可以在FreeRTOSConfig.h文件中配置portSUPPRESS_TICKS_AND_SLEEP宏定义,来映射实际执行函数。
        如果用户不想使用FreeRTOS提供的的tickless也可以自定义,方法也是在FreeRTOSConfig.h文件中配置portSUPPRESS_TICKS_AND_SLEEP宏定义,来映射实际执行函数。
        下面是FreeRTOS实现低功耗tickless模式的代码框架,方便用户对tickles模式有一个认识,同时也方便FreeRTOS没有支持的微控制器,用户可以参考实现。当然,不局限于这种方法,用户有更好的方法,也可以的。其中函数vTaskStepTick和eTaskConfirmSleepModeStatus是FreeRTOS提供的,其余的函数是需要用户实现的。
  1. /* 第1步:配置portSUPPRESS_TICKS_AND_SLEEP 宏定义,映射实际执行函数 */
  2. #define portSUPPRESS_TICKS_AND_SLEEP( xIdleTime ) vApplicationSleep( xIdleTime )
  3. /* 低功耗模式的实际执行函数,特别注意,参数xExpectedIdleTime 就是系统可以处于低功耗模式的时钟节拍数 */
  4. void vApplicationSleep( TickType_t xExpectedIdleTime )
  5. {
  6. unsigned long ulLowPowerTimeBeforeSleep, ulLowPowerTimeAfterSleep;
  7. eSleepModeStatus eSleepStatus;
  8. /* 第2步:记录当前系统时间,关闭系统时钟节拍中断,进入临界区 */
  9. /* 记录当前系统时间 */
  10.     ulLowPowerTimeBeforeSleep = ulGetExternalTime();
  11. /* 关闭系统时钟节拍中断 */
  12.     prvStopTickInterruptTimer();
  13. /* 关闭全局中断,进入临界区,虽然关闭了全局中断,但是不影响中断方式唤醒低功耗 */
  14.     disable_interrupts();
  15. /* 第3步:确定是否可以进入低功耗模式 */
  16. /* 确定是否可以进入低功耗模式 */
  17.     eSleepStatus = eTaskConfirmSleepModeStatus();
  18.     if( eSleepStatus == eAbortSleep )
  19.     {
  20.         /* 由于当前有任务从阻塞或者挂起态进入到就绪提导致不能再执行低功耗模式了,重新开启系统时钟节拍中断并
  21.            退出临界区 */
  22.         prvStartTickInterruptTimer();
  23.         enable_interrupts();
  24.     }
  25.     else
  26. {
  27.      /* 第4步:可以进入低功耗模式的话,分2种情况处理 */
  28.         if( eSleepStatus == eNoTasksWaitingTimeout )
  29.         {
  30.             /* 因为所有任务都处于永久挂起或者阻塞状态,这里无需再设置一定时间后唤醒,直接进入低功耗模式*/
  31.             prvSleep();
  32.         }
  33.         else
  34.         {
  35.             /* 配置一个唤醒中断,定时xExpectedIdleTime 个系统时钟节拍后将其从低功耗模式唤醒 */
  36.             vSetWakeTimeInterrupt( xExpectedIdleTime );
  37.             /* 进入低功耗状态 */
  38.             prvSleep();
  39.             /* 获取当前的系统时间 */
  40.             ulLowPowerTimeAfterSleep = ulGetExternalTime();
  41.             /* 通过ulLowPowerTimeAfterSleep - ulLowPowerTimeBeforeSleep 的差值获得系统实际处于低功耗模式的
  42.                时间,因为有时候不是我们设置的唤醒中断将系统从低功耗模式唤醒的,有可能是其它的中断,所以要获
  43.                取低功耗模式的实际执行时间,并通过函数vTaskStepTick 调整系统时间
  44.              */
  45.             vTaskStepTick( ulLowPowerTimeAfterSleep – ulLowPowerTimeBeforeSleep );
  46.         }
  47.    /* 第5步:退出临界区,重新开启系统时钟节拍中断 */
  48.         /* 退出临界区 */
  49.         enable_interrupts();
  50.         /* 重新开启系统时钟节拍中断 */
  51.         prvStartTickInterruptTimer();
  52.     }
  53. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-17 17:14:54 | 显示全部楼层
33.5  实验例程说明


33.5.1 STM32F103开发板实验


配套例子:
    V4-339_FreeRTOS实验_低功耗(tickless之睡眠模式)
实验目的:
    1.     学习FreeRTOS的低功耗(tickless之睡眠模式)。
    2.     FreeRTOS自带的tickless模式使用比较简单,只需用户使能宏配置:
         #defineconfigUSE_TICKLESS_IDLE         1
    3.     为了打印系统信息,前面的所有实验中初始化了一个定时器中断,精度高于滴答定时器中断,每50us进一次中断,本例子关闭了任务执行情况打印功能,因为高频率的定时器中断会影响低功耗tickless模式效率。
实验内容:
     1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     FreeRTOS自带的tickless模式是调用的指令__WFI进入睡眠模式。
    3.     各个任务实现的功能如下:
                      vTaskUserIF任务   :按键消息处理。
                      vTaskLED任务     :LED闪烁。
                      vTaskMsgPro任务 :消息处理,这里用作LED闪烁。
                      vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    4.     设计低功耗主要从以下几方面着手:
        (1)  用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。可以使用的低功耗方式有睡眠模式,待机模式,停机模式。
        (2)  选择了低功耗方式后就是关闭可以关闭的外设时钟。
        (3)  降低系统主频。
        (4)  注意I/O的状态。
            如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。
            如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。
                     a.     在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                     b.    在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                     c.     在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
                                   01、复位引脚(始终有效)
                                   02、当被设置为防侵入或校准输出时的TAMPER引脚。
                                   03、被使能的唤醒引脚。
        (5)  注意I/O和外设IC的连接。
        (6)  测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
FreeRTOS的配置:
    FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. #endif
  6. #define configUSE_PREEMPTION         1
  7. #define configUSE_IDLE_HOOK          0
  8. #define configUSE_TICK_HOOK          0
  9. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 72000000 )  
  10. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  11. #define configMAX_PRIORITIES         ( 5 )
  12. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  13. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  14. #define configMAX_TASK_NAME_LEN      ( 16 )
  15. #define configUSE_TRACE_FACILITY      1
  16. #define configUSE_16_BIT_TICKS       0
  17. #define configIDLE_SHOULD_YIELD      1
  18. #define configUSE_TICKLESS_IDLE      1
  19. /* Co-routine definitions. */
  20. #define configUSE_CO_ROUTINES            0
  21. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  22. /* Set the following definitions to 1 to include the API function, or zero
  23. to exclude the API function. */
  24. #define INCLUDE_vTaskPrioritySet          1
  25. #define INCLUDE_uxTaskPriorityGet         1
  26. #define INCLUDE_vTaskDelete               1
  27. #define INCLUDE_vTaskCleanUpResources      0
  28. #define INCLUDE_vTaskSuspend              1
  29. #define INCLUDE_vTaskDelayUntil           1
  30. #define INCLUDE_vTaskDelay                1
  31. /* Cortex-M specific definitions. */
  32. #ifdef __NVIC_PRIO_BITS
  33.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  34.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  35. #else
  36.      #define configPRIO_BITS              4        /* 15 priority levels */
  37. #endif
  38. /* The lowest interrupt priority that can be used in a call to a "set priority"
  39. function. */
  40. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  41. /* The highest interrupt priority that can be used by any interrupt service
  42. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  43. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  44. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  45. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01
复制代码
几个重要选项说明:
1、#define configUSE_PREEMPTION        1
         使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 72000000 )   
         系统主频72MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
         系统时钟节拍1KHz,即1ms。
4、#define configUSE_TICKLESS_IDLE     1
        使能tickless低功耗模式。
5、#define configMAX_PRIORITIES          ( 5 )
        定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
6、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
       定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
7、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
        定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
    更多关于这个参数说明请参看第12章。
程序设计:
任务栈大小分配:
     vTaskUserIF任务   :2048字节
     vTaskLED任务     :2048字节
     vTaskMsgPro任务 :2048字节
     vTaskStart任务    :2048字节
     任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
     #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 17 * 1024 ) )
系统栈大小分配:
33.1.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.         
  25.      /* 创建任务 */
  26.      AppTaskCreate();
  27.    
  28.     /* 启动调度,开始执行任务 */
  29.     vTaskStartScheduler();
  30.      /*
  31.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  32.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  33.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  34.      */
  35.      while(1);
  36. }
复制代码
硬件外设初始化
     硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
  5. *             全局变量。
  6. *    形    参: 无
  7. *    返 回 值: 无
  8. *********************************************************************************************************
  9. */
  10. void bsp_Init(void)
  11. {
  12.      /*
  13.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  14.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  15.          系统时钟缺省配置为72MHz,如果需要更改,可以修改 system_stm32f10x.c 文件
  16.      */
  17.      /* 保证睡眠模式下调试器继续可以连接使用 */
  18.      DBGMCU_Config(DBGMCU_SLEEP, ENABLE);
  19.    
  20.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  21.      bsp_InitUart();    /* 初始化串口 */
  22.      bsp_InitLed();     /* 初始LED指示灯端口 */
  23.      bsp_InitKey();     /* 初始化按键 */
  24. }
复制代码
FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,               /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码
四个FreeRTOS任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.    
  14.     while(1)
  15.     {
  16.          ucKeyCode = bsp_GetKey();
  17.         
  18.          if (ucKeyCode != KEY_NONE)
  19.          {
  20.               switch (ucKeyCode)
  21.               {
  22.                    /* K1键按下 串口打印 */
  23.                    case KEY_DOWN_K1:         
  24.                        printf("本例子关闭了任务执行情况打印功能,因为高频率的定时器中断影响低功耗tickless
  25. 模式效率\\r\\n");
  26.                        break;
  27.                   
  28.                    /* 其他的键值不处理 */
  29.                    default:                    
  30.                        break;
  31.               }
  32.          }
  33.         
  34.          vTaskDelay(20);
  35.      }
  36. }
  37. /*
  38. *********************************************************************************************************
  39. *    函 数 名: vTaskLED
  40. *    功能说明: LED闪烁
  41. *    形    参: pvParameters 是在创建该任务时传递的形参
  42. *    返 回 值: 无
  43. *   优 先 级: 2
  44. *********************************************************************************************************
  45. */
  46. static void vTaskLED(void *pvParameters)
  47. {
  48.      TickType_t xLastWakeTime;
  49.      const TickType_t xFrequency = 200;
  50.      /* 获取当前的系统时间 */
  51.     xLastWakeTime = xTaskGetTickCount();
  52.    
  53.     while(1)
  54.     {
  55.          bsp_LedToggle(2);
  56.          bsp_LedToggle(3);
  57.         
  58.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  59.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  60.     }
  61. }
  62. /*
  63. *********************************************************************************************************
  64. *    函 数 名: vTaskMsgPro
  65. *    功能说明: 消息处理,这里用过LED闪烁
  66. *    形    参: pvParameters 是在创建该任务时传递的形参
  67. *    返 回 值: 无
  68. *   优 先 级: 3
  69. *********************************************************************************************************
  70. */
  71. static void vTaskMsgPro(void *pvParameters)
  72. {
  73.      TickType_t xLastWakeTime;
  74.      const TickType_t xFrequency = 400;
  75.      /* 获取当前的系统时间 */
  76.     xLastWakeTime = xTaskGetTickCount();
  77.    
  78.     while(1)
  79.     {
  80.          bsp_LedToggle(1);
  81.          bsp_LedToggle(4);
  82.         
  83.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  84.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  85.     }
  86. }
  87. /*
  88. *********************************************************************************************************
  89. *    函 数 名: vTaskStart
  90. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  91. *    形    参: pvParameters 是在创建该任务时传递的形参
  92. *    返 回 值: 无
  93. *   优 先 级: 4
  94. *********************************************************************************************************
  95. */
  96. static void vTaskStart(void *pvParameters)
  97. {
  98.     while(1)
  99.     {
  100.          /* 按键扫描 */
  101.          bsp_KeyScan();
  102.         vTaskDelay(10);
  103.     }
  104. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-17 17:19:55 | 显示全部楼层
33.5.2   STM32F407开发板实验


配套例子:
    V5-339_FreeRTOS实验_低功耗(tickless之睡眠模式)
实验目的:
    1.     学习FreeRTOS的低功耗(tickless之睡眠模式)。
    2.     FreeRTOS自带的tickless模式使用比较简单,只需用户使能宏配置:
        #defineconfigUSE_TICKLESS_IDLE         1
    3.     为了打印系统信息,前面的所有实验中初始化了一个定时器中断,精度高于滴答定时器中断,每50us进一次中断,本例子关闭了任务执行情况打印功能,因为高频率的定时器中断会影响低功耗tickless模式效率。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     FreeRTOS自带的tickless模式是调用的指令__WFI进入睡眠模式。
    3.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,这里用作LED闪烁。
              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    4.     设计低功耗主要从以下几方面着手:
        (1)  用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。可以使用的低功耗方式有睡眠模式,待机模式,停机模式。
        (2)  选择了低功耗方式后就是关闭可以关闭的外设时钟。
        (3)  降低系统主频。
        (4)  注意I/O的状态。
           如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。
           如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。
                    a.     在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                    b.    在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                    c.     在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
                              01、复位引脚(始终有效)
                              02、当被设置为防侵入或校准输出时的TAMPER引脚。
                              03、被使能的唤醒引脚。
        (5)  注意I/O和外设IC的连接。
        (6)  测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
FreeRTOS的配置:
    FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. #endif
  6. #define configUSE_PREEMPTION         1
  7. #define configUSE_IDLE_HOOK          0
  8. #define configUSE_TICK_HOOK          0
  9. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 168000000 )
  10. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  11. #define configMAX_PRIORITIES         ( 5 )
  12. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  13. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
  14. #define configMAX_TASK_NAME_LEN      ( 16 )
  15. #define configUSE_TRACE_FACILITY      1
  16. #define configUSE_16_BIT_TICKS       0
  17. #define configIDLE_SHOULD_YIELD      1
  18. #define configUSE_TICKLESS_IDLE      1
  19. /* Co-routine definitions. */
  20. #define configUSE_CO_ROUTINES             0
  21. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  22. /* Set the following definitions to 1 to include the API function, or zero
  23. to exclude the API function. */
  24. #define INCLUDE_vTaskPrioritySet     1
  25. #define INCLUDE_uxTaskPriorityGet         1
  26. #define INCLUDE_vTaskDelete               1
  27. #define INCLUDE_vTaskCleanUpResources 0
  28. #define INCLUDE_vTaskSuspend              1
  29. #define INCLUDE_vTaskDelayUntil           1
  30. #define INCLUDE_vTaskDelay                1
  31. /* Cortex-M specific definitions. */
  32. #ifdef __NVIC_PRIO_BITS
  33.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  34.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  35. #else
  36.      #define configPRIO_BITS              4        /* 15 priority levels */
  37. #endif
  38. /* The lowest interrupt priority that can be used in a call to a "set priority"
  39. function. */
  40. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  41. /* The highest interrupt priority that can be used by any interrupt service
  42. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  43. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  44. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  45. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    0x01
复制代码
几个重要选项说明:
1、#define configUSE_PREEMPTION        1
        使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 168000000 )
         系统主频168MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
        系统时钟节拍1KHz,即1ms。
4、#define configUSE_TICKLESS_IDLE     1
        使能tickless低功耗模式。
5、#define configMAX_PRIORITIES          ( 5 )
         定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
6、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
         定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
7、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
         定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
    更多关于这个参数说明请参看第12章。
程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
    #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
33.2.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.    
  25.      /* 创建任务 */
  26.      AppTaskCreate();
  27.    
  28.     /* 启动调度,开始执行任务 */
  29.     vTaskStartScheduler();
  30.      /*
  31.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  32.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  33.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  34.      */
  35.      while(1);
  36. }
复制代码
硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 保证睡眠模式下调试器继续可以连接使用 */
  17.      DBGMCU_Config(DBGMCU_SLEEP, ENABLE);
  18.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  19.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  20.      bsp_InitUart();    /* 初始化串口 */
  21.      bsp_InitKey();     /* 初始化按键变量 */
  22.      bsp_InitLed();     /* 初始LED指示灯端口 */
  23. }
复制代码
FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,               /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码
四个FreeRTOS任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.    
  14.     while(1)
  15.     {
  16.          ucKeyCode = bsp_GetKey();
  17.         
  18.          if (ucKeyCode != KEY_NONE)
  19.          {
  20.               switch (ucKeyCode)
  21.               {
  22.                    /* K1键按下 串口打印 */
  23.                    case KEY_DOWN_K1:         
  24.                        printf("本例子关闭了任务执行情况打印功能,因为高频率的定时器中断影响低功耗tickless
  25. 模式效率\\r\\n");
  26.                        break;
  27.                   
  28.                    /* 其他的键值不处理 */
  29.                    default:                    
  30.                        break;
  31.               }
  32.          }
  33.         
  34.          vTaskDelay(20);
  35.      }
  36. }
  37. /*
  38. *********************************************************************************************************
  39. *    函 数 名: vTaskLED
  40. *    功能说明: LED闪烁
  41. *    形    参: pvParameters 是在创建该任务时传递的形参
  42. *    返 回 值: 无
  43. *   优 先 级: 2
  44. *********************************************************************************************************
  45. */
  46. static void vTaskLED(void *pvParameters)
  47. {
  48.      TickType_t xLastWakeTime;
  49.      const TickType_t xFrequency = 200;
  50.      /* 获取当前的系统时间 */
  51.     xLastWakeTime = xTaskGetTickCount();
  52.    
  53.     while(1)
  54.     {
  55.          bsp_LedToggle(2);
  56.          bsp_LedToggle(3);
  57.         
  58.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  59.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  60.     }
  61. }
  62. /*
  63. *********************************************************************************************************
  64. *    函 数 名: vTaskMsgPro
  65. *    功能说明: 消息处理,这里用过LED闪烁
  66. *    形    参: pvParameters 是在创建该任务时传递的形参
  67. *    返 回 值: 无
  68. *   优 先 级: 3
  69. *********************************************************************************************************
  70. */
  71. static void vTaskMsgPro(void *pvParameters)
  72. {
  73.      TickType_t xLastWakeTime;
  74.      const TickType_t xFrequency = 400;
  75.      /* 获取当前的系统时间 */
  76.     xLastWakeTime = xTaskGetTickCount();
  77.    
  78.     while(1)
  79.     {
  80.          bsp_LedToggle(1);
  81.          bsp_LedToggle(4);
  82.         
  83.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  84.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  85.     }
  86. }
  87. /*
  88. *********************************************************************************************************
  89. *    函 数 名: vTaskStart
  90. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  91. *    形    参: pvParameters 是在创建该任务时传递的形参
  92. *    返 回 值: 无
  93. *   优 先 级: 4
  94. *********************************************************************************************************
  95. */
  96. static void vTaskStart(void *pvParameters)
  97. {
  98.     while(1)
  99.     {
  100.          /* 按键扫描 */
  101.          bsp_KeyScan();
  102.         vTaskDelay(10);
  103.     }
  104. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-17 17:24:40 | 显示全部楼层
33.5.3 STM32F429开发板实验


配套例子:
     V6-339_FreeRTOS实验_低功耗(tickless之睡眠模式)
实验目的:
    1.     学习FreeRTOS的低功耗(tickless之睡眠模式)。
    2.     FreeRTOS自带的tickless模式使用比较简单,只需用户使能宏配置:
        #defineconfigUSE_TICKLESS_IDLE         1
    3.     为了打印系统信息,前面的所有实验中初始化了一个定时器中断,精度高于滴答定时器中断,每50us进一次中断,本例子关闭了任务执行情况打印功能,因为高频率的定时器中断会影响低功耗tickless模式效率。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     FreeRTOS自带的tickless模式是调用的指令__WFI进入睡眠模式。
    3.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,这里用作LED闪烁。
              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    4.     设计低功耗主要从以下几方面着手:
        (1)  用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。可以使用的低功耗方式有休眠模式,待机模式,停机模式。
        (2)  选择了低功耗方式后就是关闭可以关闭的外设时钟。
        (3)  降低系统主频。
        (4)  注意I/O的状态。
            如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。
            如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。
                    a.     在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                    b.    在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                    c.     在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
                               01、复位引脚(始终有效)
                               02、当被设置为防侵入或校准输出时的TAMPER引脚。
                               03、被使能的唤醒引脚。
        (5)  注意I/O和外设IC的连接。
        (6)  测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
FreeRTOS的配置:
    FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. #endif
  6. #define configUSE_PREEMPTION         1
  7. #define configUSE_IDLE_HOOK          0
  8. #define configUSE_TICK_HOOK          0
  9. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 168000000 )
  10. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  11. #define configMAX_PRIORITIES         ( 5 )
  12. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  13. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
  14. #define configMAX_TASK_NAME_LEN      ( 16 )
  15. #define configUSE_TRACE_FACILITY      1
  16. #define configUSE_16_BIT_TICKS       0
  17. #define configIDLE_SHOULD_YIELD      1
  18. #define configUSE_TICKLESS_IDLE      1
  19. /* Co-routine definitions. */
  20. #define configUSE_CO_ROUTINES             0
  21. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  22. /* Set the following definitions to 1 to include the API function, or zero
  23. to exclude the API function. */
  24. #define INCLUDE_vTaskPrioritySet          1
  25. #define INCLUDE_uxTaskPriorityGet         1
  26. #define INCLUDE_vTaskDelete               1
  27. #define INCLUDE_vTaskCleanUpResources      0
  28. #define INCLUDE_vTaskSuspend              1
  29. #define INCLUDE_vTaskDelayUntil           1
  30. #define INCLUDE_vTaskDelay                1
  31. /* Cortex-M specific definitions. */
  32. #ifdef __NVIC_PRIO_BITS
  33.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  34.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  35. #else
  36.      #define configPRIO_BITS              4        /* 15 priority levels */
  37. #endif
  38. /* The lowest interrupt priority that can be used in a call to a "set priority"
  39. function. */
  40. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  41. /* The highest interrupt priority that can be used by any interrupt service
  42. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  43. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  44. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  45. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01
复制代码
几个重要选项说明:
1、#define configUSE_PREEMPTION        1
        使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 168000000 )
        系统主频168MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
        系统时钟节拍1KHz,即1ms。
4、#define configUSE_TICKLESS_IDLE     1
         使能tickless低功耗模式。
5、#define configMAX_PRIORITIES          ( 5 )
        定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
6、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
         定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
7、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
        定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
     更多关于这个参数说明请参看第12章。
程序设计:
任务栈大小分配:
      vTaskUserIF任务   :2048字节
      vTaskLED任务     :2048字节
      vTaskMsgPro任务 :2048字节
      vTaskStart任务    :2048字节
      任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
      #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
33.3.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.         
  25.      /* 创建任务 */
  26.      AppTaskCreate();
  27.    
  28.     /* 启动调度,开始执行任务 */
  29.     vTaskStartScheduler();
  30.      /*
  31.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  32.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  33.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  34.      */
  35.      while(1);
  36. }
复制代码
硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 保证睡眠模式下调试器继续可以连接使用 */
  17.      DBGMCU_Config(DBGMCU_SLEEP, ENABLE);
  18.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  19.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  20.    
  21.      SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
  22.      bsp_InitUart();    /* 初始化串口 */
  23.      bsp_InitKey();     /* 初始化按键变量 */
  24.      bsp_InitExtIO();   /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
  25.      bsp_InitLed();     /* 初始LED指示灯端口 */
  26. }
复制代码
FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,              /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码
四个FreeRTOS任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.    
  14.     while(1)
  15.     {
  16.          ucKeyCode = bsp_GetKey();
  17.         
  18.          if (ucKeyCode != KEY_NONE)
  19.          {
  20.               switch (ucKeyCode)
  21.               {
  22.                    /* K1键按下 串口打印 */
  23.                    case KEY_DOWN_K1:         
  24.                        printf("本例子关闭了任务执行情况打印功能,因为高频率的定时器中断影响低功耗tickless
  25. 模式效率\\r\\n");
  26.                        break;
  27.                   
  28.                    /* 其他的键值不处理 */
  29.                    default:                    
  30.                        break;
  31.               }
  32.          }
  33.         
  34.          vTaskDelay(20);
  35.      }
  36. }
  37. /*
  38. *********************************************************************************************************
  39. *    函 数 名: vTaskLED
  40. *    功能说明: LED闪烁
  41. *    形    参: pvParameters 是在创建该任务时传递的形参
  42. *    返 回 值: 无
  43. *   优 先 级: 2
  44. *********************************************************************************************************
  45. */
  46. static void vTaskLED(void *pvParameters)
  47. {
  48.      TickType_t xLastWakeTime;
  49.      const TickType_t xFrequency = 200;
  50.      /* 获取当前的系统时间 */
  51.     xLastWakeTime = xTaskGetTickCount();
  52.    
  53.     while(1)
  54.     {
  55.          bsp_LedToggle(2);
  56.          bsp_LedToggle(3);
  57.         
  58.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  59.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  60.     }
  61. }
  62. /*
  63. *********************************************************************************************************
  64. *    函 数 名: vTaskMsgPro
  65. *    功能说明: 消息处理,这里用过LED闪烁
  66. *    形    参: pvParameters 是在创建该任务时传递的形参
  67. *    返 回 值: 无
  68. *   优 先 级: 3
  69. *********************************************************************************************************
  70. */
  71. static void vTaskMsgPro(void *pvParameters)
  72. {
  73.      TickType_t xLastWakeTime;
  74.      const TickType_t xFrequency = 400;
  75.      /* 获取当前的系统时间 */
  76.     xLastWakeTime = xTaskGetTickCount();
  77.    
  78.     while(1)
  79.     {
  80.          bsp_LedToggle(1);
  81.          bsp_LedToggle(4);
  82.         
  83.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  84.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  85.     }
  86. }
  87. /*
  88. *********************************************************************************************************
  89. *    函 数 名: vTaskStart
  90. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  91. *    形    参: pvParameters 是在创建该任务时传递的形参
  92. *    返 回 值: 无
  93. *   优 先 级: 4
  94. *********************************************************************************************************
  95. */
  96. static void vTaskStart(void *pvParameters)
  97. {
  98.     while(1)
  99.     {
  100.          /* 按键扫描 */
  101.          bsp_KeyScan();
  102.         vTaskDelay(10);
  103.     }
  104. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-17 17:25:41 | 显示全部楼层
33.6   总结

    本章节主要为大家讲解了FreeRTOS本身支持的低功耗tickless模式,对于初学者来说,刚开始学习可能不是特别理解,随着后面自己有了一定的经验后就比较容易理解了,特别是tickless的实现方法。另外tickless模式不限制用户必须采用睡眠模式,采用停机模式也是可以的,官方只是为用户提供了一种参考方法。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-1 02:01 , Processed in 0.260717 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表