1.原理
以FL2440为研究对象,DM9000A支持8位 16为模式,内部有64个寄存器、SRAM等,分别控制其工作,对于其寄存器的读写依靠地址端口和数据端口来控制,在系统移植的时候根据硬件连接设置:
#define S3C24XX_PA_DM9000 0x20000300
#define S3C24XX_VA_DM9000 0xE0000000
static struct resource s3c_dm9000_resource[] = {
[0] = {
.start = S3C24XX_PA_DM9000, .end = S3C24XX_PA_DM9000+ 0x3,
.flags = IORESOURCE_MEM
}, //定义了地址端口物理地址
[1]={
.start = S3C24XX_PA_DM9000 + 0x4, //CMD pin is A2
.end = S3C24XX_PA_DM9000 + 0x4 + 0x7c,
.flags = IORESOURCE_MEM
}, //定义了数据端口物理地址
[2] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ
},
};
其中,20000300对应着Bank4的物理空间(2000000~27FFFFFF),由nGCS4连接DM9000A的CS管脚决定,之所以定义地址端口的地址为20000300,数据端口地址为200003010,因为硬件上ADDR2连接了DM9000A的CMD管脚,该管脚决定是对地址端口,还是对数据端口读写。
2. 因此为了完成对于DM9000的读写,需要通过下面的代码:
#define DM9000_PPTR *(volatileuint16 *)( S3C24XX_PA_DM9000) //地址端口
#define DM9000_PDATA *(volatile uint16 *)( S3C24XX_PA_DM9000 +4)//数据端口
对64个8位寄存器的读写代码如下:
uint8 ior(uint8 reg) //读寄存器
{
DM9000_PPTR=reg;
return DM9000_PDATA&0xff;
}
void iow(uint8 reg, uint8 value) //写寄存器
{
DM9000_PPTR = reg;
DM9000_PDATA = value & 0xff;
}
其中由于MCU 的处理速度和DM9000 的处理速度可能有差别,最好加入适当的延迟。
对PHY16位寄存器的读写由8位寄存器的操作完成,代码如下:
uint16 phy_read(uint8 reg) //读PHY寄存器
{
uint16 val;
iow(DM9KS_EPAR, DM9KS_PHY | reg);
iow(DM9KS_EPCR, 0x0c);
iow(DM9KS_EPCR, 0x08);
val = (ior(DM9KS_EPDRH) << 8) |ior(DM9KS_EPDRL);
return val;
}
void phy_write(uint8 reg, uint16 value) //写PHY寄存器
{
iow(DM9KS_EPAR,DM9KS_PHY|reg);
iow(DM9KS_EPDRL,(value&0xff));
iow(DM9KS_EPDRH,((value>>8)&0xff));
iow(DM9KS_EPCR,0xa);
iow(DM9KS_EPCR, 0x08);
}
最后我们再一次读出DM9000的ID。
uint32 GetDM9000ID(void)
{
uint32 id_val;
DM9000_PPTR = DM9KS_PID_H;
id_val = (DM9000_PDATA & 0xff)<< 8;
DM9000_PPTR = DM9KS_PID_L;
id_val+= (DM9000_PDATA & 0xff);
id_val = id_val << 16;
DM9000_PPTR = DM9KS_VID_H;
id_val += (DM9000_PDATA & 0xff)<< 8;
DM9000_PPTR = DM9KS_VID_L;
id_val += (DM9000_PDATA & 0xff);
return id_val;
}
读写到顶端时自动返回到底端的功能。可以看作是一个循环队列,数据先进先出。
1、用户写数据到SRAM,即发生数据包,只要连续写数据到 MWCMD (0xF8,见下面) ——数据写入地址增加寄存器,然后指定长度到TXPLH,TXPLL——发送包长度寄存器,就可以完成写入操作。
如代码:
io_mode=ior(ISR)>>7;//读出io宽度
DM9000_PPTR=MWCMD;//写MWCMD寄存器,选择地址自动增加写入方式
if(io_mode==byte_mode){ //字节传送
for(i=0;i<Tx_length;i++)
DM9000_PDATA=Tx_data[i];//连续写入MWCMD寄存器
}
else if(io_mode==word_mode){//字传送
(int) length_temp=(Tx_length+1)/2;//长度修改
for(i=0;i<length_temp;i++)
DM9000_PDATA=Tx_data[i];//连续写入MWCMD寄存器
读出数据时,即读走接收数据包,只要用户从MRCMD——数据包读地址增加寄存器连续读出,数据包信息中接收状态Rx_status,及包长度Rx_length;就可以完成读出操作。
代码如下:
(uint8) io_mode=ior(ISR)>>7;//读出io宽度
DM9000_PPTR=MRCMD;//写MRCMD寄存器,选择地址自动增加读出方式
/*接收状态及包长度信息包含在接收数据包里面*/
if(io_mode==byte_mode){//字节读出
Rx_status=DM9000_PDATA+DM9000_PDATA<<8;//接受包首两个字节为状态
Rx_length=DM9000_PDATA+DM9000_PDATA<<8;//接受包次两个字节为长度
}
if(io_mode==word_mode){//字读出
Rx_status=DM9000_PDATA;//接受包首字为状态
Rx_length=DM9000_PDATA;//接受包次字为长度
}
if(io_mode==byte_mode){//字节读出
for(i=0;i<Rx_length;i++)
(uint8) Rx_data[i]=DM9000_PDATA;//保存到接收包数组 8位
}
else if(io_mode==word_mode){//字读出
(uint16) length_temp=(Rx_length+1)/2;//修改长度
for(i=0;i<length_temp;i++)
(uint16) RX_data[i]=DM9000_PDATA;//保存到接收包数组 16位
}
由此可见,DMA传送方式的确是高效的传送方式。
附:
7-0:MWCMD:写数据到发送SRAM中,之后指向内部SRAM的读指针自动增加1、2或4,根据处理器的操作模式而定(8位、16位或32位)。