📄 硬件驱动编程.htm
字号:
<BR> 我曾用过IBM PowerPC4xx和ARM7(clps7xxx),这两种CPU都集成了两个内部的串口UART,我还在外部扩展过串口芯片ns16552,基本上是一样的.
<BR><BR> MPC860的结构和上面两种不同,尽管它的核也是PowerPC,它集成了两个处理块,一个处理块是嵌入的PowerPC核,另一个是通信处理模块(CPM).通信处理模块有4个SCC和2个SMC,这六个通信口可以通过设置来支持多种协议和通信方式,也可设置为串口UART模式(大概是通过寄存器GSMR或SMCMR),功能和中断的定义和通常的串口没有区别,你可以查一下寄存器SCCM/SCCE的位14和位15定义,这里定义了在何种情况下产生硬件中断.
<BR><BR> 所以MPC860也有这样的机制.</P></TD></TR></TBODY></TABLE>
<TABLE width="80%" border=0>
<TBODY>
<TR>
<TD class=t1>
<P style="LINE-HEIGHT: 150%"><B>Re:Re:讨教</B> </P></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=10 width="80%" bgColor=#eeeeee border=0>
<TBODY>
<TR>
<TD>
<P
style="LINE-HEIGHT: 150%">860的cpm我还算熟悉,但我实在想不出如何能用程序触发一个中断,即使在看了你的贴子之后。你能不能说仔细些? </P></TD></TR></TBODY></TABLE>
<TABLE width="76%" border=0>
<TBODY>
<TR>
<TD class=t1>
<P
style="LINE-HEIGHT: 150%"><B>Re:Re:Re:讨教</B> </P></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=10 width="76%" bgColor=#eeeeee border=0>
<TBODY>
<TR>
<TD>
<P
style="LINE-HEIGHT: 150%"> 根据MPC860中SCC UART Event Register(SCCE)的位14和位15定义,如位15是数据接收中断标志位,如果串口收到数据,则产生硬件中断,所以可以写程序向串口发数据,并不是程序产生的的中断,而是用程序发送数据,数据到达串口后,串口有数据收到就会产生RX中断,通知系统有数据到达,有相应的中断例程ISR来取数据.
<BR><BR> 发送的情况类似,数据FIFO为空,产生中断,告诉系统发送准备就绪,可以发送,ISR把数据放入FIFO中,发送中断位清零.当发送完毕后,FIFO再为空,再次产生中断,告诉系统发送准备就绪,继续发送.
<BR><BR>不知这样解释的是否清楚. </P></TD></TR></TBODY></TABLE>
<TABLE width="72%" border=0>
<TBODY>
<TR>
<TD class=t1>
<P
style="LINE-HEIGHT: 150%"><B>Re:Re:Re:Re:讨教</B> </P></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=10 width="72%" bgColor=#eeeeee border=0>
<TBODY>
<TR>
<TD>
<P style="LINE-HEIGHT: 150%">你说:
<BR>“所以可以写程序向串口发数据,并不是程序产生的的中断,而是用程序发送数据”。
<BR>如何向串口发送数据? </P></TD></TR></TBODY></TABLE>
<TABLE width="68%" border=0>
<TBODY>
<TR>
<TD class=t1>
<P style="LINE-HEIGHT: 150%"><B>我明白你的意思</B> </P></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=10 width="68%" bgColor=#eeeeee border=0>
<TBODY>
<TR>
<TD>
<P style="LINE-HEIGHT: 150%">"如何向串口发送数据?" <BR><BR>这一点主要是实现的问题,和中断关系不大
<BR><BR>有三种方法实现: <BR><BR>1.一般串口都支持LOOP BACK模式,即片子内部自发自收,设置成这种模式即可.
<BR>2.将串口的发送脚TX和接收脚TX连接.
<BR>3.用PC机上的Hyper Terminal和串口相连,不用做程序,直接可通过终端向串口发数据.</P></TD></TR></TBODY></TABLE>
<TABLE width="64%" border=0>
<TBODY></TBODY></TABLE>
<TABLE width="56%" border=0></TBODY>
<TBODY></TBODY></TABLE><!-- 文章内容显示 --></DIV>
<P style="LINE-HEIGHT: 150%" align=left> </P>
<P style="LINE-HEIGHT: 150%"><BIG><STRONG> ARM
计时器中断编程实现过程</STRONG></BIG></P>
<BLOCKQUOTE>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%">
<STRONG>ARM7</STRONG>一般内部有两个16位计时器(Timer
counter)和一个32位实时时钟(<STRONG>RTC</STRONG>),计时器中断属于<STRONG>IRQ</STRONG>中断,这里以计时器1为例叙述一下中断的编程过程</P>
<P style="LINE-HEIGHT: 150%"> 设置interrup mask
<STRONG>INTMR1</STRONG>寄存器 0x80000240 第8位<STRONG>TC1OI</STRONG>计时器1为使能.
在0x800000300 计时器 1
的数据寄存器<STRONG>TC1D</STRONG>写入指定数据,这样数据开始从这个给定的数开始递减计数,计数递减至 0
后,会产生一个溢出underflow <STRONG>IRQ</STRONG>中断请求,中断状态寄存器<STRONG>INTSR1</STRONG>
0x80000240 第8位<STRONG>TC1OI</STRONG>置位.系统会跳到中断向量表地址 0x00000018
处,执行相应的中断程序,中断程序通过判断中断的类型(判断中断状态寄存器的位),来执行相应的中断服务程序<STRONG>ISR</STRONG>.
中断状态寄存器标志位复位,计时器开始重新开始计时.</P></BLOCKQUOTE></BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%" align=center> </P>
<P style="LINE-HEIGHT: 150%" align=center><A
href="http://www.embhelp.com/drew/mypage/driver.htm#returntop"><B>返回页首</B></A></P>
<P style="LINE-HEIGHT: 150%"> </P>
<P style="LINE-HEIGHT: 150%"><BIG><A name=FLASH></A><BIG><STRONG>Intel
Flash芯片</STRONG></BIG></BIG> </P>
<P style="LINE-HEIGHT: 150%"> 参见 <A
href="http://www.embhelp.com/drew/mypage/example/flashrom.htm"
target=_blank>Flash ROM示例</A></P>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%"><STRONG>问题 1</STRONG> :我们现在用的是intel E28F640
J3A120型号的falsh芯片.在该芯片上要存放配置信<BR>息、某些标志位,动态增长,减少的数据.现在有个问题:
在向某个地址写数据之前,是否一定要擦除该地址所在的块?</P>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%">
应该要擦除该地址所在的块block,先要Unlock这个块,然后擦除该块,再写操作.通常的操作都是这样。所以一个4K--128K块擦除要用几百或几千毫秒,全部Flash擦除用到多达30秒时间,很费时.这就是为什么现在有些Flash(如ATMEL的AT29C040等)采用较小的block,sector或page(64---512bytes)的原因.<BR></P></BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%"><STRONG>问题 2</STRONG>
:(一个块是128KBytes,这样我仅仅为了改写一个Byte,就必须读128Kbytes,然后擦除该块,然后再写128KBytes,太累了,不可能吧??)有没有擦除一个字节或子的方式?</P>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%"><BR>
我想肯定是这样的,因为flash的命令:Unlock,Erase,Write对flash的操作都是以块为单位的,即使你想只擦除一个字节,实际上擦除的是一个块,即128k.这是flash硬件定义的,对编程来说并不麻烦,是一样的,只是花费时间长一些。没有擦除一个字节或位的方式。
</P>
<P style="LINE-HEIGHT: 150%">
为了解决以上的问题,有些芯片如AT29c040和W29c040采用小的Sector(块)方式,每个sector大小只有256bytes,写的时候,只要打开写保护,不需要擦处,直接按sector写入.尽管也要以Sector为单位操作,由于Sector非常小,所以特别适用于修改少量字节的操作。<BR></P></BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%"><STRONG>问题 3</STRONG> : 我现在要实现对INTEL
28F320J3A的操作,但是有一个很大的问题就是我感觉擦除和写数据都比较慢,我想和我没有使用它提供的写BUFFER的命令有关,所以想向您请教写BUFFER的问题.请问是不是每一个大小为128K的块只有32bytes的buffer,如果我想用写buffer操作,应该注意哪些问题呢?<BR></P>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%">
对Flash擦除和写数据是慢的,如果用写BUFFER的命令肯定会快一点,具手册上说,会快20倍,我没试过,不知道.32bytes的buffer不是每个block都有,是整个flash只有一个32bytes的buffer,用写BUFFER命令对所有的blocks写操作,都要用同一个buffer,写Buffer是主要要检查buffer是否available,其实buffer起缓冲作用,来提高工作效率,</P></BLOCKQUOTE>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%">写Buffer的主要步骤:<BR>1.写write
buffer命令到该Block的首地址.<BR>2.先查status,看buffer是否available,<BR>3.写入所写数据的的字节数到Flash的实际地址.<BR>4,写数据<BR>5.写WRITE_BUFF_CONFIRM命令到该Block的首地址<BR>6.写READ_ARRAY命令到该Block的首地址<BR><BR>其中要注意同一组数据跨越不同block时的处理.<BR><BR>上述步骤是肯定对的,你可以先试着写出程序,有什么问题,我们再交流,不要客气,<BR></P></BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%"><STRONG>问题 4</STRONG>
:如果我不使用写buffer的命令操作是不是就会很慢(写300多K大小的东西要半分多钟),如果写300多K大小的东西要半分多钟,我觉得是不正常的,另外,我对block
erase suspend command和>program suspend
command等suspend命令的作用也不是很明白,一下子提了这么多问题,希望您没看烦,也很希望你能给我一些帮助,先谢过了<BR></P>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%">
你应该检查一下程序,是不是程序有问题,不应该这么慢.这些suspend命令,我也没有用过,应该是在对一个block造作过程中,暂停操作,来对另一个block操作(读数据或执行程序),待完成后,再恢复原来的.block
erase suspend command和program suspend
command其实是一个命令B0H</P></BLOCKQUOTE></BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%" align=center> </P>
<P style="LINE-HEIGHT: 150%" align=center><A
href="http://www.embhelp.com/drew/mypage/driver.htm#returntop"><B>返回页首</B></A></P>
<P style="LINE-HEIGHT: 150%"> </P>
<P style="LINE-HEIGHT: 150%"><STRONG><BIG><A
name=NIC></A><BIG>Cillus网卡</BIG></BIG></STRONG>CS8900A
<STRONG><BIG>Linux驱动</BIG></STRONG></P>
<P style="LINE-HEIGHT: 150%"> 可参见 <A
href="http://www.embhelp.com/drew/mypage/sourcecode.htm#NIC"
target=_blank>网卡示例</A></P><FONT class=sfont><B>
<P style="LINE-HEIGHT: 150%">Re: 谁做过网络接口控制芯片CS8900A的驱动?</B></FONT></P>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%"><FONT class=nfont>
我曾经写过这种网卡的驱动,它相对来说比其它的驱动要难一些主要在于EEPROM 和 I/O MODE上,EEPROM 是你必须要操作的,因为一般网卡的 MAC
地址要侟在这里,另外还有一些用户设置。如果你只用网卡默认的设置,可暂时不用,网卡有两种运行模式,MEMORY MODE 和 I/O MODE,MEMORY
MODE 较为简单,对任何寄存器直接操作,不过你的硬件电路应支持才行,主要看有多少地址线和网卡连.<BR>如果采用 I/O MODE
则较为麻烦,对任何寄存器操作均要通过 I/O PORT 0X300 写入或读出. <BR>你所做的只是对一些寄存器进行必要的设置(TX RX
ENABLE,IP FILTER,....),然后将莫一地址的数据包放入数据寄存器即可,无须考虑 MAC
封包解包的事.<BR><BR></FONT>你的问题我看了一下,我没有在linux下做过这类程序,不过我原来用的操作系统<BR>VxWorks是从UNIX移植过来的,和linux的环境相似,用的都是GNU环境,另外我不清楚或模<BR>糊的地方也查了一些资料.对你的问题回答了一下.大概基本上是正确的.<BR><BR>有什么不清楚的,再来信,能帮得上你,我很高兴.<BR></P>
<P style="LINE-HEIGHT: 150%"><BR><STRONG>问题 1</STRONG>
:在<<linux设备驱动程序>>P371:如果一个驱动程序做为主流Linux核心的一部分发行的话,它并不声明自己的device结构,而是使用在drivers/net/Space.c中声明的结构。Space.c声明了所有网络设备的链表,即包括plip1一类驱动程序特定的结构,也包括通用目的的eth设备。以太网根本不关心它们的device结构,因为它们使用通用目的的结构。这种通用的eth设备结构声明ethif_probe为它们的init函数。程序员要想在主流核心中插入一个新的以太网接口只需要在ethif_probe中加入一个对驱动程序初始化函数的调用。另一方面,非eth驱动程序的作者需要在Space.c中插入它们的device结构。在两种情况下,如果驱动程序必须被链到核心,只需要修改源文件Space.c。<BR><BR>在Space.c中:<BR>ethif_probe(struct
device *dev)<BR>{<BR> u_long base_addr =
dev->base_addr;<BR><BR> if ((base_addr ==
0xffe0) || (base_addr == 1))<BR>return 1; /* ENXIO
*/<BR><BR> if (1<BR>/* All PCI probes are safe, and
thus should be first. */<BR>#ifdef CONFIG_DE4X5
/*
DEC DE425, DE434, DE435 adapters */<BR>&&
de4x5_probe(dev)<BR>#endif<BR>#ifdef CONFIG_UCCS8900<BR>&&
cs89x0_probe(dev)<BR>#endif<BR>
.................<BR>
.................<BR>这里我想问的是,当我写完了自己的驱动代码比如cs89x0.c,cs89x0.h,并在space.c中#define
CONFIG_UCCS8900,接 下来在编译内核的时候我该去修改哪个文件,可以将cs89x0.c直接编译到内核中?
如果是按模块化方式写驱动,那么编译生成.o文件然后insmod一下就可以了;但现在要按非模块化的方式,直接编译到内核里去,该怎么做呢?</P>
<BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%">1. 把cs89xx编译成独立模块,执行下列命令:<BR> gcc
-D_KERNEL_-I/usr/src/linux/include-I/usr/src/linux/net/inet-Wall
-Wstrictprototypes -02 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS
-ccs89x0.c<BR> 编译结果是名为cs89x0.o的驱动程序目标模块。要装载此驱动程序,<BR>
输入下列命令: insmod cs89x0.o io=0x360
irq=10<BR>//假如网卡的起始端口号为0x360,中断号为10<BR> 要卸载此驱动程序,用rmmod命令:<BR> rmmod
cs89x0.o<BR>2.如果要将驱动程序编进系统核心,<BR> 修改/usr/src/linux/drivers/net/CONFIG,加入:<BR> CS89x0_OPTS=<BR> 修改/usr/src/linux/drivers/net/Config.in,加入:<BR> tristate‘CS8920
Support’CONFIG_CS8920<BR> 以上两行是为了让make
config在配置过程中询问是否增加CS89xx网卡的支<BR> 持。<BR>
修改/usr/src/linux/drivers/net/Makefile加入:<BR> ifeq((CONFIG_CS8920),y) L_OBJS+=cs89x0.o<BR> endif<BR> 修改/usr/src/linux/drivers/net/Space.c,加入:<BR> extern
int cs89x0_probe(struct device *dev);<BR> ……<BR> #ifdef CONFIG_CS8920&&
cs89x0_probe(dev);<BR> #endif<BR> 以上两段是为了编译并输出网卡驱动程序及其例程。<BR> 把驱动程序源代码拷到/usr/src/linux/drivers/net目录下。<BR> 在/usr/src/linux目录下执行
make config或 make menuconfig,选择核心CS89xx网卡支
持。<BR> 执行make dep、make clean命令。最后用 make zImage
编译Linux核心。<BR><BR></P></BLOCKQUOTE>
<P style="LINE-HEIGHT: 150%"><STRONG>问题 2
:</STRONG>.uCcs8900.c中的send_test_pkt函数有什么用呢?其中定义的test_packet数组<BR>那样赋值该怎么理解?<BR>send_test_pkt(struct
device *dev)<BR>{<BR>int ioaddr = dev->base_addr;<BR>char test_packet[] = {
0,1,2,3,4,5,0,3,4,5,6,7,<BR> 0, 46, /* A 46 in network
order */<BR> 0, 0, /* DSAP=0 & SSAP=0 fields
*/<BR> 0xf3, 0 /* Control (Test Req + P bit set) */
};<BR>long timenow = jiffies;<BR>unsigned short
event;<BR> writereg(dev, PP_LineCTL, readreg(dev,
PP_LineCTL) |<BR>SERIAL_TX_ON);<BR><BR>memcpy(test_packet,
dev->dev_addr,
ETH_ALEN);<BR>memcpy(test_packet+ETH_ALEN, dev->dev_addr,
ETH_ALEN);<BR>
outw(TX_AFTER_ALL, ioaddr +
TX_CMD_PORT);<BR>
outw(ETH_ZLEN, ioaddr + TX_LEN_PORT);<BR><BR>/* Test to see if the chip has
allocated memory for the packet */<BR>while (jiffies - timenow < 5)<BR>if
(readreg(dev, PP_BusST) & READY_FOR_TX_NOW)<BR>break;<BR>if (jiffies -
timenow >= 5)<BR>return 0; /* this shouldn't happen */<BR><BR>/* Write the
contents of the packet */<BR>outsw(ioaddr +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -