介绍共享存储器
linux并不是严格意义上的实时操作系统,为了实际需要,工程师们必须想尽办法来祢补这一不足,于是出现了rtlinux和rtai等并不强调商业性的软件。rtlinux是Linux中的一种实时操作系统。它由新墨西哥矿业及科技学院的V. Yodaiken开发。目前,RTLinux有一个由社区支持的版本,称为RTLinux Free,以及一个来自FSMLabs的商业版本,称作RTLinux Pro。 的rtlinux显然庞大而并不兼容大部分的嵌入式平台,版本的rtlinux也只能支持I386和PPC而已。Rtai是不错的选择,但要把它移植到你的平台上去,为了适应你的linux版本,你的CPU,你必须的花费许多的工作,比如说近比较流行的AT91RM9200DK,光修改linux版本补丁就要花费许多的功夫。Rtlinux和rtai为了增强linux操作系统的实时性,主要是通过开辟内核模块与应用程序之间可以共享的内存快来实现的。它们在内核空间控制硬实时任务的运行,并通过一个名为FIFO的共享内存块来与应用程序进行通信。他们是很不错的软件,我想用不了多久他们就会具备更强大的可移植性。
共享存储器的工作原理
众所周知,内核空间和用户空间只能通过系统调用来共享数据,如果进程要等待一个中断的发生,它所能做的就是把自己挂在等待队列里,直到中断服务程序来唤醒它。然后,进程才把内核空间的的数据通过特定的系统调用写到用户空间里。大部分程序员为了避免这样造成的不可忍耐的延时,都会把对数据的操作都放在内核空间里运行,也就是扩大中断服务程序的功能。
操作方法和步骤
AT91RM9200DK的SDRAM的大小为31Mbyte(SDRAM,即SynchrONous DRAM 同步动态随机存储器),正常情况下,System RAM的大小也是31Mbyte(RAM,即RAM -random access memory 随机存储器),我们要把31Mbyte的高端地址空出2M来作为我们的共享内存块,这个内存块是独立的,不能为linux操作系统的内存管理所用了。首先必须通知内核它的内存只有30Mbyte了,我的方法是在u-boot的环境变量里设置mem=29M。然后在include/asm-arm/目录下建立头文件:new_fifo.h
代码如下:
#ifndef NEW_FIFO
#define NEW_FIFO
#endif
#ifdef NEW_FIFO
#define AT91_NEW_FIFO_BASE 0x21d00000
#define num_base(a) (0x21d00000 (0x1000 * a))
#define SPI_NUM_FIFO 2
#define MAX_NUM_FIFO 256
#define READONLY 0
#define READEN 0x1
#define WRITONLY 0x2
#define WRITEN 0x4
typedef struct new_fifo{
int code,key;
int start,size;
int flags;
char data[4000];
int endflag;
} *at91_fifo;
static char * new_fifo_fun(int num,int flags,int code,int size)
{
at91_fifo fifo_p;
int num_addr;
char * data;
if(num > MAX_NUM_FIFO)
return -1;
num_addr = num_base(num);
/printk("the num_addr is %p \n",num_addr);
fifo_p = (at91_fifo)ioremap(num_addr,(1024 * 4));
/ printk("the fifo_p is %p\n",fifo_p);
fifo_p->code = code;
/ printk("the code addr is %p\n",&(fifo_p->code));
fifo_p->flags = flags;
fifo_p->size =size;
data = &(fifo_p->data[0]);
/printk("the data addr is %p\n",data);
return data;
}
#endif
在设备驱动程序中,首先在注册中断服务程序之前,要调用new_fifo_fun函数,得到数据区首地址的指针。这个指针在这个设备驱动程序中可被设置成全程变量。然后在中断服务程序中直接对数据进行读写。
比如说,在文件头部写:
static char * data;
然后在初始化文件中,注册中断之前加入:
data = new_fifo_fun(SPI_NUM_FIFO,WRITEN,0,100);
在中断服务程序中加入:
for(i=0;i<100;i )
*(data ) = i;
接下来,本文设计了一个简单的进程,就是读取SPI的FIFO空间的数据,通过/dev/mem来读取SDRAM高地址的数值,使用的是mmap函数。
全文如下:
#include <sys/types.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>
main()
{
int *mmaddr;
int i,fd;
fd=open("/dev/mem", O_RDWR);
mmaddr = (int *)mmap(0, 1024,PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0x21d02000);
for(i=0;i<10;i )
{printf("the mmaddr data is %p\n",*(mmaddr ));
printf("%d\n",i);
}
}
结果是:
the mmaddr data is (nil)
the mmaddr data is 0xd24e92c2
the mmaddr data is 0xf01ab26d
the mmaddr data is 0x64
the mmaddr data is 0x4
the mmaddr data is 0x3020100
the mmaddr data is 0x7060504
the mmaddr data is 0xb0a0908
the mmaddr data is 0xf0e0d0c
the mmaddr data is 0x13121110
说明我们数据读写都成功拉。同样的,如果要把用户空间的数据写到内核空间也是可以的。如果这个时候,进程在用户空间监视FIFO里的某几个数值,当这个数值变得符合要求的时候,进程认为中断已经发生,并可以读取数据了。
免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。