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.

RTOS/TM4C1292NCPDT: TcpTimeoutRexmt: Retransmit Timeout -Error while communicating to external system in 100 Mbps

Part Number: TM4C1292NCPDT

Tool/software: TI-RTOS

Hi,

In my application Modbus TCP protocol stack is integrated with TI RTOS and it was working well earlier. i.e. we will be able to continuously perform read/write operating on modbus tcp commands. Now we have been observing below error message in the console and there after that no response for even ping command.

00035.600 TcpTimeoutRexmt: Retransmit Timeout

00039.200 TcpTimeoutRexmt: Retransmit Timeout
00041.100 TcpTimeoutRexmt: Retransmit Timeout
00041.800 TcpTimeoutRexmt: Retransmit Timeout
00046.900 TcpTimeoutRexmt: Retransmit Timeout
00048.100 TcpTimeoutRexmt: Retransmit Timeout
00048.800 TcpTimeoutRexmt: Retransmit Timeout
00051.300 TcpTimeoutRexmt: Retransmit Timeout
00056.800 TcpTimeoutRexmt: Retransmit Timeout
00062.400 TcpTimeoutRexmt: Retransmit Timeout

we are using following version of TI software.

tirtos_tivac_2_16_01_14

bios_6_45_02_31

ndk_2_25_00_09

tidrivers_tivac_2_16_01_13

TivaWare_C_Series-2.1.4.178

The followings are default parameters used in my configuration.

/* ================ NDK configuration ================ */
var Ndk = xdc.loadPackage('ti.ndk.config');
var Global = xdc.useModule('ti.ndk.config.Global');
var Ip = xdc.useModule('ti.ndk.config.Ip');
var Udp = xdc.useModule('ti.ndk.config.Udp');
var Tcp = xdc.useModule('ti.ndk.config.Tcp');

Global.IPv6 = false;
Global.stackLibType = Global.MIN;
Global.networkOpenHook = "&netOpenHook";

/* automatically call fdOpen/CloseSession for our sockets Task */
Global.autoOpenCloseFD = true;


Global.pktNumFrameBufs = 10;
Global.memRawPageCount = 6;
Global.ndkThreadStackSize = 1536;
Global.lowTaskStackSize = 1024;
Global.normTaskStackSize = 1024;
Global.highTaskStackSize = 1024;
Tcp.transmitBufSize = 1024;
Tcp.receiveBufSize = 1024;

i have tried increasing the Buffer size to 4096 also but still observing the same behavior.

can anyone suggest what could be the reason for this behavior?

Regards

Bala

  • Hi Bala,
    What was changed in your code? You said that it was working well earlier. Have you checked your network (firewall setting)? Can you reproduce on different boards? Will the TivaWare ethernet or any TI-RTOS ethernet examples still work in your network?
  • Hi Charles,

    we have added one more task for processing analog input samples. this samples will be collected through SPI-DMA interface for processing. This task will run in the context of DMA interrupt and DMA interrupt frequency is 3.3ms interval. and task would take approximately 500 microsecond for processing the data for every dma interrupt.

    My system is running on 120MHz frequency. so i am sure cpu bandwidth may not be the issue.

    TI RTOS example tcpecho is working good.

    Initially i thought it could be the some memory issue due to newly added task, so i have tried increasing the buffer size. but still it does not work.

    Regards
    Bala
  • Hi Bala,
    So without the SPI-DMA task the program will always work. Is that a correct understanding? is the BIOS managing your SPI-DMA interrupt or you are mixing BIOS-managed and non-BIOS-managed interrupts together?
  • Hello Charles,

    >>>So without the SPI-DMA task the program will always work. Is that a correct understanding? 

    - Yes. Your understanding is correct.

    >>> is the BIOS managing your SPI-DMA interrupt or you are mixing BIOS-managed and non-BIOS-managed interrupts together?

    -what you meant by BIOS-managed and non-BIOS-managed interrupts? 

    i am used to configure the ISR through .cfg file as like below.

    Regards

    Bala

  • Hi Bala,
    You have the BIOS managing your interrupts.

    Does the SPI-DMA task work after you added the task? Or both the SPI-DMA and the Ethernet failed?

    What if you only keep the SPI-DMA task and not the Ethernet task will the SPI-DMA work?
  • Hello Charles,
    through variable watch i can see SPI-DMA is working good in both the cases. only Ethernet is getting failed. some more observation are here today.
    The followings are working behavior.
    - when Ethernet cable is connected while power on the Unit, after that the link can be dynamically changed .
    Non-Working behavior
    - device is not connected with Ethernet cable, and trying to connect it run time. while connecting that moment after there no expected behavior in the Unit and not able to establish the Ethernet connection.
    i am suspecting this could be the same problem which i discussed in the forum earlier.

    e2e.ti.com/.../661878


    somehow it was solved earlier and now I am facing the same issue it seems.
    I also posted my code for review in the earlier forum which I changed to configure the external Ethernet switch especially on EmacSnow.c.

    it would be helpful, If you can point me where I am doing mistake.

    Regards
    Bala
  • HI Bala,
    Just thinking out load, you are interfacing with your external PHY via the SPI interface. I just wanted to make sure that your SPI-DMA setup for the external analog input sampling is not using the same SPI as for the external PHY.

    You said that at one point of time the problem was solved. Was the problem solved at one point of time with the SPI-DMA included or excluded?

    Can you repeat the same problem as you described in the other post without the SPI-DMA? If you think that your current problem is the same as in the other post without the SPI-DMA then can you somehow revert to the identical code that you had at one point of time when you solved the problem provided that you have some version control of your programs and you know which version to fall back to.
  • Balasubramani C said:

    Now we have been observing below error message in the console and there after that no response for even ping command.

    00035.600 TcpTimeoutRexmt: Retransmit Timeout

    Can you add the following to the CCS Expressions view:

    'EMACSnow.c'::EMACSnow_private

    And expand the structure and select the "Continuous Refresh" option and watch for any change in the following counts when attempt the ping command:

        uint32_t         rxCount;
        uint32_t         rxDropped;
        uint32_t         txSent;
        uint32_t         txDropped;
        uint32_t         abnormalInts;
        uint32_t         isrCount;

    That will give an indication if the NDK is attempting to receive or transmit any Ethernet packets after the failure has occurred.

  • Hello Charles,

    >>>>Just thinking out load, you are interfacing with your external PHY via the SPI interface. I just wanted to make sure that your SPI-DMA setup for the external analog input sampling is not using the same SPI as for the external PHY.
    - Yes. Both are separate SPI Interface.

    >>>>You said that at one point of time the problem was solved. Was the problem solved at one point of time with the SPI-DMA included or excluded?
    - No that time SPI-DMA is excluded.

    >>>Can you repeat the same problem as you described in the other post without the SPI-DMA? If you think that your current problem is the same as in the other post without the SPI-DMA then can you somehow revert to the identical code that you had at one point of time when you solved the problem provided that you have some version control of your programs and you know which version to fall back to.
    - i will check the older version code and revert back.

    Regards
    Bala
  • Hi Chester,

    Than you for your suggestion. i have checked using CCS expression. but i could not locate the issue. during dead no change in the variables.

    please refer the snapshot while system is in unresponsiveness.

    Regards

    Bala

  • Balasubramani C said:
    i have checked using CCS expression. but i could not locate the issue. during dead no change in the variables.

    From the screenshot can't tell the cause of the problem, as there are no dropped packets or abnormal interrupts reported.

    Can you try enabling the "Continuous Refresh" option in the CCS expressions view (highlighted in red in the example below) before the failure has occurred and watch the updates (highlighted in yellow) and determine the last value which changes prior to the failure?

  • Hi,

    sorry for the late reply. this time i have come up with some more data which might help to solve this issue.

    Its the problem with PC which is connected to my testing device. i have not seen this problem "TcpTimeoutRexmt: Retransmit Timeout" when i connected to windows 10 OS installed PC where as i can get this timeout error in windows 7 OS installed PC.

    i am attaching the network advance settings come with default parameters. in particularly flow control enable/disable.

    Window 7 OS Settings

    Window 10 OS Settings


    if i tried changing the flow control disabled in windows 10 PC, then i am getting the transmit timeout error but the frequency for this error is minimum when compared to windows 7 PC.

    There are some other parameters like Transmission buffers and Receive Buffers are also different in both the OS.

    so i am suspecting that am i missing some NDK configuration which need to be tuned to support standard network operation?

    Regards

    Bala

  • Hi Bala,

     If you enable flow control on the Windows 7, does it make a difference? I think with the flow control enabled, your Network Adapter will be able to send pause frame to the board to pause the transmission until its buffer is free. I'm not sure if your NIC in the Windows 7 machine is of high speed one. Could this be the reason behind your Windows 7 vs Windows 10 results? Are you sending a lot of data to the PC from your board? For experiment, if you slow down the modbus transmission to the PC does it make a difference? Remember in your very first post, you mentioned all was working well at one time. Is it possible that you have changed the throughput of the data leading to the retransmission?

     Please take a look at this post here which may be helpful. Even though this post pertains to the NDK used on a Sitara processor but it talks about changing below two defines and the result was positive.

    #define TCPTV_RTXMIN            10 (       /* minimum value retransmit timer */

    (old value: 2)

    #define TCPTV_MINIMALMAXRTT     10       /* maximum allowed RTT default (.1 sec) */

    (old value: 2)

  • Hello Charles,

    >>>If you enable flow control on the Windows 7, does it make a difference? 

    - No. if i disable also i will be getting the same error in window 7 PC.

    >>> I'm not sure if your NIC in the Windows 7 machine is of high speed one. Could this be the reason behind your Windows 7 vs Windows 10 results?

    - Both NIC card is from same vendor. The only difference here is Windows operating system.

    >>> Are you sending a lot of data to the PC from your board? For experiment, if you slow down the modbus transmission to the PC does it make a difference? 

    - we are using same application in both the PC to generate the Modbus packets. normally the application is designed such way that PC will send the modbus packet and wait for the response from DUT before sending the another packet. So without response from DUT PC will not initiate another packet.

    Please refer the wireshark capture for good and bad behavior.

    >>>Remember in your very first post, you mentioned all was working well at one time. Is it possible that you have changed the throughput of the data leading to the retransmission?

    - That was for different issue. i.e. some timing issue for configuring external PHY. from the beginning of the development, we are testing with window 10 PC. we recently switched to windows 7 PC and finding the issues.

    >>>Please take a look at this post here which may be helpful. Even though this post pertains to the NDK used on a Sitara processor but it talks about changing below two defines and the result was positive.

    - i can see two more links in the mentioned forum topic where i will not be able to see one of the link and also i could not find the parameter mentioned here.

    Reagrds

    Bala

  • forgot to add wirshark capture. attaching now.

    good one

    failure one

    Regards

    Bala

  • Hi,

    can anyone help me to short out the issue?

    Bala
  • On both WireShark dumps, which IP address is the TM4C and which is the Windows box?

  • HI Todd,

    the windows pc ip are 192.168.1.7 and 192.168.8.7. Others are TM4C.

    Regards
    Bala
  • Bala,

    I'm new to this thread, so I'm trying to understand the root issue. It seems to me that adding the task for analog input processing along with the SPI-DMA driver support is what caused your network failure. Would you agree?

    There is an issue in the EMAC Snow driver recently discovered by Gillon and reported on this forum thread titled NDK in TI-RTOS for TivaC 2.16.1.14 can get into a state where unable to transmit packets. I'm thinking the issue you are observing might be related because the SPI-DMA interrupt handling might impact the NDK's ability to service its interrupt. Please have a look at the thread. Let me know what you think.

    ~Ramsey

  • Hello Ramsey,

    >>>I'm new to this thread, so I'm trying to understand the root issue. It seems to me that adding the task for analog input processing along with the SPI-DMA driver support is what caused your network failure. Would you agree?

    - No. Initially we thought its because of this could be the problem. after we removed analog input processing task, still the problem is exist.

    As suggested in the forum, i will try the changes in the EMACSnow.c file and let you know the behaviour.

    Regards

    Bala

  • tcp_EMACSnow.c
    /*
     * Copyright (c) 2014-2015 Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /*
     *  ======== EMACSnow.c ========
     *  This driver currently supports only 1 EMACSnow port. In the future
     *  when multiple ports are required, this driver needs to move all the
     *  EMACSnow_Data fields into the EMACSnow_Object structure. The APIs need
     *  to get to the fields via the pvt_data field in the NETIF_DEVICE that
     *  is passed in. ROV must be changed to support the change also.
     *  The NETIF_DEVICE structure should go into the EMACSnow_Object also.
     *
     *  This changes are not being done at this time because of the impact on
     *  the complexity of the code.
     */
    #include <string.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include <ti/sysbios/BIOS.h>
    #include <xdc/runtime/Assert.h>
    #include <xdc/runtime/Diags.h>
    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/Log.h>
    #include <xdc/runtime/System.h>
    #include <xdc/runtime/Types.h>
    #include "controller_application/ioc_mode_operation/ioc_mode.h"
    
    #include <ti/drivers/EMAC.h>
    #include <ti/drivers/emac/EMACSnow.h>
    
    /* device specific driver includes */
    
    #include <inc/hw_memmap.h>
    #include <inc/hw_types.h>
    #include <inc/hw_emac.h>
    #include <inc/hw_ints.h>
    #include <inc/hw_gpio.h>
    #include <inc/hw_flash.h>
    #include <driverlib/emac.h>
    #include <driverlib/sysctl.h>
    #include <inc/hw_sysctl.h>
    #include "tcp_EMACSnow.h"
    #include "ioc_Ethernet.h"
    //#include "phyConfig.h"
    
    /* Name of the device. */
    #define ETHERNET_NAME "eth0"
    
    #ifndef NUM_RX_DESCRIPTORS
    #define NUM_RX_DESCRIPTORS 4
    #endif
    
    #ifndef NUM_TX_DESCRIPTORS
    #define NUM_TX_DESCRIPTORS 4
    #endif
    
    #ifndef EMAC_PHY_CONFIG
    #define EMAC_PHY_CONFIG         (EMAC_PHY_TYPE_INTERNAL |                     \
                                     EMAC_PHY_INT_MDIX_EN |                       \
                                     EMAC_PHY_AN_100B_T_FULL_DUPLEX)
    #endif
    
    //uint32_t g_ulStatus;
    
    bool enablePrefetch = FALSE;
    volatile uint16_t ui16NetLedStatus;
    
    /**************************************************/
    /* Debug counters for PHY issue                   */
    /**************************************************/
    volatile unsigned int phyCounter[3] = {0, 0, 0};
    static void tcp_EMACSnow_handleRx();
    static void tcp_EMACSnow_processTransmitted();
    
    /*
     *  Helper struct holding a DMA descriptor and the pbuf it currently refers
     *  to.
     */
    typedef struct {
      tEMACDMADescriptor Desc;
      PBM_Handle hPkt;
    } tDescriptor;
    
    typedef struct {
        tDescriptor *pDescriptors;
        uint32_t     ulNumDescs;
        uint32_t     ulWrite;
        uint32_t     ulRead;
    } tDescriptorList;
    
    /*
     * Global variable for this interface's private data.  Needed to allow
     * the interrupt handlers access to this information outside of the
     * context of the lwIP netif.
     */
    static tDescriptor g_pTxDescriptors[NUM_TX_DESCRIPTORS];
    static tDescriptor g_pRxDescriptors[NUM_RX_DESCRIPTORS];
    
    static tDescriptorList g_TxDescList = {
        g_pTxDescriptors, NUM_TX_DESCRIPTORS, 0, 0
    };
    
    static tDescriptorList g_RxDescList = {
        g_pRxDescriptors, NUM_RX_DESCRIPTORS, 0, 0
    };
    
    /* EMAC function table for snowflake implementation */
    const EMAC_FxnTable tcp_EMACSnow_fxnTable = {
            EMACSnow_init,
            EMACSnow_isLinkUp
    };
    
    /* Application is required to provide this variable */
    extern EMAC_Config EMAC_config;
    
    /*
     *  The struct is used to store the private data for the EMACSnow controller.
     */
    typedef struct EMACSnow_Data {
        STKEVENT_Handle  hEvent;
        PBMQ             PBMQ_tx;
        PBMQ             PBMQ_rx;
        uint32_t         rxCount;
        uint32_t         rxDropped;
        uint32_t         txSent;
        uint32_t         txDropped;
        uint32_t         abnormalInts;
        uint32_t         isrCount;
        uint32_t         linkUp;
        tDescriptorList *pTxDescList;
        tDescriptorList *pRxDescList;
    } EMACSnow_Data;
    
    /* Only supporting one EMACSnow device */
    static EMACSnow_Data EMACSnow_private;
    
    static volatile Bool tcp_EMACSnow_initialized = FALSE;
    
    #define PHY_PHYS_ADDR 3
    
    /*
     *  ======== signalLinkChange ========
     *  Signal the stack based on linkUp parameter.
     */
    static void tcp_signalLinkChange(STKEVENT_Handle hEvent, uint32_t linkUp,
            unsigned int flag)
    {
        if (linkUp) {
            /* Signal the stack that the link is up */
            STKEVENT_signal(hEvent, STKEVENT_LINKUP, flag);
        }
        else {
            /* Signal the stack that the link is down */
            STKEVENT_signal(hEvent, STKEVENT_LINKDOWN, flag);
        }
    }
    
    /*
     *  ======== EMACSnow_processPendingTx ========
     */
    static void tcp_EMACSnow_processPendingTx()
    {
        uint8_t     *pBuffer;
        uint32_t     len;
        PBM_Handle   hPkt;
        tDescriptor *pDesc;
    
        /*
         *  If there are pending packets, send one.
         *  Otherwise quit the loop.
         */
        hPkt = PBMQ_deq(&EMACSnow_private.PBMQ_tx);
        if (hPkt != NULL) {
    
            pDesc = &(EMACSnow_private.pTxDescList->pDescriptors[EMACSnow_private.pTxDescList->ulWrite]);
            if (pDesc->hPkt) {
                PBM_free(hPkt);
                EMACSnow_private.txDropped++;
                return;
            }
    
            /* Get the pointer to the buffer and the length */
            pBuffer = PBM_getDataBuffer(hPkt) + PBM_getDataOffset(hPkt);
            len = PBM_getValidLen(hPkt);
    
            /* Fill in the buffer pointer and length */
            pDesc->Desc.ui32Count = len;
            pDesc->Desc.pvBuffer1 = pBuffer;
            pDesc->Desc.ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG;
    
            pDesc->Desc.ui32CtrlStatus |= (/*DES0_TX_CTRL_IP_ALL_CKHSUMS |*/ DES0_TX_CTRL_CHAINED);
            pDesc->Desc.ui32CtrlStatus |= (DES0_TX_CTRL_LAST_SEG |
                                           DES0_TX_CTRL_INTERRUPT);
            EMACSnow_private.pTxDescList->ulWrite++;
            if (EMACSnow_private.pTxDescList->ulWrite == NUM_TX_DESCRIPTORS) {
                EMACSnow_private.pTxDescList->ulWrite = 0;
            }
            pDesc->hPkt = hPkt;
            pDesc->Desc.ui32CtrlStatus |= DES0_TX_CTRL_OWN;
    
            EMACSnow_private.txSent++;
    
            EMACTxDMAPollDemand(EMAC0_BASE);
        }
    
        return;
    }
    
    
    /*
     *  ======== EMACSnow_handlePackets ========
     */
    static void tcp_EMACSnow_handlePackets(UArg arg0, UArg arg1)
    {
        uint32_t g_ulStatus;
        //Log_print1(Diags_USER1, "EMACSnow_handlePackets handling packets status = 0x%x", g_ulStatus);
    
        /* Process the transmit DMA list, freeing any buffers that have been
         * transmitted since our last interrupt.
         */
        g_ulStatus = Swi_getTrigger();
    
        if (g_ulStatus & EMAC_INT_TRANSMIT) {
            Log_print0(Diags_USER1, "EMACSnow_handlePackets Tx ones...");
            tcp_EMACSnow_processTransmitted();
        }
    
        /*
         * 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 (g_ulStatus & (EMAC_INT_RECEIVE | EMAC_INT_RX_NO_BUFFER |
            EMAC_INT_RX_STOPPED)) {
            Log_print0(Diags_USER1, "EMACSnow_handlePackets Rx ones...");
            tcp_EMACSnow_handleRx();
        }
    
        Log_print0(Diags_USER1, "EMACSnow_handlePackets re-enable peripheral...");
    /*    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));
                            */
    }
    
    /*
     *  ======== EMACSnow_processTransmitted ========
     */
    static void tcp_EMACSnow_processTransmitted()
    {
        tDescriptor *pDesc;
        uint32_t     ulNumDescs;
    
        /*
         * Walk the list until we have checked all descriptors or we reach the
         * write pointer or find a descriptor that the hardware is still working
         * on.
         */
        for (ulNumDescs = 0; ulNumDescs < NUM_TX_DESCRIPTORS; ulNumDescs++) {
            pDesc = &(EMACSnow_private.pTxDescList->pDescriptors[EMACSnow_private.pTxDescList->ulRead]);
            /* Has the buffer attached to this descriptor been transmitted? */
            if (pDesc->Desc.ui32CtrlStatus & DES0_TX_CTRL_OWN) {
                /* No - we're finished. */
                break;
            }
    
            /* Does this descriptor have a buffer attached to it? */
            if (pDesc->hPkt) {
                /* Yes - free it if it's not marked as an intermediate pbuf */
                if (!((uint32_t)(pDesc->hPkt) & 1)) {
                    PBM_free(pDesc->hPkt);
                }
                pDesc->hPkt = NULL;
            }
            else {
                /* If the descriptor has no buffer, we are finished. */
                break;
            }
    
            /* Move on to the next descriptor. */
            EMACSnow_private.pTxDescList->ulRead++;
            if (EMACSnow_private.pTxDescList->ulRead == NUM_TX_DESCRIPTORS) {
                EMACSnow_private.pTxDescList->ulRead = 0;
            }
        }
    }
    
    /*
     *  ======== EMACSnow_primeRx ========
     */
    static void tcp_EMACSnow_primeRx(PBM_Handle hPkt, tDescriptor *desc)
    {
        desc->hPkt = hPkt;
        desc->Desc.ui32Count = DES1_RX_CTRL_CHAINED;
    
        /* We got a buffer so fill in the payload pointer and size. */
        desc->Desc.pvBuffer1 = PBM_getDataBuffer(hPkt) + PBM_getDataOffset(hPkt);
        desc->Desc.ui32Count |= (ETH_MAX_PAYLOAD << DES1_RX_CTRL_BUFF1_SIZE_S);
    
        /* Give this descriptor back to the hardware */
        desc->Desc.ui32CtrlStatus = DES0_RX_CTRL_OWN;
    }
    
    /*
     *  ======== EMACSnow_handleRx ========
     */
    static void tcp_EMACSnow_handleRx()
    {
        PBM_Handle       hPkt;
        PBM_Handle       hPktNew;
        int32_t          len;
        tDescriptorList *pDescList;
        uint32_t         ulDescEnd;
    
        /* Get a pointer to the receive descriptor list. */
        pDescList = EMACSnow_private.pRxDescList;
    
        /* Determine where we start and end our walk of the descriptor list */
        ulDescEnd = pDescList->ulRead ? (pDescList->ulRead - 1) : (pDescList->ulNumDescs - 1);
    
        /* Step through the descriptors that are marked for CPU attention. */
        while (pDescList->ulRead != ulDescEnd) {
    
            /* Does the current descriptor have a buffer attached to it? */
            hPkt = pDescList->pDescriptors[pDescList->ulRead].hPkt;
            if (hPkt) {
    
                /* Determine if the host has filled it yet. */
                if (pDescList->pDescriptors[pDescList->ulRead].Desc.ui32CtrlStatus &
                    DES0_RX_CTRL_OWN) {
                  /* The DMA engine still owns the descriptor so we are finished. */
                  break;
                }
    
                /* Yes - does the frame contain errors? */
                if (pDescList->pDescriptors[pDescList->ulRead].Desc.ui32CtrlStatus &
                   DES0_RX_STAT_ERR) {
                    /*
                     *  This is a bad frame so discard it and update the relevant
                     *  statistics.
                     */
                    Log_error0("EMACSnow_handleRx: DES0_RX_STAT_ERR");
                    EMACSnow_private.rxDropped++;
                    tcp_EMACSnow_primeRx(hPkt, &(pDescList->pDescriptors[pDescList->ulRead]));
                    pDescList->ulRead++;
                    break;
                }
                else {
                    /* Allocate a new buffer for this descriptor */
                    hPktNew = PBM_alloc(ETH_MAX_PAYLOAD);
                    if (hPktNew == NULL) {
                        /*
                         *  Leave the packet in the descriptor and owned by the driver.
                         *  Process when the next interrupt occurs.
                         */
                        break;
                    }
    
                    /* This is a good frame so pass it up the stack. */
                    len = (pDescList->pDescriptors[pDescList->ulRead].Desc.ui32CtrlStatus &
                          DES0_RX_STAT_FRAME_LENGTH_M) >> DES0_RX_STAT_FRAME_LENGTH_S;
    
                    /* Remove the CRC */
                    PBM_setValidLen(hPkt, len - 4);
    
                    /*
                     *  Place the packet onto the receive queue to be handled in the
                     *  EMACSnow_pkt_service function (which is called by the
                     *  NDK stack).
                     */
                    PBMQ_enq(&EMACSnow_private.PBMQ_rx, hPkt);
    
                    Log_print2(Diags_USER2, "EMACSnow_handleRx: Enqueued recv packet 0x%x, length = %d",
                        (IArg)hPkt, len - 4);
    
                    /* Update internal statistic */
                    EMACSnow_private.rxCount++;
    
                    /*
                     *  Notify NDK stack of pending Rx Ethernet packet and
                     *  that it was triggered by an external event.
                     */
                    STKEVENT_signal(EMACSnow_private.hEvent, STKEVENT_ETHERNET, 1);
    
                    /* Prime the receive descriptor back up for future packets */
                    tcp_EMACSnow_primeRx(hPktNew,
                                     &(pDescList->pDescriptors[pDescList->ulRead]));
                }
            }
    
            /* Move on to the next descriptor in the chain, taking care to wrap. */
            pDescList->ulRead++;
            if (pDescList->ulRead == pDescList->ulNumDescs) {
                pDescList->ulRead = 0;
            }
        }
    }
    
    /*
     *  ======== EMACSnow_processPhyInterrupt ========
     */
    void tcp_EMACSnow_processPhyInterrupt()
    {
        uint16_t value, status;
        uint32_t config, mode, rxMaxFrameSize;
    
        /*
         * Read the PHY interrupt status.  This clears all interrupt sources.
         * Note that we are only enabling sources in EPHY_MISR1 so we don't
         * read EPHY_MISR2.
         */
        value = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1);
    
        /* Read the current PHY status. */
        status = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_STS);
    
        /* Has the link status changed? */
        if (value & EPHY_MISR1_LINKSTAT) {
            /* Is link up or down now? */
            if (status & EPHY_STS_LINK) {
                EMACSnow_private.linkUp = true;
            }
            else {
                EMACSnow_private.linkUp = false;
            }
            /* Signal the stack for this link status change (from ISR) */
            tcp_signalLinkChange(EMACSnow_private.hEvent, EMACSnow_private.linkUp, 1);
        }
    
        /* Has the speed or duplex status changed? */
        if (value & (EPHY_MISR1_SPEED | EPHY_MISR1_SPEED | EPHY_MISR1_ANC)) {
            /* Get the current MAC configuration. */
            EMACConfigGet(EMAC0_BASE, (uint32_t *)&config, (uint32_t *)&mode,
                            (uint32_t *)&rxMaxFrameSize);
    
            /* What speed is the interface running at now?
             */
            if (status & EPHY_STS_SPEED) {
                /* 10Mbps is selected */
                config &= ~EMAC_CONFIG_100MBPS;
            }
            else {
                /* 100Mbps is selected */
                config |= EMAC_CONFIG_100MBPS;
            }
    
            /* Are we in full- or half-duplex mode? */
            if (status & EPHY_STS_DUPLEX) {
                /* Full duplex. */
                config |= EMAC_CONFIG_FULL_DUPLEX;
            }
            else {
                /* Half duplex. */
                config &= ~EMAC_CONFIG_FULL_DUPLEX;
            }
    
            /* Reconfigure the MAC */
            EMACConfigSet(EMAC0_BASE, config, mode, rxMaxFrameSize);
        }
    }
    
    /*
     *  ======== EMACSnow_hwiIntFxn ========
     */
    void tcp_EMACSnow_hwiIntFxn(UArg callbacks)
    {
        EMACSnow_Object *object = (EMACSnow_Object *)(EMAC_config.object);
        uint32_t status;
    
        /* Check link status */
        status = 1; //(EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & EPHY_BMSR_LINKSTAT);
    
        /* Signal the stack if link status changed */
        if (status != EMACSnow_private.linkUp) {
            tcp_signalLinkChange(EMACSnow_private.hEvent, status, 1);
        }
    
        /* Set the link status */
        EMACSnow_private.linkUp = status;
    
        EMACSnow_private.isrCount++;
    
        /* Read and Clear the interrupt. */
        status = EMACIntStatus(EMAC0_BASE, true);
        EMACIntClear(EMAC0_BASE, status);
    
        /*
         *  Disable the Ethernet interrupts.  Since the interrupts have not been
         *  handled, they are not asserted.  Once they are handled by the Ethernet
         *  interrupt, it will re-enable the interrupts.
         */
        /*
        EMACIntDisable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT |
                         EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER |
                         EMAC_INT_RX_STOPPED | EMAC_INT_PHY));
    */
    
        if (status & EMAC_INT_ABNORMAL_INT) {
            EMACSnow_private.abnormalInts++;
        }
    
    //    g_ulStatus = status;
    #if 1
        if (status & EMAC_INT_PHY) {
            tcp_EMACSnow_processPhyInterrupt();
        }
    #endif
    //    Log_print1(Diags_USER1, "EMACSnow_hwiIntFxn Posting Swi status = 0x%x", g_ulStatus);
        Swi_or(object->swi, status);
    
        /* Have the Swi handle the incoming packets and re-enable peripheral */
        Swi_post(object->swi);
    }
    
    /*
     *  ======== EMACSnow_emacStart ========
     *  The function is used to initialize and start the EMACSnow
     *  controller and device.
     */
    int tcp_EMACSnow_emacStart(struct NETIF_DEVICE* ptr_net_device)
    {
        uint16_t value;
        EMACSnow_Object *object = (EMACSnow_Object *)(EMAC_config.object);
        EMACSnow_HWAttrs *hwAttrs = (EMACSnow_HWAttrs *)(EMAC_config.hwAttrs);
        Hwi_Params  hwiParams;
        Error_Block eb;
        UInt32 ui32FlashConf;
    
        /*
         *  Create the Swi that handles incoming packets.
         *  Take default parameters.
         */
        Error_init(&eb);
        object->swi = Swi_create(tcp_EMACSnow_handlePackets,
                                 NULL, &eb);
        if (object->swi == NULL) {
            Log_error0("EMACSnow_emacStart: Swi_create failed");
            ui16NetLedStatus = NETWORK_CONFIG_ERROR;
            return (-1);
        }
    
        /* Create the hardware interrupt */
        Hwi_Params_init(&hwiParams);
        hwiParams.priority = hwAttrs->intPriority;
    
        object->hwi = Hwi_create(hwAttrs->intNum, tcp_EMACSnow_hwiIntFxn,
                &hwiParams, &eb);
        if (object->hwi == NULL) {
            Log_error0("EMACSnow_emacStart: Hwi_create failed");
            ui16NetLedStatus = NETWORK_CONFIG_ERROR;
            return (-1);
        }
    
        /* Clear any stray PHY interrupts that may be set. */
        value = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1);
        value = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR2);
    
        /* Configure and enable the link status change interrupt in the PHY. */
        value = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR);
        value |= (EPHY_SCR_INTEN_EXT | EPHY_SCR_INTOE_EXT);
        EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR, value);
        EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1, (EPHY_MISR1_LINKSTATEN |
                     EPHY_MISR1_SPEEDEN | EPHY_MISR1_DUPLEXMEN | EPHY_MISR1_ANCEN));
    
        /* Read the PHY interrupt status to clear any stray events. */
        value = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1);
    
       /*
         *  Set MAC filtering options.  We receive all broadcast and multicast
         *  packets along with those addressed specifically for us.
         */
        EMACFrameFilterSet(EMAC0_BASE, (EMAC_FRMFILTER_HASH_AND_PERFECT |
                           EMAC_FRMFILTER_PASS_MULTICAST));
    
        /* Clear any pending interrupts. */
        EMACIntClear(EMAC0_BASE, EMACIntStatus(EMAC0_BASE, false));
    
        /* Enable the Ethernet MAC transmitter and receiver. */
        EMACTxEnable(EMAC0_BASE);
        EMACRxEnable(EMAC0_BASE);
    
        /* 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));
     //   ioc_PhyWriteOperation(INT_ENABLEREG, INT_ENABLEDATA, RTOS);
    
        /* Enable the Ethernet Interrupt handler. */
        Hwi_enableInterrupt(hwAttrs->intNum);
    
    //    EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_BMCR, (EPHY_BMCR_ANEN |
    //                 EPHY_BMCR_RESTARTAN));
        Log_print0(Diags_USER2, "EMACSnow_emacStart: start completed");
    
        /*
         * Turns ON the prefetch buffer if it was disabled in EMACSnow_NIMUInit
         */
        if (enablePrefetch == TRUE) {
            ui32FlashConf = HWREG(FLASH_CONF);
            ui32FlashConf &= ~(FLASH_CONF_FPFOFF);
            ui32FlashConf |= FLASH_CONF_FPFON;
            HWREG(FLASH_CONF) = ui32FlashConf;
        }
    
        /* Event post to poll the link status */
        Event_post(Event_Network_Initialize_Handler, Event_Id_00);
        return (0);
    }
    
    /*
     *  ======== EMACSnow_emacStop ========
     *  The function is used to de-initialize and stop the EMACSnow
     *  controller and device.
     */
    int tcp_EMACSnow_emacStop(struct NETIF_DEVICE* ptr_net_device)
    {
        EMACSnow_Object *object = (EMACSnow_Object *)(EMAC_config.object);
        EMACSnow_HWAttrs *hwAttrs = (EMACSnow_HWAttrs *)(EMAC_config.hwAttrs);
        PBM_Handle hPkt;
    
        int i = 0;
    
       // ioc_PhyWriteOperation(INT_ENABLEREG, 0x00, RTOS);
        EMACIntDisable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT |
                         EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER |
                         EMAC_INT_RX_STOPPED | EMAC_INT_PHY));
        Hwi_disableInterrupt(hwAttrs->intNum);
    
        if (object->hwi != NULL) {
            Hwi_delete(&(object->hwi));
        }
    
        if (object->swi != NULL) {
            Swi_delete(&(object->swi));
        }
        while (PBMQ_count(&EMACSnow_private.PBMQ_rx)) {
            /* Dequeue a packet from the driver receive queue. */
            hPkt = PBMQ_deq(&EMACSnow_private.PBMQ_rx);
            PBM_free(hPkt);
        }
    
        while (PBMQ_count(&EMACSnow_private.PBMQ_tx)) {
            /* Dequeue a packet from the driver receive queue. */
            hPkt = PBMQ_deq(&EMACSnow_private.PBMQ_tx);
            PBM_free(hPkt);
        }
    
        for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
            if (g_pRxDescriptors[i].hPkt != NULL) {
                PBM_free(g_pRxDescriptors[i].hPkt);
            }
        }
    
        Log_print0(Diags_USER2, "EMACSnow_emacStop: stop completed");
    
        return (0);
    }
    
    /*
     *  ======== EMACSnow_emacPoll ========
     *  The function is used to poll the EMACSnow controller to check
     *  if there has been any activity
     */
    void tcp_EMACSnow_emacPoll(struct NETIF_DEVICE* ptr_net_device, uint timer_tick)
    {
        uint32_t newLinkStatus;
    
        /* Send pending Tx packets */
        tcp_EMACSnow_processPendingTx();
    
        /* Check link status */
        newLinkStatus = (EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & EPHY_BMSR_LINKSTAT);
    
        /* Signal the stack if link status changed */
        if (newLinkStatus != EMACSnow_private.linkUp) {
            tcp_signalLinkChange(EMACSnow_private.hEvent, newLinkStatus, 0);
        }
    
        /* Set the link status */
        EMACSnow_private.linkUp = newLinkStatus;
    
    }
    
    /*
     *  ======== EMACSnow_emacSend ========
     *  The function is the interface routine invoked by the NDK stack to
     *  pass packets to the driver.
     */
    int tcp_EMACSnow_emacSend(struct NETIF_DEVICE* ptr_net_device, PBM_Handle hPkt)
    {
        /*
         *  Enqueue the packet onto the end of the transmit queue.
         *  This is done to ensure that the packets are sent in order.
         */
        PBMQ_enq(&EMACSnow_private.PBMQ_tx, hPkt);
    
        Log_print2(Diags_USER2, "EMACSnow_emacSend: enqueued hPkt = 0x%x, len = %d", (IArg)hPkt, PBM_getValidLen(hPkt));
    
        /* Transmit pending packets */
        tcp_EMACSnow_processPendingTx();
    
        return (0);
    }
    
    /*
     *  ======== EMACSnow_emacioctl ========
     *  The function is called by the NDK core stack to configure the driver
     */
    int tcp_EMACSnow_emacioctl(struct NETIF_DEVICE* ptr_net_device, uint cmd,
                   void* pbuf, uint size)
    {
        /* No control commands are currently supported for this driver */
        Log_print0(Diags_USER2, "EMACSnow_emacioctl: emacioctl called");
    
        if ((cmd == NIMU_ADD_MULTICAST_ADDRESS) || (cmd == NIMU_DEL_MULTICAST_ADDRESS)) {
            return (0);
        }
    
        return (-1);
    }
    
    /*
     *  ======== EMACSnow_pkt_service ========
     *  The function is called by the NDK core stack to receive any packets
     *  from the driver.
     */
    void tcp_EMACSnow_pkt_service(NETIF_DEVICE* ptr_net_device)
    {
        PBM_Handle  hPkt;
    
        /* Give all queued packets to the stack */
        while (PBMQ_count(&EMACSnow_private.PBMQ_rx)) {
    
            /* Dequeue a packet from the driver receive queue. */
            hPkt = PBMQ_deq(&EMACSnow_private.PBMQ_rx);
    
            /*
             *  Prepare the packet so that it can be passed up the networking stack.
             *  If this 'step' is not done the fields in the packet are not correct
             *  and the packet will eventually be dropped.
             */
            PBM_setIFRx(hPkt, ptr_net_device);
    
            Log_print1(Diags_USER2,
                       "EMACSnow_pkt_service: give packet 0x%x to NDK via NIMUReceivePacket",
                       (IArg)hPkt);
    
            /* Pass the packet to the NDK Core stack. */
            NIMUReceivePacket(hPkt);
        }
    
        /* Work has been completed; the receive queue is empty. */
        return;
    }
    
    /*
     *  ======== EMACSnow_init ========
     *  The function is used to initialize the EMACSnow driver
     */
    void EMACSnow_init(uint32_t index)
    {
        /* Currently only supports 1 EMACSnow peripheral */
        Assert_isTrue((index == 0), NULL);
    
        tcp_EMACSnow_initialized = TRUE;
    
        Log_print0(Diags_USER2, "EMACSnow_init: setup successfully completed");
    }
    
    /*
     *  ======== EMACSnow_InitDMADescriptors ========
     * Initialize the transmit and receive DMA descriptor lists.
     */
    void tcp_EMACSnow_InitDMADescriptors(void)
    {
        int32_t     i;
        PBM_Handle  hPkt;
    
        /* Transmit list -  mark all descriptors as not owned by the hardware */
        for (i = 0; i < NUM_TX_DESCRIPTORS; i++) {
            g_pTxDescriptors[i].hPkt = NULL;
            g_pTxDescriptors[i].Desc.ui32Count = 0;
            g_pTxDescriptors[i].Desc.pvBuffer1 = 0;
            g_pTxDescriptors[i].Desc.DES3.pLink = ((i == (NUM_TX_DESCRIPTORS - 1)) ?
                   &g_pTxDescriptors[0].Desc : &g_pTxDescriptors[i + 1].Desc);
            g_pTxDescriptors[i].Desc.ui32CtrlStatus = DES0_TX_CTRL_INTERRUPT |
                                                      /*DES0_TX_CTRL_IP_ALL_CKHSUMS |*/
                                                      DES0_TX_CTRL_CHAINED;
        }
    
        /*
         * Receive list -  tag each descriptor with a buffer and set all fields to
         * allow packets to be received.
         */
        for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
            hPkt = PBM_alloc(ETH_MAX_PAYLOAD);
            if (hPkt) {
                tcp_EMACSnow_primeRx(hPkt, &(g_pRxDescriptors[i]));
            }
            else {
                System_abort("EMACSnow_InitDMADescriptors: PBM_alloc error\n");
                g_pRxDescriptors[i].Desc.pvBuffer1 = 0;
                g_pRxDescriptors[i].Desc.ui32CtrlStatus = 0;
            }
            g_pRxDescriptors[i].Desc.DES3.pLink =
                    ((i == (NUM_RX_DESCRIPTORS - 1)) ?
                    &g_pRxDescriptors[0].Desc : &g_pRxDescriptors[i + 1].Desc);
        }
    
        /* Set the descriptor pointers in the hardware. */
        EMACRxDMADescriptorListSet(EMAC0_BASE, &g_pRxDescriptors[0].Desc);
        EMACTxDMADescriptorListSet(EMAC0_BASE, &g_pTxDescriptors[0].Desc);
    }
    
    /*
     *  ======== EMACSnow_NIMUInit ========
     *  The function is used to initialize and register the EMACSnow
     *  with the Network Interface Management Unit (NIMU)
     */
    int tcp_EMACSnow_NIMUInit(STKEVENT_Handle hEvent)
    {
        EMACSnow_HWAttrs *hwAttrs = (EMACSnow_HWAttrs *)(EMAC_config.hwAttrs);
        Types_FreqHz freq;
        NETIF_DEVICE *device;
        UInt32 ui32FlashConf;
    
        Log_print0(Diags_USER2, "EMACSnow_NIMUInit: init called");
    
        /* Make sure application has initialized the EMAC driver first */
        Assert_isTrue((tcp_EMACSnow_initialized == TRUE), NULL);
    
        /* Initialize the global structures */
        memset(&EMACSnow_private, 0, sizeof(EMACSnow_Data));
    
        ui16NetLedStatus = NETWORK_INITIALIZING;
    
        /*
         *  This is a work-around for EMAC initialization issues found on
         *  the TM4C129 devices. The bug number is:
         *  SDOCM00107378: NDK examples for EK-TM4C1294XL do not work
         *
         *  The following disables the flash pre-fetch (if it is not already disabled).
         *  It is enable within the in the EMACSnow_emacStart() function.
         */
        ui32FlashConf = HWREG(FLASH_CONF);
        if ((ui32FlashConf & (FLASH_CONF_FPFOFF)) == FALSE) {
            enablePrefetch = TRUE;
            ui32FlashConf &= ~(FLASH_CONF_FPFON);
            ui32FlashConf |= FLASH_CONF_FPFOFF;
            HWREG(FLASH_CONF) = ui32FlashConf;
        }
    
        /* Allocate memory for the EMAC. Memory freed in the NDK stack shutdown */
        device = mmAlloc(sizeof(NETIF_DEVICE));
        if (device == NULL) {
            Log_error0("EMACSnow: Failed to allocate NETIF_DEVICE structure");
    
            ui16NetLedStatus = NETWORK_CONFIG_ERROR;
    
            return (-1);
        }
    
        /* Initialize the allocated memory block. */
        mmZeroInit (device, sizeof(NETIF_DEVICE));
    
        device->mac_address[0] = hwAttrs->macAddress[0];
        device->mac_address[1] = hwAttrs->macAddress[1];
        device->mac_address[2] = hwAttrs->macAddress[2];
        device->mac_address[3] = hwAttrs->macAddress[3];
        device->mac_address[4] = hwAttrs->macAddress[4];
        device->mac_address[5] = hwAttrs->macAddress[5];
    
        /* Initialize the Packet Device Information struct */
        PBMQ_init(&EMACSnow_private.PBMQ_rx);
        PBMQ_init(&EMACSnow_private.PBMQ_tx);
        EMACSnow_private.hEvent       = hEvent;
        EMACSnow_private.pTxDescList  = &g_TxDescList;
        EMACSnow_private.pRxDescList  = &g_RxDescList;
        EMACSnow_private.rxCount      = 0;
        EMACSnow_private.rxDropped    = 0;
        EMACSnow_private.txSent       = 0;
        EMACSnow_private.txDropped    = 0;
        EMACSnow_private.abnormalInts = 0;
        EMACSnow_private.isrCount = 0;
        EMACSnow_private.linkUp       = false;
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);
        SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
    //    SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
    //    SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
    
        while (/*!SysCtlPeripheralReady(SYSCTL_PERIPH_EPHY0) ||*/
               !SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0)) {
            /* Keep waiting... */
            phyCounter[0]++;
        }
    
    //    EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG);
        EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_TYPE_EXTERNAL_MII );
        SysCtlDelay(1000);
    
        BIOS_getCpuFreq(&freq);
        EMACInit(EMAC0_BASE, freq.lo,
                 EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED,
                 4, 4, 0);
    
        /* Set MAC configuration options. */
        EMACConfigSet(EMAC0_BASE, (EMAC_CONFIG_FULL_DUPLEX |
                                   // EMAC_CONFIG_100MBPS     |
                                   //EMAC_CONFIG_CHECKSUM_OFFLOAD |
                                   EMAC_CONFIG_7BYTE_PREAMBLE |
                                   EMAC_CONFIG_IF_GAP_96BITS |
                                   EMAC_CONFIG_USE_MACADDR0 |
                                   EMAC_CONFIG_SA_FROM_DESCRIPTOR |
                                   EMAC_CONFIG_BO_LIMIT_1024),
                      (EMAC_MODE_RX_STORE_FORWARD |
                       EMAC_MODE_TX_STORE_FORWARD |
                       EMAC_MODE_TX_THRESHOLD_64_BYTES |
                       EMAC_MODE_RX_THRESHOLD_64_BYTES), 0);
    
        /* Program the MAC address into the Ethernet controller. */
        EMACAddrSet(EMAC0_BASE, 0, (uint8_t *)device->mac_address);
    
        /* Initialize the DMA descriptors. */
        tcp_EMACSnow_InitDMADescriptors();
    
        /* Populate the Network Interface Object. */
        strcpy(device->name, ETHERNET_NAME);
        device->mtu         = ETH_MAX_PAYLOAD - ETHHDR_SIZE;
        device->pvt_data    = (void *)&EMACSnow_private;
    
        /* Populate the Driver Interface Functions. */
        device->start       = tcp_EMACSnow_emacStart;
        device->stop        = tcp_EMACSnow_emacStop;
        device->poll        = tcp_EMACSnow_emacPoll;
        device->send        = tcp_EMACSnow_emacSend;
        device->pkt_service = tcp_EMACSnow_pkt_service;
        device->ioctl       = tcp_EMACSnow_emacioctl;
        device->add_header  = NIMUAddEthernetHeader;
    
        /* Register the device with NIMU */
        if (NIMURegister(device) < 0) {
            Log_print0(Diags_USER1, "EMACSnow_NIMUInit: failed to register with NIMU");
    
            ui16NetLedStatus = NETWORK_CONFIG_ERROR;
    
            return (-1);
        }
    
        Log_print0(Diags_USER2, "EMACSnow_NIMUInit: register with NIMU");
    
        return (0);
    }
    
    /*
     *  ======== EMACSnow_linkUp ========
     */
    bool EMACSnow_isLinkUp(uint32_t index)
    {
        uint32_t newLinkStatus;
    
        /* Check link status */
        newLinkStatus = (EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & EPHY_BMSR_LINKSTAT);
    
        /* Signal the stack if link status changed */
        if (newLinkStatus != EMACSnow_private.linkUp) {
            tcp_signalLinkChange(EMACSnow_private.hEvent, newLinkStatus, 0);
        }
    
        /* Set the link status */
        EMACSnow_private.linkUp = newLinkStatus;
    
        if (EMACSnow_private.linkUp) {
            return (true);
        }
        else {
            return (false);
        }
    }
    
    
    Hello Ramsey,

    i have tried changing the following changes in my EMACSnow.c file as suggested in the thread  but the problem still exist. i am getting same error "00006.500 TcpTimeoutRexmt: Retransmit Timeout"

    a) Delete the g_ulStatus global variable.

    b) Make EMACSnow_handlePackets() call Swi_getTrigger() to get the pending interrupts, rather than reading a global variable.

    c) Make EMACSnow_hwiIntFxn() call Swi_or() to set the pending interrupts passed to the Swi.

    d) Can also delete the disabling of the interrupts from EMACSnow_hwiIntFxn() and the re-enabling of interrupts from EMACSnow_handlePackets(). This is because the use of the Swi trigger prevents pending interrupts from being lost.

    Modified EMACSnow.c file is attached.

    can you please check the EMACSnow.c file and let me know anything if i missed?

    Regards

    Bala

  • Hi Balasubramani C,

    So timeout Re-TXD never occurs on either Windows version when Ethernet cable plugged in prior to POR, is that correct? Anyway that was my take from reading through this thread.

    Had similar issues with LWIP1.4.1 when Ethernet cable was plugged/unplugged or later plugged after POR first inside Tiva129.HAL.. Reading link state register relative to (lwiplib.c) was not using Boolean flags to change link state further up in the IP stack layers. That lead to a train wreck in PCB corruption in the pcb_pool.

    Don't know about NDK stack but it sounds a lot like this same thing is occurring when you plug the Ethernet cable in after POR.

  • Hello BP101,

    >>>>So timeout Re-TXD never occurs on either Windows version when Ethernet cable plugged in prior to POR, is that correct? Anyway that was my take from reading through this thread.

    - No. The problem is independent of Ethernet cable plugged in prior to POR or before POR. i am facing this issue when my DUT is connected to Windows 7 PC and not in windows 10 PC.

    Regards
    Bala
  • Balasubramani C said:
    The followings are working behavior.
    - when Ethernet cable is connected while power on the Unit, after that the link can be dynamically changed .
    Non-Working behavior
    - device is not connected with Ethernet cable, and trying to connect it run time. while connecting that moment after there no expected behavior in the Unit and not able to establish the Ethernet connection

    So what was all this about and what does "it run time" mean to say to us?

  • As for a few added notes:

    1. Have you tried to disable all network protocols in Win10 that are not explicitly configured in Win7?

    2. Identify why you conclude Win10 TCP protocol stack or clients somehow influence DUT to behave differently?
  • Hi BP101,

    sorry for not giving the proper information. in the course of debug, i found that Ethernet switch is not configured properly to handle the interrupt service routine for Link status change. Now the Link issues is resolved and its working fine in both the conditions i.e. Ethernet cable connected before and after POR. sorry for not informing the same in the forum.

    Now i have only one issue is "TcpTimeoutRexmt: Retransmit Timeout -Error" that too while connecting my DUT to following windows PC setup.

    1. windows 7 PC for both Flow control enabled and disabled.

    2. Window 10 PC flow control disabled.

    and also i have not seen any "TcpTimeoutRexmt: Retransmit Timeout -Error" when DUT connected with wondow 10 PC with flow control enabled. 

    This is the current summary of the issue.

    Regards

    Bala

  • Balasubramani,

    Thanks for trying out the EMACSnow driver fix.

    Would you explain test setup. Is the DUT a server or client application? What role is the Windows machine, client or server?

    Does the test fail immediately, or is there some time of normal operation before failure?

    Would you try the experiment described by Chester Gillon on post from Apr 3. Place 'EMACSnow.c'::EMACSnow_private in expression window and make note of last value to change before failure. Also, does anything change after failure?

    ~Ramsey

  • Balasubramani C said:
    i found that Ethernet switch is not configured properly to handle the interrupt service routine for Link status change

    Are you serious, there is a setting for Ethernet link state in the switch? So the application ability to control link state as it should relies on a specific brand of switch to work correctly.  

    It seems what you have proven is that your application overruns the NDK configuration of the DMA engines FIFO configuration. Although an flow control RFC exists to handle local Ethernet packet flow it is very seldom being used as we too past discovered. It requires the EMAC0 be configured for similar flow control to function correctly as the RFC has outlined. It seems all you have done by configuring windows 10 flow control is slowed down host TX data transfers to the target MCU by inserting delay states in the frames of packets. Your client experiment seemingly has masked the problem of the application to keep the EMAC TX buffers from overflowing from two protocols or IP ports hammering the wire.

    We had to boost the TM4C DMA engines TX bit rate so it would not randomly jam up from abnormal interrupts or buffer unavailable errors. It may be the RTOS kernel is controlling the data flow rate to some extent just because it slows hardware data transfer speed down in the process. That may hold true even if EMAC0 is not being used to transfer application data or even if the PHY only is external hardware to the TM4C129x MCU.

    Dual protocol stacks require high speed Ethernet data transfers or train wrecks may occur in the IP stack. Below configuration resolved uncommon packet overruns that lead to early IP stack corruption in the target EMAC when leveraging multiple protocol (pcb pools), higher up the device chain layer 3, MLSP. Typically many of TI application configure the EMAC0 DMA for TX/RX transfer bit rate 8 and below widens the TX/RX throttle restrictor plates aperture.

    EMAC_BCONFIG_TX_PRIORITY | EMAC_BCONFIG_MIXED_BURST |
     EMAC_BCONFIG_DMA_PRIO_WEIGHT_2 | EMAC_BCONFIG_PRIORITY_2_1, 16, 16, 0);

     

  • BP101 said:
    Are you serious, there is a setting for Ethernet link state in the switch? So the application ability to control link state as it should relies on a specific brand of switch to work correctly.  

    - Ethernet Switch has the Interrupt pin for generating interrupt whenever there is Port link status changed. Initially we Ethernet switch interrupt pin is connected to EN0INTRN pin of Processor. This is making some problem when is system is getting booted. Still i have not understood the exact problem why its affecting the processor booting. i have configured EN0INTRN as GPIO and made separate task to poll the Link Status.

    BP101 said:

    Dual protocol stacks require high speed Ethernet data transfers or train wrecks may occur in the IP stack. Below configuration resolved uncommon packet overruns that lead to early IP stack corruption in the target EMAC when leveraging multiple protocol (pcb pools), higher up the device chain layer 3, MLSP. Typically many of TI application configure the EMAC0 DMA for TX/RX transfer bit rate 8 and below widens the TX/RX throttle restrictor plates aperture.

    EMAC_BCONFIG_TX_PRIORITY | EMAC_BCONFIG_MIXED_BURST |
     EMAC_BCONFIG_DMA_PRIO_WEIGHT_2 | EMAC_BCONFIG_PRIORITY_2_1, 16, 16, 0);

    - As you suggested, i have changed the EMAC_Config for above settings. But still i found the same issue "

    TcpTimeoutRexmt: Retransmit Timeout -Error"

    Regards

    Bala

  • That was just an example of how you may have to change some basic EMAC0 configurations for your application to function without adding wait states into packets. Perhaps EMAC0 DMA priority is not TX rather RX and only from CCS debug register view might a specific condition be linked to the timeout error you report.

    It would surprise me that no abnormal interrupt status in EMACDMARIS REG57  or other registers are occurring prior to the timeout events. Anyway you can enable the same RFC flow control handshake (lwiplib.c) if that is what your NDK application is using.

  • Balasubramani,

    I was hoping you would be able to post the EMACSnow_private data and answer my questions from the post above. Or have you found a resolution and moved on?

    ~Ramsey

  • Balasubramani C said:

    failure one

    Balasubramani C said:
    the windows pc ip are 192.168.1.7 and 192.168.8.7. Others are TM4C.

    Looking at the failure case the packets transmitted from the TM4C appear to show the TCP Sequence Number incrementing when the transmitted Len is zero. E.g. packet numbers 138, 141, 144, 147. Was the screenshot of the wireshark capture filtered in some way?

    Can you attach the raw wireshark captures for the good and failure cases?

  • Hi Ramsey,

    Ramsey said:
    I was hoping you would be able to post the EMACSnow_private data and answer my questions from the post above

    find the snapshot of EMACSnow_private after giving Tx transmit timeout error. 

    Ramsey said:
    have you found a resolution and moved on?

    - No. still i didn't find the root cause of the problem.

    Regards

    Bala

  • Hello Chester Gillon,

    Chester Gillon said:
    Looking at the failure case the packets transmitted from the TM4C appear to show the TCP Sequence Number incrementing when the transmitted Len is zero. E.g. packet numbers 138, 141, 144, 147. Was the screenshot of the wireshark capture filtered in some way?

    - Yes . it was filtered only for TCP packets.

    Chester Gillon said:
    Can you attach the raw wireshark captures for the good and failure cases?

    -

    Here i have attached wireshark log with excel format and also attached the snapshot of Tx transmission error packets. here System IP is 192.168.8.2 and TM4C1292NCPDT IP is  192.168.8.4.

    Modbus_Tx_Timeout_error_log.xlsx

    Look at the snapshot of failure cases.

    Regards

    Bala

  • Hi Balasubramani,

    Thanks for posting the wireshark capture, but we will still need some more information about the capture. First off, I can see in rows 284 and 285 of the excel file that the NDK is responding to ARP messages, so it appears the NDK stack is still alive. Earlier you mentioned that the TM4C would not even respond to ping requests during a fail state, but I cannot see these ping attempts in the wireshark capture.

    Can you take another wireshark capture with no filters and make sure to try pinging the TM4C, so that it shows up in the capture? Additionally, can you upload the capture as a wireshark capture file instead of an excel file?

    Regards,

    Dalton

  • Hi Bala,

    Did this get resolved?

    Todd
  • Hi Todd,

    the issues not solved completely. but it solve temporarily by disabling instrumentation NDK stack. by doing this, the error messages which iare observed in wireshark got reduced to 10:1 ratio. this is meeting my system performance goal am just continuing other tasks. but i need to investigate further.

    Regards
    Bala