FreeRTOS–疑难杂症

费了3独夜晚,把此节看罢,受益匪浅。

  1. 顶实惠的应是和中断相关的谬误,优先排查中断优先级设置。
  2. 库溢出检查,可能因此到,一般先将库房设置的够用深,只要没有溢起便是善,溢起了,掌握了栈溢出钩子函数排错很便利。
  3. printf()连锁的问题应有尽可能不见面面世,毕竟如果用打印调试信息的情状下才以,而且嵌入式系统一般都是故串口重定向的。
    讲真,嵌入式中printf()确实挺烦的,严重影响属性,我的开案例中发觉,串口打印会影响板子的
    power save性能,这是实测及的。

此章节涉新手最经常遇的3种植问题:

  1. 谬误的中止优先级设置
  2. 栈溢出
  3. 匪适当的利用printf()

使用configASSERT()可知肯定地增强生产效率,它亦可捕获、识别多种类型的左。强烈建议在开发要调试中开启宏configASSERT()

停顿优先级

注意:这是顶级需要技术支持的问题,在大部分的移植版本被经过定义configASSERT()不畏可知就捕获这个错误。

如FreeRTOS移植版本支持中断嵌套,并且中断服务程序使用了FreeRTOS
API,那么要将暂停优先级设置也configMAX_SYSCALL_INTERRUPT_PRIORITY或低一些。没有如此设置以见面促成临界区失效,反过来就见面导致间歇性的错误。

当FreeRTOS运行在以下处理器上需特别注意:

  • 暂停优先级应用或的最高优先级,这虽是ARM Cortex
    处理器上的景象,还有有任何的。在这些计算机上,调用FreeRTOS API
    的中止的预级无克留未初始化。
  • 先级数值越强意味着逻辑上优先级更没有,这也许和直觉相反,因此恐怕引致混淆。同样这或者当好几ARM
    Cortex处理器上,可能还发出另外的。
  • 比如说,在有处理器上一个刹车的预级吧5,正在运行,但是能吃一个先期级也4的暂停打断。因此,如果configMAX_SYSCALL_INTERRUPT_PRIORITY设置为5,那么其它其它的应用FreeRTOS
    API的暂停的先级必须安装也5竟更胜。在这种状态下优先级也5要么6的凡行得通之,但是优先级也3底中断是不行的。
  • 差之堆栈实现巴中断优先级用不同之艺术指定。此外尤其是针对性ARM
    Cortex处理器相关的堆栈,它们的中断优先级在写入硬件寄存器之前是经各移的。某些库或者自己进行移动操作,然而其他的库期待中断优先级在传于库函数之前曾开展了活动操作。
  • 一致架构上的两样之落实,实现的凡刹车优先级的于特位不同。例如同样的Cortex-M拍卖器某一个厂商可能实现了3只优先级比特位,但是其他一个厂商实现了4单先行级比特位。
  • 概念一个戛然而止优先级的于特位被分为两单部分,一部分定义抢占的级别,另外的较特位定义子优先级。确保有的可比特位都是指定抢占的优先级,而子优先级无应用。

当少数移植版本中configMAX_SYSCALL_INTERRUPT_PRIORITY发生一个号configMAX_API_CALL_INTERRUPT_PRIORITY

栈溢出

栈溢出是第二单经常寻求技术支持的题目。FreeRTOS提供了几乎独特色来支援捕获和调剂以及栈相关的题目。

API函数uxTaskGetStackHighWaterMark()

每个任务还当保安团结之堆栈,栈的总大小在开立任务之时光就是指定了。函数uxTaskGetStackHighWaterMark()即之所以来询问分配为这个职责之栈接近栈溢出之品位。返回值称为栈的赛水位线

UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );

职责使用栈的有些,随着任务之运作和间断的处理时而长时而减少。uxTaskGetStackHighWaterMark()回到从任务开始运行以来剩余可用之栈空间的无限小价。它回到的是栈未使用的上空占据尽老价值的比率。高水位越接近于0,那么是任务的库房就越快要溢起。

运行时栈检查

FreeRTOS提供了点儿种在运作时检查栈的机制。都是由于文件FreeRTOSConfig.h中的configCHECK_FOR_STACK_OVERFLOW来以编译时展开控制的。两种植方法还见面追加上下文切换的时日。

栈溢出钩子函数(又叫做栈溢出回调函数)是一个由本检查至栈溢出时调用的函数。要使用栈溢出钩子函数要满足以下条件:

  1. 在文件FreeRTOSConfig.h中把configCHECK_FOR_STACK_OVERFLOW设置为1或者2
  2. 贯彻以下钩子函数,使用完全等同的函数名字与原型:

    void vApplicationStackOverflowHook( TaskHandle_t pxTask, signed char pcTaskName);

栈溢出钩子函数会吃捕获和调剂栈错误越来越的简,但是发生栈溢出荒谬时凡从未有过办法恢复的。此函数把有栈溢出底任务之句柄和名传递进入。

栈溢出钩子函数会于一个搁浅的上下文中开展调用。

好几微控制器在检测到一个错的内存访问时会时有发生一个左非常,这个荒唐非常的触发会使得本根本就从未有过机会调用栈溢出钩子函数。

运行时栈检查–方法1

当进行如下设置是会选择方式1.

#define configCHECK_FOR_STACK_OVERFLOW 1

每当一个职责让切换出时她的全体的履行上下文都见面为保存到它们好的栈中。很有或立马虽是仓库使用率达到极端深价值的上。当以方式1是,当任务之上下文被封存之后根本回去检查栈指针是否以栈可用空间内。如果发现栈指针已经盖了可用之限那么就算会调用栈溢出钩子函数。

道1执进度快,但是当出前后文切换时有或会见擦了栈溢出。

运作时栈检查–方法2

开展如下设置后才会择方式2.

#define configCHECK_FOR_STACK_OVERFLOW 2

除去艺术1遭之行事,方法2还会实施外的自我批评。

创任务时它们的栈会被一个已经领略的样本填充。任务2反省库空间的结尾20个字节,验证这个已知晓的样本是否曾让掩。如果及时20独字节的价值与预期值未相同那么尽管会见调用栈溢出钩子函数。

方2免使方法1抢,当时相对来讲要赶紧,毕竟才是测试20独字节。很有或方法2会捕获到拥有的栈溢出,但是来或(几乎未容许)某些栈溢出或脱了。

免恰当地使用printf()sprintf()

切莫恰当地只用printf()大凡相同种普遍的错误源,并且没有察觉及这种错误,通常采用开发者会增加又多的printf()来援助调试,结果就是深化了问题。

群交叉编译器厂商会提供平等种适合在小型嵌入式系统被采取的printf()的贯彻。即便于这种景象下,printf()的兑现可能连无是线程安全之,几乎可肯定不吻合在暂停服务程序中以,并且在输出为重定向到乌,会占用相当丰富的同等截实施时。。

要小型嵌入式系统的printf()的落实不可用,并且动用了通用的printf()的贯彻,那么就是用特别注意了:

  • 独自增加了一个对准printf()或者sprintf()的调用就见面冲的充实应用执行文书的体积;
  • 如若使用了heap_3以外的存储空间方案,printf()sprintf()调用了malloc(),这个是不行的。
  • printf()sprintf()或许会见申请一个几乎倍于常见状态的栈空间。

Printf-stdarg.c

多之FreeRTOS示例工程了动用了一个printf-stdarg.c的公文,它提供了一个极小的、栈使用率挺快捷的会替代标准库函数版本的sprintf()落实。在多数情形下,使得任务每次调用sprintf()还是相关的函数却分配更不见之栈空间。

printf-stdarg.c供了同等种植体制把printf()输出重定向,一个字节一个字节的出口,虽然缓慢,但是可大地减小了栈空间的占用。

注意:并无是拥有的FreeRTOS下充斥副本中文件printf-stdarg.c且落实了snprintf()函数。没有兑现snprintf()的副本直接忽略缓冲区大小参数,它们是一直照射到sprintf()函数。

printf-stdarg.c举凡开源的,但是是第三正值有的,因此它的授权和FreeRTOS是分离的。它的授权条款在文书之首部。

旁的泛错误

症状:添加一个概括任务及例程中倒是造成了例程挂掉

创任务急需打堆积如山着分配内存。许多示范工程的栈空间仅仅能容纳例程任务,因此当开创了例程任务后,没有足够的堆积空间留给其他还多的职责,队列,事件组,信号量。

空闲任务C语言,又可能是FreeRTOS的守护进程,在调用vTaskStartScheduler()每每凡半自动创建的。只有当堆空间不足以创建这些职责时vTaskStartScheduler()才会回到。在调用vTaskStartScheduler()然后上加一个for(;;);见面叫这个题材重新爱排错。

倘惦记补加更多之职责,要么扩大堆空间,要么减少已是的事例任务。

症状:中断中采取API导致应用挂掉

于暂停服务程序中毫无用API,除非API名字是坐FromISR()说到底。特别地,在暂停中不用创建一个临界区,除非采用中断安全之极大。

以支撑中断嵌套的FreeRTOS移植版本被,如果中断优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY虽无须以中使用
API 函数。

症状:有时应用程序在刹车服务函数中挂掉

第一使反省中断是否有了栈溢出。有的移植版本中才检查职责的栈溢出,并没有检查中断是否栈溢出。

停顿的概念和采取方法就移植版本与编译器的例外而各异。因此,其次如果检查语法,宏定义,调用规则以刹车服务程序中的利用是否与移植文档中的完全一致,是否跟例程中之完全一致。

若是用运行在数值越没有之先级表示逻辑上更为强之先行级的计算机上,那么用确保分配给中断的预先级要考虑到这种场面,因为其看起是违直觉的。

使下运行于管暂停优先级默认设置为无限特别可能的预级的计算机上,需要确保每个中断的优先级没有留为默认值。

症状:调度器尝试启动第一只任务时挂掉

保证设置了FreeRTOS的刹车句柄。参考FreeRTOS移植文档,还有示例程序。

好几处理器必须在调度器启动之前处于特权模式。最简便的兑现方式是当C语言main()事先的开行代码中即把电脑内置特权模式。

症状: 中断被充分地禁止了,又或临界区没有对地嵌套

一经以调度器启动前就调用了FreeRTOS
API函数那么中断就会见受有心地禁止,直到第一只任务启动以后才见面再也使能。这样做是为保护系统不挂掉,原因在初始化过程遭到间断尝试调用FreeRTOS
API函数,然而调度器还从未启动,它可能处于一个非雷同的状态。

除开调用taskENTER_CRITICAL()taskEXIT_CRITICAL()函数之外不要使用另外其他的方来重新改微处理器的暂停而能位和预先级标志。这半只宏会统计中断嵌套深度确保当刹车嵌套深度也0时中断而要能。需要知悉某些库函数可能于内部使能和取缔中断。

症状:远在调度器启动前运用即吊掉了

起或产生上下文切换的间歇是明令禁止以调度器启动前就是开始实施的。同样的条条框框适用于尝试发送或吸收FreeRTOS对象(例如队列和信号量)的别样中断服务程序。上下文切换必须在调度器启动之后才能够发出。

洋洋API函数必须在调度器启动之后才会调用。最好是当调用vTaskStartScheduler()后来用API的动范围以创造诸如任务,队列和信号量上,而不是以这些目标。

症状: 在调度器挂于时以要是临界区里边调用API函数会导致应用程序挂掉

调用函数vTaskSuspendAll()见面挂于调度器,调用函数xTaskResumeAll()会见东山再起调度器。

调用函数taskENTER_CRITICAL()会进去临界区,调用函数taskEXIT_CRITICAL()会晤离临界区。

在调度器挂于时要么临界区外永远不要调用API函数。

声明

欢迎转载,请注明出处和作者,同时保留声明。
作者:LinTeX9527
出处:http://www.cnblogs.com/LinTeX9527/p/8031565.html
本博客的篇章一经随便特别说明,均为原创,转载请注明出处。如未经作者同意要保留这个段子声明,且当篇章页面明显位置被起原文连接,否则保留追究法律责任的权利。