写在前面
- 2018/1/15更新了文章中的部分错误。
- FreeRTOS源码为最新版的10.0.1。FreeRTOS 10包含两个重要的新功能:流缓冲区和消息缓冲区。
- 从10.0.0开始,FreeRTOS的开源协议改为了MIT。
源码目录
首先,从官网下载最新版的源码,目前最新版为10.0.1。下载后,解压得到源码,FreeRTOS的源码包中的内容还是相当丰富的。简略目录如下:
├─FreeRTOS
│ ├─Demo // 各种开发工具的完整Demo,开发者可以方便的以此搭建出自己的项目,甚至直接使用
│ │ ├─Common // 所有例程都可以使用的演示例程文件
│ │ └─其他 // 对应平台和开发工具的项目例程(命名:平台_开发工具,例如:CORTEX_M4F_M0_LPC43xx_Keil)
│ ├─License // 使用修改过的GPL
│ └─Source // FreeRTOS的源码
│ ├─include // 源码对应的头文件
│ └─portable // 每个支持的处理器架构需要一小段与处理器架构相关的RTOS代码。该目录下即为和开发平台相关的代码
│ ├─MemMang // FreeRTOS内存管理方案(一般要根据平台来选择以下5个之一)
│ │ heap_1.c
│ │ heap_2.c
│ │ heap_3.c
│ │ heap_4.c
│ │ heap_5.c
│ └─其他 // 其他开发工具相关的代码,需要根据自己的开发工具进行选择
│ croutine.c // 协线程(协程)文件,和任务类似,在系统资源比较缺乏下使用
│ event_groups.c // 事件标志组
│ list.c // 列表结构描述,在内核整体控制上都使用了列表格式数据处理,一切数据结构的基础
│ queue.c // 队列,任务和任务之间的通讯处理
│ tasks.c // 所有任务相关函数
│ timers.c // 软件定时器,以任务形式存在
| stream_buffer.c // 10.0.0 新增
└─FreeRTOS-Plus // FreeRTOS+组件和演示例程
对于FreeRTOS的每个独立部分,其官网均有详细的说明。后续博文也会给出相应的介绍。
注意:
1. FreeRTOS-Plus下有个常用的Trace源码,但是该源码比较旧,和官网对应不上。如果要使用FreeRTOS+Trace,可以参考 此文。
移植说明
FreeRTOS源码整理
FreeRTOS源码目录中文件还是挺多的,但是真正需要使用的其实没几个(个人不喜欢在项目中放一堆实际不用的文件)!
-
list.c、tasks.c、queue.c
必不可少,这三个文件是FreeRTOS最基本的源文件。至于同目录下的timer.c、event_groups.c
等文件,根据需要添加即可。 -
/FreeRTOS/Source/portable/MemMang下的heap_x.c
也是必不可少的,根据需要选择其中一个,STM32系列一般用heap_4.c
。 -
/FreeRTOS/Source/portable/下根据开发工具选择对应目录下的文件。例如:若使用Keil,对应目录下只有一个文件,让直接用RVDS目录下对应的文件。根据芯片选择对应目录下文件
port.c、portmacro.h
即可。 -
对应的头文件当然也是必不可少。/FreeRTOS/Source/include下的文件可根据需要删除不需要的文件!
-
还有一个文件FreeRTOSConfig.h,位于/FreeRTOS/Demo/对应的平台下,这个文件其实就相当于STM32标准库中的stm32fxx_conf.h(使用标准外设库时,通过该文件进行配置)。对于该文件,下一节有详细说明。
最后,去除部分不使用的文件,整理完成后的源代码大致如下所示:
├─inc // 源码头文件,根据需要删除不必要的就可以!例如,不使用事件标志组,则可删除event_groups.h。(注意:有些头文件为FreeRTOS内容使用)
│ croutine.h
│ deprecated_definitions.h
│ event_groups.h
│ FreeRTOS.h
│ list.h
│ mpu_prototypes.h
│ mpu_wrappers.h
│ portable.h
│ portmacro.h
│ projdefs.h
│ queue.h
│ semphr.h
| stack_macros.h // V10.0.0开始为了一致性,已经重命名了StackMacros.h头文件stack_macros.h。为了兼容这两文件目前都在源码中。使用时直接删除StackMacros.h,选择stack_macros.h即可(新的源码不再使用StackMacros.h)。
│ StackMacros.h
│ stdint.readme // 为支持C99添加,使用C99时将其改为stdint.h
│ task.h
│ timers.h
└─src // 省略部分不使用文件
heap_4.c
list.c
port.c
queue.c
tasks.c
FreeRTOS配置
这里特别说明一下FreeRTOSConfig.h这个文件。FreeRTOS作为一个可高度配置的实时内核,其绝大多数配置都体现在在FreeRTOS.h。但是FreeRTOS.h是内核文件,难道需要直接改内核文件?当然不是,FreeRTOS.h通过检查FreeRTOSConfig.h中对各宏值的定义来选择功能。
如果要了解FreeRTOS的全部配置项,可以参考 FreeRTOS之全配置项详解、裁剪(FreeRTOSConfig.h)。本部分主要说明在实际移植时需要特别注意的部分。
FreeRTOS指定了用户使用一个名为FreeRTOSConfig.h
的配置文件来对FreeRTOS进行配置。这个文件是一个用户配置文件,不是内核源码的一部分,这个文件不再源码目录,而是在对应的Demo目录下。因为,这是具体的用户的实现。通过这个文件,用户可以裁剪FreeRTOS,以下是一个针对STM32F4芯片的FreeRTOS的配置文件:
/*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that is more than just the market leader, it *
* is the industry's de facto standard. *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book, reference manual, or both: *
* http://www.FreeRTOS.org/Documentation *
* *
***************************************************************************
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
the FAQ page "My application does not run, what could be wrong?". Have you
defined configASSERT()?
http://www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum.
http://www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible. Now you can receive
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
Ltd, and the world's leading authority on the world's leading RTOS.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and commercial middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
/* Ensure stdint is only used by the compiler, and not the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
#include "main.h"
extern uint32_t SystemCoreClock;
#endif
/** @addtogroup base definitions 基本参数配置
* @{
*/
/* 置1:RTOS使用抢占式调度器;置0:RTOS使用协作式调度器(时间片)
*
* 注:在多任务管理机制上,操作系统可以分为抢占式和协作式两种。协作式操作系统是任务主动释放CPU后,切换到下一个任务。任务切换的时机完全取决于正在运行的任务。
*/
#define configUSE_PREEMPTION 1
/* 某些运行FreeRTOS的硬件有两种方法选择下一个要执行的任务:通用方法和特定于硬件的方法(以下简称“特殊方法”)。
*
* 通用方法:
* 1.configUSE_PORT_OPTIMISED_TASK_SELECTION 为 0 或者 硬件不支持这种特殊方法。
* 2.可以用于所有FreeRTOS支持的硬件
* 3.完全用C实现,效率略低于特殊方法。
* 4.不强制要求限制最大可用优先级数目
* 特殊方法:
* 1.必须将configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1。
* 2.依赖一个或多个特定架构的汇编指令(一般是类似计算前导零[CLZ]指令)。
* 3.比通用方法更高效
* 4.一般强制限定最大可用优先级数目为32
*/
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
/* 置1:使能低功耗tickless模式;置0:保持系统节拍(tick)中断一直运行
*
* 注:tickless模式,比普通低功耗模式要好一些
*/
#define configUSE_TICKLESS_IDLE 0
/*
* 写入实际的CPU内核时钟频率,也就是CPU指令执行频率,通常称为Fcclk
*/
#define configCPU_CLOCK_HZ ( SystemCoreClock )
/*
* RTOS 系统节拍中断的频率。即一秒中断的次数,每次中断RTOS都会进行任务调度。
*/
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 8 ) /* 最大优先级 */
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 64 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configUSE_MUTEXES 1 /* 使用互斥信号量 */
#define configUSE_RECURSIVE_MUTEXES 0 /* 使用递归互斥信号 */
#define configUSE_COUNTING_SEMAPHORES 0 /* 使用计数信号量 */
#define configUSE_ALTERNATIVE_API 0 /* 9.0.0 已经移除 */
#define configQUEUE_REGISTRY_SIZE 10 /* 设置可以注册的信号量和消息队列个数 */
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
//#define configENABLE_BACKWARD_COMPATIBILITY 0
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/**
* @}
*/
/** @addtogroup Hook function related definitions 相关的钩子函数
* @{
*/
/* 置1:使用空闲钩子(Idle Hook类似于回调函数);置0:忽略空闲钩子
*
* 注:
* 1.空闲任务钩子是一个函数,这个函数由用户来实现,FreeRTOS规定了函数的名字和参数:void vApplicationIdleHook(void ),这个函数在每个空闲任务周期都会被调用
* 2.对于已经删除的RTOS任务,空闲任务可以释放分配给它们的堆栈内存。因此必须保证空闲任务可以被CPU执行
* 3.使用空闲钩子函数设置CPU进入省电模式是很常见的
* 4.不可以调用会引起空闲任务阻塞的API函数
*/
#define configUSE_IDLE_HOOK 0
/* 置1:使用时间片钩子(Tick Hook);置0:忽略时间片钩子
*
* 注:
* 1.时间片钩子是一个函数,这个函数由用户来实现,FreeRTOS规定了函数的名字和参数:void vApplicationTickHook(void )
* 2.时间片中断可以周期性的调用
* 3.函数必须非常短小,不能大量使用堆栈,不能调用以”FromISR" 或 "FROM_ISR”结尾的API函数
*/
#define configUSE_TICK_HOOK 0
/* 置1:使用栈溢出钩子(Tick Hook);置0:忽略栈溢出钩子
*
* 注:
* 1.栈溢出钩子是一个函数,这个函数由用户来实现,FreeRTOS规定了函数的名字和参数:void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName )
* 2.这个选项仅适用于内存映射未分段的微处理器架构
* 3.FreeeRTOS提供了两个可选机制用来辅助检测和改正堆栈溢出。配置宏configCHECK_FOR_STACK_OVERFLOW为不同的常量来使用不同堆栈溢出检测机制
*/
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
/**
* @}
*/
/** @addtogroup Run time and task stats gathering related definitions.
* @{
*/
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/**
* @}
*/
/** @addtogroup Co-routine definitions 协程相关配置
* @{
*/
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/**
* @}
*/
/** @addtogroup Software timer related definitions 软件定时器的相关配置
* @{
*/
#define configUSE_TIMERS 0
#define configTIMER_TASK_PRIORITY 3
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
/**
* @}
*/
/** @addtogroup Interrupt nesting behaviour configuration.
* @{
*/
/*
* Cortex-M内核使用8bit来配置优先级,但是STM32只使用了高4bit,数值越小,优先级越高。
* 在往寄存器里面写数值配置的时候,是按照8bit来写的,所以真正写的时候需要经过转换,公式为:
* ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff),其中的priority就是我们配置的真正的优先级
*/
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
/*============================================== SysTick中断优先级配置 ============================================*/
/*
* 1. configLIBRARY_LOWEST_INTERRUPT_PRIORITY宏定义是用来配置FreeRTOS用到的SysTick中断和PendSV中断的优先级。
* 在NVIC分组设置为4的情况下,此宏定义的范围就是0-15。这里配置为了0x0f,即SysTick和PendSV都是配置为了最低优先级。
* 这样可以提高系统的实时响应能力,即其他的外部中断可以及时的得到响应。
*
* 2. 在往寄存器里面写数值配置的时候,是按照8bit来写的,所以真正写的时候需要经过转换,公式为:
* ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff),其中的priority就是我们配置的真正的优先级。经过这个公式之后得到的是
* 下面的这个宏:configKERNEL_INTERRUPT_PRIORITY
*/
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/*===========================================可屏蔽的中断优先级配置====================================================*/
/*
*
* 1.用于配置STM32的特殊寄存器basepri寄存器的值,用于屏蔽中断,当大于basepri值的优先级的中断将被全部屏蔽。basepri只有4bit有效,
* 默认只为0,即全部中断都没有被屏蔽。
* configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY定义了受FreeRTOS管理的最高优先级中断。设置NVIC的优先级分组为4的情况下。配置为5,意思就是中断优先级大于5的中断都被屏蔽。
* 简单的说就是用户可以在抢占式优先级为5到15的中断里面调用FreeRTOS的API函数,抢占式优先级为0~4的中断里面是不允许调用的(即便API以FromISR结尾)。
*
* 2. 当把配置好的优先级写到寄存器的时候,是按照8bit来写的,所以真正写的时候需要经过转换,公式为:
* ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff),其中的priority就是我们配置的真正的优先级。经过这个公式之后得到的是下面的这个宏:
* configMAX_SYSCALL_INTERRUPT_PRIORITY
*
* 3. 在FreeRTOS中,关中断是通过配置basepri寄存器来实现的,关掉的中断由配置的basepri的值决定,小于basepri值的
* 中断FreeRTOS是关不掉的,这样做的好处是可以系统设计者可以人为的控制那些非常重要的中断不能被关闭,在紧要的关头必须被响应。
* 而在UCOS中,关中断是通过控制PRIMASK来实现的,PRIMASK是一个单1的二进制位,写1则除能除了NMI和硬 fault的所有中断。当UCOS关闭
* 中断之后,即使是你在系统中设计的非常紧急的中断来了都不能马上响应,这加大了中断延迟的时间,如果是性命攸关的场合,那后果估计挺严重。
* 相比UCOS的关中断的设计,FreeRTOS的设计则显得人性化很多。
*
*/
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/**
* @}
*/
/** @addtogroup Define to trap errors during development.
* @{
*/
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
/**
* @}
*/
/** @addtogroup FreeRTOS MPU specific definitions.
* @{
*/
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
/**
* @}
*/
/** @addtogroup Set the following definitions to 1 to include the API function, or 0 to exclude the API function.
* @{
*/
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
#define INCLUDE_pcTaskGetTaskName 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 0
#define INCLUDE_xTimerPendFunctionCall 0
/**
* @}
*/
/** @addtogroup Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names.
* @{
*/
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
//#define xPortSysTickHandler SysTick_Handler /* 该中断需要特殊处理,否则在启动过程中会有问题 */
/**
* @}
*/
/** @addtogroup Integrates the Tracealyzer recorder with FreeRTOS.
* @{
*/
/* 以下为使用Percepio Tracealyzer需要的东西,不需要时将 configUSE_TRACE_FACILITY 定义为 0 */
#if ( configUSE_TRACE_FACILITY == 1 )
#include "trcRecorder.h"
#define INCLUDE_xTaskGetCurrentTaskHandle 1 // 启用一个可选函数(该函数被 Trace源码使用,默认该值为0 表示不用)
#endif
/**
* @}
*/
#endif /* FREERTOS_CONFIG_H */
无论使用什么开发环境,对于FreeRTOS的配置均在此文件中进行。例如,在使用FreeRTOS+Trace时,需要启用一些辅助函数!当然,为了FreeRTOS能正常运行,也需要在该文件中进行配置。这里只针对FreeRTOS运行进行说明。
处理系统中断
在Cortex-M3硬件下,FreeRTOS使用SysTick
作为系统节拍时钟,使用SVC和PendSVC
进行上下文切换。异常中断服务代码位于port.c
文件中,FreeRTOS的作者已经为各种架构的CPU写好了这些代码。
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
需要特殊注意的是SysTick中断,该终端需要进行特殊处理,否则在启动过程中将出现错误。:
void SysTick_Handler(void)
{
#if (INCLUDE_xTaskGetSchedulerState == 1 )
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
#endif /* INCLUDE_xTaskGetSchedulerState */
xPortSysTickHandler();
#if (INCLUDE_xTaskGetSchedulerState == 1 )
}
#endif /* INCLUDE_xTaskGetSchedulerState */
}
需要注意的是需要合理安排FreeRTOS使用的系统中断。例如在STM32中,有以下处理
/* FreeRTOS使用的优先级配置 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
SysTick_Config(SystemCoreClock / 1000);
NVIC_SetPriority(SVCall_IRQn, 0x0);
NVIC_SetPriority(PendSV_IRQn, 15);
最后,建立任务,启动调度器,FreeRTOS就可以运行了!
void Main_task(void * pvParameters)
{
unsigned char buf[4] = {0};
unsigned int i = 0;
for( ;; )
{
vTaskDelay(1000);
}
vTaskDelete(NULL);
}
int main(void)
{
/* 省略*/
/* Init task */
xTaskCreate(Main_task, "Main", configMINIMAL_STACK_SIZE * 2, NULL,MAIN_TASK_PRIO, NULL);
/* Start scheduler */
vTaskStartScheduler();
/* We should never get here as control is now taken by the scheduler */
for( ;; );
}
至于文件中的其他值,后面再详细说明!