[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lwip-users] Deinitializing the LwIP stack

From: OK2NMZ
Subject: [lwip-users] Deinitializing the LwIP stack
Date: Wed, 21 Aug 2013 14:21:24 -0700 (PDT)

Hello everyone,
 I have been struggling for several days making work LwIP stack HEAD version
with CoOS RTOS from CooCox on LPC1768 NXP microcontroller.
After many problems with memory allocation and SRAM fragmentation (I have
only 32+32kB of memory) I decided to use POOLs in my system.
Nevertheless, sometimes, when I send a lot of traffic to my device, ICMP
echoes (PING) stops to work... The interesting thing is, that my telnet
server keeps running (I can disconnect, connect etc...). I have noticed,
that the problem occurrs SOMETIMES when my system runs low on memory. I
suspect the function low_level_output to somehow badly allocate and free the
pbufs, but I cant figure out how...

Since I really need something robust (the problem occurs really rarely, but
it does), I have for now implemented the LwIP deinitialization. Here is what
I basicaly do:
- I disable ethernet interrupt, I deinit the MCU MAC interface.
- I send a message to a "manager" thread, where I then kill the thread where
the uni-threaded version (NO_OS) is running.
- I clear all pointers to TCP connections to NULL (I added this to
tcp_init() function, which is being called on lwip init)
- during memp_init(), I clear entirely the memp pools.

The system is capable of reseting many times, each time it restarts with no
The beautiful thing I appreciate in this approach is, that I dont need to
reset the whole MCU, other tasks can keep running. I only kill and restart
the TCP/IP stack if needed.

Do you think, that my lwip "deinit" is correct? Should I add something?

Thank you for your suggestions, if you are trying to implement something
simillar, I can share some code with you.

I attach the lpc_low_level_output() function, which I suspect from bad
behavior (sometimes, rarely):

Thank you,

static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p) {
        struct lpc_enetdata *lpc_enetif = netif->state;
        struct pbuf *q;
        u8_t *dst;
        u32_t idx, sz = 0;
        err_t err = ERR_OK;
        struct pbuf *np;
        u32_t dn, notdmasafe = 0;

        /* Zero-copy TX buffers may be fragmented across mutliple payload
         chains. Determine the number of descriptors needed for the
         transfer. The pbuf chaining can be a mess! */
        dn = (u32_t) pbuf_clen(p);

        /* Test to make sure packet addresses are DMA safe. A DMA safe
         address is once that uses external memory or periphheral RAM.
         IRAM and FLASH are not safe! */
        for (q = p; q != NULL; q = q->next)
                notdmasafe += lpc_packet_addr_notsafe(q->payload);

        /* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be
         created that will be used instead. This requires an copy from the
         non-safe DMA region to the new pbuf */
        if (notdmasafe) {
                /* Allocate a pbuf in DMA memory */
                np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
                if (np == NULL)
                        return ERR_MEM;

                /* This buffer better be contiguous! */
                LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is 
                                (pbuf_clen(np) == 1));

                /* Copy to DMA safe pbuf */
                dst = (u8_t *) np->payload;
                for (q = p; q != NULL; q = q->next) {
                        /* Copy the buffer to the descriptor's buffer */
                        MEMCPY(dst, (u8_t *) q->payload, q->len);
                        dst += q->len;
                np->len = p->tot_len;

                                ("lpc_low_level_output: Switched to DMA safe 
buffer, old=%p, new=%p\n",
q, np));

                /* use the new buffer for descrptor queueing. The original pbuf 
                 be de-allocated outsuide this driver. */
                p = np;
                dn = 1;
        if (notdmasafe)
        LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf", (notdmasafe ==

        /* Wait until enough descriptors are available for the transfer. */
        while (dn > lpc_tx_ready(netif))
#if NO_SYS == 0
                sys_arch_sem_wait(&(lpc_enetif->xTXDCountSem), 0);

        /* Get free TX buffer index */
        idx = LPC_EMAC->TxProduceIndex;

#if NO_SYS == 0
        /* Get exclusive access */

        /* Prevent LWIP from de-allocating this pbuf. The driver will
         free it once it's been transmitted. */
        if (!notdmasafe)

        /* Setup transfers */
        q = p;
        while (dn > 0) {

                /* Only save pointer to free on last descriptor */
                if (dn == 0) {
                        /* Save size of packet and signal it's ready */
                        lpc_enetif->ptxd[idx].control = (q->len - 1) | 
                                        | EMAC_TCTRL_LAST;
                        lpc_enetif->txb[idx] = q;
                } else {
                        /* Save size of packet, descriptor is not last */
                        lpc_enetif->ptxd[idx].control = (q->len - 1) | 
                        lpc_enetif->txb[idx] = NULL;

                                ("lpc_low_level_output: pbuf packet(%p) sent, 
                                                " size = %d (index=%d)\n", 
q->payload, dn, q->len, idx));

                lpc_enetif->ptxd[idx].packet = (u32_t) q->payload;

                q = q->next;

                if (idx >= LPC_NUM_BUFF_TXDESCS)
                        idx = 0;

        LPC_EMAC->TxProduceIndex = idx;


#if NO_SYS == 0
        /* Restore access */

        return ERR_OK;

View this message in context: 
Sent from the lwip-users mailing list archive at Nabble.com.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]