The nitty gritty of EK-TM4C1294XL MPU resets during TCP transmit / receive. Random halts during EMAC transmit when two separate IP struct lists bind into TCP stack allowing separate multiple TCP ports to exist in virtual EMAC PCB memory pool space. Sometimes an LWIP debug STAT message follows: Assert Fails (p = !NULL), PCB (p->1), but not always. The allocator de-allocator often have or show LWIP debug Assert Panic Sanity as sane when not at all sane.
One issue an orphaned configured EMAC transmit interrupt and seemingly unbalanced interrupt handling in the EMAC.
A few minor code changes in PHY interrupt handling and DMA descriptor intermediate PBUF storage (type) SRAM seem to help in the Fickle LWIP memory management obscure payload-> [methods]. Seems to make since the DMA scatter gather process intermediate (type) {RAM_POOL} leaving LWIP priority at the network transport layers to manage {PBUF_POOL} PBUFS. LWIP allocating / de-allocating PBUFS to the pool via descriptor Blocks previously stored in SRAM at the hardware data link and physical layers. A very complicated packet handling schema indeed. The oddest part (tiva-tm4c129.c) snatches incoming receive frames and attaches available PBUFS with previously assigned receive descriptors passing them up to LWIP.
4.28.2015: Must add proper include path for (tiva-tm4c129.c) to find NETIF_DEBUG==1 in (lwipopts.h).
{${SW_ROOT}/third_party/lwip-1.4.1/ports/tiva-tm4c129}
Type PBUF_RAM uses mem_free() call found inside pbuf_free() also appears to have timing issues. Systick 2.5us LWIP timer interval range (5-10ms) often cause random MPU Resets or the Exosite client Halts during pbuf_free(). Yet at times the Telnet client will still be functional as if noting has gone wrong in TCP stack.
ASSERT_FAIL at line 825 of C:/Software/Tivaware/TivaWare_C_Series-2.1.0.12573/third_party/lwip-1.4.1/src/core/ipv4/ip.c: p->ref == 1
ASSERT_FAIL at line 668 of C:/Software/Tivaware/TivaWare_C_Series-2.1.0.12573/third_party/lwip-1.4.1/src/core/ipv4/ip.c: p->ref == 1
ASSERT_FAIL at line 339 of C:/Software/Tivaware/TivaWare_C_Series-2.1.0.12573/third_party/lwip-1.4.1/src/core/mem.c: mem_free: mem->used
ASSERT_FAIL at line 651 of C:/Software/Tivaware/TivaWare_C_Series-2.1.0.12573/third_party/lwip-1.4.1/src/core/pbuf.c: pbuf_free: p->ref > 0
* 5.3.2015: The other issue is type {PBUF_POOL} is falling through invoking mem_free() (RAM_POOL) during pbuf_free() versus memp_free() no matter if {MEMP_MEM_MALLOC == 1 or 0}. That seems to contradict the way the code is written in pbuf_free() to explicitly invoke memp_free() for (pbuf_pool) type Macro definition. Seems as if CCS5 may be linking the wrong Macro confusing anyone who trouble shoots Heap memory related issues involving (pbuf.c).
LWIP 1.4.1 Seemingly has timing issues that effect DMA transfers and can not pass the litmus test when NETIF is being heavily tasked at high speeds with multiple TCP struct port list bindings.
Also read packet drops LWIP timeout errors:
https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/412465
(tiva-tm4c129.c) for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++) { g_pRxDescriptors[ui32Loop].pBuf = pbuf_alloc(PBUF_TRANSPORT, PBUF_POOL_BUFSIZE, PBUF_RAM); //was PBUF_POOL /* This buffer is outside the DMA-able memory space so we need * to copy the pbuf. */ pBuf = pbuf_alloc(PBUF_TRANSPORT, p->tot_len, PBUF_RAM); /* Allocate a new buffer for this descriptor */ pDescList->pDescriptors[pDescList->ui32Read].pBuf = pbuf_alloc(PBUF_TRANSPORT, PBUF_POOL_BUFSIZE, PBUF_RAM); //was PBUF_POOL
4.22.2015
Found a hidden Macro clokes the PBUF_POOL(type), defined in (memp_std.h) description "PBUF_POOL"
/* * A list of pools of pbuf's used by LWIP. * * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) * creates a pool name MEMP_pool_name. description is used in stats.c * This allocates enough space for the pbuf struct and a payload. * (Example: pbuf_payload_size=0 allocates only size for the struct) */ LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM") LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL")
(pbuf.c) struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { struct pbuf *p, *q, *r; u16_t offset; s32_t rem_len; /* remaining length */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); /* determine header offset */ switch (layer) { case PBUF_TRANSPORT: /* add 56 bytes room for transport (often TCP) layer header */ offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; break; case PBUF_IP: /* add room for IP layer header */ offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; break; case PBUF_LINK: /* add room for link layer header */ offset = PBUF_LINK_HLEN; break; case PBUF_RAW: offset = 0; break; default: LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); return NULL; }
(tiva-tm4c129.c) Interrupt source set for {EMAC_INT_TX_STOPPED} Orphaned Netif interrupt had no vector - added to transmit below. Called from tivaif_init() static void tivaif_hwinit(struct netif *psNetif) { /* Enable the Ethernet RX and TX interrupt source. */ EMACIntEnable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT | EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER | EMAC_INT_RX_STOPPED | EMAC_INT_PHY)); void tivaif_interrupt(struct netif *psNetif, uint32_t ui32Status) { tStellarisIF *tivaif; /* Process the transmit DMA list, freeing any buffers that have been * transmitted since our last interrupt. We also call this function in cases * where the transmitter has stalled due to missing buffers and break to * to avoid a hanging interrupts for descriptors that have no pbufs attached. */ if(ui32Status & (EMAC_INT_TRANSMIT | EMAC_INT_RX_NO_BUFFER |
EMAC_INT_TX_STOPPED)) { tivaif_process_transmit(tivaif); } /** * Process the receive DMA list and pass all successfully received packets * up the stack. We also call this function in cases where the receiver has * stalled due to missing buffers since the receive function will attempt to * allocate new pbufs for descriptor entries which have none. */ if(ui32Status & (EMAC_INT_RECEIVE | EMAC_INT_RX_NO_BUFFER | EMAC_INT_RX_STOPPED)) { tivaif_receive(psNetif); } }