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 Discussions

Altera TSE driver and example program for lwIP (1.3.2)

Altera_Forum
Honored Contributor II
39,387 Views

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 Kudos
257 Replies
Altera_Forum
Honored Contributor II
3,378 Views

Stephan, 

 

This is interesting. I see how you're right, but I also think there is a change that does not increase latency. The reason it was kept so short is that our system requires as close to 0 latency as possible. 

 

I think the root problem is the location of this line: 

 

// decrement packet counter --tse_info->mRxCount;  

 

I believe the following also solves the problem since the packet count (which tells us if there is a free space) is decremented last: 

 

// start the critical section by disabling IRQs const alt_irq_context cpu_sr; // 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); } cpu_sr = alt_irq_disable_all(); // decrement packet counter --tse_info->mRxCount; // stop the critical section by enabling IRQs alt_irq_enable_all(cpu_sr);  

 

This also could make the second change uneccessary since the count doesn't show a free slot until the pbuf pointer has replaced the previous one. 

 

Good catch. We, as well might be the case with most users, don't load the system until the buffers are full. We have enough memory that this array is quite large. 

 

Bill
0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

Hi BillA (and others !), 

 

Really big thanks for your lwip port on altera. 

I have succefully implemented the webserver template with lwip on a bemicro SDK from arrow. 

 

I have a question because i don't know how to do it : 

 

actually i have my sgdma Tx and sgdma Rx mapped on a DDR , 

the same DDR where the CPU data an instruction is mapped. 

 

Now imagine i want to use an onchip ram for sgdma tx and sgdmarx instead of DDR. 

(but CPU still mapped to DDR) 

 

I tried direclty but this is not working. 

 

if you have any idea . 

 

thanks
0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

 

--- Quote Start ---  

 

actually i have my sgdma Tx and sgdma Rx mapped on a DDR , 

the same DDR where the CPU data an instruction is mapped. 

 

--- Quote End ---  

 

 

I'm almost positive that this can't work. Every example I've seen has SGDMA writing to onchip memory. 

 

 

--- Quote Start ---  

 

Now imagine i want to use an onchip ram for sgdma tx and sgdmarx instead of DDR. 

(but CPU still mapped to DDR) 

 

--- Quote End ---  

 

 

I would agree with this too. :-) 

 

 

--- Quote Start ---  

 

I tried direclty but this is not working. 

 

if you have any idea . 

 

--- Quote End ---  

 

 

Maybe it's not working for a non-SGDMA or memory reason. Compare to an example (e.g. the Altera NEEK development kit Ethernet code) and see if you're in the ballpark setting-wise. 

 

Bill A.
0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

Thanks BillA, 

 

My problem was solved by using an equivalent SOPC as in Altera NEEK development kit Ethernet code. 

 

thanks for the idea . 

 

Laurent 

 

 

0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

Hi, 

Just want to say that the example compiles under 12.1 with no effort. 

 

Then a question, i am getting a code size of 180KB. I have not started tuning the code yet, but do any of you thinks it's possible to get down to 30-40Kb for a simple telnet server? 

I need a small footprint to get it into internal mem. Would make our life much easier. 

 

Apus
0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

 

--- Quote Start ---  

 

Then a question, i am getting a code size of 180KB. I have not started tuning the code yet, but do any of you thinks it's possible to get down to 30-40Kb for a simple telnet server? 

I need a small footprint to get it into internal mem. Would make our life much easier. 

--- Quote End ---  

 

 

My guess as a long-time user of lwIP (going back 10 years now) is that 30-40k will not likely be possible. TCP takes up a good bit of code. I could see 60k possibly. If you find out the smallest you can make it, please post back so others will know what is the smallest possible footprint. 

 

Bill A.
0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

Hi, 

 

I have read through several threads on the subject but haven't been able to find the answer I am looking for. I would like to use lwIP with Altera TSE with no OS to receive TCP. I need to support about 10MB/s (80 Mb/s) shared between multiple TCP connections. There is very little other processing on the NIOS II/f. From reading it seems that if I do the following: 

1) Run out of on chip memory. 

2) Increase Processor clock speed as much as possible (Using Stratix IV) 

3) Add TCP checksum offloading 

4) possibly some other optimizations like endian conversion 

then i should be able to reach that speed but I was wondering if anyone could give me a more firm answer of if this is feasible or not. 

 

 

Thanks, 

Arthur
0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

 

--- Quote Start ---  

Hi, 

 

I have read through several threads on the subject but haven't been able to find the answer I am looking for. I would like to use lwIP with Altera TSE with no OS to receive TCP. I need to support about 10MB/s (80 Mb/s) shared between multiple TCP connections. There is very little other processing on the NIOS II/f. From reading it seems that if I do the following: 

1) Run out of on chip memory. 

 

--- Quote End ---  

 

I would run just select parts - inet_chksum, some of ethernetif, and maybe the oft-used pbuf functions. For a start, move nothing and see how it goes. It's so easy to move functions to on-chip memory there's no urgency to do that up front. 

 

And use code and data cache. 4k each if you can. 

 

--- Quote Start ---  

 

2) Increase Processor clock speed as much as possible (Using Stratix IV) 

3) Add TCP checksum offloading 

 

--- Quote End ---  

 

This is the biggest thing you can do. If not in hardware, using assembly for the checksum is still good. And an optimized memcpy too! The built-in memcpy is OK but can be better. Oh, and the macro SMEMCPY replace with an inline copy - it's always a small copy with a constant size. 

 

--- Quote Start ---  

 

4) possibly some other optimizations like endian conversion 

 

--- Quote End ---  

 

For Cyclone-III the endian opcodes are included for htonl/ntohl. There was none for hton/ntoh - we did our own but I don't know if it's really used enough to matter. 

 

--- Quote Start ---  

 

then i should be able to reach that speed but I was wondering if anyone could give me a more firm answer of if this is feasible or not. 

 

--- Quote End ---  

 

 

Yes, it's feasible. Close but I see not much reason for it not to work. 

 

Bill A
0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

Thanks! Thats a big help and exactly what I was looking for.

0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

Hello fellow adventurers, 

 

I am currently trying to port the FreeRTOS+lwIP environment onto the Stratix-V fpga eval board under the Quartus-II 13.0sp1 toolset. I've already ran into a number of issues, but so far managed to plow through most (tool name changes, some FreeRTOS/lwIP syntax changes after upgrading to latest, etc..). 

 

I was wondering if anyone else has tried running FreeRTOS+lwIP on Stratix V eval board, and if so, how successful were you? 

I am happy to provide feedback/share my findings (assuming we don't scrap this approach and go with Micrium+NicheStack... not my preferred choice). 

 

Thanks for your help! 

sjp
0 Kudos
Altera_Forum
Honored Contributor II
3,522 Views

The following optimization can be applied to lwip_tse_mac.c: 

 

In function tse_sgdmaRx_isr: Replace the init_tset_descriptor function call (spans 6 or 7 lines) just after label _dump: with the following: 

 

IOWR_32DIRECT(&tse_ptr->desc[ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST].write_addr, 0, (u32_t) ethernetif->lwip_rx_pbuf[ethernetif->lwipRxIndexIsr]->payload); 

IOWR_8DIRECT(&tse_ptr->desc[ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST].control, 0, ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK); 

 

I don't claim credit for this - I see they did this in the NIOS 12.1 TSE driver and it makes a lot of sense. 

 

Bill A
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

 

--- Quote Start ---  

You can use the one that the dev kit will use when running e.g. the Interniche examples. If it doesn't come with a MAC address, you will have to use a temporary one but be sure to stay behind a router or directly connected to a PC. I use a real test MAC address from our block of addresses that I know is not in use locally. 

 

Bill 

--- Quote End ---  

 

 

 

ims,can you send your project to me ?I have the same problem with you.my email is 763475917@qq.com,thanks!
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

Dear billa: 

My board can ping it,But I meet another qusetion,I want to use the udp protocol to send and receive message!Unfortunately I can't send.I want to use the board acts as client and send the message to computer.maybe my code lose someting important,could you help me check it?  

waiting for your reply,thank you very much!  

here is my code: 

/* 

* Simple lwIP 1.3.1 example program. 

* Expects no Operating System (NO_SYS=1) 

* lwIP initialization and optional DHCP and WEB server support can be 

* enabled by setting# defines described below. 

* You must plug in your board's MAC address below before compiling! 

* Contributed by: Bill Auerbach lwip@softools.com 

*/ 

 

# include <stdio.h> 

# include <unistd.h> 

# include "system.h" 

# include "sys/alt_timestamp.h" 

# include "sys/alt_alarm.h" 

 

# include "lwip/init.h" 

# include "lwip/netif.h" 

# include "lwip/dhcp.h" 

# include "lwip/tcp.h" 

# include "lwip/udp.h" 

# include "lwip/stats.h" 

# include "lwip/ip_frag.h" 

# include "lwip/ip_addr.h" 

# include "netif/etharp.h" 

# include "string.h"  

# include "INC/alteraTseEthernetif.h" 

 

# include "alt_types.h" 

# include "sys/alt_irq.h" 

 

# define mSdelay(x) usleep(x*1000) 

//#define USE_DHCP 1 

//#define LWIP_UDP 1 

 

# define STATIC_IP IP4_ADDR(&lwipStaticIp,219,245,66,185)  

# define STATIC_NM IP4_ADDR(&lwipnetmask,255,255,255,0)  

# define STATIC_GW IP4_ADDR(&lwipgw,219,245,66,254)  

# define STATIC_DA IP4_ADDR(&destAddr,219,245,66,112) 

 

struct ip_addr lwipStaticIp; 

struct ip_addr lwipnetmask; 

struct ip_addr lwipgw; 

struct ip_addr destAddr; 

 

// Define BUILD_HTTPD to 1 to build the httpserver_raw contrib example 

# define BUILD_HTTPD 1 

 

// Alarm & timer variables - provides a 250mS counter 

void lwipProcessTimers(void); 

void Init_UDP(); 

static alt_alarm lwipAlarm; 

static alt_u32 lwipProcessTimerFlag; 

static alt_u32 lwipTicksPer250mS; 

static alt_u32 lwip250mStimer; 

 

// Alarm callback function. 

alt_u32 lwipAlarmCallback(void* context) 

lwipProcessTimerFlag = 1; // Set flag to process timers 

return lwipTicksPer250mS; 

 

// UDP callback function. 

void UDP_Receive(void *arg, struct udp_pcb *upcb, struct pbuf *p,struct ip_addr *addr, u16_t port)  

{  

struct ip_addr dAddr = *addr; 

if(p != NULL)  

{  

udp_sendto(upcb,p,&dAddr,port);  

pbuf_free(p);  

}  

}  

 

// Define netif for lwIP 

struct netif alteraTseNetif; 

struct udp_pcb *UdpPcbR; 

 

int main() 

char udpdata[] = "UDP has Initialed successfully, begin to transfer!\r\n"; 

static struct ip_addr ip_zero = { 0 }; 

struct pbuf *psend; 

struct udp_pcb *UdpPcbS; 

void httpd_init(void); 

 

mSdelay(1000); 

// test_jtag_uart(); 

 

printf("Running...\n"); 

lwip250mStimer = 0; 

lwipProcessTimerFlag = 0; 

lwipTicksPer250mS = alt_ticks_per_second() / 4; 

if (alt_alarm_start (&lwipAlarm, lwipTicksPer250mS, lwipAlarmCallback, NULL) < 0) 

printf ("System clock is required!\n"); 

for(;; 

 

// Load platform specific MAC address into netif 

alteraTseNetif.hwaddr[0] = 0x00; 

alteraTseNetif.hwaddr[1] = 0x1C; 

alteraTseNetif.hwaddr[2] = 0x23; 

alteraTseNetif.hwaddr[3] = 0x17; 

alteraTseNetif.hwaddr[4] = 0x4A; 

alteraTseNetif.hwaddr[5] = 0xCB; 

 

// Initialize lwIP, Altera TSE and the ethernetif 

lwip_init(); 

if(netif_add(&alteraTseNetif, &ip_zero, &ip_zero, &ip_zero, alteraTseNetif.state, ethernetif_init, ethernet_input) == NULL) 

printf( "Fatal error initializing...\n" ); 

goto fatal; 

netif_set_default(&alteraTseNetif); 

 

// Initialize Altera TSE in a loop if waiting for a link 

printf("Waiting for link..."); 

while(((struct ethernetif *) alteraTseNetif.state)->link_alive!=1) 

mSdelay(1000); 

putchar('.'); 

tse_mac_init(0, alteraTseNetif.state); 

printf("OK\n"); 

 

STATIC_IP; 

STATIC_NM; 

STATIC_GW; 

netif_set_addr(&alteraTseNetif, &lwipStaticIp, &lwipnetmask, &lwipgw); 

//netif_add(&alteraTseNetif, &lwipStaticIp, &lwipnetmask, &lwipgw, NULL, ethernetif_init, ethernet_input); 

//netif_set_default(&alteraTseNetif); 

netif_set_up(&alteraTseNetif); 

printf("IP address: %s\n", ip_ntoa(&alteraTseNetif.ip_addr)); 

printf("IP netmask: %s\n", ip_ntoa(&alteraTseNetif.netmask)); 

printf("IP gateway: %s\n", ip_ntoa(&alteraTseNetif.gw)); 

 

# if BUILD_HTTPD 

httpd_init(); 

# endif 

 

Init_UDP(); 

STATIC_DA; 

printf("UDP Dest IP address: %s\n", ip_ntoa(&destAddr)); 

//psend = pbuf_alloc(PBUF_RAW, sizeof(udpdata), PBUF_POOL); 

psend = pbuf_alloc(PBUF_RAW, sizeof(udpdata), PBUF_RAM); 

psend->payload = (void *)udpdata;  

 

if (!psend) 

printf("Can't allocate buffer.\n"); 

goto fatal; 

}  

 

UdpPcbS = udp_new();  

if (!UdpPcbS) 

printf("udp_new() failed.\n"); 

goto fatal; 

}  

 

udp_bind(UdpPcbS, &lwipStaticIp, 67); 

if (udp_bind(UdpPcbS, &lwipStaticIp, 67) != ERR_OK) 

printf("udp_bind() failed.\n"); 

goto fatal; 

 

udp_connect(UdpPcbS, &destAddr, 67); 

if (udp_connect(UdpPcbS, &destAddr, 67) != ERR_OK) 

printf("udp_connect() failed.\n"); 

goto fatal; 

 

// This is the main loop for lwIP - other processing can be done by calling application functions. 

printf("SUCCESS\n"); 

while(1) 

udp_send(UdpPcbS,psend); 

mSdelay(1000); 

}  

 

fatal: 

for(;; 

/* { 

// Process lwIP timer dependent code 

if(lwipProcessTimerFlag) 

lwipProcessTimers(); 

// Poll lwIP for incoming packets. 

ethernetif_input(&alteraTseNetif); 

}  

return 0; */ 

 

 

//UDP Init  

void Init_UDP() 

UdpPcbR = udp_new();  

udp_bind(UdpPcbR, IP_ADDR_ANY, 67); 

udp_recv(UdpPcbR,UDP_Receive,NULL);  

}  

 

// Run this every 250mS to update lwIP timers 

void lwipProcessTimers(void) 

lwipProcessTimerFlag = 0; 

lwip250mStimer += 250; 

if( (lwip250mStimer % TCP_TMR_INTERVAL) == 0 ) { tcp_tmr(); } 

if( (lwip250mStimer % ARP_TMR_INTERVAL) == 0 ) { etharp_tmr(); } 

# if IP_REASSEMBLY 

if( (lwip250mStimer % IP_TMR_INTERVAL) == 0 ) { ip_reass_tmr(); } 

# endif 

# if LWIP_AUTOIP 

if( (lwip250mStimer % AUTOIP_TMR_INTERVAL ) == 0 ) { autoip_tmr(); } 

# endif 

# if LWIP_IGMP 

if( (lwip250mStimer % IGMP_TMR_INTERVAL ) == 0 ) { igmp_tmr(); }  

# endif 

# if LWIP_DHCP 

if( (lwip250mStimer % DHCP_FINE_TIMER_MSECS ) == 0 ) { dhcp_fine_tmr(); } 

if( (lwip250mStimer % (DHCP_COARSE_TIMER_SECS*1000) ) == 0 ) { dhcp_coarse_tmr(); } 

# endif 

# if LWIP_DNS 

if( (lwip250mStimer % DNS_TMR_INTERVAL) == 0 ) { dns_tmr(); } 

# endif 

}
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

Add Include Path ${workspace_loc:/altera.components/Nios II Software Packages/altera_iniche/UCOSII/inc} 

 

I cannot unstand why? this example use UC/OS???
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

Billa I meet this problem,can anyone help me?thanks 

waiting for your reply,thank you!
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

HI 

I met this problem,how can i solved?can you give me some advices?which path may i chose?
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

Dear Daixiwen 

how does this error happen?can you give some advices?
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

Hi,billa 

cannot insert breakpoint 0 is my problem! 

I use quartus 9.0 and nios 9.0&#65292;and I use this example to build the project http://www.alteraforum.com/forum/showthread.php?t=23787&page=3 

now I can ping the board,but I can not use UDP to send the packget&#65292;so I try to debug step by step,and set the breakpoint at function udpsend().(see in picture1)As I seeing the flow,when it return,until to the function udp_sendto_if() ,pointout wrong(see in picture 2),this problem makes me truble,a week,could you give me some advices. 

best wishes to you,waiting for your reply.thank you!
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

Please stop sending the same question multiple times. It won't get you more answers. 

I rarely use the debugger so I can't be of much help here. For starters is 0xe11fc a valid program address, i.e. an address in your main RAM region? 

IF the address is complete bogus, it could indicate a memory corruption or a head/stack collision.
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

 

--- Quote Start ---  

Hi BillA (and others !), 

 

Really big thanks for your lwip port on altera. 

I have succefully implemented the webserver template with lwip on a bemicro SDK from arrow. 

 

I have a question because i don't know how to do it : 

 

actually i have my sgdma Tx and sgdma Rx mapped on a DDR , 

the same DDR where the CPU data an instruction is mapped. 

 

Now imagine i want to use an onchip ram for sgdma tx and sgdmarx instead of DDR. 

(but CPU still mapped to DDR) 

 

I tried direclty but this is not working. 

 

if you have any idea . 

 

thanks 

--- Quote End ---  

 

 

 

I haven't had much luck getting this to port on the BemicroSDK... do you have any pointers on the changes you needed to make to get it to work?
0 Kudos
Altera_Forum
Honored Contributor II
3,532 Views

 

--- Quote Start ---  

Hi,billa 

cannot insert breakpoint 0 is my problem! 

I use quartus 9.0 and nios 9.0&#65292;and I use this example to build the project http://www.alteraforum.com/forum/showthread.php?t=23787&page=3 

now I can ping the board,but I can not use UDP to send the packget&#65292;so I try to debug step by step,and set the breakpoint at function udpsend().(see in picture1)As I seeing the flow,when it return,until to the function udp_sendto_if() ,pointout wrong(see in picture 2),this problem makes me truble,a week,could you give me some advices. 

best wishes to you,waiting for your reply.thank you! 

--- Quote End ---  

 

 

This kind of error typically means the hardware definition is wrong. Something is wrong with memory, clocks, speeds or something. In the past I've told people that have problems with this example to get a standard Altera example running - like Simple Socket Server as-is on your hardware (create app and BSP with that template). If the Simple Socket Server won't run, this lwIP example will never run either. It's pretty hard to test and debug software with unstable hardware. 

 

BillA
0 Kudos
Reply