This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LC4357: Missing EMAC RX packets

Part Number: TMS570LC4357
Other Parts Discussed in Thread: DP83848YB

Hello,

I'm using the EMAC module C0 receive channel 0 with RX interrupts enabled. When an interrupt is received it signals a receive RTOS task with a semaphore, then the RX0 interrupts are disabled. The receive task checks for the semaphore, then reads the owner bit to start processing the packet. When it finished it the RX0 interrupt has been re-enabled. Everything works fine, I print out the address of the current buffer descriptor and the RX header pointer. If multiple packets are received all of them are processed, then the task exits with enabling the interrupt. But I know for sure that some of the pockets are missing, not even an interrupt generated for these. In wireshark I can see the packet sent from my computer, but it does not appear on the receive side.

Do anyone experienced something similar whit the emac interface? Is there something that I am still missing that could cause this issue?

I have uploaded my partial code, maybe someone can spot out what I am missing.

Thanks!

#pragma INTERRUPT(emacRxInterrupt, IRQ)
void emacRxInterrupt(void)
{
    disableEmacInterrupts();    ///< According to Technical Reference Manual 32.2.17.3 Proper Interrupt Processing
    hdkif_t * const hdkif = &mHdkifData[0u];

    // Disable RX0 interrupt
    EMACRxIntPulseDisable(hdkif->emac_base, hdkif->emac_ctrl_base, (uint32_t)EMAC_CHANNELNUMBER, (uint32_t)EMAC_CHANNELNUMBER);

    mEmacRxBdIntGenerated = (uint32_t)HWREG(hdkif->emac_base + EMAC_RXCP(EMAC_CHANNELNUMBER));

    EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);                                                ///< Acknowledge RX interrupt

    mEmacRxIntCounter++;

    semaphore_give(&mEmacRxSemaphore);
    enableEmacInterrupts();
}

void rx_task(void)
{
    while (1)
    {
        if (isOk(semaphore_take(&mEmacRxSemaphore, mEmacTaskRxBlockTime)))
        {
            LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: Start! Semaphore Received! Int count: %d, Int BD: %x", mEmacRxIntCounter, mEmacRxBdIntGenerated));

            while ((BYTE_SWAP(currentBufferDescriptor->flags_pktlen) & EMAC_BUF_DESC_OWNER) != EMAC_BUF_DESC_OWNER )
            {
                LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: SOP set! Current BD: %x", currentBufferDescriptor));

                // Start processing the received packet only after SOP(Start Of Packet) received and we have the ownership
                if ((BYTE_SWAP(currentBufferDescriptor->flags_pktlen) & EMAC_BUF_DESC_SOP) == EMAC_BUF_DESC_SOP)
                {
                    if ((BYTE_SWAP(currentBufferDescriptor->flags_pktlen) & EMAC_DSC_FLAG_ERROR_MASK) == 0)
                    {
                        // Check received packet size
                        packetSize = BYTE_SWAP(currentBufferDescriptor->flags_pktlen) & 0xffffu;

                        // Invalidate cache, to not to interfere with new packets in memory
                        _dcacheInvalidateRange_(BYTE_SWAP(currentBufferDescriptor->bufptr), BYTE_SWAP(currentBufferDescriptor->bufptr) + packetSize);

                        LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: Packet arrived, BD: %x, RXHP: %x size: %d\r\n", currentBufferDescriptor, HWREG(hdkif->emac_base + EMAC_RXHDP(EMAC_CHANNELNUMBER)), packetSize));

                        if ((BYTE_SWAP(currentBufferDescriptor->flags_pktlen) & EMAC_BUF_DESC_EOP) != EMAC_BUF_DESC_EOP)
                        {
                            LWIP_DEBUGF(NETIF_DEBUG, ("EMACRX: NO EOP: %x, RXHP: %x\r\n", currentBufferDescriptor, HWREG(hdkif->emac_base + EMAC_RXHDP(EMAC_CHANNELNUMBER))));
                        }

                        if (packetSize > 0u && packetSize <= ETH_MAX_FRAME_SIZE)
                        {
                            pbuf_t *p;
                            p = pbuf_alloc(PBUF_RAW, packetSize, PBUF_POOL);    ///< We allocate a pbuf chain of pbufs from the pool.

                            LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: Packet processing!"));

                            if (NN(p))
                            {
                                memcpy(p->payload, (void *)(BYTE_SWAP(currentBufferDescriptor->bufptr)), packetSize);

                                eth_hdr_t *ethhdr;
                                ethhdr = p->payload;

                                switch (htons(ethhdr->type))
                                {
                                // IP or ARP packet?
                                case ETHTYPE_ARP:
                                case ETHTYPE_IP:
                                    // full packet send to tcpip_thread to process
                                    if (mLwipRuntimeData.netif.input(p, &mLwipRuntimeData.netif) != ERR_OK)
                                    {
                                        LWIP_DEBUGF(NETIF_DEBUG, ("ifx_netif_input: IP input error\n"));
                                        pbuf_free(p);
                                        p = NULL;
                                    }
                                    break;

                                default:
                                    LWIP_DEBUGF(NETIF_DEBUG, ("ifx_netif_input: type unknown\n"));
                                    pbuf_free(p);
                                    p = NULL;
                                    break;
                                }
                            }
                            else
                            {
                                LWIP_DEBUGF(NETIF_DEBUG, ("EMACRX: pbuf allocation error\n"));
                            }
                        }
                        else
                        {
                            LWIP_DEBUGF(NETIF_IN_DEBUG, ("Too large: %d\n", packetSize));
                        }

                        mEmacRxBdAcknowledged = (uint32_t)currentBufferDescriptor;
                        HWREG(hdkif->emac_base + EMAC_RXCP(EMAC_CHANNELNUMBER)) = (uint32_t)currentBufferDescriptor;        ///< To acknowledge BD
                        LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: Acknowledged BD[1]: %x", mEmacRxBdAcknowledged));

                        volatile emac_rx_bd_t *currentBufferDesListStart = currentBufferDescriptor;
                        while((BYTE_SWAP(currentBufferDescriptor->flags_pktlen) & EMAC_BUF_DESC_EOP) != EMAC_BUF_DESC_EOP)
                        {
                            currentBufferDescriptor->bufoff_len = BYTE_SWAP(ETH_MAX_FRAME_SIZE);
                            currentBufferDescriptor->flags_pktlen = BYTE_SWAP(EMAC_BUF_DESC_OWNER);
                            currentBufferDescriptor = (emac_rx_bd_t *)BYTE_SWAP((uint32_t)currentBufferDescriptor->next);

                            mEmacRxBdAcknowledged = (uint32_t)currentBufferDescriptor;
                            HWREG(hdkif->emac_base + EMAC_RXCP(EMAC_CHANNELNUMBER)) = (uint32_t)currentBufferDescriptor;        ///< To acknowledge BD
                            LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: Acknowledged BD[2]: %x", mEmacRxBdAcknowledged));
                        }

                        // free up the current BD
                        currentBufferDescriptor->bufoff_len = BYTE_SWAP(ETH_MAX_FRAME_SIZE);
                        currentBufferDescriptor->flags_pktlen = BYTE_SWAP(EMAC_BUF_DESC_OWNER);
                        volatile emac_rx_bd_t *currentBufferDescTemp = (emac_rx_bd_t *)BYTE_SWAP((uint32_t)currentBufferDescriptor->next);
                        currentBufferDescriptor->next = NULL;

                        // update the linked list
                        tailBufferDescriptor->next = (emac_rx_bd_t *)BYTE_SWAP((uint32_t)currentBufferDesListStart);

                        // Check if we are at the end of queue
                        if ((BYTE_SWAP(tailBufferDescriptor->flags_pktlen) & EMAC_BUF_DESC_EOQ) == EMAC_BUF_DESC_EOQ)
                        {
                            while (HWREG(hdkif->emac_base + EMAC_RXHDP(EMAC_CHANNELNUMBER)) != 0u) { task_sleep((sysTimeDuration_t)DURATION_MS(1)); }
                            // Restart EMAC reception with updating the head pointer
                            HWREG(hdkif->emac_base + EMAC_RXHDP(EMAC_CHANNELNUMBER)) = (uint32_t)currentBufferDescriptor;
                            LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: RX restarted at BD: %x\r\n", currentBufferDescriptor));
                        }
                        tailBufferDescriptor = currentBufferDescriptor;
                        currentBufferDescriptor = currentBufferDescTemp;

                        LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: End of packet!"));
                    }
                    else
                    {
                        LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: Packet error!"));
                    }
                }
                else
                {
                    LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: BD no SOP found!"));
                    break;
                }
            }

            // Re-enable RX0 interrupt
            EMACRxIntPulseEnable(hdkif->emac_base, hdkif->emac_ctrl_base, (uint32_t)EMAC_CHANNELNUMBER, (uint32_t)EMAC_CHANNELNUMBER);

            LWIP_DEBUGF(NETIF_IN_DEBUG, ("EMACRX: End!"));
        }
        else
        {
            // We didn't receive semaphore inside the given blocking time, but the head pointer is on the next location -> IRQ lost
            if (HWREG(hdkif->emac_base + EMAC_RXHDP(EMAC_CHANNELNUMBER)) == 0u)
            {
                // Restart EMAC reception with updating the head pointer
                HWREG(hdkif->emac_base + EMAC_RXHDP(EMAC_CHANNELNUMBER)) = (uint32_t)currentBufferDescriptor;
                LWIP_DEBUGF(NETIF_DEBUG, ("EMACRX: IRQ lost RX restarted at BD: %x\r\n", currentBufferDescriptor));
            }
        }
    }
}

  • But I know for sure that some of the pockets are missing, not even an interrupt generated for these.

    I haven't yet studied your code, but the EMAC module has some Network Statistics Registers described in the TMS570LC43x 16/32 RISC Flash Microcontroller Technical Reference Manual (Rev. A).

    Have you tried looking at the Network Statistics Registers for signs of errors?

    Since wireshark shows the packets being transmitted from your PC, are any of the following showing non zero values, which would indicate the EMAC was unable to receive the frames:

    • 32.5.50.34 Receive FIFO or DMA Start of Frame Overruns Register (RXSOFOVERRUNS) (offset = 284h)
    • 32.5.50.35 Receive FIFO or DMA Middle of Frame Overruns Register (RXMOFOVERRUNS) (offset = 288h)
    • 32.5.50.36 Receive DMA Overruns Register (RXDMAOVERRUNS) (offset = 28Ch)
  • I have checked the Network Statistics Registers. There's no sign of any kind of error indicating lost packets. I've made a test run for about 1 minute, there were 3 packets missing on the receive side, but no sign of it in the statistics.

  • Hi Marton,

    We have two demo projects: lwip demo, and active webserver demo. 

  • I've found out that if Half Duplex mode is enabled there are no missing packets with either 10 or 100 Mbps. If I re-enable full duplex mode with both speed options the packet miss issue is back.

    Could it be some hardware issue, or some issue with the PHY?
    The PHY used is a DP83848YB.

  • I've found out that if Half Duplex mode is enabled there are no missing packets with either 10 or 100 Mbps. If I re-enable full duplex mode with both speed options the packet miss issue is back.

    Are the PHYs at both ends of the link set to auto-negotiate?

    If not, perhaps you are suffering from Effects of duplex mismatch

    In your previous screen shot of the Network Statistics Registers there was a non-zero value for Transmit Carrier Sense Errors Register (TXCARRIERSENSE). Is the value of EMAC_TXCARRIERSENSE increasing when packets are lost?

  • Thank you Chester for the help. The TXCARRIERSENSE is constantly incrementing when I set my ethernet adapter to Full Duplex mode, and this time I have missing packets. I've figured out that my EMAC is only initialized once after boot, and I use auto negotiation feature of the DP83848YB. But it failed to do the auto-negotiation in the given time window, so the wrong (default) duplex mode was detected (half-  instead of full-duplex). So my issue as you thought was duplex mismatch. I've set the EMAC at startup to fixed 100Mbps-FDX, and it works now.