Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Valued Contributor III
815 Views

DE2 Ethernet Primitive Solution

With the DE2 board, the Ethernet controller does not seem to work in Quartus II 8.0 or 8.1. There are several problems with the DE2_NET demonstration; it was built pre-7.1, the software driver does not work, the support is for crap, nobody seems to post anything useful on this topic etc. So here is the answer I would have killed for a month ago; in the DM9000A ISR, re-initialize the DM9000A and set a flag. In the main program loop, register the ISR again and clear the flag.  

 

Sample code: 

 

//--------------------------------------------------------------# include "basic_io.h"# include "test.h"# include "LCD.h"# include "DM9000A.C" 

# define DE2_8_7Segs_BASE 0x01901028 

 

 

unsigned int aaa,rx_len,i,packet_num; 

unsigned char RXT[68]; 

unsigned int EnetReceive; 

 

 

void ethernet_interrupts() 

packet_num++; 

aaa=ReceivePacket (RXT,&rx_len); 

 

//Do your processing here.  

 

//Reinitialize the DM9000A and set the flag to setup the  

//ISR pointer. 

DM9000_init(); 

EnetReceive = TRUE; 

 

 

int main(void) 

unsigned int Success; 

 

unsigned char TXT[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 

0x01,0x60,0x6E,0x11,0x02,0x0F, 

0x08,0x00,0x11,0x22,0x33,0x44, 

0x55,0x66,0x77,0x88,0x99,0xAA, 

0x55,0x66,0x77,0x88,0x99,0xAA, 

0x55,0x66,0x77,0x88,0x99,0xAA, 

0x55,0x66,0x77,0x88,0x99,0xAA, 

0x55,0x66,0x77,0x88,0x99,0xAA, 

0x55,0x66,0x77,0x88,0x99,0xAA, 

0x55,0x66,0x77,0x88,0x99,0xAA, 

0x00,0x00,0x00,0x20 }; 

 

 

//Initialize the LCD. 

LCD_Init(); 

 

//Test the LCD. 

Success = DM9000_init(); 

LCD_Show_Text(""); 

if (Success == DMFE_SUCCESS) 

//Tell the user if the DM9000A initialize or failed.  

LCD_Show_Text("DM9000A"); 

LCD_Line2(); 

LCD_Show_Text("Initialized."); 

alt_irq_register( DM9000A_IRQ, NULL, (void*)ethernet_interrupts );  

else 

LCD_Show_Text("DM9000 Failed."); 

 

 

packet_num=0; 

EnetReceive = FALSE; 

//Main loop. 

while (Success == 0) 

//Register the ISR again after the ISR has fired and the device has been  

//re-initialized.  

if (EnetReceive == TRUE) 

alt_irq_register( DM9000A_IRQ, NULL, (void*)ethernet_interrupts );  

EnetReceive = FALSE; 

Success = TransmitPacket(TXT,0x40); 

msleep(500); 

outport(DE2_8_7SEGS_BASE ,packet_num); 

 

LCD_Show_Text("TX Failed."); 

 

return 0; 

 

//------------------------------------------------------------------------- 

/* 

To get a full grasp of why this works read ·http://www.altera.com/literature/hb/nios2/n2sw_nii52006.pdf 

If you are doing this as a continuing project, become very familiar with  

 

the ISO-OSI 7 model and device networking. 

Note: 

Currently this code is very sloppy and needs revision. The true event 

in the init function needs to be determined. The only reason I posted this 

"as-is" was because of the crazy ammount of time I spent on this problem 

and the elation which comes with success. 

 

*/
0 Kudos
21 Replies
Highlighted
Valued Contributor III
4 Views

Hi Adam. 

I don´t think that is a solution for the problem. 

One, because you get a very slow transfer data rate after that. 

And another curious thing, is that I get the DE2_NET working fine with a loop pack (like the DE2 manual example), without re initializing the DM9000. 

Although is correct that initializing the DM9000 you can get it working, it is not very usefull, should be something missing more, to avoid the init() routine each time to recieve a packet. 

 

Just a thought.
0 Kudos
Highlighted
Valued Contributor III
4 Views

I agree fully; the central reason I posted the code was it worked. With Quartus 8 and 8.1 web, I could not get packet reception, even at a very slow rate, without the system crashing.  

 

Re-initializing is sloppy and is probably the equivalent of killing a fly with an RPG. I will post a later revision, probably toward the end of this month, or early April, which will contain the the proper sequence for packet reception.  

 

For some reason, I could not get the loop-back functionality to work for packet reception; I'll have to play around with it. The primary reasoning for this thread is to get someone off the ground who is having the same problem.  

 

My current thought is the drive is not entirely functional for reception; the interrupt mask may not be cleared or the memory does not flush, indicative of an issue with the DE2_NET demo.  

 

Thank you for taking the time to go through this; if you find a solution before me, I would love to see it. I'm really only interested in the primitives. 

 

Thank You, 

Adam F.
0 Kudos
Highlighted
Valued Contributor III
4 Views

I am trying to use ur code for DM9000A, but without LCD.h and test.h. 

but the driver could not initialize the DM9000A and prompts "DM9000A failed" 

what may be the problem? can u help
0 Kudos
Highlighted
Valued Contributor III
4 Views

Hello, 

 

I am having different problem. I send one packet to board, ISR executes, ReceivePacket function executes but then even though I don't send any packet, the ISR keeps running. 

When I set a breakpoint in ReceivePacket, I see  

rx_READY = IORD(DM9000A_BASE,IO_data)&0x03; 

 

rxReady is 0. But the algorithm doesn't care for this status. 

So I changed it like this: 

 

rx_READY = IORD(DM9000A_BASE,IO_data); 

 

if ((rx_READY & 0x01) == 1 ) 

... receive packet... 

else //---UNCOMMENTED rest-- if ((rx_READY & 0x02) != 0 )//rx_READY) /* status check first byte: rx_READY Bit[1:0] must be "00"b or "01"b */ 

//same code 

 

but this is still not a good solution since ISR enters once more to reset the device. So how can I tell ISR not to enter ISR again after receiving the packet I already sent. What should I do? Clear ISR status/stop int request etc.. after receiving packet? 

 

According to datasheet, ISR Status Register-Packet Received bit is a RW/C1 so one has to write 1 to correspond bit. So I did a iow to ISR in ReceivePacket function. This solved the problem but I still don't think this as a good solution.  

Many thanks, 

Luisa
0 Kudos
Highlighted
Valued Contributor III
4 Views

:confused: 

 

--- Quote Start ---  

I am trying to use ur code for DM9000A, but without LCD.h and test.h. 

but the driver could not initialize the DM9000A and prompts "DM9000A failed" 

what may be the problem? can u help 

 

--- Quote End ---  

 

 

Are you using the DE2_NET example? 

 

It shipped with the board on a disk; without it, the code I wrote is pretty useless. 

 

Also, an e-mail address will help. I'm usually against doing other people's work, but I can hand over what I developed if everything is on a university chain. 

 

This is pretty involved, I also need to know a bit about which HW modules you are using. The problem I ran into was I would receive one packet and never get another.
0 Kudos
Highlighted
Valued Contributor III
4 Views

TO_BE_DONE

0 Kudos
Highlighted
Valued Contributor III
4 Views

hi, 

I found there are some problem with the ReceivePacket function: I post my code: 

unsigned int ReceivePacket (unsigned char *data_ptr,unsigned int *rx_len) 

unsigned char rx_READY,GoodPacket; 

unsigned char Tmp, RxStatus; 

unsigned int high_b,low_b; 

unsigned int i; 

 

RxStatus = rx_len[0] = 0; 

GoodPacket=FALSE; 

 

/* mask NIC interrupts IMR: PAR only */ 

iow(IMR, PAR_set); 

 

 

/* dummy read a byte from MRCMDX REG. F0H */ 

rx_READY = ior(MRCMDX); 

 

/* got most updated byte: rx_READY */ 

rx_READY = IORD(DM9000A_BASE,IO_data)&0x03; 

usleep(STD_DELAY); 

/* reset the read pointer*/  

Tmp = ior(0xF5);  

printf("RD_P:0x%02X",Tmp);  

Tmp = ior(0xF4);  

printf("%02X\n",Tmp);  

 

Tmp = ior(0x25);  

printf("WR_P:0x%02X",Tmp);  

Tmp = ior(0x24);  

printf("%02X\n",Tmp);  

 

 

/* check if (rx_READY == 0x01): Received Packet READY? */ 

if (rx_READY == DM9000_PKT_READY) 

/* got RX_Status & RX_Length from RX SRAM */ 

 

 

 

IOWR(DM9000A_BASE, IO_addr, MRCMD); /* set MRCMD REG. F2H RX I/O port ready */ 

usleep(STD_DELAY); 

IORD(DM9000A_BASE,IO_data); /*move pointer to status address*/  

RxStatus = IORD(DM9000A_BASE,IO_data); 

usleep(STD_DELAY); 

low_b = IORD(DM9000A_BASE,IO_data); 

high_b = IORD(DM9000A_BASE,IO_data); 

rx_len[0] = high_b<<8; 

rx_len[0] = rx_len[0]+low_b - 4; 

 

/* Check this packet_status GOOD or BAD? */ 

if ( !(RxStatus & 0xBF) && (rx_len[0] < MAX_PACKET_SIZE) ) 

/* read 1 received packet from RX SRAM into RX buffer */ 

for (i = 0; i < rx_len[0]; i += 1) 

usleep(STD_DELAY); 

data_ptr[i] = IORD(DM9000A_BASE, IO_data); 

 

/* dump the 4 BYTE FCS */ 

IORD(DM9000A_BASE, IO_data); 

IORD(DM9000A_BASE, IO_data); 

IORD(DM9000A_BASE, IO_data); 

IORD(DM9000A_BASE, IO_data); 

GoodPacket=TRUE; 

} /* end if (GoodPacket) */ 

else 

/* this packet is bad, dump it from RX SRAM */ 

for (i = 0; i < rx_len[0]; i += 1) 

usleep(STD_DELAY); 

Tmp = IORD(DM9000A_BASE, IO_data);  

/* dump the 4 BYTE FCS */ 

IORD(DM9000A_BASE, IO_data); 

IORD(DM9000A_BASE, IO_data); 

IORD(DM9000A_BASE, IO_data); 

IORD(DM9000A_BASE, IO_data); 

printf("\nError\n"); 

rx_len[0] = 0; 

} /* end if (!GoodPacket) */ 

} /* end if (rx_READY == DM9000_PKT_READY) ok */ 

else if(!rx_READY) /* status check first byte: rx_READY Bit[1:0] must be "00"b or "01"b */ 

 

/* software-RESET NIC */ 

iow(NCR, 0x03); /* NCR REG. 00 RST Bit [0] = 1 reset on, and LBK Bit [2:1] = 01b MAC loopback on */ 

usleep(20); /* wait > 10us for a software-RESET ok */ 

iow(NCR, 0x00); /* normalize */ 

iow(NCR, 0x03); 

usleep(20); 

iow(NCR, 0x00);  

/* program operating registers~ */ 

iow(NCR, NCR_set); /* NCR REG. 00 enable the chip functions (and disable this MAC loopback mode back to normal) */ 

iow(0x08, BPTR_set); /* BPTR REG.08 (if necessary) RX Back Pressure Threshold in Half duplex moe only: High Water 3KB, 600 us */ 

iow(0x09, FCTR_set); /* FCTR REG.09 (if necessary) Flow Control Threshold setting High/ Low Water Overflow 5KB/ 10KB */ 

iow(0x0A, RTFCR_set); /* RTFCR REG.0AH (if necessary) RX/TX Flow Control Register enable TXPEN, BKPM (TX_Half), FLCE (RX) */ 

iow(0x0F, 0x00); /* Clear the all Event */ 

iow(0x2D, 0x80); /* Switch LED to mode 1 */ 

/* set other registers depending on applications */ 

iow(ETXCSR, ETXCSR_set); /* Early Transmit 75% */ 

/* enable interrupts to activate DM9000 ~on */ 

iow(IMR, INTR_set); /* IMR REG. FFH PAR=1 only, or + PTM=1& PRM=1 enable RxTx interrupts */ 

/* enable RX (Broadcast/ ALL_MULTICAST) ~go */ 

iow(RCR , RCR_set | RX_ENABLE | PASS_MULTICAST); /* RCR REG. 05 RXEN Bit [0] = 1 to enable the RX machine/ filter */ 

} /* end NIC H/W system Data-Bus error */ 

iow(ISR, 0x01); 

iow(IMR, INTR_set); 

// iow(0x0F, 0x00); 

//iow(IMR, INTR_set); 

return GoodPacket ? DMFE_SUCCESS : DMFE_FAIL; 

 

I added the code(red), the problem you mentioned is solved.  

 

the reason is MII added 4 byte FCS, When you read the packet, you should discard them, otherwise when you read the packet next time,you SRAM read pointer will point to the address less 4 byte than the right address,so it doesn't work. 

 

I also find the receive packet function doesn't clear the interrupt and re enable the receive packet interrupt again, so I added the code for it. 

 

Now ,you can try it , good luck
0 Kudos
Highlighted
Valued Contributor III
4 Views

That's fantastic!  

 

I chewed through that example so many times it drove me nuts. Plus the DM900A thing was about 1/8th of my project.  

 

Thanks, 

Adam F.
0 Kudos
Highlighted
Valued Contributor III
4 Views

You are welcome! 

:)
0 Kudos
Highlighted
Valued Contributor III
4 Views

huwenmin :cool:  

thanks a lot
0 Kudos
Highlighted
Valued Contributor III
4 Views

now another problem is that when you ISR read a packet from DM9000A, maybe another packet is coming, but it doesn't produce interrupt signal,so after you read a packet,you need read the next status word to check if there is another packet is in the buffer, when your ISR finish, you should make sure that there is no packet in the buffer. 

 

good luck!
0 Kudos
Highlighted
Valued Contributor III
4 Views

Better solution than my solution: unloading and reloading the ISR. 

 

Soap Box: 

That makes sense. I can't confirm this with any hard evidence; but every time I ran code on a NIOS II, it seemed as though the ISR automatically created a critical section without any extra effort on the programmer's part.  

 

I can't believe Terasic and Altera can get away with this MSDN setup for embedded development. It is possible they expected user's to us MicroLinux and not really care about how things where cobbled together. 

 

Looks like Cornell does Junior Projects for Master's Degrees; however, the report is well formatted. 

 

This may help some people: 

http://instruct1.cit.cornell.edu/courses/ece576/finalprojects/f2007/mjk64_hmm32_jdp45/mjk64_hmm32_jd...
0 Kudos
Highlighted
Valued Contributor III
4 Views

 

--- Quote Start ---  

That's fantastic!  

 

I chewed through that example so many times it drove me nuts. Plus the DM900A thing was about 1/8th of my project.  

 

Thanks, 

Adam F. 

--- Quote End ---  

 

 

I have try to send a udp packets to de2, but it can only received a arp request packet, which tell who's the 192.168.0.55, tell the host. 

so I make a arp reply packet manually ,and send it back to the host pc, 

after that, I can't receive any udp packet more. 

appreciate your help!
0 Kudos
Highlighted
Valued Contributor III
4 Views

I will need some specifics on the setup, but I can give some broad suggestions. For anything which helps you get to the solution faster, I need to know the basics of what you are trying to do.  

 

If you are manually handling ARP, a number of things can go wrong. The address is taken or incorrect, the HW type could be incorrect, or (likely), it sounds like DHCP could be assigning an IP, the reply is not what it should bind to.  

 

First, if there is only one PC in the loop, why bother with ARP? It makes the system more robust and it will play nicely with a router, but it doesn't provide a lot of utility unless the end goal is a server.  

 

Second, the more a network can be simplified, the faster a problem can be diagnosed. In this situation, use a hub between the PC and DE2. Have the PC bind to one port, the DE2 another.  

 

If microLinux is used, more complexity is added to the system. A problem above the hardware layer is a discussion of RFCs.
0 Kudos
Highlighted
Valued Contributor III
4 Views

thanks for your reply. 

My goal is using the pc to transfer the video streams to DE2, and to make some video proccess, such as decode, enhance. I need to make a rate controller in pc to controller it , like a video player, vlc, the rate is about 3m/s.
0 Kudos
Highlighted
Valued Contributor III
4 Views

The best advice I can give is to put a hub between the PC and the DE2 and use a sniffer for DE2 packets while going through the NIOS debugger. If the system is going down after an ARP, best guess is you are sending an ARP packet which something on the network is unhappy about.  

 

If the hub doesn't get you any farther, check the OS requirements for the DE2. 

 

Using a switch, and not sending ARP, with just a PC and DE2 connected should tell you if that is the problem. Routers usually require a bit of work to shut off enough functionality to turn it into a switch. 

 

If the DE2 dies after the first packet sent, there is likely an issue with the DM9000 registers. Sending broadcasts will tell if that's the issue.  

 

One thing that is strange, if you only have the one DE2, then you only have to worry about a MAC address. Tell me how things go with the DE2 and a PC connected via switch.
0 Kudos
Highlighted
Valued Contributor III
4 Views

Thanks for your advice. 

 

I have added the codes , 

Tmp = ior(0xF5);  

Tmp = ior(0xF4);  

into ReceivePacket function. It works! I can receive continuous data from pc. 

It seems to reset the DM9000A memory data address to 0x0c00. 

In the read memory operation, when the bit 7 of IMR is set, the memory  

address increment will wrap to location 0x0c00.
0 Kudos
Highlighted
Valued Contributor III
4 Views

 

--- Quote Start ---  

Thanks for your advice. 

 

I have added the codes , 

Tmp = ior(0xF5);  

Tmp = ior(0xF4);  

into ReceivePacket function. It works! I can receive continuous data from pc. 

It seems to reset the DM9000A memory data address to 0x0c00. 

In the read memory operation, when the bit 7 of IMR is set, the memory  

address increment will wrap to location 0x0c00. 

--- Quote End ---  

 

 

to Li.Huiliang, 

you did it successfully,while i'll do the same thing with you with a DE2 ,but i don't know how to start it ,can you give me the code that you just succeed.please send to kediqun.123@163.com ,i'll be very thankful!
0 Kudos
Highlighted
Valued Contributor III
4 Views

Is there any special software to send packets to the FPGA board

0 Kudos