For any hardware module design, the first step is to first understand the hardware itself, and then start the program software design. Because of the DM9000 chip document content, to drive a good network card, it takes a long time, especially for beginners more difficult, so you can refer to the Linux kernel code in the network card driver, porting it to bare-metal programs. The detailed procedures for DM9000 bare-metal program drivers are described below, and the programming of the ARP protocol is completed ok6410.
1. DM9000 Hardware interface
Open the ok6410 floor schematic can see the DM9000 and ok6410 hardware interface, through the DM9000 of the document about some of the more important pin interface,
Then refer to the ok6410 Core board schematic diagram can be very clear about the hardware interface corresponding to the PIN:
Sd0~sd15:data0~data15:xm0data0~xm0data15
CMD:ADDR2:XM0ADDR2
INT:IRQ_LAN:GPN7
IOR:OEN:XM0OEN
IOW:WEN:XM0WEN
CS:CSN1:XM0CSN1
From the corresponding relationship of some of the above pins, it may be difficult to understand the way of control, which differs greatly from the bare-metal programs of some modules such as Gpio. Searching for keywords in the 6410-chip handbook makes it difficult for beginners to understand the relationship of each pin. But through the online information can still know DM9000 interface, connected to the ROM1 control module, ok6410 is not connected ROM. This makes it clear that the following relationships
DATA0~DATA15:ROM1 Data Bus
Second bit of address bus for ADDR2:ROM1
Irq_lan: Interrupt Interface
Oen:noe
Wen:nwe
Csn1:xm0csn
This reads and writes to the DM9000 module is equivalent to the ROM read and write, the key is the cmd pin is ADDR2.
When CMD is 1 o'clock data0~data15 for data bus
When CMD is 0 o'clock Data0~data15 is address bus.
From the ok6410 manual you can conclude that the ROM1 start address is: 0x18000000
2. DM9000 Program Design
2.1 Initializing read-write timing
Configure the following registers with the timing diagram
void Cs_init ()
{
SROM_BW &= (~ (0xf<<4));
SROM_BW |= (0x1<<4);
SROM_BC1 = (0<<0) | (0x2<<4) | (0x2<<8) | (0x2<<12) | (0x2<<16) | (0x2<<24) | (0x2<<28);
}
2.2 Read-write operation function
#define DM_ADD (* (volatile unsigned short *) 0x18000000)
#define DM_DAT (* (volatile unsigned short *) 0x18000004)
void Dm9000_reg_write (U16 reg,u16 data)
{
Dm_add = reg;
Dm_dat = data;
}
U8 Dm9000_reg_read (U16 Reg)
{
Dm_add = reg;
return dm_dat;
}
The hardware interface analysis shows that CMD is the second bit of the address bus of ROM1, which is a data bus at 1, and 0 is address bus, so it can read and write according to the macro definition.
2.3 DM9000 Initialization
Refer to the Linux kernel's DM9000 driver for a clear understanding of the steps to initialize
void Dm9000_reset ()
{
Dm9000_reg_write (DM9000_GPCR, gpcr_gpio0_out);
Dm9000_reg_write (DM9000_GPR, 0);
Dm9000_reg_write (DM9000_NCR, (Ncr_lbk_int_mac | Ncr_rst));
Dm9000_reg_write (DM9000_NCR, 0);
Dm9000_reg_write (DM9000_NCR, (Ncr_lbk_int_mac | Ncr_rst));
Dm9000_reg_write (DM9000_NCR, 0);
}
void Dm9000_probe (void)
{
U32 Id_val;
Id_val = Dm9000_reg_read (dm9000_vidl);
Id_val |= dm9000_reg_read (Dm9000_vidh) << 8;
Id_val |= dm9000_reg_read (dm9000_pidl) << 16;
Id_val |= dm9000_reg_read (dm9000_pidh) << 24;
if (Id_val = = dm9000_id)
{
printf ("dm9000 is found!\n");
return;
}
Else
{
printf ("dm9000 is not found!\n");
return;
}
}
void Dm9000_init ()
{
U32 i;
Set up the chip selection
Cs_init ();
Reset Device
Dm9000_reset ();
Capture dm9000
Dm9000_probe ();
Mac initialization
Program operating register, only internal PHY supported
Dm9000_reg_write (DM9000_NCR, 0x0);
TX Polling Clear
Dm9000_reg_write (DM9000_TCR, 0);
Less 3Kb, 200US
Dm9000_reg_write (Dm9000_bptr, BPTR_BPHW (3) | BPTR_JPT_600US);
Flow Control:high/low Water
Dm9000_reg_write (Dm9000_fctr, Fctr_hwot (3) | Fctr_lwot (8));
SH Fixme:this looks strange! Flow Control
Dm9000_reg_write (DM9000_FCR, 0x0);
Special Mode
Dm9000_reg_write (DM9000_SMCR, 0);
Clear TX Status
Dm9000_reg_write (DM9000_NSR, Nsr_wakest | Nsr_tx2end | Nsr_tx1end);
Clear Interrupt Status
Dm9000_reg_write (DM9000_ISR, Isr_roos | Isr_ros | isr_pts | ISR_PRS);
Populate MAC Addresses
for (i = 0; i < 6; i++)
Dm9000_reg_write (Dm9000_par+i, macc_addr[i]);
Activating DM9000
Dm9000_reg_write (DM9000_RCR, Rcr_dis_long | RCR_DIS_CRC | Rcr_rxen);
Enable Tx/rx Interrupt Mask
Dm9000_reg_write (DM9000_IMR, Imr_par);
}
2.4 DM9000 Send function
void Dm9000_tx (U8 *data,u32 length)
{
U32 i;
Disable interrupts
Dm9000_reg_write (dm9000_imr,0x80);
Length of write sent data
Dm9000_reg_write (DM9000_TXPLL, length & 0xff);
Dm9000_reg_write (DM9000_TXPLH, (length >> 8) & 0xff);
Write data to be sent
Dm_add = Dm9000_mwcmd;
for (i=0;i
{
Dm_dat = Data[i] | (DATA[I+1]<<8);
}
Start send
Dm9000_reg_write (DM9000_TCR, tcr_txreq);
Wait for Send to end
while (1)
{
U8 status;
Status = Dm9000_reg_read (DM9000_TCR);
if ((status&0x01) ==0x00)
Break
}
Clear Send Status
Dm9000_reg_write (DM9000_NSR,0X2C);
Recovery interrupt Enable
Dm9000_reg_write (DM9000_IMR,0X81);
}
2.5 DM9000 receive function
#define Ptk_max_len 1522
U32 Dm9000_rx (U8 *data)
{
U8 Status,len;
U16 TMP;
U32 i;
Determine if an interrupt is generated and clear
if (Dm9000_reg_read (DM9000_ISR) & 0x01)
Dm9000_reg_write (DM9000_ISR,0X01);
Else
return 0;
Empty Read
Dm9000_reg_read (DM9000_MRCMDX);
Read status
Status = Dm9000_reg_read (Dm9000_mrcmd);
Read Package length
len = Dm_dat;
Read package data
if (len
{
for (i=0;i
{
TMP = Dm_dat;
Data[i] = tmp & 0x0ff;
Data[i+1] = (tmp>>8) &0x0ff;
}
}
}
DM9000 Bare Metal Driver design