搜档网
当前位置:搜档网 › SAFERTOS中文用户手册(FreeRTOS)

SAFERTOS中文用户手册(FreeRTOS)

SAFERTOS中文用户手册(FreeRTOS)
SAFERTOS中文用户手册(FreeRTOS)

Safertos用户手册

一、关于这个用户手册

1.说明

这是关于Safertos的文档说明,safertos是一个低开销、小型化、抢占式任务调度的实时操作系统。SAFERTOS预先编译在ROM中,提供了一种独特的方式去快速开发可靠的高度集成的嵌入式系统。

嵌入式应用程序包含了SAFERTOS,这样应用程序就可以被结构化为一系列独立自主的任务。在任何时间中任务调度器将会通过任务的优先级和当前状态来选择执行任务。第一章,系统概述将会详细说明任务的执行。

这个文档将详细说明如何在ROM中来调用SAFERTOS。

SAFERTOS基于FREERTOS和OPENRTOS代码编写,SAFERTOS可以应用于通用实时操作系统和关键环境的任务。

2.应用在安全相关的系统

SAFERTOS在正式的和严格的流程中被开发。这个流程被TüV SüD组织认定符合SIL3级标准。SAFERTOS开发中使用了这样的流程。在没有相关组织的认证下使用SAFERTOS 开发程序不代表你的程序符合SIL3级标准。在没有相关认证下,你的程序是不可靠和不安全的。

3.文档概述

涉及范围

工程师在安全和商用关键领域应用团队中工作必须要有足够的训练或者足够的经验去满足职责的胜任。本文档假定在读者已经了解概念和多任务操作系统,所以这些基本概念将被忽略。详细信息在FREERTOS中可以查询到。叹号表明在一些需要注意的地方提醒读者。

4.目录内容

第一章,“系统概述”提供了SAFERTOS的概述和描述了SAFERTOS的任务、队列、信号量、调度器。

第二章,“安装”描述了安装和在你的应用中安装SAFERTOS所需要的。

第三章,“API相关”提供了SAFERTOS的API函数。

第四章,“Stellaris? ARM? Cortex?-M3 处理器内核特殊接口信息”提供了使用处理器内核变量的信息。

注意:用户不能够在SAFERTOS引用没有在第三章中API中包含的函数。

第一章系统概述

这章提供了SAFERTOS系统的概述

1.SAFERTOS的调度器总述

SAFERTOS抢占式实时调度器具有如下特点:

1.只要不超过内存容量,可以建立任意多的任务数量。

2.每个任务被分配优先级从0到10,0为最低优先级。SAFERTOS的源代码(相对于ROM中的

版本)不限制优先级的数量。

3.任务调度器将执行最高优先级的任务。

4.相同优先级的每个任务将分享处理器的处理时间。时间分片将被使用。

5.任务可以被锁定一个固定的时间。

6.任务可以锁定去等待一个绝对精确的时间。

7.任务可以锁定在一个精确的时间区间去等待队列事件。

8.队列可以在任务之间、任务和中断函数之间传递数据。

9.消息可以用于一个任务和其他任务的同步,同步任务和中断服务周期。

10.信号可以用来确保相互排斥的对共享资源的访问。

2.SAFERTOS和OPENRTOS的不同

虽然SAFERTOS和OPENRTOS有着许多相同点,但是开发过程必须要指出值得注意的不同点。通常下SAFERTOS不执行动态内存分配,SAFERTOS执行参数数量和数据有效性检查。SAFERTOS 是OPENRTOS的静态子集,OPENRTOS向SAFERTOS转换在其他的技术文档中。

3.设计目标

SAFERTOS的设计目标是实现既定功能使用一种小型的,简单的, (和最重要的是)鲁棒实施。

4.编码

这个部分将定义使用SAFERTOS API的编码。

1.工程定义

每个C文件使用API必须包含SAFERTOS.h头文件。这个头文件包含了ProjDefs.h头文件,这个头文件包含了如下定义:

2.命名转换

·历史上的函数名通常以他们返回值类型作为前缀。新增的有效性检查导致了几乎所有的API 函数将会有返回值,这个值将会是portBASE_TYPE(前缀为‘ x’)。这就可以想象函数前面有x表示它的返回值为portBASE_TYPE,如果为v表示,返回为空。

·API函数也将包含与它相关的特性为前缀,例如Task或者Queue,举例说明:xTaskGetTickCount(),xQueueSend()

·宏定义将会用大写字母表示。例外是,错误代码将以err为前缀但是它包含在ProjDefs.h 中。

系统组成

1.任务

你的应用使用了SAFERTOS,那么你的应用程序可被构建为多个独立自主的任务组成。每个任务在自己的环境内执行和其他系统和调度器任务没有偶然的依赖关系。

2.任务函数

函数如果声明一个任务就必须以pdTASK_CODE类型

pdTASK_CODE声明如下:

typedef void (*pdTASK_CODE) (void *pvParameters);

void vATaskFunction( void *pvParameters )

{

/* The function executes indefinitely so enter an infinite loop. */

for( ;; )

{

/* -- Task application code goes here. -- */

}

}

注意:

任务函数不能够被终结通过返回调用(或使用exit())如果这样做了会导致未定义的行为。如果需要函数使用如下例子:

void vATaskFunction( void *pvParameters )

{

for( ;; )

{

/* -- Task application code here. -- */

}

/* The task deletes itself (indicated by the NULL parameter)

before reaching the end of the task function. */

xTaskDelete( NULL );

}

3.任务状态

在一个时间内只有一个任务可以被执行,任务调度器将会执行任务根据优先级和当前的状态。任务会位于以下的状态之一中。

任务之间的转换

每个任务在其自己环境中执行。使一个任务从运行状态跳出,另一个任务进行运行状态叫做环境变换。

xTaskSuspend()API函数可以使任务从运行状态、阻塞状态、准备状态进入暂停状态。

xTaskDelay()和xTaskDelayUntil()API函数可以使任务从运行状态到阻塞状态去等待短暂的事件,这个时间必须在等待的时间段内。

xQueueSend(),xQueueReceive()API函数可以使任务从运行状态转换到阻塞状态去等待消息队列中的事件。这个事件可以使数据进入队列或者是数据从队列中移除。

4.任务优先级

系统将为每个任务设定优先级xTaskPriorityGet()函数去获得优先级,使用

xTaskPrioritySet()去设定优先级。

0为最低优先级,10为最高优先级

5.任务调度器

其具有如下功能:

决定哪个任务将进入运行状态。执行运行状态转换。测试流失的时间。将任务从阻塞状态转换为准备状态。

6.时间测量

一个滴答时钟定时器将被用于时间的测量。在连续的两个时钟中断下的时间段定义为一个节拍。所有的时间将以时钟节拍为测量单元。vTaskInitializeScheduler() API中的ulTickRateHz将定义有多少个ms在一个时钟节拍中。

7.调度策略

调度器将选择优先级最高的任务进入运行状态。在阻塞状态和暂停状态下的任务将不能够进入运行状态。不同的任务可以赋值相同的优先级。在这种情况下,具有相同优先级的任务将轮流进入运行状态。每个任务将最长运行在1个时钟节拍下,在其他相同的优先级的任务进入运行状态之前。注意:这不表明,每个相同优先级的任务将获取相同系统处理时间。

8.启动调度器

使用xTaskStartScheduler()函数去启动任务调度器,在启动调度器之前必须要有一个任务。调用xTaskStartScheduler()函数将会启动一个idle任务。Idle任务将不会进入阻塞和暂停状态。Idle任务的建立确保了系统在任何时刻都至少有一个任务进入运行状态。Hook函数将会启动idle函数。

9.Yielding

10. 调度器状态

一段代码必须以原子化运行(即没有其他任务和中断)才能保证代码的完整性,这样的代码段叫做关键区域。传统处理的方法是在进入关键区域之前关闭中断,在执行关键区域之后打开中断。taskENTER_CRITICAL(),taskEXIT_CRITICAL()宏定义就是为此设定的。关键区域将会使大于5包含5的中断优先级屏蔽掉。

执行关键代码段通过使用task_CRITICAL(),taskEXIT_CRITICAL(),的不利之处是无法对大于5的优先级号作出反应。任务暂停机制提供了另外一个方式去保证在关键区域不去关闭中断。

xTaskSuspendScheduler()函数将调度器从运行状态转换为暂停状态。从而任务的转换将不会发生。在进入关键区域是始终保持只有一个任务持续的运行,直到使用xTaskResumeScheduler()调度器进入运行状态。

注意:

·在调度器进入暂停状态后,中断还是使能的。使用调度器暂停在运行到关键区域时只是防止调度器跳转到其他任务,而不是中断。在调度器进入暂停状态中时,对于中断来存取队列和信号量的操作是安全的。

·不使用调度器暂停也是可取的,在有更高优先级运行的任务中,使用调度器暂停将会降低高优先级任务的反应速度。

11.任务间的通信

SAFERTOS提供了队列的形式去进行任务间的相互通信。使用队列的机制将不会使用全局变量这一形势去进行任务间的通信,或者是应用程序使用互斥源语去获取数据。队列是可以灵活使用的,可以用于简单的数据交换,同步,信号行为。

队列的特点:

·在任何时刻队列可以拥有0或多个条目。

·当队列确定后,它所拥有的条目是可控的。

·发送条目到队列使用xQueueSend(),xQueueSendFromISR().

·队列读取一个条目使用xQueueReceive(),xQueueReceiveFromISR()

·队列是个FIFO结构。

·队列是以字节复制的形式获取数据。

队列事件

发送或读取队列数据称为队列事件。

·当使用xQueueSend()函数时,任务可以在阻塞状态被指定等待一段时间直到一个满的队列变为空。任务将跳出阻塞状态当其他的任务或者中断取出一个条目从队列中。

·当使用xQueueReceive()函数是,任务可指定等待一个空的队列收到一个条目时间,任务就会跳出阻塞状态。

·如果有多个任务等待事件,那第一个跳出阻塞状态的是优先级最高的任务。如果优先级相同那么为等待时间最长的任务。

12.数据格式

队列的数据事先定义一致,例如,结构体等。如果条目过大,这最好是使用指针操作。

注意:

如果数据是通过复制的方式进行获取,必须确保获取数据是一致的,多个任务要获取数据必须协商一致,并且相互排斥。

13.使用队列去建立信号量

队列建立信号量,可以保证在获取共有资源时,独自取用,不发生冲突。被允许获得资源许可的任务将获取信号量,在完成获取资源后交回信号量。另外的任务等待信号量。

队列可以设置为有一个条目,当任务取得这个条目时,队列为空,其他任务将不能够获取信号量从而等待。当任务取得资源后,向队列发送条目,队列为满,其他的任务将可以获取条目,取得资源。

看例子:

portBASE_TYPE xSemaphoreCreateBinary( xSemaphoreHandle *xCreatedHandle )

{

/* The first two parameters define the memory buffer to be used to hold

the created semaphore. 1 is the length of the queue being created (1 as

this is a binary semaphore), 0 is the queue item size.

pdPASS will be returned if the semaphore is created successfully. */

return xQueueCreate( pcBuffer, uxBufferLengthBytes, 1, 0, xCreatedHandle );

}

portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore, portTickTYpe xBlockTime )

{

/* The queue item size is zero so we do not need to specify the buffer

into which the received data will be placed, therefore NULL is passed.

pdPASS will be returned if the semaphore is successfully 'taken'. */

return xQueueReceive( xSemaphore, NULL, xBlockTime );

}

portBASE_TYPE xSemaphoreGive( xSemaphoreHandle xSemaphore )

{

/* The queue item size is zero so we do not need to specify the buffer

from which the sent data will be retrieved, therefore NULL is passed. */

return xQueueSend( xSemaphore, NULL, 0 );

}

Gatekeeper函数是一个用来管理共有资源的函数,举例说明:有多个任务同时想向stdout 输出显示,stdout由gatekeeper来管理,任务想显示的信息被送入队列之中,gatekeeper 大多数时间在阻塞状态,当队列中有数据时,将其唤醒进入运行状态,进而显示队列中的信息。

14.任务和中断通信

注意:

在中断中不要应用API函数,这样回导致任务进入阻塞状态,出于这个原因,xQueueSend()和xQueueReceive()不能有中断函数引用,而应该使用

xQueueReceiveFromISR(),xQueueSendFromISR().

通常xQueueReceiveFromISR()和xQueueSendFromISR()通常用在任务在中断函数返回后继续执行。不要用许多的Item去恢复任务,最好使用一个Item去恢复。

15.中断

为了预测内存的使用情况和促进分析系统的行为,中断处理应只收集事件数据,清中断。

因此迅速退出,通过推迟处理事件数据到任务等级。在中断使能的条件下任务等级任务被执行

注意:

·不要允许在调度器运行之前由中断服务例程调用的API任务。最简单的方法是,在调度器没有运行之前关闭中断。在第一个任务运行之后使能中断。

·不要在中断中调用大于5优先级的API函数。

·在调度器初始化时调用API函数将会关闭中断。

·API函数名中没有FromISR的不要在中断函数中使用

第二章移植

这章将描述如何通过集成在ROM中的RTOS来生成主应用程序。

1.源代码和库

SAFERTOS预先集成在ROM中。在主应用程序中可使用SAFERTOS的API函数,需要在主应用文件中包含SAFERTOS.h头文件。

2.hook函数

主应用程序需要提供3个hook函数。

(A)vApplicationErrorHook():

当发现严重的错误时,例如调度器的数据结构的破坏,在任务环境切换时的潜在的数据栈溢出,vApplicationErrorHook()函数被引用。

vApplicationErrorHook()函数可使主应用去执行特定的应用确保系统运行在安全的环境下。注意:

·函数没有返回

·在关闭中断时才可使用。

参数说明:

·xCurrentTask:在任务在运行状态时发生错误句柄将执行任务。

·pcErrorString:错误信息。

·可以为以下值。

(B)vApplicationTaskDeleteHook():

当任务退出时使用此函数,功能是回收任务删除后的内存空间。

参数说明:

·xDeletedTask:任务的句柄将被删除。

(C)vApplicationIdleHook():

此函数重复的被idle任务调用以运行特定函数在idle任务环境中执行。通常使用它来实现例如使用idle hook去实现低优先级,特定任务的背景任务,或者简单的将处理器运行在低功耗睡眠状态。

注意:

·包含了vApplicationIdleHook的代码不要引用API函数,这样会导致idle进入阻塞状态。·如果使用hook函数是处理器进入睡眠模式,请不要关闭滴答定时器。

3.配置

通过调用vTaskInitializeScheduler()API函数去执行配置。

注意:·必须首先调用vTaskInitializeScheduler()在其他API函数之前,且只能调用一次。

第三章 API参考目录

这章提供了API的参考目录,并分为如下几个部分:

·任务功能

·调度器控制函数

·队列函数

所有的API函数都位于ROM中,只需在主函数中调用SAFERTOS.h,附加的功能以宏定义的方式给出在semphr.h头文件中。

一、任务功能

目录:

·vTaskInitializeScheduler()

·xTaskCreate()

·xTaskDelete()

·xTaskDelay()

·xTaskDelayUntil()

·xTaskPriorityGet()

·xTaskPrioritySet()

·xTaskSuspend()

·xTaskResume()

1.vTaskInitializeScheduler()

总述:

初始化所有调度器私有数据和将特定程序的配置数据传递到调度器和便携层。这将移除所有c启动代码去执行此任务。

参数

·pcInIdleTaskStackBuffer:指向idle任务的任务栈的指针。·ulInIdleTaskStackSizeBytes:idle任务栈空间的实际大小,以bytes为单位。·ulAdditionalStackCheckMarginBytes:当任务跳出运行状态时,任务栈将会被存储起来,如果存储后的剩余栈空间小于ulAdditionalStacCheckMarginBytes时,任务错误hook函数将会被调用。所以越大的值将导致栈溢出检查越敏感,0值也是有效的,但是会导致降低栈溢出检查的敏感度。

当溢出错误被发现,则错误hook函数被调用而不进行环境的保存。·pxPortInitParameters:指向包含初始化数据的结构体。

返回值:空

注意:在所有API函数之前调用,且只能调用一次。

2.创建新的任务

参数:

·pvTaskCode:一个指向执行这个任务的函数指针。

·pcName:用于描述任务名称,主要用于调试方便。

·pcStackBuffer:指向任务栈指针,以8Bytes为界。

·ulStackDepthBytes:任务栈的大小。

·pvParameters:任务又有一个空指针——当任务创建的时候pvParameters将给其赋值。·uxPriority:任务的优先级。0到configMAX_PRIORITIES-1,越小优先级越低。·pxCreatedTask:通过哪个被创建的任务可以被引用来交回控制权。举例,当改变任务的优先级和随后的删除任务。

返回值

·pdPASS:任务成功创建。

·errINVALID_PRIORITY:创建的任务的优先级过高。

·errSUPPLIED_BUFFER_TOO_SMALL:任务栈的空间过小

·errINVALID_BYTE_ALIGNMENT:任务栈指针指向地址与硬件冲突

·errNULL_PARAMETER_SUPPLIED:任务栈指针指向的地址为空。

创建的任务的处理权被返回在pxCreatedTask参数中。任务可以在调度器在初始化中被创建,或者是当调度器在运行或者是暂停状态从其他的任务中创建。任务创建的优先级高于引用xTaskCreate()任务优先级,创建的任务会不等创建它的任务运行完成而直接运行。

注意:

·如果任务拥有比xTaskCreate()更高级别优先级,那在关闭中断时去引用xTaskCreate ()函数不能阻止被创建的任务进入运行状态。被创建的任务在中断使能的情形下运行。中断再次关闭当任务调用xTaskCreate()再次进入运行状态。

·调度器在暂停时调用xTaskCreate()函数将会推延任何必要的环境转换直到调度器再次进入运行状态。

·在中断中不要调用xTaskCreate()函数。

3.

总述:通过参数pxTaskToDelete来删除任务。

参数:

·pxTaskToDelete:要删除任务的句柄,此句柄为在任务创建时使用xTaskCreate()函数中的pxCreatedTask所创建的。任务可以删除自己通过传递NULL参数。

返回值

·pdPASS:任务成功的删除

·errNVALID_TASK_HANDLE:没有能够找到参数所对应的任务。

注意:

·调用xTaskDelete()函数将会应用Delete hook函数,这将使应用程序知道内存可以重新使用。删除任务的句柄是无效的,若要删除删除任务将会引起错误。

·xTaskDelete()函数在调度器初始化中不能引用。

·在调度器位于暂停状态时,xTaskDelete()不能被引用。

·中断中不能引用xTaskDelete()函数。

·xTaskDelete()不能删除idle任务,除非有其他的任务被创建,且此任务不能进入阻塞和等待状态。

·一旦任务被删除,其使用的内存将被释放。如果还是这块内存被用于其它任务的创建则删除任务的句柄和创建新任务的句柄是相同的。

4.

总述:

使任务进入阻塞状态一定系统时间。

参数:

xTicksToDelay 进入阻塞状态的系统节拍数。

返回值:

pdPASS:任务成功的进入了阻塞状态。

errSCHEDULER_IS_SUSPENDED:当调度器进入暂停状态时,任务延时函数将失效。

笔记:

任务延时段时间的解决方法是使用xTaskDelay()函数使任务进入阻塞状态一定的系统节拍。延时的任务在下个系统节拍到来之前调用,那么计数值将按照为1个增量来计算。如果使用0延时,那么相当于使用xTaskYIELD()。

注意:

·在任务运行状态使用。

·不能在中断函数中使用

·当中断关闭时调用xTaskDelay()函数不能阻止任务进入阻塞状态。

5.

总述:

将任务进入阻塞状态一段时间直到一个绝对的时间的到达。

xTaskDelayUntil()和xTaskDelay()的区别:

xTaskDelay()函数固定一个时间延时。xTaskDelayUntil()则是相对于此调用后的一定时间的延时。当需要一个循环函数延时固定的时间,则需使用xTaskDelayUntil().使用xTaskDelay()函数将很困难的完成这一点。因为程序包含有不同的任务分支及中断。

参数:

·pxPreviousWakeTime 一个指针指向一个参数,这个参数将保持一定时间,这个时间是任务最后被阻塞开始计算。在初次使用之前这个参数必须以当前时间初始化。这样,此参数将自动更新。

·xTimeIncrement 循环周期时间。

返回值:

·pdPASS 任务已进入阻塞状态直到特定时间的到来。

·errSCHEDULER_IS_SUSPEND 错误调度器位于阻塞状态。

相关主题