方法/步骤
嵌入式 *** 作系统有分时 *** 作系统和实时 *** 作系统,如果 *** 作系统能够使计算机系统及时响应外部事件请求,并能控制所有实时设备和实时任务协调运行,且能在一个规定的时间内完成对事件的处理,怎么这种系统称为实时 *** 作系统。
如果系统必须在极其严格的时间内完成的任务叫做硬件的实时 *** 作系统,如果不是很严格的话就是软件的实时 *** 作系统。
前往官网下载最新版的FreeRTOS系统,然后解压缩到本地。有两个文件夹,FreeRTOS文件夹里面是 *** 作系统内核,FreeRTOS-Plus里面是一些中间件如文件系统,网络协议栈等。
值得一提的是,FreeRTOS的教学用书和API参考手册电子版均已免费提供,建议在现在安装FreeRTOS的同时也一并下载到本地,以供后期学习查阅。
FreeRTOS的主要特点如下:
1. 支持抢占式调度,合作式调度和时间片调度
2. 具有低功耗模式,称为tickless模式
3. FreeRTOS-MPU支持M3/M4/M7内核的MPU(内存保护单元)
4. 典型的内核使用大小在4k~9k
5. 支持消息队列、二值信号量、计数信号量、递归信号量和互斥信号量,可用于任务与任务之间的消息传递和同步,任务与终端间的消息传递和同步
6. 任务数量不限,任务优先级数量不限
7. 高效的软件定时器,不需要损耗额外的CPU时间,除非需要执行定时器任务
8. 任务间直接的消息传递,速度较快
9. FreeRTOS的队列是其它通信和同步机制的基础
移植FreeRTOS之前,原有的工程(比如跑马灯,越简单越好)中不能有SysTick、PendSV和SVC三个系统中断的使用,因为FreeRTOS系统要使用这三个中断。
1. 准备好简单工程的模板
2. 在工程模板中创建FreeRTOS文件夹,并将解压后源码FreeRTOS文件夹中Source目录下的所有内容复制进来
3. 在user目录下需要手动窗件FreeRTOSConfig.h的配置文件,也可以从官方demo中拿来修改后使用,比如从下载的源码目录下的FreeRTOS/Demo/CORTEX_M4F_STM32F407ZG-SK中进行拷贝
4. 将源码文件添加到MDK的工程目录中,其中heap_4.c文件路径Source/portable/MemMang,port.c的路径FreeRTOS/Source/portable/RVDS/ARM_CM4F,这是因为我们使用的M451是CM4F内核的
在工程中添加新的头文件搜索路径:
.\FreeRTOS\include
.\FreeRTOS\portable\RVDS\ARM_CM4F
打开FreeRTOSConfig.h配置文件,根据自己硬件配置进行修改
1. 首先将文件开头的__ICCARM__修改为__CC_ARM,即把编译器从IAR改为RealView
2. 将以下宏配置为0
configUSE_IDLE_HOOK
configUSE_TICK_HOOK
configCHECK_FOR_STACK_OVERFLOW
configUSE_MALLOC_FAILED_HOOK
3. #define configUSE_PREEMPTION 1 将会使能抢占式调度器
4. #define configCPU_CLOCK_HZ ( SystemCoreClock )设置系统主频(M451的系统主频为72MHz)
5. #define configTICK_RATE_HZ ( ( TickType_t ) 1000 )设置系统节拍为1kHz,即1ms
6. #define configMAX_PRIORITIES ( 5 )定义可供用户使用的最大优先级数为5,那么用户可以使用的优先级号是0,1,2,3,4
6. #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) )定义堆大小,FreeRTOS内核,用户动态申请内存,任务栈等都需要这个空间
4. 将工程整体重新编译一次,这样FreeRTOS基本移植结束了
编写测试程序来验证一致的FreeRTOS是否已经可以使用
1. 在main.c中添加一下几个头文件
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "croutine.h"
2. 在main函数的开头,禁止全局中断(除了NMI和HardFault),具体方法是:__set_PRIMASK(1)这样做的好处是可以防止执行的中断服务程序中有FreeRTOS的API函数,保证系统正常启动,不受别的中断影响。在port.c中的函数prvStartFirstTask中会重新开启全局中断
3. 创建任务AppTaskCreate()
4. 启动调度,开始执行任务vTaskStartScheduler()
烧写程序,运行,可以从串口看到正确的输出信息
* 1. 学习FreeRTOS的任务栈溢出检测方法一(模拟栈溢出)。
* 2. FreeRTOS的任务栈溢出检测方法一说明:
* a. FreeRTOSConfig.h文件中配置宏定义:
* #define configCHECK_FOR_STACK_OVERFLOW 1
* b. 在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函数。
* void vApplicationStackOverflowHook( TaskHandle_t xTask,
* signed char *pcTaskName )
* 用户可以在钩子函数里面做一些处理。本实验是在钩子函数中打印出现栈溢出的任务。
* c. 这种方法不能保证所有的栈溢出都能检测到。比如任务在执行的过程中发送过栈溢出。任务切换前
* 栈指针又恢复到了正常水平,这种情况在任务切换的时候是检测不到的。又比如任务栈溢出后,把
* 这部分栈区的数据修改了,这部分栈区的数据不重要或者暂时没有用到还好,如果是重要数据被修
* 改将直接导致系统进入硬件异常。这种情况下,栈溢出检测功能也是检测不到的。
* d. 本实验就是简单的在任务vTaskUserIF中申请过大的栈空间,模拟出一种栈溢出的情况,溢出后触
* 发钩子函数,因为我们将溢出部分的数据修改了,进而造成进入硬件异常。
#define configCHECK_FOR_STACK_OVERFLOW 1
/*
*********************************************************************************************************
* 函 数 名: StackOverflowTest
* 功能说明: 任务栈溢出测试
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void StackOverflowTest(void)
{
int16_t i
uint8_t buf[2048]
(void)buf/* 防止警告 */
/*
1. 为了能够模拟任务栈溢出,并触发任务栈溢出函数,这里强烈建议使用数组的时候逆着赋值。
因为对于M3和M4内核的MCU,堆栈生长方向是向下生长的满栈。即高地址是buf[2047], 低地址
是buf[0]。如果任务栈溢出了,也是从高地址buf[2047]到buf[0]的某个地址开始溢出。
因此,如果用户直接修改的是buf[0]开始的数据且这些溢出部分的数据比较重要,会直接导致
进入到硬件异常。
2. 栈溢出检测是在任务切换的时候执行的,我们这里加个延迟函数,防止修改了重要的数据导致直接
进入硬件异常。
3. 任务vTaskTaskUserIF的栈空间大小是2048字节,在此任务的入口已经申请了栈空间大小
------uint8_t ucKeyCode
------uint8_t pcWriteBuffer[500]
这里再申请如下这么大的栈空间
-------int16_t i
-------uint8_t buf[2048]
必定溢出。
*/
for(i = 2047i >= 0i--)
{
buf[i] = 0x55
vTaskDelay(1)
}
}
/*
*********************************************************************************************************
* 函 数 名: vApplicationStackOverflowHook
* 功能说明: 栈溢出的钩子函数
* 形 参: xTask 任务句柄
* pcTaskName 任务名
* 返 回 值: 无
*********************************************************************************************************
*/
void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
{
printf("任务:%s 发现栈溢出\r\n", pcTaskName)
}
实验目的:
* 1. 学习FreeRTOS的任务栈溢出检测方法二(模拟栈溢出)。
* 2. FreeRTOS的任务栈溢出检测方法二说明:
* a. FreeRTOSConfig.h文件中配置宏定义:
* #define configCHECK_FOR_STACK_OVERFLOW 2
* b. 在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函数。
* void vApplicationStackOverflowHook( TaskHandle_t xTask,
* signed char *pcTaskName )
* 用户可以在钩子函数里面做一些处理。本实验是在钩子函数中打印出现栈溢出的任务。
* c. 任务创建的时候将任务栈所有数据初始化为0xa5,任务切换时进行任务栈检测的时候检测末尾
* 的16个字节是否都是0xa5,通过这种方式来检测任务栈是否溢出了。相比方法一,这种方法的速度
* 稍慢些,但是这样就有效的避免了方法一里面的部分情况。不过依然不能保证所有的栈溢出都能检测
* 到,比如任务栈末尾的16个字节没有用到,即没有被修改,但是任务栈已经溢出了,这种情况是检
* 测不到的。另外任务栈溢出后,任务栈末尾的16个字节没有修改,但是溢出部分的栈区的数据修改
* 了,这部分栈区的数据不重要或者暂时没有用到还好,如果是重要数据被修改将直接导致系统进入硬
* 件异常。这种情况下,栈溢出检测功能也是检测不到的。
* d. 本实验就是简单的在任务vTaskUserIF中申请过大的栈空间,模拟出一种栈溢出的情况,溢出后触
* 发钩子函数,因为我们将溢出部分的数据修改了,进而造成进入硬件异常。
#define configCHECK_FOR_STACK_OVERFLOW 2
函数内容和上面一样:
static void StackOverflowTest(void)
void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)