> Effectively, I don't describe the functions BEFORE interrupt happen and (oh surprise !),
> it was fnet_fec_output().
> This is my program:
> For now, I have deleted the while loop.
Don't do that. It is essential. You'll cause worse problems, possibly data corruptions. Wait until it is fixed properly.
Your program has nothing to do with the problem. This looks like a bug in the FEC driver where critical data structures aren't being protected against interrupts.
It would be easier to debug if you copied the entire stack dump including the line numbers. The critical part is what LINE in fnet_fec_output was it executing when the interrupt happened.
The more often your code is making FNET send Ethernet messages, the more likely a FEC interrupt will arrive with an ICMP packet at exactly the right time (exactly the wrong time) to show this bug.
You're using FNET 2.3.0 release in Feb 2013. The current version is 2.6.0. This may have been fixed, but there's nothing in the change log indicating this:
Embedded TCP/IP stack: FNET Change Log
The relevant code in FNET 1.1.0
void fnet_eth_output_low(fnet_netif_t *netif, unsigned short type, const fnet_mac_addr_t dest_addr, fnet_netbuf_t* nb)
{
fnet_fec_if_t *ethif = (fnet_fec_if_t *)netif->if_ptr;
fnet_eth_header_t * ethheader;
if((nb!=0)&&(nb->flags & FNET_NETBUF_FLAG_FIRST)&&(nb->total_length<=netif->mtu))
{
while(ethif->tx_buf_desc_cur->status & FNET_HTONS(FNET_FEC_TX_BD_R))
{};
The same code in FNET 2.6.0:
void fnet_fec_output(fnet_netif_t *netif, unsigned short type, const fnet_mac_addr_t dest_addr, fnet_netbuf_t* nb)
{
fnet_fec_if_t *ethif = ((fnet_eth_if_t *)(netif->if_ptr))->if_cpu_ptr;
fnet_eth_header_t * ethheader;
if((nb!=0) && (nb->total_length<=netif->mtu))
{
while(ethif->tx_buf_desc_cur->status & FNET_HTONS(FNET_FEC_TX_BD_R))
{};
It doesn't look like that has changed much between 1.1.0 and 2.6.0.
The problem is most likely that "ethif->tx_buf_desc_cur" has changed somewhere, possibly HERE (why won't this forum let me copy/paste without messing it up completely???):
/* Update pointer to next entry. */
if (ethif->tx_buf_desc_cur->status & FNET_HTONS(FNET_FEC_RX_BD_W))
ethif->tx_buf_desc_cur = ethif->tx_buf_desc
else
ethif->tx_buf_desc_cur++;
while(ethif->reg->TDAR) /* Workaround.*/
{};
ethif->reg->TDAR=1; /* Indicate that there has been a transmit buffer produced.*/
My guess is the interrupt happened between the "ethif->tx_buf_desc_cur++" and the "ethif->reg->TDAR=1". That would increment the pointer, but the FEC wouldn't then advance to that next buffer.
I think that code needs "fnet_isr_lock(); ... fnet_isr_unlock();" around the above section. That's something for Andrey to look at.
I've just looked at how "fnet_isr_lock()" works. Weird. It makes interrupts PENDING, and then has them run later. I'd be interested to know why this code doesn't simply disable the CPU interrupts around critical sections.
Tom