嵌入式uClinux下的CAN总线设备驱动程序设计
发布时间:2008/6/24 0:00:00 访问次数:829
1、uclinux操作系统概述
uclinux是linux2.0的一个分支,它被设计用于没有mmu的微控制器领域,即被广泛应用于嵌入式linux领域。uclinux的最大特征就是没有mmu(内存管理单元模块)。它很适合那些没有mmu的处理器,如arm7tdmi,m68ez328等。
uclinux具有完全的tcp/ip协议栈,同时对其他许多的网络协议都提供支持。这些网络协议都在uclinux上得到了很好的实现。uclinux可以称作是一个针对嵌入式系统的优秀网络操作系统。
2、linux驱动程序设计概述
linux系统内核通过设备驱动程序与外围设备交互,设备驱动程序是linux内核的一部分,它是一组数据结构和函数,这些数据结构和函数通过定义的接口控制一个或多个设备。
和unix一样,linux中所有的设备均作为文件来对待,这些文件一般称为特殊文件,这样做的一个好处是使用户或应用程序可按操纵普通文件的方式进行访问控制硬件设备。
linux内核有三种类型的设备驱动程序:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。linux的设备由一个主设备号(major)和一个次设备号(minor)标识。主设备号唯一标识了设备类型,它是块设备表或字符设备表中设备表的索引。次设备号仅由设备驱动程序解释,用于识别同类设备中,i/o请求所涉及到的那个设备。设备驱动程序可以分为3个主要组成部分:
(l)自动配置和初始化子程序,负责检测所要驱动的硬件设备是否能正常工作。
(2)服务于i/o请求的子程序,又称为驱动程序的上半部分。
(3)中断服务子程序,又称为驱动程序的下半部分。
3、uclinux下can设备的驱动程序编写
根据上文对linux下设备驱动程序的描述,以及参考相关的实例分析,下面对can总线设备sja1000的驱动程序进行编写。
can设备驱动程序实际上是linux内核直接对sja1000器件的初始化与读写操作。经分析,sja1000 can驱动程序构成包括如下几个部分:
1)定义sja1000芯片内所有寄存器的访问地址,用于完成对其内部寄存器以及缓冲区的读写访问。例如:
#define io_pmod (*(volatile unsigned *)0x3ff5000)
#define io_pdata (*(volatile unsigned *)0x3ff5008)
#define io_pcon (*(volatile unsigned *)0x3ff5004)
#define sja_mod (0x2700000) #define sja_cmr (0x2700004)
…………………
#define sja_canrxb7 (0x270006c) #define sja_canrxb8 (0x2700070)
因为在我们的系统中,对sja1000的读写是采用的部分模拟时序的方式,所以用到了s3c4510的io端口。下面对sja1000地址的定义进行分析。因为uclinux运行的时候,采用的是32位方式,即两个相邻地址间相隔4个字节,而在sja1000内部的地址间的间隔只有1个字节。虽然可以对s3c4510的内部寄存器定义为在访问sja1000的时候,将位宽度定义为8位,但这样会与linux系统运行不匹配,经测试发现读写不正常。所以将sja1000的地址定义为32位宽度。于是各个寄存器地址为(基址+sja1000内部地址×4)。这里将sja1000的基址定义为0x2700000。
2)编写对sja1000内部寄存器访问的读写函数
因为s3c4510b处理器的地址和数据总线是分开的,而sja1000的地址与数据总线是8位分时复用的。所以我们只有采用先向sja1000的8位地址数据总线上送出地址,然后再送数据或者读数据的方式。片选信号/cs,读信号/rd,写信号/wr仍由s3c4510b自己产生。需要模拟的是锁存信号ale、地址数据总线ad0-ad7。参照sja1000时序图,具体的操作步骤见下面程序和注释。
写子程序如下:
void sja_write(unsigned int data, unsigned int addr)
{ unsigned char tmp;
tmp=(addr)>>2;//将32位地址右移2位,tmp的低8位即为sja1000实际地址。
outl(tmp,addr);//将地址信息作为数据送往sja1000数据总线
io_pdata=0x32;//ale=0,让sja1000将该地址锁存
outl(data,addr);//将数据信息送往sja1000数据总线
o_pdata=0x33; } //将ale置高电平,74hc245的/oe置高位
读子程序如下:
unsigned char sja_read(unsigned int addr)
{ unsigned char data;
volatile unsigned int data1;
unsigned char tmp;
tmp=(addr)>>2; //将32位地址右移2位,tmp的低8位即为sja1000实际地址s3c2410
outl(tmp,addr); //将地址信息作为数据送往sja1000数据总线
io_pdata=0x32; //p0-ale=0,锁存地址信息
io_pdata=0x12; //p5-245dir=0,将74hc245的方向置为cpu输入方向
data1=inl(addr); //读出所需的数据
io_pdata=0x33; //ale置高,74hc245置为不工
1、uclinux操作系统概述
uclinux是linux2.0的一个分支,它被设计用于没有mmu的微控制器领域,即被广泛应用于嵌入式linux领域。uclinux的最大特征就是没有mmu(内存管理单元模块)。它很适合那些没有mmu的处理器,如arm7tdmi,m68ez328等。
uclinux具有完全的tcp/ip协议栈,同时对其他许多的网络协议都提供支持。这些网络协议都在uclinux上得到了很好的实现。uclinux可以称作是一个针对嵌入式系统的优秀网络操作系统。
2、linux驱动程序设计概述
linux系统内核通过设备驱动程序与外围设备交互,设备驱动程序是linux内核的一部分,它是一组数据结构和函数,这些数据结构和函数通过定义的接口控制一个或多个设备。
和unix一样,linux中所有的设备均作为文件来对待,这些文件一般称为特殊文件,这样做的一个好处是使用户或应用程序可按操纵普通文件的方式进行访问控制硬件设备。
linux内核有三种类型的设备驱动程序:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。linux的设备由一个主设备号(major)和一个次设备号(minor)标识。主设备号唯一标识了设备类型,它是块设备表或字符设备表中设备表的索引。次设备号仅由设备驱动程序解释,用于识别同类设备中,i/o请求所涉及到的那个设备。设备驱动程序可以分为3个主要组成部分:
(l)自动配置和初始化子程序,负责检测所要驱动的硬件设备是否能正常工作。
(2)服务于i/o请求的子程序,又称为驱动程序的上半部分。
(3)中断服务子程序,又称为驱动程序的下半部分。
3、uclinux下can设备的驱动程序编写
根据上文对linux下设备驱动程序的描述,以及参考相关的实例分析,下面对can总线设备sja1000的驱动程序进行编写。
can设备驱动程序实际上是linux内核直接对sja1000器件的初始化与读写操作。经分析,sja1000 can驱动程序构成包括如下几个部分:
1)定义sja1000芯片内所有寄存器的访问地址,用于完成对其内部寄存器以及缓冲区的读写访问。例如:
#define io_pmod (*(volatile unsigned *)0x3ff5000)
#define io_pdata (*(volatile unsigned *)0x3ff5008)
#define io_pcon (*(volatile unsigned *)0x3ff5004)
#define sja_mod (0x2700000) #define sja_cmr (0x2700004)
…………………
#define sja_canrxb7 (0x270006c) #define sja_canrxb8 (0x2700070)
因为在我们的系统中,对sja1000的读写是采用的部分模拟时序的方式,所以用到了s3c4510的io端口。下面对sja1000地址的定义进行分析。因为uclinux运行的时候,采用的是32位方式,即两个相邻地址间相隔4个字节,而在sja1000内部的地址间的间隔只有1个字节。虽然可以对s3c4510的内部寄存器定义为在访问sja1000的时候,将位宽度定义为8位,但这样会与linux系统运行不匹配,经测试发现读写不正常。所以将sja1000的地址定义为32位宽度。于是各个寄存器地址为(基址+sja1000内部地址×4)。这里将sja1000的基址定义为0x2700000。
2)编写对sja1000内部寄存器访问的读写函数
因为s3c4510b处理器的地址和数据总线是分开的,而sja1000的地址与数据总线是8位分时复用的。所以我们只有采用先向sja1000的8位地址数据总线上送出地址,然后再送数据或者读数据的方式。片选信号/cs,读信号/rd,写信号/wr仍由s3c4510b自己产生。需要模拟的是锁存信号ale、地址数据总线ad0-ad7。参照sja1000时序图,具体的操作步骤见下面程序和注释。
写子程序如下:
void sja_write(unsigned int data, unsigned int addr)
{ unsigned char tmp;
tmp=(addr)>>2;//将32位地址右移2位,tmp的低8位即为sja1000实际地址。
outl(tmp,addr);//将地址信息作为数据送往sja1000数据总线
io_pdata=0x32;//ale=0,让sja1000将该地址锁存
outl(data,addr);//将数据信息送往sja1000数据总线
o_pdata=0x33; } //将ale置高电平,74hc245的/oe置高位
读子程序如下:
unsigned char sja_read(unsigned int addr)
{ unsigned char data;
volatile unsigned int data1;
unsigned char tmp;
tmp=(addr)>>2; //将32位地址右移2位,tmp的低8位即为sja1000实际地址s3c2410
outl(tmp,addr); //将地址信息作为数据送往sja1000数据总线
io_pdata=0x32; //p0-ale=0,锁存地址信息
io_pdata=0x12; //p5-245dir=0,将74hc245的方向置为cpu输入方向
data1=inl(addr); //读出所需的数据
io_pdata=0x33; //ale置高,74hc245置为不工
上一篇:三极管的三个极性的关系是什么