RTLinux编程总结

做过一个有关RTLinux的项目,时间一长,差不多忘光了,现在尽量把原来做过的东西总结一下,以备后用,同时正在做类似项目的一个借鉴
平台
主机:redhat 8.0
目标机:PC104模块、ISA总线脉冲输出、实时串口通信
         linux-2.4.18.tar.bz2 +rtlinux-3.2-pre1.tar.bz2
简述
Linux是典型的分时应用系统,对于实时性要求很高的应用,必须对内核本身动手术。而RTLinux则采取了一种比较聪明也比较折中的办法:他们实现一个最底层的精简的调度器,用于调度实时线程,原来的内核本身则成为实时调度器的一个优先级最低的任务。这样,当有实时任务时,普通内核已经建立于其上的普通进程被强制中断,实时线程被强制执行;只有当若有实时线程都让出cpu之后,普通内核才被运行,再由普通内核去调度执行普通的应用程序……
实例

  1. #include <rtl_fifo.h>
  2. #include <rtl.h>
  3. #include <rtl_sched.h>
  4. #include <time.h>
  5. #include <pthread.h>
  6. #include <rtl_time.h>
  7. #include <signal.h>
  8. #include "rt_com.h"
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. MODULE_LICENSE("GPL v2");
  12. MODULE_AUTHOR("Wind-Son");
  13. MODULE_DESCRIPTION("Pulse-Control system");
  14. typedef unsigned short __u16;
  15. void io_bit_on(__u16 port, unsigned int pos, __u16 *status)
  16. {
  17.         __asm__ __volatile__(
  18.                 "movl %1,%?x\n\t"
  19.                 "movl %0,%?x\n\t"
  20.                 "btsl %2,(%?x)\n\t"
  21.                 "mov (%?x),%%al\n\t"
  22.         "out %%al,(%%dx)\n\t"
  23.         "out %%al,$0x80\n\t"
  24.                 :
  25.                 :"m"(status), "rm"(port), "Ir"(pos)
  26.         );
  27. }
  28. void io_bit_off(__u16 port, unsigned int pos, __u16 *status)
  29. {
  30.         __asm__ __volatile__(      
  31.                 "movl %1,%?x\n\t"
  32.                 "movl %0,%?x\n\t"
  33.                 "btrl %2,(%?x)\n\t"
  34.                 "mov (%?x),%%al\n\t"
  35.         "out %%al,(%%dx)\n\t"
  36.         "out %%al,$0x80\n\t"
  37.                 :
  38.                 :"m"(status), "rm"(port), "Ir"(pos)
  39.         );
  40. }
  41. #define dbg_print rtl_printf
  42. #define MIN_TIME              5000
  43. static void get_time_interval(void)
  44. {
  45. }
  46. void* pulse_generate_thread(void *arg)
  47. {
  48.         static __u16 io_status = 0;
  49.         struct sched_param p;
  50.         hrtime_t current_time;
  51.         REAL_TIME_GET_ENABLE;
  52.         int intrrupt_sched_period = 180000;
  53.         p.sched_priority = 1;
  54.         struct timespec resolution;
  55.        
  56.         rtl_setclockmode(CLOCK_REALTIME, RTL_CLOCK_MODE_PERIODIC,
  57.                         intrrupt_sched_period);
  58.         clock_getres(rtl_getschedclock(), &resolution);
  59.         intrrupt_sched_period = timespec_to_ns(&resolution);
  60.        
  61.         pthread_make_periodic_np(pthread_self(), clock_gethrtime(rtl_getschedclock()),
  62.                 intrrupt_sched_period);
  63.         pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
  64.         for (;;) {
  65.                 dbg_print("debug entry\n");
  66.                 while (!ready)
  67.                     pthread_wait_np();
  68.                 dbg_print("debug exit\n");
  69.                 if (!init_rt_clock) {
  70.                        
  71.                         init_rt_clock = 1;
  72.                         pthread_wait_np();
  73.                         current_time = clock_gethrtime(CLOCK_REALTIME);
  74.                 } else {
  75.                     if (intrrupt_sched_period < MIN_TIME)
  76.                                 intrrupt_sched_period = MIN_TIME;
  77.                     current_time += intrrupt_sched_period;
  78.                        
  79.                     clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, hrt2ts(current_time), NULL);
  80.                 }
  81.                
  82.                 io_bit_on(IO_PORT_OUT, XPULSE, &io_status);
  83.                
  84.             intrrupt_sched_period = get_time_interval();
  85.         }
  86.         return 0;
  87. }
  88. static void init_for_rt_mm(void)
  89. {
  90. }
  91. static void rt_alloc_mm(void)
  92. {
  93.         thread_wait_np();
  94.         buf = kmalloc(size, GFP_ATOMIC);
  95. }
  96. static int kmalloc_thread(void * kthread_arg)
  97. {
  98.         unsigned long timeout = HZ;
  99.         init_for_rt_mm();
  100.         for (;;) {
  101.                 while (!get_flag(MM_ALLOC_FLAG)) {
  102.                        
  103.                         if( signal_pending(current))
  104.                                 return 0;
  105.                         timeout = interruptible_sleep_on_timeout(&wq, timeout);
  106.                 }
  107.                 rt_alloc_mm();
  108.                 clear_flag(MM_ALLOC_FLAG);
  109.         }
  110.         return -1;
  111. }
  112. wait_queue_head_t wq;
  113. static pid_t kmalloc_kthread_id;
  114. static int kmalloc_kthread_state = 1;
  115. static int pulse_generate_thread_created = 0;
  116. static int main_ctrl_thread_created = 0;
  117. static pthread_t pulse_generate_pthread;      
  118. static pthread_t main_ctrl_pthread;
  119. static pthread_mutex_t cache_mutex;
  120. void rt_mm_request(void)
  121. {
  122.         set_flag(MM_ALLOC_FLAG);
  123.        
  124.         while(get_flag(MM_ALLOC_FLAG))      
  125.                 pthread_wait_np();
  126. }
  127. void* main_ctrl_thread(void *arg)
  128. {
  129.         int work_sched_period = 160000;
  130.         struct timespec resolution;
  131.         int ret1 = rtl_setclockmode(rtl_getschedclock(), RTL_CLOCK_MODE_PERIODIC,
  132.                 work_sched_period);              
  133.         if (ret1) {
  134.                 dbg_print("seting periodic mode failed\n");
  135.                 clear_flag(WORK_SCHED_MODE);
  136.         }
  137.         clock_getres(rtl_getschedclock(), &resolution);
  138.         work_sched_period = timespec_to_ns(&resolution);
  139.         pthread_make_periodic_np(pthread_self(), clock_gethrtime(rtl_getschedclock()),
  140.             work_sched_period);
  141.         init_task();      
  142.         for (;;) {
  143.                 if (work) {
  144.                         dbg_print("work\n");
  145.                         rt_mm_request();
  146.                         calc_time_interval();
  147.                         if (exit)
  148.                             break;
  149.                 } else
  150.                         pthread_wait_np();
  151.         }
  152.         exit_task();
  153.     return 0;
  154. }
  155. int init_module(void)
  156. {
  157.         pthread_attr_t attr;
  158.         struct sched_param p;
  159.         int ret;
  160.         rtf_destroy(0);
  161.         rtf_destroy(1);
  162.         rt_com_clr_in(0);
  163.         rt_com_clr_out(0);
  164.        
  165.         int fifo_status = rtf_create(0,100);
  166.         if(fifo_status)
  167.                 dbg_print("FIFO Create failed!");
  168.         fifo_status = rtf_create(1, 4000);
  169.         if(fifo_status)
  170.                 dbg_print("FIFO Create failed!");
  171.        
  172.         rt_com_setup(0, 9600, RT_COM_PARITY_NONE, 1, 8);
  173.         hrtime_t now = gethrtime();
  174.         pthread_attr_init(&attr);
  175.         pthread_mutex_init(&cache_mutex, NULL);
  176.         pthread_attr_setfp_np(&attr, 1);
  177.        
  178.         ret = pthread_create(&pulse_generate_pthread, &attr,
  179.                 pulse_generate_thread, (void *)0);
  180.         if (!ret)
  181.                 pulse_generate_thread_created = 1;
  182.         pthread_make_periodic_np (pulse_generate_pthread, now + 2 * 240000, 80000);
  183.         p . sched_priority = 1;
  184.         pthread_setschedparam (pulse_generate_pthread, SCHED_FIFO, &p);
  185.        
  186.         ret = pthread_create(&main_ctrl_pthread, &attr, main_ctrl_thread, (void *)1);
  187.         if (!ret)
  188.                 main_ctrl_thread_created=1;
  189.         pthread_make_periodic_np (main_ctrl_pthread, now + 2 * 160000, 30000);
  190.         p . sched_priority = 2;
  191.         pthread_setschedparam (main_ctrl_pthread, SCHED_FIFO, &p);
  192.         init_waitqueue_head(&wq);
  193.         kmalloc_kthread_id = kernel_thread(kmalloc_thread, NULL, 0);
  194.         if (kmalloc_kthread_id < 0) {
  195.                 printk(KERN_ERR "fork failed, errno %d\n", -kmalloc_kthread_id);
  196.                 return kmalloc_kthread_id;
  197.         }
  198.         return ret;
  199. }
  200. void cleanup_module(void)
  201. {
  202.        
  203.         int ret = kill_proc(kmalloc_kthread_id, SIGKILL, 1);
  204.         if (!ret) {
  205.                 int count = 10 * HZ;
  206.                
  207.                 while (kmalloc_kthread_state && --count) {
  208.                         current->state = TASK_INTERRUPTIBLE;
  209.                         schedule_timeout(1);
  210.                 }
  211.         }
  212.         if (main_ctrl_thread_created) {
  213.                 pthread_cancel(main_ctrl_pthread);
  214.                 pthread_join(main_ctrl_pthread, NULL);
  215.                 pthread_delete_np(main_ctrl_pthread);
  216.         }
  217.         if (pulse_generate_thread_created) {
  218.                 pthread_cancel(pulse_generate_pthread);
  219.                 pthread_join(pulse_generate_pthread, NULL);
  220.                 pthread_delete_np(pulse_generate_pthread);
  221.         }
  222.         rt_com_setup(0, -1, 0, 0, 0);
  223.         rtf_destroy(0);
  224.         rtf_destroy(1);
  225.         pthread_mutex_destroy (&cache_mutex);
  226. }

复制代码

其实现在有关Linux实时应用的原理和应用方面的介绍已经不少,所以我主要是想从自己的亲身实践中的经验教训出发总结一下。
我遇到的主要问题主要有以下几个:
1、硬实时调度精度不够的问题。刚开始产生脉冲驱动的线程我按照例子程序采样如下方式
   pthread_make_periodic_np();  //设置调度方式和周期等参数
    pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
    pthread_wait_np(); //让出cpu进入睡眠
  可实际情况总是不理想,输出波形不够稳定,离预想的效果也很远。试着将调度策略SCHED_FIFO改其他几种方式,也一样。最后尝试用clock_nanosleep()才达到了比较理想的效果。理论上clock_nanosleep()应该达到ns级别的精度,当然实际精度还要取决于硬件。
2、实时线程所能到达的实时效果和精度极限也就是定时器本身的精度了。有过在51上做开发经验的都有这样一个意识:定时器中断处理例程里尽量只做最简单、最必须的工作,但毕竟还是有开销的。如果你对精度还有更高的要求,可在main_ctrl_thread()即负责计算脉冲间隔时间的例程中加入补偿值,以抵消脉冲输出例程中的时间开销。
3、实时线程中频繁的动态申请内存时常宕机。后来经过实验摸索才采取了上面代码中所述的拐弯抹角的办法。如果谁碰到过类似问题有更好的办法,还望指出。
4、应用程序直接向串口输出时总出错。
   开始方法是system("/bin/ls ./data/ >> /dev/ttyS0";在没有实时线程的影响的情况下,这样是没有问题。开启实时线程后就老出错。
后改成如下方式就好了:由实时模块通过实时调用rt_com_write()和rt_com_read()读写串口;再通过实时管道rtl_fifo转发到应用程序
另外,纯粹经验谈,实时线程如果不主动让出cpu,任何用户程序无法运行,包括你的键盘响应!如果你的某个环节可能陷入循环,你能做的就只有poweroff了;被迫重启后在ext2文件系统上随之而来的是漫长的fscheck……所以我在调试阶段,基本上是只要有循环的的方,就加上pthread_wait_np();以后再慢慢把不必要的去掉。

时间: 2024-12-03 15:17:17

RTLinux编程总结的相关文章

基于RT-Linux的开放式数控系统软件平台的研究

1 引言 90年代以来,数控技术发展的一个重要趋势是数控系统的开放化.目前,关于开放式控制系统的研究方兴米艾,全国都在抓紧进行开放式数控系统平台标准和规范的研究制定以及相关产品的开发.开放式数控系统允许用户根据需要自由选择和配置标准的硬件和软件模块,实现系统积本式"的集成,或者在开放平台基础上开发特定的功能模块,形成适合需要的专用系统.开放式数控系统具有如卜的基本特征: 互操作性:提供标准的数据格式.通信及交互机制; 可移植性:系统可运行不同的软硬件平台之上; 可扩充性:允许用户对系统进行扩展或

硬实时操作系统-RTLinux

硬实时操作系统-RTlinux 摘要: 介绍了RTLinux的两个重点特点:硬实时性和完备性,及其在嵌入式系统应用中的一些重要功能,并结合实时处理的具体实例对其编程方法加以说明.  关键词:操作系统 实时处理 Linux 嵌入式系统近年来,基于PC的嵌入式系统得到迅速的发展.在各种不同的操作系统中,由于Linux操作系统的廉价.源代码的开放性以及系统的稳定性,使其在基于PC的嵌入式系统中的应用日益广泛.RTLinux(RealTime Linux)[1]是一种基于Linux的实时操作系统,是由F

python网络编程之数据传输UDP实例分析

  本文实例讲述了python网络编程之数据传输UDP实现方法.分享给大家供大家参考.具体分析如下: 一.问题: 你觉得网络上像msn,qq之类的工具在多台机器之间互相传输数据神秘吗?你也想玩一下在两台机器之间传数据吗?今天让python告诉我们基本原理吧,当然只是做简单的了解,实际情况复杂的多. 我们今天用python实现一个简单的udp程序. 二.程序实现: 1) 使用模块 (socket)套接字模块: 套接字模块是一个非常简单的基于对象的接口,它提供对低层BSD套接字样式网络的访问 .使用

python网络编程之文件下载实例分析

  本文实例讲述了python网络编程之文件下载实现方法.分享给大家供大家参考.具体如下: 真是越看越喜欢python啊,想要了解它提供的http和ftp下载功能,原来是如此的简单. 1.相应模块 ftplib模块定义了FTP类和一些方法,用以进行客户端的ftp编程.我们可用python编写一个自已的ftp客户端程序,用于下载文件或镜像站点.如果想了解ftp协议的详细内容,请参考RFC959或是查看python帮助吧. Urllib模块提供了非常高级的接口来从网络上抓取数据,主要使用到的是url

asp编程中的测试打印、有效性检查及错误处理

编程|错误|错误处理|打印 经常看到一些初学asp的朋友为了测试一个值到处用response.write来打印, 而要看页面效果时再删除这些语句或加上注释,在正式版本出来以前要如此反复 多次.而有些人为了减少麻烦,干脆全当它是正确的,不做测试输出,像这样极 易出现各种各样的问题,最常见的是如果要生成一条sql语句,需要使用变量,如 果不做测试打印,很难做到一次正确,在chinaasp论坛里经常见到这种问题,老 是有人问这条语句为什么会出错等问题,实际上他只要打印出这条语句看一下语 法是否正确就行

求助贴:c语言编程问题

问题描述 求助贴:c语言编程问题 解决方案 在你的程序里scanf()函数返回的是一个正整数,无论你输入的是不是-1,他接收的一直是一个参数,所以返回的一直是1.并且还是使用"%lu"来接收参数的,输入-1一定不会退出程序的,输入1.2scanf()只接收到了1,因为1.2不符合输入的规则"%lu",也会返回1.程序不会停下 解决方案二: 疑惑:1.输入0有效,输出真确2.输入-1不退出,-1被强制转换为int类型3.输入1.2输出1个奇数后又printf();然后

面向服务编程

    从最初的面向过程编程,到后来觉得难以理解的面向对象编程,从软件工程的发展历程中来看,这已经成为我们编程路上熟知的两种编程方式.     接触了ITOO项目这么长时间,才发现,不知不觉,我们已经进入了软件工程发展历程之面向服务编程的开发.本篇博客的主题便是面向服务编程.     [一.面向服务编程从何而来?]     想要了解面向服务编程的发展方向以及它在软件行业中所占的地位,我们首先要了解的便是它的起源和发展.没有任何一种方法是一蹴而就的,应该是经历了数十年渐进的演化历程.下面,我们就来

一道百度之星编程大赛题的随笔联想·(2)

百度之星,是全球最大的中文搜索引擎,百度公司面向中国高校学生和编程爱好者所举办的高水平的程序设计大赛.他所考试的题目,全部都是算法的题目. 鄙人虽然是一个.net程序员,在工作之余,喜爱算法. 我觉得这个题目有点意思,故而分享给大家,我想到两种方法,提供大家,希望对大家起了一个开阔思路的作用. 下面介绍解法二了.  解法二,是抓小放大.  由小及大.首先,说一说我分析的思路吧.  第一步,还是判断i是不小于i/2,以此循环了.  第二步,是不是判断此范围的值的累加是不是等于相应某个值. 第三步,

PHP 编程标准

编程|标准 PHP 编程标准 最后修改日期: 2000-11-16 PHP编程标准是经由Todd Hoff许可,基于<C++ 编程标准>为PHP而重写的, 作者为Fredrik Kristiansen, 使用本标准,如果您想拷贝一份留做自用的话,那是完全免费的,这也是我们制作它的原因.假如您发现了任何的错误又或者是有任何的改进,请您给笔者发一个email,以便笔者将它们合并到最新更新中去. 目录 介绍 标准化的重要性 解释 认同观点 项目的四个阶段 命名规则 合适的命名 缩写词不要全部使用大写