两个驱动之差
DM9000A的DATASHEET中给出的原理图
根据在网上看到这个网友所说的,两个驱动的差别是,对IC的操作方式的不同,即操作寄存器及操作数据的方式不同
在ARM的驱动中,操作底层的核心语句是(DM9000.h):
#define DM9000_PPTR *(volatile unsigned short *)(DM9000_BASE)
#define DM9000_PDATA *(volatile unsigned short *)(DM9000_BASE + 0x10)
在DM9000.c中应用方式为:
static void iow(int32 reg, uint8 value)
{
DM9000_PPTR = reg;
DM9000_PDATA = value & 0xff;
}
static uint8 ior(int32 reg)
{
DM9000_PPTR = reg;
return DM9000_PDATA & 0xff;
}
无论读或写的话都是先将要操作的寄存器地址送到命令地址去,再将要写的数据写到地址数据中去。
而这两个地址到底是怎么一回事,我看了很多个版本的驱动发现第二个数据地址后面加的偏移量都不一样,后来看了这个人的博客终于明白了。
写操作时,处理器先拉低与CMD引脚相连的地址线和IOW#引脚,选择对DM9000的地址端口进行操作,此时数据线输出需要操作的寄存器地址,DM9000接收这个寄存器地址并存入地址端口。这里需要说明的是这个寄存器地址为相对地址,即相对于DM9000基地址的一个地址偏移,在数据手册中给出的各种寄存器地址就是相对地址。处理器发送完寄存器地址后,拉高与CMD引脚相连的地址线,选择对DM9000的数据端口进行操作,此时数据线输出需要向寄存器写入的值,DM9000接收这个值后根据刚才地址端口内存储的寄存器地址,将其写入相应寄存器。对寄存器进行读操作与写操作唯一不同的是,需要拉低IOR#引脚,而不是IOW#引脚。需要注意的是无论读还是写,对DM9000的地址端口都是写操作,即需要告知DM9000对哪个寄存器进行访问,而对DM9000的数据端口是读还是写则要根据IOR#及IOW#的电平来判断。
更为明确的说,读写数据或是命令是由CMD线决定的,如下的数据手册写的明确,而读或写很明显是由IOR#及IOW#决定的。
这样,原来数据地址后面那个相对于基地址的偏移量就是使得硬件上拉高CMD线。
终于豁然开朗,如下就是先写命令后写数据的时序
详见下面的这个博客,这个网友点通了我
http://hi.baidu.com/heaton007/blog/item/f1b903b27eb247a1d8335ae1.html
而在NIOS中友晶写的驱动,操作底层的核心语句是:
#define IORD(BASE, REGNUM) \
__builtin_ldwio (__IO_CALC_ADDRESS_NATIVE ((BASE), (REGNUM)))
#define IOWR(BASE, REGNUM, DATA) \
__builtin_stwio (__IO_CALC_ADDRESS_NATIVE ((BASE), (REGNUM)), (DATA))
这个语句调用了ALTERA的库io.h,在DM9000.h中有如下定义:
#define IO_addr 0
#define IO_data 1
在DM9000.c中应用方式则为:
void iow(unsigned int reg, unsigned int data)
{
IOWR(DM9000A_BASE,IO_addr,reg);
usleep(STD_DELAY);
IOWR(DM9000A_BASE,IO_data,data);
}
unsigned int ior(unsigned int reg)
{
IOWR(DM9000A_BASE,IO_addr,reg);
usleep(STD_DELAY);
return IORD(DM9000A_BASE,IO_data);
}
友晶的驱动并没有提供关于读取接受包长度的函数,而在大部分基于ARM平台的驱动中都给出了这个函数,这也是我之所以去分析ARM与友晶驱动的区别。通过以上的分析可以看见友晶的驱动,和网上大部分ARM芯片关于读写寄存器的方式很相似,我起初想着去通过例程的RTL去找寻这个硬件CMD线地址,发现可能有点困难,在庞大的NIOS RTL图中找到这个网卡并不难,可是通过他跟NIOS核的地址线去算出他CMD线的地址,恐怕有点困难。最后我想既然他们类似,我可以模仿ARM中的函数书写,在NIOS中写个同样功能的函数。
通过了解了两者表达形式的不同,修改两者的表达形式。
DM9000_PPTR = REG_OFFSET;
等效为
IOWR(DM9000A_BASE , IO_addr , REG_OFFSET);
---------------
DM9000_DATA = DATA;
等效为
IOWR(DM9000A_BASE , IO_data,data);
---------------
DATA = DM9000_DATA;
等效为
IORD(DM9000A_BASE , IO_data);