LXRT-RTAI用户空间编程

更新时间:2023-10-31 00:27:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

LXRT

——RTAI的用户空间编程

目录

一.

rt_task_init_schmod(启用RTAI实时功能/实时任务的创建) ............ 2 1. 函数 ........................................................... 2 2. 参数 ........................................................... 2 3. 注意 ........................................................... 2 4. 示例代码 ....................................................... 2 二. 实时任务定时器设置(rt_set_oneshot_mode等) ....................... 3

1. rt_set_oneshot_mode ............................................ 3 2. rt_set_periodic_mode ........................................... 3 3. start_rt_timer ................................................. 3 4. 注意 ........................................................... 3 5. 示例代码 ....................................................... 3 三. rt_task_make_periodic(定期运行一个任务) .......................... 4

1. 函数 ........................................................... 4 2. 参数 ........................................................... 4 3. 注意 ........................................................... 4 四. 代码基础框架 ....................................................... 4

1. Makefile ....................................................... 4 2. run ............................................................ 4 3. .runinfo ....................................................... 5 4. 代码 ........................................................... 5 五. 注意事项 ........................................................... 7

1. 所谓的LXRT实即Linux Real Time module,不存在LXRT scheduler ... 7 2. LXRT下的硬实时相对于内核态下而言仍有若干微秒的差别 ............ 7 3. 在进入和离开LXRT域这两段时间,系统的实时性是无法保证的。 ...... 8 4. LXRT Tips And Tricks ........................................... 8 六. 管道通讯 ........................................................... 8

1. 发送函数 ....................................................... 9 2. 接收函数 ....................................................... 9 3. 示例代码 ....................................................... 9 七. 共享内存通讯 ...................................................... 12

1. 创建函数 ...................................................... 12 2. Free函数 ..................................................... 12

一. rt_task_init_schmod(启用RTAI实时功能/实时任务的创建)

实时任务的创建主要完成对代表实时任务实体的任务结构变量的初始化操作,包括分配任务栈、初始化任务栈、初始化链表指针等。 1. 函数

RT_TASK* rt_task_init(unsigned long name, int priority, int stack_size, int max_msg_size)

RT_TASK*rt_task_init_schmod(unsigned long name, int priority, int stack_size, int max_msg_size, int policy, int cpus_allowed)

正如你可以看到的,有两个选项可以用来创建一个用户模式下的实时任务。在用户模式下,rt_task_init被认为是一个更简单但因此有限的捷径。总之他们都可以用于这个特定的目的。只是为了记录第一个被定义为以下的:

RTAI_PROTO(RT_TASK *,rt_task_init,(unsigned long name, int priority, int stack_size, int max_msg_size)) {

return rt_task_init_schmod(name, priority, 0, max_msg_size, SCHED_FIFO, 0xFF); }

它的意思是,它使用SCHED_FIFO策略并且设置cpu允许0XFF。 他们创建一个新的实时任务在用户空间,或者更好的说法是,他们在用户空间为LINUX进程/任务创建了一个RTAI任务扩展。 2. 参数

Name:任务名。

Priority:任务优先级,0最高。 stack_size:栈大小(不再被使用的遗留参数,只是为了可移植性才保留的)。默认值是512。 max_msg_size:可为0,在这种情况下使用一个默认的内部值。默认值为256。为了适合你的需求,有可能需要设置一个更大的值。在这种情况下,要么合理设置宏MSG_SIZE来重新编译sys.c,要么在这里明确分配大点的尺寸。但是,注意这点,消息大小不是关键的。事实上在任何需要的时候,模块都会重新分配它,动态并且设置好了合适的大小。

policy:调度策略,默认的是SCHED_FIFO,也可以设置成 RT_SCHED_RR。RR只是在有多个使用相同的优先级并且不释放CPU的任务的时候使用,。在这种情况下,RR政策将会照顾它的平衡

cpus_allowed:你想让任务运行的CPU。它是个bit。当RTAI希望一个任务静态地在一个特定的CPU上运行的时候,它是强制性的。注意,如果你想在任务创建之后改变CPU,这一举动将会杀死real_time。如果指定了更多的bit,RTAI通过尽量平衡这工作强迫任务运行在第一个可用的CPU上。//SMP用的 3. 注意

? 消息有个动态内存增加,每次buffer大小溢出时,现有的都会被释放,RTAI real_time

heap会新创建一个大约比原来大20%新buffer。这个操作显然是时间消费, 所以为了最好的性能表现,强烈建议从最初始阶段就定义正确的大小。 4. 示例代码 int main(void) {

RT_TASK *Main_Task; if (!(Main_Task = rt_task_init_schmod(nam2num(\0, 0, 0, SCHED_FIFO, 0xF))) {

printf(\exit(1); }

return 0;

}

二. 实时任务定时器设置(rt_set_oneshot_mode等)

在创建实时任务的过程中,主要通过3个函数对定时器进行设置,它们分别是:rt_set_oneshot_mode,rt_set_periodic_mode和start_rt_timer,下面分别对这3个函数进行分析。

1. rt_set_oneshot_mode

用于将定时器设置为单触发模式,所谓单触发模式,就是说,每当定时器产生一次中断后,系统都要根据目前系统任务对时间精度的要求情况对定时器重新进行编程,设定下一次触发的时间。rt_set_oneshot_mode完成的功能如下: 1.调用stop_rt_timer停止定时器的运行;

2.设置全局变量oneshot_timer的值为1;在时钟中断函数中,系统会检查oneshot_timer的值,判断定时器的工作模式,然后根据定时器的模式对定时器进行相应的操作。 2. rt_set_periodic_mode

rt_set_periodic_mode的操作与rt_set_oneshot_mode的类似,只不过它将oneshot_timer的值设为0,表示定时器应工作在周期模式;当定时器工作在周期模式下时,系统只要对定时器进行一次初始化,指定定时器产生中断的周期,以后就不再需要对定时器进行编程了。 3. start_rt_timer

根据设定的定时器运行模式对定时器进行初始化,它完成的主要功能如下: 1.调用函数rt_request_timer注册时钟中断服务程序rt_timer_handler;

2.初始化系统用于保存时间信息的结构rt_smp_times(就是前面所说的rt_times); 3.调用rt_request_linux_irq注册一个Linux下的中断服务程序recover_jiffies,这个中断程序和Linux的时钟中断服务程序共享时钟中断,recover_jiffies用于补偿Linux所丢失的时钟中断(因为可能由于实时任务的运行,使Linux很长一段时间得不到运行的机会,无法响应时钟中断)。 4. 注意

? 请注意,如果你不设置模式,默认是周期性的。

? 使用stop_rt_timer停止定时器,会设置定时器返回默认的状态(即周期性的)。如果

没有删除在使用的RTAI调度程序,你想确定在多模块上是单触发模式,在每一个start_rt_timer前总要调用rt_set_oneshot_mode。 ? 使用start_rt_timer(0),自动强制进入单触发模式。

? rt_is_hard_timer_running API可以知道是否已经有个计时器在运行了,该函数应该

小心使用,因为它会形成一个“race”情况。

? 在使用任何与时间处理相关的函数前调用start_rt_timer API很重要,否则所有的值

都被认为是错误的。

? 实时任务(本文所指的实时任务,如果没有特别说明都是硬实时的)都是以Linux内核

模块方式实现的,要实现一个实时任务,在模块初始化的时候要调用RTAI的任务创建函数初始化实时任务相关的数据和环境,指定定时器的运行模式(单触发模式或周期模式),初始化定时器,然后开始执行任务;需要注意的是,当没有加载任何RTAI的实时任务模块的时候,RTAI的任务调度和时钟中断都没有启动。 5. 示例代码

#define TICK_TIME 1000000

if ((hard_timer_running = rt_is_hard_timer_running())) {

printf(\sampling_interval = nano2count(TICK_TIME); } else {

printf(\rt_set_oneshot_mode();

start_rt_timer(0); }

sampling_interval = nano2count(TICK_TIME);

三. rt_task_make_periodic(定期运行一个任务) 1. 函数

在这个阶段,计时器根据定时器政策选择(单触发vs周期)以适当的周期运行,它允许设置一个实时任务定期调度。这可以用以下API实现:

Int rt_task_make_periodic (RT_TASK *task, RTIME start_time, RTTIME period); Int rt_task_make_periodic (RT_TASK *task, RTIME start_delay, RTTIME period); 2. 参数

task任务指针,之前由rt_task_init()创建的,当rt_task_wait_period()被调用时,以period为周期执行。

start_time:第一次执行时间,是一个以clock ticks测量的绝对值。 start_delay:第一次执行时间,相对于当前时间,以纳秒测量。 period:任务循环周期。 3. 注意

? 为了更方便的处理clock ticks和纳秒,在rtai_sched.h中有两个宏定义能帮助你,

他们是RTIME count2nano (RTIME timercounts);RTIME nano2count (RTIME nanosecs);,它们只转换时间单位,但是你要记住,计数单位与选择的时间模式(单触发/周期)相关。

? Recall that the term clock ticks depends on the mode in which the hard timer

runs. So ifthe hard timer was set as periodic a clock tick will last as the period set in start_rt_timer,while if oneshot mode is used a clock tick will last as the inverse of the runningfrequency of the hard timer in use and irrespective of any period used in the call tostart_rt_timer.

四. 代码基础框架 前面先准备三个文件: 1. Makefile

TARGET = periodic_task SRCS = periodic_task.c

prefix := $(shell rtai-config --prefix) ifeq ($(prefix),)

$(error Please add /bin to your PATH variable) endif

OBJECTS = $(SRCS:.c=.o)

CC = $(shell rtai-config --cc)

LXRT_CFLAGS = $(shell rtai-config --lxrt-cflags) LXRT_LDFLAGS = $(shell rtai-config --lxrt-ldflags all: $(TARGET) %.o: %.c

$(CC) -c $(LXRT_CFLAGS) $< $(TARGET) : $(OBJECTS)

$(CC) -o $(TARGET) $(LXRT_LDFLAGS) -llxrt $(OBJECTS) clean:

rm -f *.o *~ core.* $(TARGET) .PHONY: clean

2. run

实际上是调用rtai-load来运行的.

${DESTDIR}/usr/realtime/bin/rtai-load 3. .runinfo

隐藏文件rtai-load根据这个来运行

prog_name:lxrt+sem+mbx+msg+fifos:!./prog_name; popall:control_c

(2 、3步骤可以简化成另一种方式,直接进入RTAI安装目录,然后insmod rtai_hal.ko insmod rtai_sched.ko insmod rtai_lxrt.ko??,然后运行程序./prog_name 就行了) 4. 代码

? 单触发模式 #include #include #include #include #include #include #include //#include //#include #include #include

#include //#include //#include

static int thread0;

static void *fun0(void *arg) {

RT_TASK *task;

task = rt_task_init_schmod(nam2num(\ mlockall(MCL_CURRENT | MCL_FUTURE);

//设置优先级和调度算法 这里他用SCHED_FIFO,而SCHED_OTHER(基于时间片)优先会低些,这个Name就是实时任务的标识 nam2num 是把名字转为name id 以免命名冲突

// 进入硬实时模式,无此语句时,默认的是软实时

//rt_make_hard_real_time();

//此处添加代码,如下语句

//rt_printk(\

//将实时任务或者线程返回到标准linux的状态 rt_make_soft_real_time();

//删除任务

rt_task_delete(task); return 0; }

int main(void) {

RT_TASK *task;

本文来源:https://www.bwwdw.com/article/ekh2.html

Top