Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12745 討論

Altera TSE driver and example program for lwIP (1.3.2)

Altera_Forum
榮譽貢獻者 II
39,570 檢視

After many many requests and complaints about lack of support and/or documentation for support of lwIP for the Altera TSE, I have developed a drop-in TSE driver and example program and made this available to the NIOS II community. This was done for NIOS II 8.1 SP0.01. I don't expect difficulty with version 9.x. 

 

This is for the latest version of lwIP (the latest is as of this post) for a minimal program and HTTP server based on the http server in the lwIP contrib folder. The lwIP TSE driver uses the altera_avalon_tse driver and SGDMA as-is. There is a complete (as in 41-step) set of instructions on creating the project and example program. More information and the link to the driver is available here: 

 

http://lwip.wikia.com/wiki/available_device_drivers#lwip_1.3.2 

 

Please direct any questions, changes for NIOS II 9.1, or comments to this thread. 

 

12-16-2010 update: This example works with NIOS Version 10.0 with some tweaks to the procedure to create the project. Also, a lwIP 1.4 release candidate has been out for a while and it drops into this example (in place of 1.3) without changes. 

 

Bill
0 積分
257 回應
Altera_Forum
榮譽貢獻者 II
2,141 檢視

 

--- Quote Start ---  

 

i got now an other prob i tried to make my own example with tcp and exclude the http files and make my own tcp files. I can connect and i can receive data over port 7 TCP but when i try to make pbuf_free() after the receive tcp_recevd i get the error 

 

--- Quote End ---  

 

Rene, Your Receive_cbf() must return 0. See doc/rawapi.txt. Igor
Altera_Forum
榮譽貢獻者 II
2,164 檢視

Thanks ims it works. Im very thankfull for your support and thanks BillA for this great example. 

 

 

Rene
Altera_Forum
榮譽貢獻者 II
2,164 檢視

You're welcome. And be sure to apply this change which works around a bug in the Altera SGDMA which I missed in the original driver (nor have I seen to date in 5 NIOS II applications): http://www.alteraforum.com/forum/showpost.php?p=146506&postcount=164 

 

Bill
Altera_Forum
榮譽貢獻者 II
2,164 檢視

 

--- Quote Start ---  

Rene, PHY is managed by altera_avalon_tse.c, not by lwip. To enable debug output compile your BSP with -dALT_DEBUG. 

--- Quote End ---  

 

Where do you enable this? When I change -g to -dALT_DEBUG in the debug option, I get this error when I compile: 

cc1.exe: warning: unrecognized gcc debugging option: _ cc1.exe: warning: unrecognized gcc debugging option: U
Altera_Forum
榮譽貢獻者 II
2,164 檢視

I have this under "NIOS II BSP Properties" - Flags: Defined Symbols. 

 

I use -DALT_DEBUG. I don't know if it's case sensitive -dALT_DEBUG may not work. 

 

Bill
Altera_Forum
榮譽貢獻者 II
2,164 檢視

 

--- Quote Start ---  

 

I use -DALT_DEBUG. I don't know if it's case sensitive -dALT_DEBUG may not work. 

 

--- Quote End ---  

 

Yes, it must be -DALT_DEBUG. Options are case sensitive.
Altera_Forum
榮譽貢獻者 II
2,164 檢視

Thanks. I am running the example on a custom board with 88E1111 PHY and Cyclone III chip. I'm having a problem with the program crashing at the start and haven't been able to track down the problem with debug. I've taken out the timer function and input polling function to try and track down the problem so all the main loop is doing right now is printing a message every 250 ms.  

 

It reaches the main loop, goes through the loop a few times, then the whole thing dies within 5 seconds. 

 

Does anyone have any suggestions for tracking down what is causing this problem? I am also turned off DHCP and the BUILD_HTTPD part. I am on an isolated network. My board is connected to a router by itself so no traffic coming or going. 

 

Here is the output by the way. The "at 250" is the print I added. There are several more before it crashes. 

Running... INFO : TSE MAC 0 found at address 0x0c000000 INFO : PHY Marvell 88E1111 found at PHY address 0x12 of MAC Group INFO : PHY - Automatically mapped to tse_mac_device INFO : PHY - Restart Auto-Negotiation, checking PHY link... INFO : PHY - Auto-Negotiation PASSED INFO : PHY - Checking link... INFO : PHY - Link established INFO : PHY - Speed = 100, Duplex = Full Waiting for link...OK IP address: 192.168.1.100 at 250Edit: 

I have tracked down to this: 

if (init(netif) != ERR_OK) { return NULL; }in netif.c. If I comment this out, the program doesn't crash (but doesn't init properly obviously). 

 

Edit again: 

Sorry for the multiple edits but I'm working on this right now in case that isn't obvious :cool: 

 

I've traced the problem down to this: 

tse_sgdma_read_init(&tse); 

in lwip_tse_mac.c. 

 

So it seems there is a problem with the RX SGDMA but I am at a loss for what that could be. Thanks again for any help that you can offer. I am not very experienced with the ethernet applications for FPGA platforms.
Altera_Forum
榮譽貢獻者 II
2,164 檢視

Hi guys, 

I'm not a software person. 

I have a custom board with all needed hardware and i'm able to run an example connected with Altera driver and i'm using lwip-1.4.0. 

I'm connecting my board directly to my PC (no DHCP) and I can see in "Network Connections" in Windows that i'm connected successfully. And I'm getting standard output on Nios 2 IDE console. 

But I want to do something more. 

First I would like to ping my board from the windows console.  

when I do "ping 192.168.1.100" it says that request is timed out. 

1. Do i need to add something more to the Altera driver example to be able to ping? 

I do have contrib-1.4.0 folder and there is a ping application there, i've added 2 files to my altera driver example but the thing is still not working.  

2. Do i need to change my main.c file? What should i add there? 

 

The third question - i would like to use httpserver_raw application to show the web-page on my PC. What should i do to be able to do this? 

Best Regards, 

uilka_b
Altera_Forum
榮譽貢獻者 II
2,164 檢視

How do You guys start all the program if the ethernet cable is unplugged? Seems like lwIP then waits in a while forever...

Altera_Forum
榮譽貢獻者 II
2,164 檢視

 

--- Quote Start ---  

How do You guys start all the program if the ethernet cable is unplugged? Seems like lwIP then waits in a while forever... 

--- Quote End ---  

 

Socrates, I’ve attached snapshots from my working code as a demo. I use standard lwip timer to check ethernet link periodically and call netif_set_link_up() / netif_set_link_down() when appropriate. Other tasks may be scheduled through sys_timeout() or called from the loop in main(). Feel free to ask for clarification. 

 

Igor
Altera_Forum
榮譽貢獻者 II
2,164 檢視

For those who uses sys_timeout() as a general purpose timer -  

 

I’ve found that under certain circumstances lwip timeouts become extremely inaccurate. The reason is that sys_timeout() effectively schedules the handler not relative to the current time (result of sys_now()), but relative to the moment, when previous handler was called (stored in timers.c: static u32_t timeouts_last_time) 

 

This does not affect internal lwip timers because they always reschedule themselves inside timeout handler routine, i.e. when timeouts_last_time is equal to sys_now(). On the contrary, if one calls sys_timeout() in arbitrary moment in time, say, inside UDP packet handler, difference between sys_now() and timeouts_last_time may be large. In such a case effective timeout value will be shorter by (sys_now() - timeouts_last_time) and all subsequent timeouts will be offset by the same value. 

 

This can be fixed at the cost of extra sys_now() call by inserting 

 

msecs += sys_now() - timeouts_last_time; 

 

in the very beginning of void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg). 

 

Igor
Altera_Forum
榮譽貢獻者 II
2,164 檢視

I removed (all?) the bugs (The 4 byte SGDMA bug is available in code, but I didn't enable it yet, because I haven't seen any problems) and added multiple PHY support. If you are interested in using this BSP you will have to read the README and the lwip_main.h file to see how you can implement it. 

 

Please have a look at : https://github.com/engineeringspirit/freelwip-nios-ii if you're interested in an FreeRTOS with LwIP BSP for in your Nios II IDE (tested with 11.0 till 12.0sp1)
Altera_Forum
榮譽貢獻者 II
2,159 檢視

Hello, 

 

I have a strange problem with Altera TSE driver and example program for lwIP (1.3.2) using Quartus 12 SP1, Cyclone III Development Board with Triple Speed Ethernet Design Example (altera.com/support/examples/nios2/exm-tse-sgdma.html). I don't programm anything to flash, usb blaster is used. 

 

An example from BillA does not work in my case, SignalTap shows no activity on RX and TX Avalon Stream. But if I run Altera's example webserver using NicheStack on the MicroC/OS-II RTOS and the example from BillA thereafter everything is fine -lwIP web serwer works. 

 

Where is the difference in interniche and lwIP initialization routines?
Altera_Forum
榮譽貢獻者 II
2,159 檢視

Did You copy RGMII initialization file into the project? You can take it from RGMII web server example or RGMII simple socket server example projects. Afaik it's called tse_my_system.c. Just copy it to the project tree and recompile.

Altera_Forum
榮譽貢獻者 II
2,159 檢視

Thank you, Socrates, that was exactly what I needed to get it running!!! 

 

P.S. The recipe how to get lwIP 1.3.2 running didn't work. I needed to edit the makefile and add the source as well as header files manually: 

 

# Paths to C, C++, and assembly source files. 

C_SRCS += lwip/src/api/api_lib.c 

C_SRCS += lwip/src/api/api_msg.c 

C_SRCS += lwip/src/api/err.c 

C_SRCS += lwip/src/api/netbuf.c 

C_SRCS += lwip/src/api/netdb.c 

C_SRCS += lwip/src/api/netifapi.c 

C_SRCS += lwip/src/api/sockets.c 

C_SRCS += lwip/src/api/tcpip.c 

C_SRCS += lwip/src/core/dhcp.c 

C_SRCS += lwip/src/core/dns.c 

C_SRCS += lwip/src/core/ipv4/autoip.c 

C_SRCS += lwip/src/core/ipv4/icmp.c 

C_SRCS += lwip/src/core/ipv4/igmp.c 

C_SRCS += lwip/src/core/ipv4/inet_chksum.c 

C_SRCS += lwip/src/core/ipv4/inet.c 

C_SRCS += lwip/src/core/ipv4/ip_frag.c 

C_SRCS += lwip/src/core/ipv4/ip_addr.c 

C_SRCS += lwip/src/core/ipv4/ip.c 

C_SRCS += lwip/src/core/init.c 

C_SRCS += lwip/src/core/mem.c 

C_SRCS += lwip/src/core/memp.c 

C_SRCS += lwip/src/core/netif.c 

C_SRCS += lwip/src/core/pbuf.c 

C_SRCS += lwip/src/core/raw.c 

C_SRCS += lwip/src/core/stats.c 

C_SRCS += lwip/src/core/sys.c 

C_SRCS += lwip/src/core/tcp_in.c 

C_SRCS += lwip/src/core/tcp_out.c 

C_SRCS += lwip/src/core/snmp/asn1_dec.c 

C_SRCS += lwip/src/core/snmp/asn1_enc.c 

C_SRCS += lwip/src/core/snmp/mib_structs.c 

C_SRCS += lwip/src/core/snmp/mib2.c 

C_SRCS += lwip/src/core/snmp/msg_in.c 

C_SRCS += lwip/src/core/snmp/msg_out.c 

C_SRCS += lwip/src/core/tcp.c 

C_SRCS += lwip/src/core/udp.c 

C_SRCS += lwip/src/netif/etharp.c 

C_SRCS += lwip/src/netif/ppp/auth.c 

C_SRCS += lwip/src/netif/ppp/chpms.c 

C_SRCS += lwip/src/netif/ppp/fsm.c 

C_SRCS += lwip/src/netif/ppp/lcp.c 

C_SRCS += lwip/src/netif/ppp/pap.c 

C_SRCS += lwip/src/netif/ppp/ppp.c 

C_SRCS += lwip/src/netif/ppp/ppp_oe.c 

C_SRCS += lwip/src/netif/ppp/randm.c 

C_SRCS += alteraTseEthernetif.c 

C_SRCS += fs.c 

C_SRCS += fsdata.c 

C_SRCS += httpd.c 

C_SRCS += lwip_tse_mac.c 

C_SRCS += main.c 

C_SRCS += tse_my_system.c 

 

# List of application specific include directories, library directories and library names 

APP_INCLUDE_DIRS += ../clean_lwip_project/lwip/src/include 

APP_INCLUDE_DIRS += ../clean_lwip_project/lwip/src/include/ipv4 

APP_INCLUDE_DIRS += ../clean_lwip_project
Altera_Forum
榮譽貢獻者 II
2,159 檢視

Maybe this would be helpful for those who need to know link status.  

I've added this to lwip_tse_mac.c 

 

int tse_link_status(int iface, struct ethernetif *ethernetif) { 

np_tse_mac *mi_base; 

mi_base = tse[iface].mi.base; 

alt_tse_mac_info *pmac_info; 

 

tse_sgdma_read_init(&tse[iface]); 

pmac_info = alt_tse_get_mac_info(mi_base); 

alt_tse_phy_wr_mdio_addr(pmac_info->pphy_info, pmac_info->pphy_info->mdio_address); 

int link_alive; 

link_alive = alt_tse_phy_rd_mdio_reg(pmac_info->pphy_info, TSE_PHY_MDIO_STATUS, TSE_PHY_MDIO_STATUS_AN_COMPLETE, 1) != 0; 

return link_alive; 

 

Or is there another way to check for link status ?
Altera_Forum
榮譽貢獻者 II
2,159 檢視

Petrak, 

 

That will work fine unless you're doing realtime processing and using Ethernet too. Reading the PHY like this stalls the NIOS II interrupt response for a significant time period. I know this because it affected my project. When I reported this to Altera the response was "this is how it works". While the PHY shifts in serial data on this MDIO read, the NIOS II will not respond to interrupt requests. We used logic in the Cyclone to delay the task the interrupt was performing to hide this latency that the PHY causes. It was a real pain but we have to respond to an external interrupt within a few uS. Fortunately there was a workaround or our product would have been dead. The MDIO read was causing additional interrupt latency from 31 to 48uS over normal latency times. 

 

Bill A.
Altera_Forum
榮譽貢獻者 II
2,159 檢視

 

--- Quote Start ---  

Petrak, 

 

That will work fine unless you're doing realtime processing and using Ethernet too. Reading the PHY like this stalls the NIOS II interrupt response for a significant time period. I know this because it affected my project. When I reported this to Altera the response was "this is how it works". While the PHY shifts in serial data on this MDIO read, the NIOS II will not respond to interrupt requests. We used logic in the Cyclone to delay the task the interrupt was performing to hide this latency that the PHY causes. It was a real pain but we have to respond to an external interrupt within a few uS. Fortunately there was a workaround or our product would have been dead. The MDIO read was causing additional interrupt latency from 31 to 48uS over normal latency times. 

 

Bill A. 

--- Quote End ---  

 

 

I assumed that this will cause something like this. Interrupts you are talking about are all interrupts in system ? During the read from PHY all interrupts will be delayed ? 

For us this is not big issue, we don't have such realtime processing. 

So for Altera devices there is no ("right") way to handle info about link state from PHY without this issues ? :( 

Thanks
Altera_Forum
榮譽貢獻者 II
2,159 檢視

 

--- Quote Start ---  

I assumed that this will cause something like this. Interrupts you are talking about are all interrupts in system ? During the read from PHY all interrupts will be delayed ? 

For us this is not big issue, we don't have such realtime processing. 

So for Altera devices there is no ("right") way to handle info about link state from PHY without this issues ? :( 

Thanks 

--- Quote End ---  

 

 

PETRAK, PHY chips usually have some pins intended to drive status leds. It is convenient to use them as a workaround to reduce slow MDIO exchange. For example, 88E1119R asserts LED2 pin on connect and de-asserts on disconnect. If you wire this signal into FPGA you will be able to read link status by PIO with zero overhead.
Altera_Forum
榮譽貢獻者 II
2,159 檢視

 

--- Quote Start ---  

PETRAK, PHY chips usually have some pins intended to drive status leds. It is convenient to use them as a workaround to reduce slow MDIO exchange. For example, 88E1119R asserts LED2 pin on connect and de-asserts on disconnect. If you wire this signal into FPGA you will be able to read link status by PIO with zero overhead. 

--- Quote End ---  

 

 

IMS, in fact that is *exactly* what we did - we use the same PHY and used that LED on an FPGA input pin. I did not experiment with making that an interrupt but I wanted to. Detecting loss of link was not a real-time problem for us. 

 

The workaround I mentioned wasn't just for the PHY but also for general poor and inconsistent interrupt latency on the external interrupt. The MDIO made it so bad we had to use the LED. We latched the effective start of the external interrupt to hide the normal latency that is added since we need to do something exactly timed off the external interrupt without bobble. So in effect the ISR handling is in the middle of the window from external interrupt to when we need the hardware to do its thing. We can handle this skew as long as the interrupt to hardware processing is the same. 

 

Bill A.
Altera_Forum
榮譽貢獻者 II
2,159 檢視

Hello, 

 

we used the lwIP port in our project, and experienced problems when there is heavy traffic. After some research, two bugs were fixed, related to concurrency (variable names are renamed w.r.t. the original sources): 

 

- function low_level_input in alteraTseEthernetif: critical section needs to be extended (next_packet must be assigned within critical section; otherwise, when the ISR would be called in the mean time, it may result in the current packet being overwritten by the new one): 

 

// start the critical section by disabling IRQs const alt_irq_context cpu_sr = alt_irq_disable_all(); // decrement packet counter --tse_info->mRxCount; // assign current packet from lwIP packet buffer as the new data *data = tse_info->mRxBuffer; // assign next packet instead and move forward in buffer tse_info->mRxBuffer = (void*)next_packet; if (++tse_info->mRxIndex >= TSE_RX_BUFFER) { tse_info->mRxIndex = UINT32_L(0); } // stop the critical section by enabling IRQs alt_irq_enable_all(cpu_sr);  

 

- function tse_mac_recv in lwip_tse_mac.c: (mRxCount > TSE_RX_BUFFER) ==> (mRxCount >= (TSE_RX_BUFFER - 1)); may otherwise result in packets being overwritten 

 

// check if contents of memory are valid if ((IORD_ALTERA_TSE_SGDMA_DESC_STATUS(&tse_info->mSgdmaDescriptor) & (ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK | ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK | ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK |ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK | ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK | ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK | ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK )) == 0) { // contents are valid // check if there is place for the next packet // this function always prepares for the next DMA transfer, so at least one packet must be available for that if (tse_info->mRxCount >= (TSE_RX_BUFFER - UINT32_L(1))) { // there is no place // drop this packet LINK_STATS_INC(link.drop); } else { // there is place // allow this packet ++tse_info->mRxCount; if (++tse_info->mRxIndexIsr >= TSE_RX_BUFFER) { tse_info->mRxIndexIsr = UINT32_L(0); } } } else { // contents are invalid // drop this packet LINK_STATS_INC(link.drop); }  

 

greetings, 

 

Stephan Orban
回覆