Welcome, guest ( Login )

WikiHome » OperatingSystems » µClinux » EtherNet

EtherNet

Version 79, changed by hippo5329@yahoo.com.tw. 04/13/2008.   Show version history

To enable network driver support, in uClinux-dist kernel config,

 
Device Drivers -->Network device support ─>
[*] Network device support
[*] Ethernet (10 or 100Mbit)

 
[*] SMC 91C9x/91C1xxx support            # only if you use Altera Nios dev board with SMC91111,
[ ] Opencores (Igor) Emac support                
[ ] MoreThanIP 10_100_1000 Emac support
[*] DM9000 support                                 
# only if you use DE2 with DM9000A

[ ] DM9000A with checksum offloading    # alternative driver for DM9000A , BROKEN!!

If you use Altera's Nios dev board, select "SMC 91C9x/91C1xxx support"  . linux-2.6.x/drivers/net/smc91x.c .
If you use DE2 board, you should enable "DM9000 support" . linux-2.6.x/drivers/net/dm9000.c .
 
If you use Altera Stratix dev board, you must change the irq number of the ether chip to a non-zero value in SOPC builder and rebuild.
 
Then rebuild the kernel, and boot nios2 uclinux. It should detect the SMC 91111 or DM9000 device as eth0.
 
If your board has only a PHY, you may use Avalon OpenCores 10/100 Ethernet MAC (you have to register nios forum to download this core) . Name the component as "igor_mac" and select "[*] Opencores (Igor) Emac support" .

Every board should have a unique ethernet hardware address. In file linux-2.6.x/arch/nios2nommu/kernel/setup.c, kernel get the hw addr from the flash on Altera dev board. You may use 'ifconfig' to find out. If you use custom boards, you need to change setup.c or use ifconfig to set hw address.
ifconfig eth0 hw ether 00:07:ed:0a:03:29      #  hardware MAC address 00:07:ed:0a:03:<random 00-ff>
 
Then config the ip address and router.
ifconfig eth0 192.168.1.10      # static ip
route add default gw 192.168.1.254     # gateway

Or, use dhcp client if you have a dhcp server on the local network ( it won't work if you don't have a dhcp server),
ifconfig eth0 up
dhcpcd &

 
To check the ethernet connection, try "ping" the board to and from your PC or gateway. eg,
/> ping 192.168.1.254


 
The telnetd and ftpd should be invoked by inetd with the default config. The BOA is standalone.
/> inetd &   # start inetd to invoke telnetd and ftpd services
[15]
/> boa &   # start httpd with cgi-demo
[16]
/> netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 *:http                  *:*                     LISTEN
tcp        0      0 *:ftp                   *:*                     LISTEN
tcp        0      0 *:telnet                *:*                     LISTEN
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path

 
You may try these servers from your PC,
ftp 192.168.1.10 # user ftp, password anything
 
telnet 192.168.1.10
http://192.168.1.10
 
  from a web brower


 
You may add these setup for ethernet to the file vendors/Altera/nios2nommu/rc (which will become /etc/rc ) in uClinux-dist dir, follow the setup for "lo" . So that the ethernet will be configed by init.


 
With dm9ks driver in DE2 the ftpd transfer rate is around 1.5-1.7 MByte/s.


 
To set name server (DNS) , create the file vendors/Altera/nios2nommu/resolv.conf , with a line of your name server, eg
nameserver 192.168.1.254

 
Then add a line to romfs: target in file vendors/Altera/nios2nommu/Makefile
$(ROMFSINST) /etc/resolv.conf
 
Which will be /etc/resolve.conf on your board.


 
Or if you use DHCP, the dhcpcd will create the file /etc/resolv.conf .
Refer to the end of
 
NFSFileSytem wiki page for a sample dhcpd.conf.


 
You may use "ntpdate" to get date & time from internet. Set TZ  env to your timezone, eg "TZ=CST-8" for east China. Or edit the file vendors/Altera/nios2nommu/TZ , which will be /etc/TZ as the cache of TZ env.
/> TZ=CST-8
/> ntpdate pool.ntp.org
Looking for host pool.ntp.org and service ntp
host found : 71.237.179.90
13 Dec 11:05:33 ntpdate[20]: step time server 71.237.179.90 offset 222059037.166530 sec
/> date
Wed Dec 13 11:05:39 2006


 
Reading about performance issues,
 
Zero Copy I: User-Mode Perspective
Linux Ethernet-Howto: Technical Information
Choosing an Ethernet NIC for Linux 2.4
gigabit ethernet over copper performance comparison at University of Northern Iowa.
 
Jumbo Frames support can be enabled by changing the MTU to a value larger than the default of 1500.  Use the ifconfig command to increase the MTU size.
eg,   ifconfig eth<x> mtu 6000 up


SOPC Component for DM9000

 

For SOPC Builder, create a new component using this verilog file DM9000A_CTRL.v. Click next until the "interface" tab, then make the following changes :

  •     Slave Adressing : Registers
  •     Units : ns
  •     Setup : 0
  •     Read Wait : 40
  •     Write Wait : 40
  •     Hold : 0

After creating the component, add it to your design. Make sure it is named "DM9000". Thats it. The code includes a clock divider for 25MHz, which means that the input clock to it must be 50MHz.

 

After compiling the design, the pin assignments must be set. The pin names used in the verilog code matches the pin names used in the DE2 User manual. Make sure the pin assignment is done correctly.

This works in Altera Quartus 7.1sp1.

 

we try it in Quatus 7.2 I  there is somthing different  

add a type of signal when creat commpoment interrupt sender

then change the irq signal to this type others is same to front steps



DM9000A Avalon tristate slave, and debug guide

Here is another approach for Quartus v7.1 and later. We use Avalon tristate bridge to connect the DM9000A. This has the advantage that many external peripheral chips can share some signals on the bus, such as CFI flash, SRAM, USB or multiple DM9000A.

Put dm9000a_hw.tcl  in your project directory. Open SOPC Builder, and you can find a new "dm9000a" component.


Add a new Avalon-MM tristate bridge. Add a "dm9000a" component, name it as "dm9000", and connect it  to the Avalon tristate bridge master. You don't need other VHDL or Verilog for this component, because the SOPC builder will generate a wrapper inside. Note, don't assign irq 0 to dm9000.

 

 
There is no clock output in this component. The DM9000A needs a 25MHz clock. You can add a crystal to the DM9000A on-chip OSC. Or you can generate the clock in your top level design using counter, eg 50MHz div 2. for DE2,  (PLL has larger jitter, and not so good)

   reg     ENET_CLK;
   always @(posedge CLOCK_50) ENET_CLK<= ~ENET_CLK;
   wire [1:0] cmd_dm9000;
   assign     ENET_CMD = cmd_dm9000[1];  


// in the sopc system (cpu) module instance

               // the_DM9000A
                 .cmd_to_the_dm9000(cmd_dm9000),
                 .cs_n_to_the_dm9000(ENET_CS_N),
                 .data_to_and_from_the_dm9000(ENET_DATA),
                 .irq_from_the_dm9000(ENET_INT),
                 .ior_n_to_the_dm9000(ENET_RD_N),
                 .rst_n_to_the_dm9000(ENET_RST_N),
                 .iow_n_to_the_dm9000(ENET_WR_N),
 

 ++++++++++++++++++++++++++++++ debug ++++++++++++++++++++++++++++

 To debug this componet,

In Quartus memu Tools --> Signal Tap II Logic Analizer,

Signal Configuration window , Clock: ... select your processor clock.
Setup tab, add signals ior,iow,cs,cmd and data. Add DM9000 clock if it is generated from FPGA.
Save the stp file, as dm9000.stp . Recompile in Quartus. Then download the new sof. In Signal Tap window, setup Trigger with rising edge of ior, and Run Analysis.
Then you can check the waveform.

Follow DebugKernel . Open a nios2-terminal and start insight GDB. In the "source" window of Insight, open dm9000.c and set breakpoint at the line of id_val check in dm9000_probe(),

    /* try two times, DM9000 sometimes gets the first read wrong */
    for (i = 0; i < 2; i++) {
        id_val  = ior(db, DM9000_VIDL);
        id_val |= (u32)ior(db, DM9000_VIDH) << 8;
        id_val |= (u32)ior(db, DM9000_PIDL) << 16;
        id_val |= (u32)ior(db, DM9000_PIDH) << 24;

        if (id_val == DM9000_ID)   <== set breakpoint here
            break;
        printk("%s: read wrong id 0x%08x\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", CARDNAME, id_val);
    }

    if (id_val != DM9000_ID) {
        printk("%s: wrong id: 0x%08x\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", CARDNAME, id_val);
        goto release;
    }

When it hits breakpoint, check the "local" window, db->io_addr and db->io_data should have your port address.
Then open "memory" window and display or modify these address.

Otherwise, you can debug using printk(). Add printk() before the id check of dm9000_probe() in dm9000.c, to show db->io_addr and db->io_data.
And loop forever in the id check.

You can use git to help you restore the source after you made debug changes.
git checkout linux-2.6.x/drivers/net/dm9000.c

++++++++++++++++++++++ component timing +++++++++++++++++++++++++++++++++++++++

This component is created using Component Editor. Then add a line,

set_module_property "instantiateInSystemModule" "false"

You should read the data sheet of DM9000. The chip needs an inactive time between read and write, timing t6, which can be 4-2 DM9000 internal clock, ie 80-20ns. So it won't help to use longer "wait states", if the data sheet is true. You should use longer "setup" time. The DM9000 HAL driver, they added a lot of usleep() for the inactive time. But the Linux driver does not.

The slave interface timing of this component is,
setup time 1 cycle, read wait 1 cycle, write wait 1cycle, hold time 1 cycle.

At 100MHz clock, this provides 20ns command active time, and 20ns inactive time. With two additional instructions cycles, it gives 40ns inactive time, and the timing requirement is met.

You may change the interface timing using Component Editor if your clock is different.

++++++++++++++++++++++ only for 8 bits interface +++++++++++++++++++++++++++++++++++++++

If you need 8 bits interface, add a resistor to pull high the EECS pin of DM9000A, edit the component in SOPC builder, change the "width" of signal "data" to "8". The bit shift cmd_dm9000 is not needed for 8 bits interface, and should be removed. Just use,
                .cmd_to_the_dm9000(ENET_CMD),

There is no need to change the dm9000 driver. But you need to tell the driver that you want to use 8 bits mode.

Edit the file, linux-2.6.x/arch/nios2nommu/kernel/setup.c , locate the flags,

 
static struct dm9000_plat_data dm9k_platdata = {

  .flags = DM9000_PLATF_16BITONLY, ===> change 16 to 8

};

 The DM9000 port address binding is in the same file, linux-2.6.x/arch/nios2nommu/kernel/setup.c , using platform_device data structure.



Optimized DM9000A SOOPC component with variable wait-state:


Here is an optimized DM9000A component for Quartus/SOPC Builder 7.2.  If timing margins have been reached for the DM9000A chip, I believe it operates a read in one wait state, and a write in zero wait-states.  If not, it stalls the avalon transaction until it is safely able to perform a read/write.

It only takes 14 logic elements, and is actually very simple.  A lot of trial and error went into achieving the lowest delay and logic utilization.  I believe the performance can be improved slightly at the expense of more complicated logic by checking which register was read last, or by a slight change to the dm9ks.c file (only one place uses the read instruction from the register that causes the most delay on the next read/write) but I do not consider the minimal benefit worth pursuing any further.

It has been tested with a DE2-70 board, only as far as pinging for both the dm9000 and dm9ks drivers.

Put DM9000A_IF.v and DM9000A_hw.tcl in a subfolder under your quartus project directory.  In SOPC Builderr, add the path to your new IP in the menu Tools->Options->IP Search Path.  You may have to refresh the component list in the File->Refresh Component List...  It gets put into "USER_IP" section.

Add the new component to your SOPC Builder project, name is DM9000A or dm9000, set an interrupt other than 0, and have its clock reference your CPU clock in SOPC Builder (up to 100 Mhz).  Beyond 100 Mhz will  violate DM9000A timing.

Add to your top level file, the new information like:

// the_DM9000A
.ENET_CLK_from_the_DM9000A(oENET_CLK),
.ENET_CMD_from_the_DM9000A(oENET_CMD),
.ENET_CS_N_from_the_DM9000A(oENET_CS_N),
.ENET_DATA_to_and_from_the_DM9000A(ENET_D),
.ENET_INT_to_the_DM9000A(iENET_INT),
.ENET_RD_N_from_the_DM9000A(oENET_IOR_N),
.ENET_RST_N_from_the_DM9000A(oENET_RESET_N),
.ENET_WR_N_from_the_DM9000A(oENET_IOW_N),
.clk50_to_the_DM9000A(iCLK_50)

and change the name of the signals passed to the component if they are different.

Attachments (7)

  File By Size Attached Ver.
 DM9000A_CTRL.v vishnu350 1K 03/11/2008 1 Delete attachment
 DM9000A.rar laoniu85 15K 03/14/2008 1 Delete attachment
 dm9000a_hw.tcl hippo5329@yahoo.com.tw 2K 03/19/2008 5 Delete attachment
 neek_ocm.zip hippo5329@yahoo.com.tw 1M 03/23/2008 1 Delete attachment
 DM9000A_IF.v j_a_lockwood 3K 03/25/2008 1 Delete attachment
 DM9000A_hw.tcl j_a_lockwood 2K 03/25/2008 1 Delete attachment
 cycloneIII_embedded_evaluation_kit_standard_ocm.qar hippo5329@yahoo.com.tw 2M 04/13/2008 2 Delete attachment