freertos 中断管理中断是硬件中断还是软件中断

最近在调试程序时发现程序会在运行一段时间后崩溃。在仔细阅读FreeRTOS和PIC32MX的相关资料后,修改了FreeRTOS配置,调整了优先级设置,优化了关键区域的代码,显著降低了崩溃的概率。在这里分享一些心得。
想学习FreeRTOS的基础知识请阅读专栏:
2. 配置FreeRTOSConfig.h
这里主要提几个与PIC32MX微处理器的特性有关的配置项,其他通用的配置请参考
/* Interrupt nesting behaviour configuration. */
/* The priority at which the tick interrupt runs.
This should probably be kept at 1. */
#define configKERNEL_INTERRUPT_PRIORITY
/* The maximum interrupt priority from which FreeRTOS.org API functions can be called.
Only API functions that end in ...FromISR() can be used within interrupts. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY
PIC32MX的中断优先级为1-7,其中1最低,7最高。低优先级的中断触发的中断服务程序可以被高优先级的中断打断,从而执行更紧急的中断服务程序。
系统定时器中断使用最低优先级1,其可以被中断优先级为2-7的中断嵌套。
优先级为2-6的中断触发的中断服务程序里,可以使用FreeRTOS提供的后缀为FromISR()的API函数。
优先级为7的中断触发的中断服务程序不受FreeRTOS的影响,且不可以使用后缀为FromISR()的API函数。
设置configMAX_SYSCALL_INTERRUPT_PRIORITY的意义在于,使一些中断服务函数可以使用自己的栈空间。不高于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断服务程序都使用相同的中断栈空间。
/* Records the interrupt nesting depth.
This is initialised to one as it is
decremented to 0 when the first task starts. */
volatile UBaseType_t uxInterruptNesting = 0x01;
/* Stores the task stack pointer when a switch is made to use the system stack. */
UBaseType_t uxSavedTaskStackPointer = 0;
/* The stack used by interrupt service routines that cause a context switch. */
StackType_t xISRStack[ configISR_STACK_SIZE ] = { 0 };
/* The top of stack value ensures there is enough space to store 6 registers on
the callers stack, as some functions seem to want to do this. */
const StackType_t * const xISRStackTop = &( xISRStack[ configISR_STACK_SIZE - 7 ] );
uxInterruptNesting用来标示中断嵌套层数。每进入一次中断,uxInterruptNesting值自加;每退出一次中断,uxInterruptNesting自减。嵌套次数越多,这个数越大。程序在保存现场时使用这个值来判断是将CPU寄存器组压入任务栈还是中断栈。
uxSavedTaskStackPointer用来在进入中断服务程序前保存任务栈,在退出中断服务程序时将sp指针指向任务栈。
xISRStack是中断服务程序用到的栈。进入中断服务程序时,sp指针被指向这个中断栈的顶部xISRStackTop;退出中断服务程序时,sp指针恢复到任务的栈指针uxSavedTaskStackPointer。
明确了这几个变量的用途后,程序编写时需要注意如下几点:
uxInterruptNesting最大不应该超过硬件中断源的总数,否则可以判定程序运行异常;
xISRStack的大小由configISR_STACK_SIZE设置,单位是字节。所有中断服务程序中创建的局部变量都会使用这个栈。需要确保中断嵌套层数达到最大时xISRStack也够用,否则会产生栈的溢出,后果很可能是程序崩溃;
不要在中断服务程序中随意移动sp指针,否则中断嵌套发生时,被中断的服务程序的栈有可能被破坏。
3. 优化任务优先级
在创建FreeRTOS任务时需要为任务指定一个优先级。优先级高的任务更容易获得CPU的使用权。
产品代码创建了17个任务,其中有一个任务专门用于访问串口硬件以发送串口log,优先级设成最高。将这个任务的优先级设成最低后,系统崩溃的概率降低了。
4. 优化中断处理
中断服务程序会打断任务代码的执行,且进入和退出中断时需要频繁调用入栈和出栈函数,加重CPU的运行负担。
中断处理的优化方法一般有如下几种:
降低中断嵌套次数
减少中断产生频率
缩短中断处理时间
4.1. 降低中断嵌套次数
产品程序崩溃一般发生在硬件中断频繁产生的时候。为了降低中断嵌套次数,根据中断触发的频率,调整了硬件的中断优先级:
2个I2C中断(优先级4)
2个SPI中断(优先级6)
3个UART中断(优先级3)
2个定时器中断(优先级2)
1个输入电平捕捉中断(优先级5)
I2C中断和UART中断触发的频率最高,然后是定时器中断和SPI中断,最后是输入电平捕捉中断。调整的原则是使触发频率高的中断在执行中断服务程序时可以被触发频率低的中断打断,降低中断嵌套的可能性。
4.2. 减少中断产生频率
减少中断产生频率的方法可以有:
尽量用FreeRTOS提供的时间函数
硬件驱动方式从中断式改成轮询式
在产品代码中,定时器2周期性给一个全局变量加1作为时钟节拍。但FreeRTOS已经能够产生系统时钟节拍,因此定时器2可以去掉。
PIC32MX的硬件驱动方式支持轮询式。
4.3. 缩短中断处理时间
在中断服务程序中,只接收和发送数据,而不作数据的解析。接收到的数据通过队列发送给中断延时服务任务:
uint8_t recvBuf[100];
void func_ISR(void)
receiveData(recvBuf);
queueSend(&recvBuf);
clearISRFlag();
void func_task(void)
if (TRUE == queueRecv(&recvBuf))
parse(recvBuf);
5. 分析系统崩溃原因
PIC32MX的CPU提供了一种程序异常处理的机制。当程序运行异常时,程序会跳转到_general_exception_handler函数:
void _general_exception_handler ( void )
/* Mask off Mask of the ExcCode Field from the Cause Register
Refer to the MIPs Software User's manual */
_excep_code = (_CP0_GET_CAUSE() & 0x0000007C) && 2;
_excep_addr = _CP0_GET_EPC();
_cause_str
= cause[_excep_code];
_excep_code 给出产生exception的原因:
_excep_addr给出直接导致exception的地址。
6. 优化底层移植汇编代码
调试时程序经常崩溃在如下汇编代码:
ehb指令的作用主要是解决流水线执行异常,但不能解决流水线指令异常。
浏览官方技术支持论坛后,发现有人遇到类似的问题:
他的解决办法是在ehb之前加上ssnop指令。
我试着在vPortYieldISR和portRESTORE_CONTEXT里的ehb之前添加了ssnop指令,与ehb相关的程序崩溃解决了。
7. 解决堆栈溢出
7.1. 任务堆栈的溢出
configCHECK_FOR_STACK_OVERFLOW设成1或2,任务堆栈溢出时会执行vApplicationStackOverflowHook()。
可以通过查看xPortGetFreeHeapSize()的返回值获取剩余任务堆栈的大小,其中包含所有。
也可以通过查看uxTaskGetStackHighWaterMark()的返回值获取单个任务在运行时的堆栈使用情况,返回值越小,可用的堆栈越少。
7.2. 中断堆栈的溢出
configCHECK_FOR_STACK_OVERFLOW设成3,xPortStartScheduler会将中断堆栈内的初值全部设为相同值,便于检查中断堆栈用了多少。
8. 预防进程死锁
程序执行过程中尽量不要使用OSA_Delay(portMAX_DELAY),防止某个进程一直得不到执行。
本文已收录于以下专栏:
相关文章推荐
最近忙着新员工培训的事情,项目事情也比较多。人也越来越懒了。以下是即将下布的文章:《ajaxPro.net实战入门》《CVSNT配置与权限管理》《敏捷软件开发经验谈》不知道这些内容大家喜不喜欢。 请大...
在嵌入式操作系统中队列是任务间数据交换的常用手段,队列是生产者消费者模型的重要组成部分。FreeRTOS的队列简单易用,下面结合一个具体例子说明FreeRTOS中的队列如何使用。
看到一篇有趣的文章The Eight Levels of Programmers。以前似乎看过不少这种程序员的多少个级别、境界,但这篇语言很风趣,而且分类比较细化,让人觉得挺合情合理、无法反驳的。绝大...
任务应用函数是一组辅助类函数,一般用于调试信息输出、获取任务句柄、获取任务状态、操作任务标签值等等。1.获取任务系统状态1.1函数描述
UBaseType_t uxTaskGetSys...
第一:其实说不上移植笔记,FreeRTOS已经移植至众多平台(MCU),包括MSP430,STM32等,这份笔记完全建立在官方代码的基础之上,简单的说就是修改一些设置从而完成一个呼吸灯实验。
第二:虽...
(图片来源于网络) 很多的软件Bug源自于输入错误,即便像Google这样的国际大公司。 在Google上搜索的时候,有些结果列表项中带有一条警告,表明Google认为它带有恶意代码。 如果你在200...
继续任务操作相关函数
.cn/s/blog_98ee3au.html
本章教程为大家讲解两个重要的概念,FreeRTOS的临界段和开关中断。
使用FreeRTOS,一个最基本的程序架构如下所示:int main(void)
必要的初始化工作;
创建任务1;
创建任务2;
vTaskSta...
他的最新文章
讲师:汪剑
讲师:刘道宽
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)&& & 在阅读本文之前,有两个定义在FreeRTOSConfig.h中的宏,你必须先明白它们是什么意思,一文中,讲解了这两个宏:
configKERNEL_INTERRUPT_PRIORITYconfigMAX_SYSCALL_INTERRUPT_PRIORITY
& & & &FreeRTOS与Cortex-M内核可谓是绝配,以至于让移植和使用FreeRTOS都变得更简单起来。根据FreeRTOS官方反馈,在Cortex-M内核上使用FreeRTOS大多数的问题点是由不正确的优先级设置引起的。这个问题也是在意料之中的,因为尽管Cortex-M内核的中断模式是非常强大的,但对于那些使用来说,Cortex-M内核中断机制也有点笨拙(或者是说使用比较繁琐),并且违反直觉(这个主要是因为Cortex-M中断优先级数值越大代表的优先级反而越小)。本章打算描述Cortex-M的中断优先级机制,并描述怎样结合RTOS内核使用。
& & & &说明:虽然Cortex-M内核的优先级方案看上去比较复杂,但每一个官方发布的FreeRTOS 接口包(在FreeRTOSV7.2.0\FreeRTOS\Source\portable文件夹中,一般为port.c)内都会有正确配置的演示例程,可以以此为参考。
1.有效优先级
1.1Cortex-M 硬件详述
& & & &首先需要清楚有效优先级的总数,这取决于微控制器制造商怎么使用Cortex内核。所以,并不是所有的Cortex-M内核微处理器都具有相同的中断优先级级别。
& & & &Cortex-M构架自身最多允许256级可编程优先级(优先级配置寄存器最多8位,所以优先级范围从0x00~0xFF),但是绝大多数微控制器制造商只是使用其中的一部分优先级。比如,TI Stellaris Cortex-M3和Cortex-M4微控制器使用优先级配置寄存器的3个位,能提供8级优先级。再比如,NXP LPC17xx Cortex-M3微控制器使用优先级配置寄存器的5个位,能提供32级优先级。
1.2应用到RTOS
& & & &RTOS中断嵌套方案将有效的中断优先级分成两组:一组可以通过RTOS临界区屏蔽,另一组不受RTOS影响,永远都是使能的。宏configMAX_SYSCALL_INTERRUPT_PRIORITY在FreeRTOSConfig.h中配置,定义两组中断优先级的边界。逻辑优先级高于此值的中断不受RTOS影响。最优值取决于微控制器使用的优先级配置寄存器的位数。
2.与数值相反的优先级值和逻辑优先级设置
2.1Cortex-M 硬件详述
& & & &有必要先解释一下优先级值和逻辑优先级:在Cortex-M内核中,假如有8级优先级,我们说优先级值是0~7,但数值最大的优先级7却代表着最低的逻辑优先级。很多使用传统传统中断优先级的工程师会觉得这样比较绕,违反直觉。以下内容提到的优先级要仔细区分是优先级数值还是逻辑优先级。
& & & &接下来需要清楚的是,在Cortex-M内核中,一个中断的优先级数值越低,逻辑优先级却越高。比如,中断优先级为2的中断可以抢占中断优先级为5的中断,但反过来就不行。换句话说,中断优先级2比中断优先级5的优先级更高。
& & & &这是Cortex-M内核最容易让人犯错之处,因为大多数的非Cortex-M内核微控制器的中断优先级表述是与之相反的。
2.2应用到 RTOS
& & & &以“FromISR”结尾的FreeRTOS函数是具有中断调用保护的(执行这些函数会进入临界区),但是就算是这些函数,也不可以被逻辑优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断服务函数调用。(宏configMAX_SYSCALL_INTERRUPT_PRIORITY定义在头文件FreeRTOSConfig.h中)。因此,任何使用RTOSAPI函数的中断服务例程的中断优先级数值大于等于configMAX_SYSCALL_INTERRUPT_PRIORITY宏的值。这样就能保证中断的逻辑优先级等于或低于configMAX_SYSCALL_INTERRUPT_PRIORITY。
& & & &Cortex中断默认情况下有一个数值为0的优先级。大多数情况下0代表最高级优先级。因此,绝对不可以在优先级为0的中断服务例程中调用RTOSAPI函数。
3.Cortex-M 内部优先级概述
3.1Cortex-M 硬件详述
& & & &Cortex-M内核的中断优先级寄存器是以最高位(MSB)对齐的。比如,如果使用了3位来表达优先级,则这3个位位于中断优先级寄存器的bit5、bit6、bit7位。剩余的bit0~bit4可以设置成任何值,但为了兼容,最好将他们设置成1.
& & & &Cortex-M优先级寄存器最多有8位,如果一个微控制器只使用了其中的3位,那么这3位是以最高位对齐的,见下图:
& & & 某微控制器只使用了优先级寄存器中的3位,下图展示了优先级数值5(二进制101B)是怎样在优先级寄存器中存储的。如果优先级寄存器中未使用的位置1,下图也展示了为什么数值5(二进制B)可以看成数&#(二进制)的。
& & & 某微控制器只使用了优先级寄存器中的4位,下图展示了优先级数值5(二进制101B)是怎样在优先级寄存器中存储的。如果优先级寄存器中未使用的位置1,下图也展示了为什么数值5(二进制B)可以看成数值95(二进制)的。
3.2应用到 RTOS
& & & 上文中已经描述,那些在中断服务例程中调用RTOS API函数的中断逻辑优先级必须低于或等于configMAX_SYSCALL_INTERRUPT_PRIORITY(低逻辑优先级意味着高优先级数值)。
& & & CMSIS以及不同的微控制器供应商提供了可以设置某个中断优先级的库函数。一些库函数的参数使用最低位对齐,另一些库函数的参数可能使用最高位对齐,所以,使用时应该查阅库函数的应用手册进行正确设置。
& & & 可以在FreeRTOSConfig.h中设置宏configMAX_SYSCALL_INTERRUPT_PRIORITY和configKERNEL_INTERRUPT_PRIORITY的值。这两个宏需要根据Cortex-M内核自身的情况进行设置,要以最高有效位对齐。比如某微控制器使用中断优先级寄存器中的3位,设置configKERNEL_INTERRUPT_PRIORITY的值为5,则代码为:
& & & &宏configKERNEL_INTERRUPT_PRIORITY指定RTOS内核使用的中断优先级,因为RTOS内核不可以抢占用户任务,因此这个宏一般设置为硬件支持的最小优先级。对于Cortex-M硬件,RTOS使用到硬件的PendSV和SysTick硬件中断,在函数xPortStartScheduler()中(该函数在port.c中,由启动调度器函数vTaskStartScheduler()调用),将PendSV和SysTick硬件中断优先级寄存器设置为宏configKERNEL_INTERRUPT_PRIORITY指定的值。
& & & &有关代码如下(位于port.c):
4.1Cortex-M 硬件详述
& & & RTOS内核使用Cortex-M内核的BASEPRI寄存器来实现临界区(注:BASEPRI为优先级屏蔽寄存器,优先级数值大于或等于该寄存器的中断都会被屏蔽,优先级数值越大,逻辑优先级越低,但是为零时不屏蔽任何中断)。这允许RTOS内核可以只屏蔽一部分中断,因此可以提供一个灵活的中断嵌套模式。
& & & 那些需要在中断调用时保护的API函数,FreeRTOS使用寄存器BASEPRI实现中断保护临界区。当进入临界区时,将寄存器BASEPRI的值设置成configMAX_SYSCALL_INTERRUPT_PRIORITY,当退出临界区时,将寄存器BASEPRI的值设置成0。很多Bug反馈都提到,当退出临界区时不应该将寄存器设置成0,应该恢复它之前的状态(之前的状态不一定是0)。但是Cortex-M NVIC决不会允许一个低优先级中断抢占当前正在执行的高优先级中断,不管BASEPRI寄存器中是什么值。与进入临界区前先保存BASEPRI的值,退出临界区再恢复的方法相比,退出临界区时将BASEPRI寄存器设置成0的方法可以获得更快的执行速度。
4.2应用到RTOS kernel
& & & RTOS内核通过写configMAX_SYSCALL_INTERRUPT_PRIORITY的值到BASEPRI寄存器的方法创建临界区。中断优先级0(具有最高的逻辑优先级)不能被BASEPRI寄存器屏蔽,因此,configMAX_SYSCALL_INTERRUPT_PRIORITY绝不可以设置成0。
本文已收录于以下专栏:
相关文章推荐
典型情况下,程序进入临界区将关闭所有中断。FreeRTOS则提供了一种机制,在进入临界区时仅关闭部分中断,另一部分中断可以继续响应。这种机制让系统享有多任务特性的同时保证极高的实时性。
在阅读本文之前,有两个定义在FreeRTOSConfig.h中的宏,你必须先明白它们是什么意思,《FreeRTOS内核配置说明》一文中,讲解了这两个宏:
configKERNEL_INTERRUP...
FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制。每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核。这个配置文件是针...
CORTEX内核的优先级是数值越小优先级越高,即0是最高优先级。FreeRTOS正好相反,为了满足某些应用对中断实时性要求高的需求,使得中断优先级高于某个值之后,就不能调用操作系统的内核函数来提高实时...
FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制。每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核。这个配置文件是针...
(原创文章,欢迎转载,请注明出处)
有朋友问我,为什么有些 RTOS 支持中断嵌套, 有些 RTOS 不支持?
这个问题,我想了一下。先从中断来说吧,中断是什么。当CPU在做一件事情的时候,现在有...
RTOS中断处理Interrupt Handling在RTOS中使用信号来触发线程间的行为是比较简单和高效的,而对于Cortex-M微控制器来讲,从中断源获取信号来触发线程同样是一种重要的方式。虽然在...
xTaskIncrementTick
节拍计数器溢出
唤醒超时任务
任务时间片轮循
系统延时函数
普通延时函数 vTaskDelay
循环延时函数 vTaskDelayU...
浅析FreeRTOS_v4.5.0延时机制---vTaskDelay()的实现
文章来源:[转载请声明出处]
void vTaskDel...
FreeRTOS 的移植主要需要改写如下三个文件。
1.        portmacro.h
2.        port.c
他的最新文章
讲师:汪剑
讲师:刘道宽
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)【FreeRTOS操作系统教程】第15章
FreeRTOS临界段和开关中断_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
【FreeRTOS操作系统教程】第15章
FreeRTOS临界段和开关中断
&&【FreeRTOS操作系统教程】第15章
FreeRTOS临界段和开关中断
阅读已结束,下载文档到电脑
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,方便使用
还剩31页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢1. FreeRTOS下载包的文件结构& & & 在FreeRTOS官方网站可以下载到最新版的FreeRTOS包,我这里使用的是V8.2.3版本。& & & 下载包内的总文件数量多的令人生畏,但文件结构却很简洁。一文的第3节详细描述了下载包文件结构,我们这里只是简单提一下。& & & 下载包根目录下包含两个子目录:FreeRTOS和FreeRTOS-Plus。其中,FreeRTOS-Plus文件夹中包含一些FreeRTOS+组件和演示例程(组件大都收费),我们不对这个文件夹下的内容多做了解,重点说一下FreeRTOS文件夹。& & & FreeRTOS文件夹下包含两个子目录:Demo和Source。其中,Demo包含演示例程的工程文件,Source包含实时操作系统源代码文件。& & & FreeRTOS实时操作系统内核仅包含三个必要文件,此外还有三个可选文件。RTOS核心代码位于三个源文件中,分别是tasks.c、queue.c和list.c。这三个文件位于FreeRTOS/Source目录下,在同一目录下还有3个可选的文件,叫做timers.c、event_groups.c和croutine.c,分别用于软件定时器、事件组和协程。& & & 对于支持的处理器架构,RTOS需要一些与处理器架构相关的代码。可以称之为RTOS硬件接口层,它们位于FreeRTOS/Source/Portable/[相应编译器]/[相应处理器架构]文件夹下。我们这次要移植到Cortex-M3微控制,使用Keil MDK编译器,所以需要的RTOS硬件接口代码位于:FreeRTOS\Source\portable\RVDS\ARM_CM3文件夹下。& & & 堆栈分配也是属于硬件接口层(移植层),在FreeRTOS/Source/portable/MemMang文件夹下具有各种类型的堆栈分配方案。这里我们使用heap_1.c提供的堆栈分配方案。关于FreeRTOS的内存管理,后续一文中会详细介绍FreeRTOS内存管理的特性和用法,一文会从源码级别分析FreeRTOS内存管理的具体实现,这里不用多纠结,你也可以快速的浏览一下这两篇文章,里面或许有许多不懂的,但不要着急,先放过它们。& & & FreeRTOS文件夹下的Demo文件夹中还包括各种演示例程,涉及多种架构的处理器以及多种编译器。FreeRTOS/Demo/Common/Minimal文件夹下的演示例程代码中,绝大部分对所有移植硬件接口都是适用的。FreeRTOS/Demo/Common/Full文件夹下的代码属于历史遗留代码,仅用于PC移植层。2. 移植前的一些准备一块具有Cortex-M3微处理器的硬件板子,并且保证板子可以正常运转。下载FreeRTOS程序包(一文中有下载地址,这是我在CSDN下载频道做的镜像文件。如果你能忍受下载网速慢,也可以去官方网站下载。)下载CMSIS-M3,其实主要是需要里面的core_cm3.h文件(可以去ARM官方下载,如果你安装了keil 5或比较新的Keil 4 MDK编译器,在目录:Keil\ARM\CMSIS文件夹下也可以找到)3.移植过程3.1 添加RTOS核心代码&&&&&&&& 将tasks.c、queue.c和list.c这三个内核代码加入工程,将port.c和heap_1.c这两个与处理器相关代码加入工程。port.c位于FreeRTOS\Source\portable\RVDS\ARM_CM3文件夹下,heap_1.c位于FreeRTOS/Source/portable/MemMang文件夹下。3.2 添加头文件路径&...\FreeRTOS\Source\portable\RVDS\ARM_CM3&…\FreeRTOS\Source\include3.3 编写FreeRTOSConfig.h文件& & & 对于刚接触FreeRTOS的用户来说,最简单方法是找一个类似的Demo工程,复制该工程下的FreeRTOSConfig.h文件,在这个基础上进行修改。详细的配置说明将在后续一文中给出,这里依然不必纠结。3.4 编写一些钩子函数& & & 如果你在FreeRTOSConfig.h中设置了configUSE_TICK_HOOK=1,则必须编写voidvApplicationTickHook( void )函数。该函数利用时间片中断,可以很方便的实现一个定时器功能。详见后续文章有关宏configUSE_TICK_HOOK一节。& & & 如果你在FreeRTOSConfig.h中设置了configCHECK_FOR_STACK_OVERFLOW=1或=2,则必须编写voidvApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName )函数,该函数用于检测堆栈溢出,详见后续文章《FreeRTOS内核配置说明》有关宏configCHECK_FOR_STACK_OVERFLOW一节。3.5 检查硬件& & & 为了验证你的硬件板子是否可靠的工作,首先编写一个小程序片,比如闪烁一个LED灯或者发送一个字符等等,我们这里使用UART发送一个字符。代码如下所示(假设你已经配置好了启动代码,并正确配置了UART):
#include&task.h&
#include&queue.h&
#include&list.h&
#include&portable.h&
#include&debug.h&
int main(void)
init_rtos_debug();
//初始化调试串口
MAP_UARTCharPut('A');
//发送一个字符
}& & & 如果硬件可以正常发送字符,说明硬件以及启动代码OK,可以进行下一步。3.6 挂接中断& & & 在Cortex-M3硬件下,FreeRTOS使用SysTick作为系统节拍时钟,使用SVC和PendSVC进行上下文切换。异常中断服务代码位于port.c文件中,FreeRTOS的作者已经为各种架构的CPU写好了这些代码,可以直接拿来用,需要用户做的,仅仅是将这些异常中断入口地址挂接到启动代码中。& & & 在startup.s中,使用IMPORT关键字声明要挂接的异常中断服务函数名,然后将:
SVC_Handler
vPortSVCHandler
PendSV_Handler
xPortPendSVHandler
SysTick_Handler
xPortSysTickHandler3.7 建立第一个任务Task& & & 在步骤3.5中,我们为了测试硬件是是否能够工作,编写了一个发送字符的小函数,这里我们将把这个小函数作为我们第一个任务要执行的主要代码:每隔1秒钟,发送一个字符。代码如下所示:
voidvTask(void *pvParameters)
MAP_UARTCharPut(0x31);
vTaskDelay(1000/portTICK_RATE_MS);
}& & & FreeRTOS的任务以及编写格式将在后续文章一文中详述,这里只是一个很简单的任务,先有有大体印象。这里面有一个API函数vTaskDelay(),这个函数用于延时,具体用法将在后续文章一文中详细介绍,延时函数代码级分析将在《》。这里不必在意太多的未知情况,因为后面会一点点将这些未知空间探索一遍的。3.8 设置节拍时钟& & & 这里我们使用SysTick定时器作为系统的节拍时钟,设定每隔10ms产生一次节拍中断。由于FreeRTOS对移植做了非常多的工作,以至于我们只需要在FreeRTOSConfig.h中配置好以下两个宏定义即可:configCPU_CLOCK_HZ&&&& (/*你的硬件平台CPU系统时钟,Fcclk*/)configTICK_RATE_HZ&&&&&& ((portTickType)100) & & & &&& & & 第一个宏定义CPU系统时钟,也就是CPU执行时的频率。第二个宏定义FreeRTOS的时间片频率,这里定义为100,表明RTOS一秒钟可以切换100次任务,也就是每个时间片为10ms。& & & 在prot.c中,函数vPortSetupTimerInterrupt()设置节拍时钟。该函数根据上面的两个宏定义的参数,计算SysTick定时器的重装载数值寄存器,然后设置SysTick定时器的控制及状态寄存器,设置如下:使用内核时钟源、使能中断、使能SysTick定时器。另外,函数vPortSetupTimerInterrupt()由函数vTaskStartScheduler()调用,这个函数用于启动调度器。3.9设置中断优先级相关宏& & & 这里特别重要,因为涉及到中断优先级和中断嵌套。这里先给出基于Cortex-M3硬件(lpc177x_8x系列微控制器)的一个配置例子,在FreeRTOSConfig.h中:#ifdef __NVIC_PRIO_BITS
#defineconfigPRIO_BITS
__NVIC_PRIO_BITS
#defineconfigPRIO_BITS
/*lpc177x_8x微处理器使用优先级寄存器的5位*/
/*设置内核使用的中断优先级*/
#define configKERNEL_INTERRUPT_PRIORITY
( 31 && (8 - configPRIO_BITS) )
/*定义RTOS可以屏蔽的最大中断优先级,大于这个优先级的中断,不受RTOS控制*/
#defineconfigMAX_SYSCALL_INTERRUPT_PRIORITY
( 5&& (8 - configPRIO_BITS) )& & & 后续文章会详细介绍这些宏的含义,对于Cortex-M内核,后续文章一文,会讲述这些宏与硬件的联系,那个时候你一定会清楚这些宏所定义的数字会对你的硬件产生什么影响的。现在,我们只需要知道他们很重要就足够了,没人能一口吃成胖子。3.10 设置其它宏& & & 还需要在FreeRTOSConfig.h设置一些必要的宏,这些宏如下所示:#define configUSE_PREEMPTION 1
//配置为1使用抢占式内核,配置为0使用时间片
#define configUSE_IDLE_HOOK
//设置为1使用空闲钩子;设置为0不使用空闲钩子
#define configMAX_PRIORITIES
//应用程序任务中可用优先级数目
#define configUSE_TICK_HOOK
//就设置为1使用时间片钩子,设置为0不使用
#define configMINIMAL_STACK_SIZE
( ( unsigned short ) 80 )
//最小空闲堆栈
#define configTOTAL_HEAP_SIZE
( ( size_t ) ( 5 * 1024 ) )
//内核总共可用RAM3.11 创建任务& & & 调用FreeRTOS提供的API函数来创建任务,代码如下所示:
xTaskCreate(vTask,&Task1&,50,NULL,1,NULL);& & & 关于详细的创建任务API函数,会在后续文章一文中介绍。3.12 开启调度器& & & 调用FreeRTOS提供的API函数来启动调度器,代码如下所示:
vTaskStartScheduler();& & & 关于详细的开启调度器API函数,会在后续文章一文中介绍。& & & 此时的main函数代码如下所示:
int main(void)
init_rtos_debug();
//初始化调试串口
xTaskCreate(vTask,&Task1&,50,NULL,1,NULL);
vTaskStartScheduler();
}4. 小结& & & 到这里,一个最基本的FreeRTOS应用程序就已经运行起来,将硬件板子接到PC的RS232串口,可以观察到每隔一秒钟,板子都会向PC发送一个指定的字符。& & & 回头看一下移植过程,FreeRTOS移植到Cortex-M3硬件是多么的简单,这一方面归功于FreeRTOS的设计师已经为移植做了大量工作,同时,新一代的Cortex-M3硬件也为操作系统增加了一些列便利特性,比如SysTick定时器和全新的中断及异常。& & & 但是移植成功也只是万里长征的第一步,因为这只是最简单的应用。我们还不清楚FreeRTOS背后的机理、调度算法的面貌、甚至连信号量也都没有涉及。就本文的移植过程来看,我们也刻意忽略了很多细节,比如FreeRTOSConfig.h文件中的宏都有什么意义?改动后对RTOS有何影响?比如FreeRTOS任务API的细节、调度API的细节,再比如FreeRTOS的内存如何分配?如何进行堆栈溢出检查等等。& & & 所以,先不要沾沾自喜,曲折的道路还远没到来呢。& & & 接下来的很多篇文章会围绕这个最简单的移植例程做详细的讲解,要把本篇文章中刻意隐藏的细节一一拿出来。这要一直持续到我们介绍队列、信号量、互斥量等通讯机制为止。
本文已收录于以下专栏:
相关文章推荐
FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制。每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核。这个配置文件是针...
FreeRTOS可以被移植到很多不同架构的处理器和编译器。每一个RTOS移植都附带一个已经配置好的演示例程,可以方便快速启动开发。更好的是,每个演示例程都附带一个说明网页,提供如何定位RTOS演示工程...
using Susing System.Dusing System.Cusing System.Wusing System.Web.Security...
第一:其实说不上移植笔记,FreeRTOS已经移植至众多平台(MCU),包括MSP430,STM32等,这份笔记完全建立在官方代码的基础之上,简单的说就是修改一些设置从而完成一个呼吸灯实验。
第二:虽...
转自:http://blog.csdn.net/djjyi/article/details/6170025
Freertos泛泛看了很多相关文章,有点头绪,除了不太喜欢其变量的名字,其他的倒还...
port.c 中主要实现了几个函数:
pxPortInitialiseStack()
xPortStartScheduler()
vPortEndScheduler()
摘要:FreeRTOS是一个源码公开的免费的嵌入式实时操作系统,通过研究其内核可以更好地理解嵌入式操作系统的实现原理.本文主要阐述FreeRTOS系统中的任务调度机制、时间管理机制、任务管理机制以及内...
Select a number, between the 10-99. Use this number minus its bits and 10. Derive a new result. And ...
他的最新文章
讲师:汪剑
讲师:刘道宽
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)}

我要回帖

更多关于 freertos 进入中断 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信