TI-RTOS Kernel(SYS/BIOS)---SYS/BIOS简介

本章提供了SYS/BIOS及其与TI-RTOS和其他TI-RTOS组件的关系

什么是SYS/BIOS

SYS/BIOS是一个可扩展的实时内核。它被设计为实时调度和同步或实时监测。提供抢先多线程、硬件抽象、实时分析和配置工具。SYS/BIOS最小化目标上内存和CPU的需求

SYS/BIOS是TI-RTOS产品的"TI-RTOS Kernel"组件

SYS/BIOS有下列优点:

  1. 所有的SYS/BIOS对象都可以静态或动态的配置
  2. 为了最小化内存大小,应用编程接口被模块化,这样只有那些被程序使用的API才需要绑定到可执行程序中。此外,静态配置的对象通过消除包含对象创建调用的需要来减少代码大小。
  3. 错误检查和调式工具是可配置的,可以从生产代码版本中完全删除,以最大化地提高性能并最小化内存大小
  4. 几乎所有地系统调用都提供了确定性的性能,使应用程序能够可靠地满足实时截止日期
  5. 为了提高性能,在主机上监测数据(如日志和跟踪)要被格式化
  6. 线程模型为各种情况提供了线程类型。硬件中断、软件中断、任务、空闲函数和周期函数都可以被支持。可以通过选择线程类型来控制线程地优先级和阻塞特性。
  7. 提供了支持线程之间通信和同步的结构。其中包括信号量(semaphores)、邮箱(mailboxs)、事件(events)、门(gates)和可变长度的消息(variable-length messaging)
  8. 动态内存管理服务提供可变大小和固定大小的块分配
  9. 中断调度器处理低级上下文保存/恢复操作,并使中断服务例程完全用C语言编写
  10. 系统服务支持启用/禁用中断和插入中断向量,包括将中断向量多路复用到多个源上。

SYS/BIOS与TI-RTOS如何关联

TI-RTOS是针对TI设备的可扩展、一站式嵌入式工具生态系统。它从一个实时多任务内核(SYS/BIOS)扩展到一个完整的RTOS解决方案,包括附加的中间件组件和设备驱动程序。通过提供经过预测试和预集成的基本系统软件组件,TI-RTOS使程序员能够专注于应用程序开发

TI-RTOS的组件

  1. TI-RTOS Kernel:SYS/BIOS
  2. TI-RTOS Instrumentation:UIA
  3. TI-RTOS Networking:NDK
  4. TI-RTOS File System:FatFS
  5. TI-RTOS USB:USB stack
  6. TI-RTOS Drivers and Board Initialization:Drivers *Ware,TI-RTOS examples

SYS/BIOS与XDCtools如何关联

XDCtools提供TI-RTOS及其组件(包括SYS/BIOS)所需的底层核心工具。要使用TI-RTOS,必须同时安装XDCtools和SYS/BIOS。

XDCtools在CCS安装过程中自动安装。

如果将TI-RTOS或SYS/BIOS作为独立产品安装(CCS之外),则还需要下载并安装XDCtools。

XDCtools对SYS/BIOS用户很重要,因为:

  1. XDCtools提供了用户来配置应用程序使用的SYS/BIOS和XDCtools模块的技术
  2. XDCtools提供用于构建配置文件的工具。此构建步骤生产源代码文件,然后编译这些文件将其与应用程序代码链接
  3. XDCtools提供了许多模块和运行时API,SYS/BIOS利用这些模块和API进行内存分配、日志记录、系统控制等

SYS/BIOS是一组包的集合

SYS/BIOS和XDCtools是一组"包",每个包都提供产品功能的一个子集。XDCtools使用包名约定来帮助可读性,并确保从不同来源交付的包不会出现名称空间冲突,这会给系统集成带来问题。

SYS/BIOS软件包符合此约定,其名称由分层命名模式组成,每个级别由一个句号(".")分隔。

下图是创建应用程序的工具体系结构图,XDCtools提供的xdc.runtime包包含应用程序可以与SYS/BIOS中的模块和API一起使用的模块和API。
在这里插入图片描述

使用XDCtools来配置SYS/BIOS

配置是使用SYS/BIOS的重要部分,用于以下目的:

  1. 它指定应用程序将使用的模块和包
  2. 它可以静态地为应用程序使用的模块创建对象
  3. 它验证显示和隐式使用的模块集,以确保它们兼容
  4. 它静态地设置系统、模块和对象的参数,以更改其运行时行为

应用程序的配置存储在一个或多个脚本文件中,文件扩展名为*.cfg。XDCtools解析这些文件以生产相应的C源代码、C头文件和连接器命令文件,然后将这些文件编译并链接到最终的应用程序中。

下图是典型的SYS/BIOS应用程序构建的流程图:
在这里插入图片描述
配置(*.cfg)文件使用简单的类似JavaScript的语法来设置对象提供的属性和调用方法。可以通过下面的方式创建和修改配置文件:

  1. 在CCS中使用可视化配置工具(XGCONF)
  2. 在CCS中XGCONF编辑器的cfg脚本选项卡中编辑配置文本
  3. 使用文本编辑器直接编辑*.cfg文件

XDCtools模块和运行时APIs

XDCtools包含几个模块,这些模块提供SYS/BIOS应用程序成功运行所需的基本系统服务。这些模块中的大多数位于XDCtools中的xdc.runtime包中。默认情况下,所有SYS/BIOS应用程序都会在生成时自动添加xdc.runtime包

XDCtools提供的用于C代码和配置文件的功能大致分为四类:
在这里插入图片描述

SYS/BIOS Packages and APIs

SYS/BIOS提供了下列的包:
在这里插入图片描述
每个SYS/BIOS包提供了一个或多个模块。每个模块又提供了使用该模块的API。API的函数名的形式为Module_actionDescription()。例如,Task_setPri()设置Task线程的优先级

为了使用一个模块,应用程序必须包含标准的SYS/BIOS头文件和指定模块的头文件。例如:

#include<xdc/std.h>  //initializes XDCtools
#include<ti/sysbios/BIOS.h>  //initializes SYS/BIOS
#include<ti/sysbios/knl/Task.h> //initializes Task module

每个模块提供的API函数不同

SYS/BIOS对象创建

有几个模块支持创建的实例对象。这些模块包括Hwi,Task,Swi,Semaphore,Mailbox,Queue,Event,Clock,Timer和各种各样的Gate和Heap模块。例如,Task模块允许创建多个Task对象。每个Task对象对应一个线程,该线程有子集的函数、优先级和时间。

这些实例对象按下面三种方式创建

  1. Module_create():创建API需要一个堆来允许对象动态内存分配。所有模块创建函数都要求一个Error_Block传递给创建函数。

     Error_init(&eb);
     Semaphore_Params_init(&semaphoreParams);
     semaphore0 = Semaphore_create(0,&semaphoreParams,&eb);
    
  2. Module_construct():construct必须传递一个对象结构,而不是从堆中动态分配对象。避免动态内存分配有助于减少代码占用。大多数Module_construct() API不需要Error_block,这也有助于减少代码占用。某些Module_construct() API可能会在内部分布内存

     Semaphore_Struct semaphore0Struct;
     Semaphore_Params semaphoreParams;
     
     Semaphore_Params_init(&semaphoreParams);
     Semaphore_construct(&semaphore0Struct,0,&semaphoreParams);
    
  3. Static creation允许在应用程序的*.cfg文件。如果是静态分配对象,则不需要堆。对象的结构被添加到为配置的生成的源文件中。下面的 *.cfg 语句配置一个Semaphore对象。Semaphore将使用与Semphore_create()相同的Semaphore_post()调用来post:

     var semaphore0Params = new Semaphore.Params();
     Program.global.semaphore = Semaphore.create(0,semaphore0Params );
    

    静态创建的对象不能在运行时销毁

TI-RTOS例子使用了Module_construct()机制,这是静态和动态创建之间的一个很好的折衷。但是,每种类型的对象都有各自的优缺点,如下表:

在这里插入图片描述
每种对象创建方法都使用一个Module_Params结构体。这些结构体包含实例配置参数来控制实例的行为。下面的是SYS/BIOS中定义的Semaphore_Params结构体:

typedef struct Semaphore_Params{	//Instance config-params structure
	IInstance_Params * instance;	//Common per-instance configuration
	Event_Handle event;	//Event instance to use if non-NULL
	UInt eventId;	//eventId if using Events
	Semaphore_Mode mode;	//Semaphore mode:COUNTING or BINARY
}Semaphore_Params;

下列的应用程序代码创建了Semaphore parameters结构体,用默认参数进行初始化,并且"mode"参数设置为BINARY来指定这是一个二进制的信号量。然后就可以调用Semaphore_create()或者Semaphore_construct()来创建一个实例:

Semaphore_Params semaphoreParams;

Semaphore_Params_init(&semaphoreParams);
semaphore.mode = Semaphore_Mode_BINARY;

POSIX线程支持

SYS/BIOS提供了一组POSIX线程(pthread) API的集合。这些包括pthread线程,互斥锁,读写锁,障碍和条件变量。pthread API可以简化将应用程序从POSIX环境移植到SYS/BIOS的过程,并允许在POSIX环境和SYS/BIOS中编译相同的代码。由于pthread API构建在SYS/BIOS中的task和Semaphore模块之上,因此可以从SYS/BIOS Tasks调用一些POSIX API

Using C++ with SYS/BIOS

SYS/BIOS应用程序可以用C或C++编写。了解C++和SYS/BIOS的几个问题有助于C++应用程序的顺利开发。问题涉及内存管理、名称修改、配置属性的调用类方法,以及类构造函数和析构函数的注意事项。

内存管理

new和delete的函数是用于动态内存分配和释放的C++操作符。对于TI设备,这些操作符使用malloc()和free()。SYS/BIOS提供内部使用xdc的malloc()和free()的可重入版本,内部使用xdc.runtime.Memory模块和默认为ti.sysbios.heaps.HeapMem模块。

名字修改

C编译器通过在函数的链接级别名称中的编码函数的签名来实现函数重载、运算符重载和类型安全链接。将签名编码为linkname的过程称为名称修改

名字修改可能会干扰SYS/BIOS应用程序,因为在配置中使用函数名来引用C源文件中声明的函数。为了防止名称混乱,从而使函数在配置中要可识别,因此有必要在外部C块中声明函数,有必要在外部的C块中声明函数。

/*
extern "C" block to prevent name mangling of Functions called within the Configuration Tool
*/
extern “C” {
	void clockTask(Clock clock);
	void clockPrd(Clock clock);
	void clockIdle(void);
}	//end extern "C"

extern C块允许在配置文件中引用这些函数。如下:

var taskoParams = new Task.Params();
task0Params.instance.name = "task0";
task0Params.arg0 = $externPtr("cl3");
Program.global.task0 = Task.create("&clockTask",task0Params);

注意,在上面的配置中,Task的arg0参数被设置为$externPtr(“cl3”)。为该参数创建全局时钟对象的C++代码如下:

/*Global clock objects*/
Clock cl3(3);	/*task clock*/

在extern C块中声明的函数不受名称损坏的影响。由于函数重载是通过名称损坏完成的,因此函数重载对于配置中调用的函数有限制。extern C块中只能出现一个函数重载的版本。下面示例中的代码将导致错误。

extern "C" {	//Example causes ERROR
	Int addNums(Int x,Int y);	
	Int addNums(Int x,Int y,Int z)//error,only one version of addNums is allowed
};

虽然可以在SYS/BIOS C++应用程序中使用名称重载,但从配置中只能调用一个重载函数的版本

默认参数是一个C++特性,不适用于从配置调用的函数。C++允许在函数声明中指定形式参数的默认值。但是,从配置调用的函数必须提供参数值。如果未指定值,则实际参数值未定义。

从配置文件中调用类方法

通常,要在配置中引用的函数是类对象的成员函数。不能直接从配置中调用这些成员函数,但可以通过封装函数来完成相同的操作。通过写一个封装函数并接收一个类的实例作为一个参数,可以从封装封装函数中调用类的成员函数

/*
=======clockPrd=======
Wrapper function for PRD objects calling Clock::tick()
*/
void clockPrd(Clock clock)
{
	clock.tick();
	return;
}

类方法所需的任何附加参数都可以传递给封装函数

类的构造函数和析构函数

在C++类对象实例化的时候,类的构造函数都会执行。类似地,每当删除类对象时,都会调用类的析构函数。因此,在编写构造函数和析构函数时,应考虑函数预期执行的时间并相应地对它们进行裁剪。当调用类构造函数或析构函数时,考虑什么类型的线程将运行是非常重要的。

不同的准则适用于可以从不同的SYS/BIOS线程(任务、软件中断和硬件中断)调用哪些SYS/BIOS API函数。例如,内存分配APIs(如memory_alloc()和memory_calloc())不能在软件中断的上下文中调用。因此,如果一个特定的类被软件中断实例化,它的构造函数必须避免执行内存分配。

同样,类析构函数预期执行的时间也很重要。类析构函数不仅在显示删除对象时执行,而且本地对象执行超出范围。需要知道调用类析构函数时正在执行的线程类型,并且只进行适合该线程的SYS/BIOS API调用。

参考文献:

  1. 《TI-RTOS Kernel (SYS/BIOS) User’s Guide》

猜你喜欢

转载自blog.csdn.net/Xiao_Jie123/article/details/120215119