Hi,
I'm having problems with iwIP as supplied in StarterWare 2.00.00.05 for the AM335x and targeted to the BeagleBone.
I made a very simple change to the example program "enetEcho" to add a periodic broadcast of a UDP packet every 1/2 second.
Here is the code segment with what I added: (in bold)
..... SNIP ......
/* Initialize the sample httpd server. */ echo_init();
struct udp_pcb* pcb = udp_new(); struct pbuf *p; udp_bind(pcb, IP_ADDR_ANY, 1235); char msg[80]; int packet = 0;
/* Loop forever. All the work is done in interrupt handlers. */ while(1) {
packet++; p = pbuf_alloc(PBUF_TRANSPORT, sizeof(msg), PBUF_RAM); // allocate a pbuf, (ref=1) if (!p || 1!=p->ref) { UARTPuts("pbuf_alloc failed!\n", -1); while (1) ; } sprintf(msg, "test packet %d", packet); memcpy(p->payload, msg, strlen(msg)); UARTprintf("packet %d, PBuf at 0x%08X, ref = %d sending...", packet, p, p->ref); udp_sendto(pcb, p, IP_ADDR_BROADCAST, 1234); delay(500); // half second delay - should have plenty of time to send UARTprintf("ref is now %d \n", p->ref); pbuf_free(p); // ref should be zero after we free. }}
This works great for about 30 packets or so. Then suddenly they stop being sent. Below is a typical output:
StarterWare AM335x Boot LoaderCopying application image from MMC/SD card to RAMAcquiring IP Adress...EVM IP Address Assigned: 192.168.9.106packet 1, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 2, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 3, PBuf at 0x80018060, ref = 1 sending...ref is now 1.... and so on....
packet 21, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 22, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 23, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 24, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 25, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 26, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 27, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 28, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 29, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 30, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 31, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 32, PBuf at 0x80018060, ref = 1 sending...ref is now 1packet 33, PBuf at 0x80018060, ref = 1 sending...ref is now 2packet 34, PBuf at 0x80018100, ref = 1 sending...ref is now 2packet 35, PBuf at 0x800181a0, ref = 1 sending...ref is now 2packet 36, PBuf at 0x80018240, ref = 1 sending...ref is now 2
I can monitor the packets on the wire, and in this case, the last one sent was number 32. This is consistient with the reference count not being decremented on packet 33. Sometimes it will make it to 50 packets before the stack dies, but never much longer.
Further investigation revealed that the interrupt handler that should be called after transmission stops being called after so many packets... But why? Any Ideas would be very welcome! I hope I haven't made some silly assumption on the use of lwIP under StarterWare.
Cheers,
-Jay
Hi Jay,
At last it worked for me with a small change in tx buffer descriptor configuration !
In /third_party/lwip-1.3.2/ports/am335x/netif/sitaraif.c, define a macro,
#define CPDMA_BUF_DESC_TO_PORT(port) ((port << 16) | 0x100000)
and in sitaraif_transmit() function, replace the line
curr_bd->flags_pktlen |= ((CPDMA_BUF_DESC_SOP | CPDMA_BUF_DESC_OWNER)
with
curr_bd->flags_pktlen |= ((CPDMA_BUF_DESC_SOP | CPDMA_BUF_DESC_OWNER) |CPDMA_BUF_DESC_TO_PORT(1));
Could you please verify this ? (The additional flag indicates to which port it has to send, But it is not mandatory. And EVM works without this change !)
We will include the above changes in next StarterWare release.
Regards,
Sujith.
Hello Sujith,
That fixes the problem for me too! Many Many thanks!!
It is very strange that the problem doesn't come up with the EVM. Could that be because the unused interface is differently terminated on the beaglebone?
May be. We can also try the experiment by removing all the configuration for the unused port in sitaraif.c.
Hi Sujith,
I've been reviewing the code in sitaraif.c. It looks like the flags in the buffer descriptor are uninitialized at the point of use at the beginning of sitarif_transmit.
Would it not be more defensive to initilize the entire flags_pktlen word to zero rather than just clearing the least significant 16 bits? That is, change:
curr_bd->flags_pktlen &= ~0xFFFF; curr_bd->flags_pktlen |= pbuf->tot_len;
to:
curr_bd->flags_pktlen = 0; curr_bd->flags_pktlen |= pbuf->tot_len;
or perhaps better:
curr_bd->flags_pktlen = 0x3FF & pbuf->tot_len; // clear flags and set 10 bit total length
I do see that the flags are cleared when the descriptors are inititially created, but I think that it is generally better to initialize things at the point of use rather than rely on them being already initialized.
Also, would it be good to use the actual port number used (To_Port) in the buffer descripter flags rather than the a #define constant? sitaraif_transmit is passed a pointer to the sitaraif structure so we know what port it should be goint to using its port field, so we would use:
curr_bd->flags_pktlen |= ((CPDMA_BUF_DESC_SOP | CPDMA_BUF_DESC_OWNER) | CPDMA_BUF_DESC_TO_PORT(sitarif->port));
instead of:
curr_bd->flags_pktlen |= ((CPDMA_BUF_DESC_SOP | CPDMA_BUF_DESC_OWNER) | CPDMA_BUF_DESC_TO_PORT(1));
Just some thoughts. I'm just happy it is now working well! I had it run over the weekend and it still going. So I'm sure you squashed that bug.
Thank you very much for your valuable inputs.
[Jay :Would it not be more defensive to initilize the entire flags_pktlen word to zero rather than just clearing the least significant 16 bits? That is, change:]
You are correct. its better if we give curr_bd->flags_pktlen = 0.
[Jay: Also, would it be good to use the actual port number used (To_Port) in the buffer descripter flags rather than the a #define constant? sitaraif_transmit is passed a pointer to the sitaraif structure so we know what port it should be goint to using its port field, so we would use:]
Yes, we have to give sitaraif->port as you explained. I wanted to verify if that works. Anyway, this shall be properly given in the next release.
Trying to run starterware 2.0.0.6 with Beaglebone. On console i get "Acquiring IP address " and seems to be hanging there.
Using wireless router as dhcp server for providing IP address to the board.
Need some help here.
This fix has helped us also(for IDK). The application was crashing consistently while using a particular feature of EthernetIP Protocol. On debugging, it pointed out to the rx_handler where curr_bd->next was a null pointer. Incorporating
the above change has helped in solving this issue.
Also, we have used lwip v1.4.0, and an interesting bug came up(in SYS/Bios). v1.4.0, unlike v1.3.2 uses mutexes to manage the mem_alloc(in mem.c). As we are processing rx in the context of interrupts, these gate mutexes are being called from the ISR, leading to a crash.
Thanks once again!
Regards,Vinesh