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.

TMS320F28388D: Cannot get "enet_lwip" example to run

Part Number: TMS320F28388D
Other Parts Discussed in Thread: C2000WARE,

Hello TI Support Team,

I imported both "cm_common_config_c28x" and "enet_lwip" from C2000Ware_3_03_00_00 into CCS.
Then, I set the following macros in the "cm_common_config_c28x" project through predefined symbols:
- ETHERNET
- USE_20MHZ_XTAL (my ControlCARD is rev MCU063A-)
Since my LAN is on 192.168.11.x I set in "enet_lwip"
    unsigned long IPAddr = 0xC0A80B20;
I also changed the following line in 2838x_flash_lnk_cm_lwip.cmd
.const           : > SRAM
to
.const           : > CMBANK0_SECTOR0
Next, I compiled both projects for FLASH and programmed the two cores.
 
Unfortunately, the CM does not respond to ping 192.168.11.32
My Ethernet cable is plugged into the single connector on the back of the card.

Are any hardware configurations required on the ControlCARD?

Any other suggestions on how to debug this?

Thanks,
Beat

  • Hi Beat,

    The DMA of ethernet cannot access FLASH sector. Without the change .const SRAM to CMBANK0_SECTOR is it working? In order to make it work standalone you can do something like this. Load const from Flash, copy it to sram in your main function before ethernet init.

    Linker cmd change:

    .const : {} LOAD = CMBANK0_SECTOR0 | CMBANK0_SECTOR1 ,
    RUN = SRAM,
    LOAD_START(constLoadStart),
    LOAD_SIZE(constLoadSize),
    LOAD_END(constLoadEnd),
    RUN_START(constRunStart),
    RUN_SIZE(constRunSize),
    RUN_END(constRunEnd)

    Main function addition:

    memcpy(&constRunStart, &constLoadStart, (size_t)&constLoadSize);

    Thanks,

    Yashwant

  • Hello Yashwant,

    Thank you for the quick response and explanations.

    I tried your modification, but was still unable to ping the CM. Let me investigate further and provide you with more information.

    In the meantime, can you please point me to a document that describes which portions of lwip are supported by your port. For example, I see the following comment in the code: "Current implementation works with Static IP address only."

    Regards,

    Beat

  • Hello Yashwant,

    I experimented some more this evening but without success.

    Are you able to able to run the demo from Flash as a standalone application, or are you always loading/debugging via CCS?

    Thanks,

    Beat

  • Hi Beat,

    We currently have tested it only through JTAG (debugging). For the future release we will be testing for the standalone mode.

    Have you used the FLASH configuration in the cm_common_config_c28x as well? As it will be needed to update the boot mode of CM from FLASH.

    Thanks,

    Yashwant

  • Yashwant,

    Yes, "_FLASH" is defined. "cm_common_config_c28" also misses an endless loop at the end of the main function, which I added.

    I suspect the problem is on the CM side. Probably with the device initialization (flash, peripheral clocks, watchdog?) when it boots without CCS configurations.

    By when do you think will you be able to make an updated release?

    Also, do you have any feedback on this:

    In the meantime, can you please point me to a document that describes which portions of lwip are supported by your port. For example, I see the following comment in the code: "Current implementation works with Static IP address only."

    Thanks,

    Beat

  • Hi Beat,

    Can you confirm you are using latest C2000Ware ?

    Regards,

    Vivek Singh

  • Hi Vivek,

    Affirmative: C2000Ware_3_03_00_00

    Thanks,

    Beat

  • Hi Beat,

    These are the latest files that have been tested for standalone mode. Can you try with the new updates.

    Regarding the lwip features support the comments are self explanatory. 

    5556.f2838xif.c
    //###########################################################################
    //
    // FILE:   f2838xif.c
    //
    // TITLE:  F2838x interface port file.
    //
    //###########################################################################
    // $TI Release: $
    // $Release Date: $
    // $Copyright: $
    //###########################################################################
    
    /**
     * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice,
     *    this list of conditions and the following disclaimer.
     * 2. 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.
     * 3. The name of the author may not be used to endorse or promote products
     *    derived from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
     *
     * This file is part of the lwIP TCP/IP stack.
     *
     * Author: Adam Dunkels <adam@sics.se>
     *
     */
    
    /**
     * Copyright (c) 2018 Texas Instruments Incorporated
     *
     * This file is dervied from the ``ethernetif.c'' skeleton Ethernet network
     * interface driver for lwIP.
     *
     */
    
    #include <string.h>
    /**
     * lwIP specific header files
     */
    #include "lwip/opt.h"
    #include "lwip/def.h"
    #include "lwip/mem.h"
    #include "lwip/pbuf.h"
    #include "lwip/sys.h"
    #include <lwip/stats.h>
    #include <lwip/snmp.h>
    #include "netif/etharp.h"
    #include "netif/ppp/pppoe.h"
    #include "netif/f2838xif.h"
    
    /**
     * f2838x device specific header files
     */
    #include "inc/hw_emac.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib_cm/ethernet.h"
    #include "driverlib_cm/interrupt.h"
    #include "driverlib_cm/sysctl.h"
    
    #include "utils/lwiplib.h"
    /**
     * Sanity Check:  This interface driver will NOT work if the following defines
     * are incorrect.
     *
     */
    #if (PBUF_LINK_HLEN != 16)
    #error "PBUF_LINK_HLEN must be 16 for this interface driver!"
    #endif
    #if (ETH_PAD_SIZE != 0)
    #error "ETH_PAD_SIZE must be 0 for this interface driver!"
    #endif
    #if (!SYS_LIGHTWEIGHT_PROT)
    #error "SYS_LIGHTWEIGHT_PROT must be enabled for this interface driver!"
    #endif
    
    /**
     * Number of pbufs supported in low-level tx/rx pbuf queue.
     *
     */
    #ifndef F2838X_NUM_PBUF_QUEUE
    #define F2838X_NUM_PBUF_QUEUE    20
    #endif
    
    #define EMAC_BASE                   0x400C0000U //EMAC
    #define EMAC_SS_BASE                0x400C2000U //EMACSS
    
    /* Define those to better describe your network interface. */
    #define IFNAME0 't'
    #define IFNAME1 'i'
    
    struct pbuf *transmitPbufSave;
    
    /* Helper struct to hold a queue of pbufs for transmit and receive. */
    struct pbufq
    {
        struct pbuf *pbuf[F2838X_NUM_PBUF_QUEUE];
        unsigned long qwrite;
        unsigned long qread;
        unsigned long overflow;
    };
    
    /* Helper macros for accessing pbuf queues. */
    #define PBUF_QUEUE_EMPTY(q) \
        (((q)->qwrite == (q)->qread) ? true : false)
    
    #define PBUF_QUEUE_FULL(q) \
        ((((((q)->qwrite + 1) % F2838X_NUM_PBUF_QUEUE)) == (q)->qread) ? \
        true : false )
    
    /**
     * Helper struct to hold private data used to operate your ethernet interface.
     * Keeping the ethernet address of the MAC in this struct is not necessary
     * as it is already kept in the struct netif.
     * But this is only an example, anyway...
     */
    struct f2838xif
    {
        struct eth_addr *ethaddr;
        /* Add whatever per-interface state that is needed here. */
        struct pbufq txq;
        Ethernet_Pkt_Desc *pktDesc;
    };
    
    /**
     * A structure used to keep track of driver state and error counts.
     */
    typedef struct {
        uint32_t ui32TXCount;
        uint32_t ui32TXCopyCount;
        uint32_t ui32TXCopyFailCount;
        uint32_t ui32TXNoDescCount;
        uint32_t ui32TXBufQueuedCount;
        uint32_t ui32TXBufFreedCount;
        uint32_t ui32RXBufReadCount;
        uint32_t ui32RXPacketReadCount;
        uint32_t ui32RXPacketErrCount;
        uint32_t ui32RXPacketCBErrCount;
        uint32_t ui32RXNoBufCount;
    }
    tDriverStats;
    
    tDriverStats g_sDriverStats = {0};
    
    #define DRIVER_STATS_INC(x) do{ g_sDriverStats.ui32##x++; } while(0)
    #define DRIVER_STATS_DEC(x) do{ g_sDriverStats.ui32##x--; } while(0)
    #define DRIVER_STATS_ADD(x, inc) do{ g_sDriverStats.ui32##x += inc; } while(0)
    #define DRIVER_STATS_SUB(x, dec) do{ g_sDriverStats.ui32##x -= dec; } while(0)
    
    /*
     * Creating a queue that maps an ethernet packet descriptor with
     * the corresponding pbuf. It is useful to free up the allocated pbuf memory
     * after the packet has been sent.
     */
    #ifndef F2838X_INTERFACE_NUM_PKT_DESC_QUEUE
    #define F2838X_INTERFACE_NUM_PKT_DESC_QUEUE    20
    #endif
    
    /**
     * 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 struct f2838xif f2838xif_data;
    
    Ethernet_Handle emac_handle;
    
    /**
     * A macro which determines whether a pointer is within the SRAM address
     * space and, hence, points to a buffer that the Ethernet MAC can directly
     * DMA from.
     */
    #define PTR_SAFE_FOR_EMAC_DMA(ptr) (((uint32_t)(ptr) >= 0x2000800) &&   \
                                        ((uint32_t)(ptr) < 0x2000FFFF))
    
    /**
     * In this function, the hardware should be initialized.
     * Called from f2838xif_init().
     *
     * @param netif the already initialized lwip network interface structure
     *        for this ethernetif
     */
    static void
    f2838xif_hwinit(struct netif *netif)
    {
        uint32_t mac_low,mac_high;
        uint8_t *pucTemp;
    
        /* set MAC hardware address length */
        netif->hwaddr_len = ETHARP_HWADDR_LEN;
    
        /* set MAC address */
        Ethernet_getMACAddr(EMAC_BASE, 0, &mac_high, &mac_low);
    
        pucTemp = (uint8_t *)&mac_low;
        netif->hwaddr[0] = pucTemp[0];
        netif->hwaddr[1] = pucTemp[1];
        netif->hwaddr[2] = pucTemp[2];
        netif->hwaddr[3] = pucTemp[3];
    
        pucTemp = (uint8_t *)&mac_high;
        netif->hwaddr[4] = pucTemp[0];
        netif->hwaddr[5] = pucTemp[1];
    
        /* maximum transfer unit */
        netif->mtu = 1500;
    
        /* device capabilities */
        /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
        netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_IGMP;
    }
    
    /**
     * This function should do the actual transmission of the packet. The packet is
     * contained in the pbuf that is passed to the function. This pbuf might be
     * chained.
     *
     * @param netif the lwip network interface structure for this ethernetif
     * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
     * @return ERR_OK if the packet could be sent
     *         an err_t value if the packet couldn't be sent
     * @note This function MUST be called with interrupts disabled or with the
     *       F2838x Ethernet transmit fifo protected.
     */
    static err_t
    f2838xif_transmit(struct netif *netif, struct pbuf *p)
    {
        struct pbuf *q;
    
        /* No of pbufs (if chained)*/
        int n=0;
        int i=0;
        Ethernet_Pkt_Desc *pktDescOrigPtr, *pktDescPtr;
    
        /* ENTER CRITICAL SECTION
         * This is to protect the forming of packetc descriptor chain using pbufs
         * passed to the function.
         */
        Interrupt_disable(INT_EMAC_TX0);
        Interrupt_disable(INT_EMAC_RX0);
    
        /*
         * Make sure we still have a valid buffer (it may have been copied)
         */
        if(!p)
        {
            LINK_STATS_INC(link.memerr);
    
            /* EXIT CRITICAL SECTION */
            Interrupt_enable(INT_EMAC_TX0);
            Interrupt_enable(INT_EMAC_RX0);
    
            return(ERR_MEM);
        }
    
        /*
         * Count the number of the pbufs in the chain that we are passed with.
         */
        for(q = p; q != NULL; q = q->next)
                n++;
    
        /*
         * Get the head of the packet descriptor chain that will be passed to
         * the driver for sending.
         */
        pktDescOrigPtr = mem_malloc(sizeof(Ethernet_Pkt_Desc));
        if(pktDescOrigPtr == NULL)
        {
            __asm("   bkpt #0");
        }
    
        /*
         * Go over the pbufs present in the chain and allot a packet descriptor for
         * each pbuf. The descriptors will also be chained in the same order as
         * pbufs before passing the head of the chain to the driver.
         */
        //pbuf_ref(p);
        transmitPbufSave = p;
        for(q = p, pktDescPtr = pktDescOrigPtr; // Initialization
            q != NULL; // Condition evaluation
            q = q->next, pktDescPtr = pktDescPtr->nextPacketDesc) // Manipulation
        {
            /*
             * Initializing this data structure, otherwise garbage values will
             * result in rogue results while running.
             */
            memset(pktDescPtr,0,sizeof(Ethernet_Pkt_Desc));
    
            pktDescPtr->dataOffset = 0;
            pktDescPtr->dataBuffer = q->payload;
            pktDescPtr->pktChannel = ETHERNET_DMA_CHANNEL_NUM_0;
            pktDescPtr->pktLength = q->tot_len;
            pktDescPtr->bufferLength = q->len;
            pktDescPtr->validLength = q->len;
    
    
              if(i==0)
              {
                    if(n!=1)
                    {
                        /*
                         * Prepare the next ethernet packet descriptor holder if
                         * there is a pbuf next in the chain.
                         */
                        pktDescPtr->nextPacketDesc =
                                mem_malloc(sizeof(Ethernet_Pkt_Desc));
                        if(pktDescPtr->nextPacketDesc == NULL)
                            {
                                __asm("   bkpt #0");
                            }
                        pktDescPtr->flags = ETHERNET_PKT_FLAG_SOP ;
                    }
                    else
                    {
                        pktDescPtr->nextPacketDesc = 0;
                        pktDescPtr->flags = ETHERNET_PKT_FLAG_SOP |
                                            ETHERNET_PKT_FLAG_EOP;
                    }
              }
              else
              {
                  if(q->next != NULL)
                  {
                      /*
                       * Prepare the next ethernet packet descriptor holder if
                       * there is a pbuf next in the chain.
                       */
                      pktDescPtr->nextPacketDesc =
                              mem_malloc(sizeof(Ethernet_Pkt_Desc));
                      if(pktDescPtr->nextPacketDesc == NULL)
                          {
                              __asm("   bkpt #0");
                          }
                      pktDescPtr->flags = 0;
                  }
                  else
                  {
                      pktDescPtr->nextPacketDesc = 0;
                      pktDescPtr->flags = ETHERNET_PKT_FLAG_EOP;
                  }
              }
    
              i++;
        }
    
        /* EXIT CRITICAL SECTION */
        Interrupt_enable(INT_EMAC_TX0);
        Interrupt_enable(INT_EMAC_RX0);
    
        /*
         * Hand over the packet descriptor to the driver.
         */
        pktDescOrigPtr->numPktFrags = n;
        Ethernet_sendPacket(emac_handle,pktDescOrigPtr);
    
        LINK_STATS_INC(link.xmit);
    
        return(ERR_OK);
    }
    
    /**
     * This function will process all transmit descriptors and free pbufs attached
     * to any that have been transmitted since we last checked.
     *
     * This function is called only from the Ethernet interrupt handler.
     *
     * @param netif the lwip network interface structure for this ethernetif
     * @return None.
     */
    int descriptorFreeErr=0;
    static void
    f2838xif_process_transmit(struct netif *netif, Ethernet_Pkt_Desc *pPacket)
    {
        Ethernet_Pkt_Desc *pktDescPtr, *pktDescPtrShadow;
    
        /*
         * Free the packet descriptor memory.
         */
        if (pPacket == 0)
            return;
    
        pktDescPtr = pPacket;
    
        /* ENTER CRITICAL SECTION */
        Interrupt_disable(ETHERNET_TX_INTR_CH0);
        Interrupt_disable(ETHERNET_RX_INTR_CH0);
    
        do
        {
            pktDescPtrShadow = pktDescPtr->nextPacketDesc;
            mem_free(pktDescPtr);
            pktDescPtr = pktDescPtrShadow;
        }
        while(pktDescPtr != 0);
        //pbuf_free(transmitPbufSave);
        /* EXIT CRITICAL SECTION */
        Interrupt_enable(ETHERNET_TX_INTR_CH0);
        Interrupt_enable(ETHERNET_RX_INTR_CH0);
    }
    
    /**
     * This function with either place the packet into the F2838x transmit fifo,
     * or will place the packet in the interface PBUF Queue for subsequent
     * transmission when the transmitter becomes idle.
     *
     * @param netif the lwip network interface structure for this ethernetif
     * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
     * @return ERR_OK if the packet could be sent
     *         an err_t value if the packet couldn't be sent
     *
     */
    
    static err_t
    f2838xif_output(struct netif *netif, struct pbuf *p)
    {
        f2838xif_transmit(netif, p);
    
        return ERR_OK;
    }
    
    /**
     * This function will read a single packet from the F2838x ethernet
     * interface, if available, and return a pointer to a pbuf.  The timestamp
     * of the packet will be placed into the pbuf structure.
     *
     * @param netif the lwip network interface structure for this ethernetif
     * @return pointer to pbuf packet if available, NULL otherswise.
     */
    Ethernet_Pkt_Desc*
    f2838xif_receive( struct netif *netif, Ethernet_Pkt_Desc *pPacket )
    {
        struct pbuf *p;
    
    #if LWIP_PTPD
        u32_t time_s, time_ns;
        /* Get the current timestamp if PTPD is enabled */
        lwIPHostGetTime(&time_s, &time_ns);
    #endif
    
        p = pbuf_alloc(PBUF_RAW, sizeof(struct pbuf), PBUF_POOL);
        if(p)
        {
            p->payload = pPacket->dataBuffer;
    
            p->len = pPacket->pktLength;
            p->tot_len = p->len;
    
        #if LWIP_PTPD
            /* Place the timestamp in the PBUF */
            p->time_s = time_s;
            p->time_ns = time_ns;
        #endif
    
            if(ethernet_input(p, netif)!=ERR_OK)
            {
                /* drop the packet */
                LWIP_DEBUGF(NETIF_DEBUG, ("f2838xif_input: input error\n"));
                pbuf_free(p);
                p = NULL;
                /* Adjust the link statistics */
                LINK_STATS_INC(link.memerr);
                LINK_STATS_INC(link.drop);
            }
        }
    
    
        Ethernet_Pkt_Desc *newPacket = mem_calloc(1, sizeof(Ethernet_Pkt_Desc));
        newPacket->dataBuffer = pPacket->dataBuffer;
        if(pPacket != NULL)
            mem_free(pPacket);
    
        LINK_STATS_INC(link.recv);
    
        return(newPacket);
    }
    
    Ethernet_Pkt_Desc *f2838xif_newbuffcallback(void)
    {
        Ethernet_Pkt_Desc *newPacket = mem_calloc(1, sizeof(Ethernet_Pkt_Desc));
    
        if(newPacket)
        {
            newPacket->dataBuffer= memp_malloc(MEMP_PBUF_POOL);
        }
        return newPacket;
    }
    
    /**
     * Should be called at the beginning of the program to set up the
     * network interface. It calls the function f2838xif_hwinit() to do the
     * actual setup of the hardware.
     * This function should be passed as a parameter to netif_add().
     *
     * @param netif the lwip network interface structure for this ethernetif
     * @return ERR_OK if the loopif is initialized
     *         ERR_MEM if private data couldn't be allocated
     *         any other err_t on error
     */
    err_t
    f2838xif_init(struct netif *netif)
    {
        LWIP_ASSERT("netif != NULL", (netif != NULL));
    
    #if LWIP_NETIF_HOSTNAME
        /* Initialize interface hostname */
        netif->hostname = "lwip";
    #endif /* LWIP_NETIF_HOSTNAME */
    
        /*
         * Initialize the snmp variables and counters inside the struct netif.
         * The last argument should be replaced with your link speed, in units
         * of bits per second.
         */
        NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 1000000);
    
        netif->state = &f2838xif_data;
        netif->name[0] = IFNAME0;
        netif->name[1] = IFNAME1;
    
        /* We directly use etharp_output() here to save a function call.
         * You can instead declare your own function an call etharp_output()
         * from it if you have to do some checks before sending (e.g. if link
         * is available...) */
        netif->output = etharp_output;
        netif->linkoutput = f2838xif_output;
    
        f2838xif_data.ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
        f2838xif_data.txq.qread = f2838xif_data.txq.qwrite = 0;
        f2838xif_data.txq.overflow = 0;
    
        /* initialize the hardware */
        f2838xif_hwinit(netif);
    
        return ERR_OK;
    }
    
    /**
     * Process tx and rx packets at the low-level interrupt.
     *
     * Should be called from the F2838x Ethernet Interrupt Handler.  This
     * function will read packets from the F2838x Ethernet fifo and place them
     * into a pbuf queue.  If the transmitter is idle and there is at least one packet
     * on the transmit queue, it will place it in the transmit fifo and start the
     * transmitter.
     *
     */
    
    Ethernet_Pkt_Desc*
    f2838xif_interrupt(struct netif *netif, Ethernet_Pkt_Desc *pPacket)
    {
        Ethernet_Pkt_Desc *sPacket = NULL;
    
        /**
         * Based on the flags we get from pPacket, we should decide whether
         * to trasnmit or receive. Currently, it works for only incoming
         * ICMP ping requests.
         */
    
        /* ENTER CRITICAL SECTION
         * This is to protect the forming of packetc descriptor chain using pbufs
         * passed to the function.
         */
        Interrupt_disable(INT_EMAC_TX0);
        Interrupt_disable(INT_EMAC_RX0);
    
        if(pPacket->flags & ETHERNET_INTERRUPT_FLAG_RECEIVE)
            sPacket = f2838xif_receive(netif, pPacket);
    
        if(pPacket->flags & ETHERNET_INTERRUPT_FLAG_TRANSMIT)
            f2838xif_process_transmit(netif, pPacket);
    
        /* EXIT CRITICAL SECTION */
        Interrupt_enable(INT_EMAC_TX0);
        Interrupt_enable(INT_EMAC_RX0);
    
        return (sPacket);
    }
    

    3731.enet_lwip.c
    //###########################################################################
    //
    // FILE:   enet_lwip.c
    //
    // TITLE:  lwIP based Ethernet Example.
    //
    //###########################################################################
    // $TI Release: $
    // $Release Date: $
    // $Copyright: $
    //###########################################################################
    
    #include <string.h>
    
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_nvic.h"
    #include "inc/hw_types.h"
    #include "inc/hw_sysctl.h"
    #include "inc/hw_emac.h"
    
    #include "driverlib_cm/ethernet.h"
    #include "driverlib_cm/gpio.h"
    #include "driverlib_cm/interrupt.h"
    #include "driverlib_cm/flash.h"
    
    #include "driverlib_cm/sysctl.h"
    #include "driverlib_cm/systick.h"
    
    #include "utils/lwiplib.h"
    #include "board_drivers/pinout.h"
    
    #include "lwip/apps/httpd.h"
    //*****************************************************************************
    //
    //! \addtogroup master_example_list
    //! <h1>Ethernet with lwIP (enet_lwip)</h1>
    //!
    //! This example application demonstrates the operation of the F2838x
    //! microcontroller Ethernet controller using the lwIP TCP/IP Stack. Once
    //! programmed, the device sits endlessly waiting for ICMP ping requests. It
    //! has a static IP address. To ping the device, the sender has to be in the
    //! same network. The stack also supports ARP.
    //!
    //! For additional details on lwIP, refer to the lwIP web page at:
    //! http://savannah.nongnu.org/projects/lwip/
    //
    //*****************************************************************************
    
    // These are defined by the linker (see device linker command file)
    extern uint16_t RamfuncsLoadStart;
    extern uint16_t RamfuncsLoadSize;
    extern uint16_t RamfuncsRunStart;
    extern uint16_t RamfuncsLoadEnd;
    extern uint16_t RamfuncsRunEnd;
    extern uint16_t RamfuncsRunSize;
    
    extern uint16_t constLoadStart;
    extern uint16_t constLoadEnd;
    extern uint16_t constLoadSize;
    extern uint16_t constRunStart;
    extern uint16_t constRunEnd;
    extern uint16_t constRunSize;
    
    #define DEVICE_FLASH_WAITSTATES 2
    
    //*****************************************************************************
    //
    // Driver specific initialization code and macro.
    //
    //*****************************************************************************
    
    #define ETHERNET_NO_OF_RX_PACKETS   2U
    #define ETHERNET_MAX_PACKET_LENGTH 1538U
    #define NUM_PACKET_DESC_RX_APPLICATION 8
    
    Ethernet_Handle emac_handle;
    Ethernet_InitConfig *pInitCfg;
    uint32_t Ethernet_numRxCallbackCustom = 0;
    uint32_t releaseTxCount = 0;
    uint32_t genericISRCustomcount = 0;
    uint32_t genericISRCustomRBUcount = 0;
    uint32_t genericISRCustomROVcount = 0;
    uint32_t genericISRCustomRIcount = 0;
    
    uint32_t systickPeriodValue = 15000000;
    Ethernet_Pkt_Desc  pktDescriptorRXCustom[NUM_PACKET_DESC_RX_APPLICATION];
    extern uint32_t Ethernet_numGetPacketBufferCallback;
    extern Ethernet_Device Ethernet_device_struct;
    uint8_t Ethernet_rxBuffer[ETHERNET_NO_OF_RX_PACKETS *
                              ETHERNET_MAX_PACKET_LENGTH];
    
    extern Ethernet_Pkt_Desc*
    lwIPEthernetIntHandler(Ethernet_Pkt_Desc *pPacket);
    
    void CM_init(void)
    {
        //
        // Disable the watchdog
        //
        SysCtl_disableWatchdog();
    
    #ifdef _FLASH
        //
        // Copy time critical code and flash setup code to RAM. This includes the
        // following functions: InitFlash();
        //
        // The RamfuncsLoadStart, RamfuncsLoadSize, and RamfuncsRunStart symbols
        // are created by the linker. Refer to the device .cmd file.
        // Html pages are also being copied from flash to ram.
        //
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
        memcpy(&constRunStart, &constLoadStart, (size_t)&constLoadSize);
        //
        // Call Flash Initialization to setup flash waitstates. This function must
        // reside in RAM.
        //
        Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES);
    #endif
    
        //
        // Sets the NVIC vector table offset address.
        //
    #ifdef _FLASH
        Interrupt_setVectorTableOffset((uint32_t)vectorTableFlash);
    #else
        Interrupt_setVectorTableOffset((uint32_t)vectorTableRAM);
    #endif
    
    }
    //*****************************************************************************
    //
    // HTTP Webserver related callbacks and definitions.
    //
    //*****************************************************************************
    //
    // Currently, this implemented as a pointer to function which is called when
    // corresponding query is received by the HTTP webserver daemon. When more
    // features are needed to be added, it should be implemented as a separate
    // interface.
    //
    void httpLEDToggle(void);
    void(*ledtoggleFuncPtr)(void) = &httpLEDToggle;
    
    //*****************************************************************************
    //
    // The interrupt handler for the SysTick interrupt.
    //
    //*****************************************************************************
    void
    SysTickIntHandler(void)
    {
        //
        // Call the lwIP timer handler.
        //
        lwIPTimer(systickPeriodValue);
    }
    
    //*****************************************************************************
    //
    //  This function is a callback function called by the example to
    //  get a Packet Buffer. Has to return a ETHERNET_Pkt_Desc Structure.
    //  Rewrite this API for custom use case.
    //
    //*****************************************************************************
    Ethernet_Pkt_Desc* Ethernet_getPacketBufferCustom(void)
    {
        //
        // Get the next packet descriptor from the descriptor pool
        //
        uint32_t shortIndex = (Ethernet_numGetPacketBufferCallback + 3)
                    % NUM_PACKET_DESC_RX_APPLICATION;
    
        //
        // Increment the book-keeping pointer which acts as a head pointer
        // to the circular array of packet descriptor pool.
        //
        Ethernet_numGetPacketBufferCallback++;
    
        //
        // Update buffer length information to the newly procured packet
        // descriptor.
        //
        pktDescriptorRXCustom[shortIndex].bufferLength =
                                      ETHERNET_MAX_PACKET_LENGTH;
    
        //
        // Update the receive buffer address in the packer descriptor.
        //
        pktDescriptorRXCustom[shortIndex].dataBuffer =
                                          &Ethernet_device_struct.rxBuffer [ \
                   (ETHERNET_MAX_PACKET_LENGTH*Ethernet_device_struct.rxBuffIndex)];
    
        //
        // Update the receive buffer pool index.
        //
        Ethernet_device_struct.rxBuffIndex += 1U;
        Ethernet_device_struct.rxBuffIndex  = \
        (Ethernet_device_struct.rxBuffIndex%ETHERNET_NO_OF_RX_PACKETS);
    
        //
        // Receive buffer is usable from Address 0
        //
        pktDescriptorRXCustom[shortIndex].dataOffset = 0U;
    
        //
        // Return this new descriptor to the driver.
        //
        return (&(pktDescriptorRXCustom[shortIndex]));
    }
    
    //*****************************************************************************
    //
    //  This is a hook function and called by the driver when it receives a
    //  packet. Application is expected to replenish the buffer after consuming it.
    //  Has to return a ETHERNET_Pkt_Desc Structure.
    //  Rewrite this API for custom use case.
    //
    //*****************************************************************************
    Ethernet_Pkt_Desc* Ethernet_receivePacketCallbackCustom(
            Ethernet_Handle handleApplication,
            Ethernet_Pkt_Desc *pPacket)
    {
        //
        // Book-keeping to maintain number of callbacks received.
        //
    #ifdef ETHERNET_DEBUG
        Ethernet_numRxCallbackCustom++;
    #endif
    
        //
        // This is a placeholder for Application specific handling
        // We are replenishing the buffer received with another buffer
        //
        return lwIPEthernetIntHandler(pPacket);
    }
    
    void Ethernet_releaseTxPacketBufferCustom(
            Ethernet_Handle handleApplication,
            Ethernet_Pkt_Desc *pPacket)
    {
        //
        // Once the packet is sent, reuse the packet memory to avoid
        // memory leaks. Call this interrupt handler function which will take care
        // of freeing the memory used by the packet descriptor.
        //
        lwIPEthernetIntHandler(pPacket);
    
        //
        // Increment the book-keeping counter.
        //
    #ifdef ETHERNET_DEBUG
        releaseTxCount++;
    #endif
    }
    
    interrupt void Ethernet_genericISRCustom(void)
    {
        genericISRCustomcount++;
        Ethernet_RxChDesc *rxChan;
        Ethernet_TxChDesc *txChan;
        Ethernet_HW_descriptor    *descPtr;
        Ethernet_HW_descriptor    *tailPtr;
        if((ETHERNET_DMA_CH0_STATUS_AIS |
                           ETHERNET_DMA_CH0_STATUS_RBU) ==
                         (HWREG(Ethernet_device_struct.baseAddresses.enet_base +
                                ETHERNET_O_DMA_CH0_STATUS) &
                                (uint32_t)(ETHERNET_DMA_CH0_STATUS_AIS |
                                           ETHERNET_DMA_CH0_STATUS_RBU)))
        {
            genericISRCustomRBUcount++;
            /*
                 * Clear the AIS and RBU status bit. These MUST be
                 * cleared together!
                 */
                Ethernet_clearDMAChannelInterrupt(
                        Ethernet_device_struct.baseAddresses.enet_base,
                        ETHERNET_DMA_CHANNEL_NUM_0,
                        ETHERNET_DMA_CH0_STATUS_AIS |
                        ETHERNET_DMA_CH0_STATUS_RBU);
    
                /*
               *Recover from Receive Buffer Unavailable (and hung DMA)
             *
             * All descriptor buffers are owned by the application, and
             * in result the DMA cannot transfer incoming frames to the
             * buffers (RBU condition). DMA has also entered suspend
             * mode at this point, too.
             *
             * Drain the RX queues
             */
    
                /* Upon RBU error, discard all previously received packets */
                if(Ethernet_device_struct.initConfig.pfcbDeletePackets != NULL)
                    (*Ethernet_device_struct.initConfig.pfcbDeletePackets)();
    
                rxChan =
                   &Ethernet_device_struct.dmaObj.rxDma[ETHERNET_DMA_CHANNEL_NUM_0];
    
        /*
         * Need to disable multiple interrupts, so protect the code to do so within
         * a global disable block (to prevent getting interrupted in between)
         */
    
                if(NULL!= Ethernet_device_struct.ptrPlatformInterruptDisable)
                {
                    (*Ethernet_device_struct.ptrPlatformInterruptDisable)(
                        Ethernet_device_struct.interruptNum[
                            ETHERNET_RX_INTR_CH0 + rxChan->chInfo->chNum]);
    
                    (*Ethernet_device_struct.ptrPlatformInterruptDisable)(
                        Ethernet_device_struct.interruptNum[
                            ETHERNET_GENERIC_INTERRUPT]);
                }
    
                /* verify we have full capacity in the descriptor queue */
                if(rxChan->descQueue.count < rxChan->descMax) {
                  /* The queue is not at full capacity due to OOM errors.
                  Try to fill it again */
                    Ethernet_addPacketsIntoRxQueue(rxChan);
                }
    
        /*
         * Need to re-enable multiple interrupts. Again, protect the code to do so
         * within a global disable block (to prevent getting interrupted in between)
         */
    
                if(NULL!= Ethernet_device_struct.ptrPlatformInterruptEnable)
                {
                    (*Ethernet_device_struct.ptrPlatformInterruptEnable)(
                        Ethernet_device_struct.interruptNum[
                            ETHERNET_RX_INTR_CH0 + rxChan->chInfo->chNum]);
                    (*Ethernet_device_struct.ptrPlatformInterruptEnable)(
                        Ethernet_device_struct.interruptNum[
                            ETHERNET_GENERIC_INTERRUPT]);
                }
                Ethernet_removePacketsFromRxQueue(rxChan,
                        ETHERNET_COMPLETION_NORMAL);
    
                /* To un-suspend the DMA:
                 *
                 * 1. Change ownership of current RX descriptor to DMA
                 *
                 * 2. Issue a receive poll demand command
                 *
                 * 3. Issue a write to the descriptor tail pointer register
                 */
    
                /* 1. Change current descriptor owernship back to DMA */
                descPtr = (Ethernet_HW_descriptor *)(HWREG(
                        Ethernet_device_struct.baseAddresses.enet_base +
                        (uint32_t)ETHERNET_O_DMA_CH0_CURRENT_APP_RXDESC));
    
                descPtr->des3 = ETHERNET_DESC_OWNER | ETHERNET_RX_DESC_IOC |
                                  ETHERNET_RX_DESC_BUF1_VALID;
    
                /* 2. Issue a receive poll demand command */
    
                /* 3. Issue a write to the descriptor tail pointer register */
                tailPtr = (Ethernet_HW_descriptor *)(HWREG(
                            Ethernet_device_struct.baseAddresses.enet_base +
                            (uint32_t)ETHERNET_O_DMA_CH0_RXDESC_TAIL_POINTER));
    
                Ethernet_writeRxDescTailPointer(
                        Ethernet_device_struct.baseAddresses.enet_base,
                        ETHERNET_DMA_CHANNEL_NUM_0,
                        tailPtr);
    
    
        }
        if((ETHERNET_MTL_Q0_INTERRUPT_CONTROL_STATUS_RXOVFIS) ==
                             (HWREG(Ethernet_device_struct.baseAddresses.enet_base +
                                    ETHERNET_O_MTL_Q0_INTERRUPT_CONTROL_STATUS) &
                                    (uint32_t)(ETHERNET_MTL_Q0_INTERRUPT_CONTROL_STATUS_RXOVFIS
                                               )))
        {
            genericISRCustomROVcount++;
    
            //Acknowledge the MTL RX Queue overflow status
            Ethernet_enableMTLInterrupt(Ethernet_device_struct.baseAddresses.enet_base,0,
                                        ETHERNET_MTL_Q0_INTERRUPT_CONTROL_STATUS_RXOVFIS);
            /*
                     *Recover from Receive Buffer Unavailable (and hung DMA)
                   *
                   * All descriptor buffers are owned by the application, and
                   * in result the DMA cannot transfer incoming frames to the
                   * buffers (RBU condition). DMA has also entered suspend
                   * mode at this point, too.
                   *
                   * Drain the RX queues
                   */
    
                      /* Upon RBU error, discard all previously received packets */
                      if(Ethernet_device_struct.initConfig.pfcbDeletePackets != NULL)
                          (*Ethernet_device_struct.initConfig.pfcbDeletePackets)();
    
                      rxChan =
                         &Ethernet_device_struct.dmaObj.rxDma[ETHERNET_DMA_CHANNEL_NUM_0];
    
              /*
               * Need to disable multiple interrupts, so protect the code to do so within
               * a global disable block (to prevent getting interrupted in between)
               */
    
                      if(NULL!= Ethernet_device_struct.ptrPlatformInterruptDisable)
                      {
                          (*Ethernet_device_struct.ptrPlatformInterruptDisable)(
                              Ethernet_device_struct.interruptNum[
                                  ETHERNET_RX_INTR_CH0 + rxChan->chInfo->chNum]);
    
                          (*Ethernet_device_struct.ptrPlatformInterruptDisable)(
                              Ethernet_device_struct.interruptNum[
                                  ETHERNET_GENERIC_INTERRUPT]);
                      }
    
                      /* verify we have full capacity in the descriptor queue */
                      if(rxChan->descQueue.count < rxChan->descMax) {
                        /* The queue is not at full capacity due to OOM errors.
                        Try to fill it again */
                          Ethernet_addPacketsIntoRxQueue(rxChan);
                      }
    
              /*
               * Need to re-enable multiple interrupts. Again, protect the code to do so
               * within a global disable block (to prevent getting interrupted in between)
               */
    
                      if(NULL!= Ethernet_device_struct.ptrPlatformInterruptEnable)
                      {
                          (*Ethernet_device_struct.ptrPlatformInterruptEnable)(
                              Ethernet_device_struct.interruptNum[
                                  ETHERNET_RX_INTR_CH0 + rxChan->chInfo->chNum]);
                          (*Ethernet_device_struct.ptrPlatformInterruptEnable)(
                              Ethernet_device_struct.interruptNum[
                                  ETHERNET_GENERIC_INTERRUPT]);
                      }
                      Ethernet_removePacketsFromRxQueue(rxChan,
                              ETHERNET_COMPLETION_NORMAL);
    
                      /* To un-suspend the DMA:
                       *
                       * 1. Change ownership of current RX descriptor to DMA
                       *
                       * 2. Issue a receive poll demand command
                       *
                       * 3. Issue a write to the descriptor tail pointer register
                       */
    
                      /* 1. Change current descriptor owernship back to DMA */
                      descPtr = (Ethernet_HW_descriptor *)(HWREG(
                              Ethernet_device_struct.baseAddresses.enet_base +
                              (uint32_t)ETHERNET_O_DMA_CH0_CURRENT_APP_RXDESC));
    
                      descPtr->des3 = ETHERNET_DESC_OWNER | ETHERNET_RX_DESC_IOC |
                                        ETHERNET_RX_DESC_BUF1_VALID;
    
                      /* 2. Issue a receive poll demand command */
    
                      /* 3. Issue a write to the descriptor tail pointer register */
                      tailPtr = (Ethernet_HW_descriptor *)(HWREG(
                                  Ethernet_device_struct.baseAddresses.enet_base +
                                  (uint32_t)ETHERNET_O_DMA_CH0_RXDESC_TAIL_POINTER));
    
                      Ethernet_writeRxDescTailPointer(
                              Ethernet_device_struct.baseAddresses.enet_base,
                              ETHERNET_DMA_CHANNEL_NUM_0,
                              tailPtr);
        }
        if(0U != (HWREG(Ethernet_device_struct.baseAddresses.enet_base +
                                     ETHERNET_O_DMA_CH0_STATUS) &
                               (uint32_t) ETHERNET_DMA_CH0_STATUS_RI))
        {
            genericISRCustomRIcount++;
            Ethernet_clearDMAChannelInterrupt(
                            Ethernet_device_struct.baseAddresses.enet_base,
                            ETHERNET_DMA_CHANNEL_NUM_0,
                            ETHERNET_DMA_CH0_STATUS_NIS | ETHERNET_DMA_CH0_STATUS_RI);
        }
    }
    
    void
    Ethernet_init(const unsigned char *mac)
    {
        Ethernet_InitInterfaceConfig initInterfaceConfig;
        uint32_t macLower;
        uint32_t macHigher;
        uint8_t *temp;
    
        initInterfaceConfig.ssbase = EMAC_SS_BASE;
        initInterfaceConfig.enet_base = EMAC_BASE;
        initInterfaceConfig.phyMode = ETHERNET_SS_PHY_INTF_SEL_MII;
    
        //
        // Assign SoC specific functions for Enabling,Disabling interrupts
        // and for enabling the Peripheral at system level
        //
        initInterfaceConfig.ptrPlatformInterruptDisable =
                                                        &Platform_disableInterrupt;
        initInterfaceConfig.ptrPlatformInterruptEnable =
                                                         &Platform_enableInterrupt;
        initInterfaceConfig.ptrPlatformPeripheralEnable =
                                                        &Platform_enablePeripheral;
        initInterfaceConfig.ptrPlatformPeripheralReset =
                                                         &Platform_resetPeripheral;
    
        //
        // Assign the peripheral number at the SoC
        //
        initInterfaceConfig.peripheralNum = SYSCTL_PERIPH_CLK_ENET;
    
        //
        // Assign the default SoC specific interrupt numbers of Ethernet interrupts
        //
        initInterfaceConfig.interruptNum[0] = INT_EMAC;
        initInterfaceConfig.interruptNum[1] = INT_EMAC_TX0;
        initInterfaceConfig.interruptNum[2] = INT_EMAC_TX1;
        initInterfaceConfig.interruptNum[3] = INT_EMAC_RX0;
        initInterfaceConfig.interruptNum[4] = INT_EMAC_RX1;
    
        pInitCfg = Ethernet_initInterface(initInterfaceConfig);
    
        Ethernet_getInitConfig(pInitCfg);
        pInitCfg->dmaMode.InterruptMode = ETHERNET_DMA_MODE_INTM_MODE2;
    
        //
        // Assign the callbacks for Getting packet buffer when needed
        // Releasing the TxPacketBuffer on Transmit interrupt callbacks
        // Receive packet callback on Receive packet completion interrupt
        //
        pInitCfg->pfcbRxPacket = &Ethernet_receivePacketCallbackCustom;
        pInitCfg->pfcbGetPacket = &Ethernet_getPacketBufferCustom;
        pInitCfg->pfcbFreePacket = &Ethernet_releaseTxPacketBufferCustom;
    
        //
        //Assign the Buffer to be used by the Low level driver for receiving
        //Packets. This should be accessible by the Ethernet DMA
        //
        pInitCfg->rxBuffer = Ethernet_rxBuffer;
    
        //
        // The Application handle is not used by this application
        // Hence using a dummy value of 1
        //
        Ethernet_getHandle((Ethernet_Handle)1, pInitCfg , &emac_handle);
    
        //
        // Disable transmit buffer unavailable and normal interrupt which
        // are enabled by default in Ethernet_getHandle.
        //
        Ethernet_disableDmaInterrupt(Ethernet_device_struct.baseAddresses.enet_base,
                                     0, (ETHERNET_DMA_CH0_INTERRUPT_ENABLE_TBUE |
                                         ETHERNET_DMA_CH0_INTERRUPT_ENABLE_NIE));
    
        //
        // Enable the MTL interrupt to service the receive FIFO overflow
        // condition in the Ethernet module.
        //
        Ethernet_enableMTLInterrupt(Ethernet_device_struct.baseAddresses.enet_base,0,
                                    ETHERNET_MTL_Q0_INTERRUPT_CONTROL_STATUS_RXOIE);
    
        //
        // Disable the MAC Management counter interrupts as they are not used
        // in this application.
        //
        HWREG(Ethernet_device_struct.baseAddresses.enet_base + ETHERNET_O_MMC_RX_INTERRUPT_MASK) = 0xFFFFFFFF;
        HWREG(Ethernet_device_struct.baseAddresses.enet_base + ETHERNET_O_MMC_IPC_RX_INTERRUPT_MASK) = 0xFFFFFFFF;
        //
        //Do global Interrupt Enable
        //
        (void)Interrupt_enableInProcessor();
    
        //
        //Assign default ISRs
        //
        Interrupt_registerHandler(INT_EMAC_TX0, Ethernet_transmitISR);
        Interrupt_registerHandler(INT_EMAC_RX0, Ethernet_receiveISR);
        Interrupt_registerHandler(INT_EMAC, Ethernet_genericISRCustom);
    
        //
        //Enable the default interrupt handlers
        //
        Interrupt_enable(INT_EMAC_TX0);
        Interrupt_enable(INT_EMAC_RX0);
        Interrupt_enable(INT_EMAC);
    
        //
        // Convert the mac address string into the 32/16 split variables format
        // that is required by the driver to program into hardware registers.
        // Note: This step is done after the Ethernet_getHandle function because
        //       a dummy MAC address is programmed in that function.
        //
        temp = (uint8_t *)&macLower;
        temp[0] = mac[0];
        temp[1] = mac[1];
        temp[2] = mac[2];
        temp[3] = mac[3];
    
        temp = (uint8_t *)&macHigher;
        temp[0] = mac[4];
        temp[1] = mac[5];
    
        //
        // Program the unicast mac address.
        //
        Ethernet_setMACAddr(EMAC_BASE,
                            0,
                            macHigher,
                            macLower,
                            ETHERNET_CHANNEL_0);
    }
    
    
    //*****************************************************************************
    //
    // This example demonstrates the use of the Ethernet Controller.
    //
    //*****************************************************************************
    int
    main(void)
    {
        unsigned long ulUser0, ulUser1;
        unsigned char pucMACArray[8];
    
        //
        // User specific IP Address Configuration.
        // Current implementation works with Static IP address only.
        //
        unsigned long IPAddr = 0xC0A80004;
        unsigned long NetMask = 0xFFFFFF00;
        unsigned long GWAddr = 0x00000000;
    
        //
        // Initializing the CM. Loading the required functions to SRAM.
        //
        CM_init();
    
        SYSTICK_setPeriod(systickPeriodValue);
        SYSTICK_enableCounter();
        SYSTICK_registerInterruptHandler(SysTickIntHandler);
        SYSTICK_enableInterrupt();
    
        //
        // Enable processor interrupts.
        //
        Interrupt_enableInProcessor();
            
        // Set user/company specific MAC octets
        // (for this code we are using A8-63-F2-00-00-80)
        // 0x00 MACOCT3 MACOCT2 MACOCT1
        ulUser0 = 0x00F263A8;
    
        // 0x00 MACOCT6 MACOCT5 MACOCT4
        ulUser1 = 0x00800000;
    
        //
        // Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC
        // address needed to program the hardware registers, then program the MAC
        // address into the Ethernet Controller registers.
        //
        pucMACArray[0] = ((ulUser0 >>  0) & 0xff);
        pucMACArray[1] = ((ulUser0 >>  8) & 0xff);
        pucMACArray[2] = ((ulUser0 >> 16) & 0xff);
        pucMACArray[3] = ((ulUser1 >>  0) & 0xff);
        pucMACArray[4] = ((ulUser1 >>  8) & 0xff);
        pucMACArray[5] = ((ulUser1 >> 16) & 0xff);
    
        //
        // Initialize ethernet module.
        //
        Ethernet_init(pucMACArray);
    
        //
        // Initialze the lwIP library, using DHCP.
        //
        lwIPInit(0, pucMACArray, IPAddr, NetMask, GWAddr, IPADDR_USE_STATIC);
    
        //
        // Initialize the HTTP webserver daemon.
        //
        httpd_init();
    
        //
        // Loop forever. All the work is done in interrupt handlers.
        //
        while(1);
    }
    
    //*****************************************************************************
    //
    // Called by lwIP Library. Toggles the led when a command is received by the
    // HTTP webserver.
    //
    //*****************************************************************************
    void httpLEDToggle(void)
    {
        //
        // Toggle the LED D1 on the control card.
        //
        GPIO_togglePin(DEVICE_GPIO_PIN_LED1);
    }
    
    
    //*****************************************************************************
    //
    // Called by lwIP Library. Could be used for periodic custom tasks.
    //
    //*****************************************************************************
    void lwIPHostTimerHandler(void)
    {
    
    }
    
    2352.startup_ccs.c
    //###########################################################################
    //
    // FILE:   startup_ccs.c
    //
    // TITLE:  startup file for f2838x device.
    //
    //###########################################################################
    // $TI Release: $
    // $Release Date: $
    // $Copyright: $
    //###########################################################################
    
    //*****************************************************************************
    //
    // Forward declaration of the default fault handlers.
    //
    //*****************************************************************************
    void ResetISR(void);
    static void NmiSR(void);
    static void FaultISR(void);
    static void IntDefaultHandler(void);
    
    //*****************************************************************************
    //
    // External declaration for the reset handler that is to be called when the
    // processor is started
    //
    //*****************************************************************************
    extern void _c_int00(void);
    
    //*****************************************************************************
    //
    // Linker variable that marks the top of the stack.
    //
    //*****************************************************************************
    extern unsigned long __STACK_END;
    
    //*****************************************************************************
    //
    // External declarations for the interrupt handlers used by the application.
    //
    //*****************************************************************************
    extern void lwIPEthernetIntHandler(void);
    extern void SysTickIntHandler(void);
    extern void Ethernet_genericISRCustom(void);
    
    //*****************************************************************************
    //
    // The vector table.  Note that the proper constructs must be placed on this to
    // ensure that it ends up at physical address 0x0000.0000 or at the start of
    // the program if located at a start address other than 0.
    //
    //*****************************************************************************
    #pragma DATA_ALIGN(vectorTableFlash, 1024)
    #pragma DATA_SECTION(vectorTableFlash, ".vftable")
    
    void (* const vectorTableFlash[])(void) =
    {
     (void (*)(void))((unsigned long)&__STACK_END),
                                                 /* The initial stack pointer */
         ResetISR,                               /* The reset handler         */
         NmiSR,                                  /* The NMI handler           */
         FaultISR,                               /* The hard fault handler    */
         IntDefaultHandler,                      /* The MPU fault handler     */
         IntDefaultHandler,                      /* The bus fault handler     */
         IntDefaultHandler,                      /* The usage fault handler   */
         0,                                      /* Reserved                  */
         0,                                      /* Reserved                  */
         0,                                      /* Reserved                  */
         0,                                      /* Reserved                  */
         IntDefaultHandler,                      /* SVCall handler            */
         IntDefaultHandler,                      /* Debug monitor handler     */
         0,                                      /* Reserved                  */
         IntDefaultHandler,                      /* The PendSV handler        */
         SysTickIntHandler,                      /* The SysTick handler       */
         IntDefaultHandler,                      /* MCANSS_0 handler          */
         IntDefaultHandler,                      /* MCANSS_1 handler          */
         IntDefaultHandler,                      /* MCANSS_WAKE_AND_TS_PLS ISR*/
         IntDefaultHandler,                      /* MCANSS_ECC_CORR_PLS ISR   */
         IntDefaultHandler,                      /* Reserved                  */
         IntDefaultHandler,                      /* ECAT ISR                  */
         IntDefaultHandler,                      /* ECAT_SYNC0 ISR            */
         IntDefaultHandler,                      /* ECAT_SYNC1 ISR            */
         IntDefaultHandler,                      /* ECAT_RST ISR  ISR         */
         IntDefaultHandler,                      /* CANA0 ISR                 */
         IntDefaultHandler,                      /* CANA1 ISR                 */
         IntDefaultHandler,                      /* CANB0 ISR                 */
         IntDefaultHandler,                      /* CANB1 ISR                 */
         Ethernet_genericISRCustom,              /* EMAC ISR                  */
         lwIPEthernetIntHandler,                 /* EMAC_TX0 ISR              */
         IntDefaultHandler,                      /* EMAC_TX1 ISR              */
         lwIPEthernetIntHandler,                 /* EMAC_RX0 ISR              */
         IntDefaultHandler,                      /* EMAC_RX1 ISR              */
         IntDefaultHandler,                      /* UART0 ISR                 */
         IntDefaultHandler,                      /* Reserved                  */
         IntDefaultHandler,                      /* SSI0 ISR                  */
         IntDefaultHandler,                      /* Reserved                  */
         IntDefaultHandler,                      /* I2C0 ISR                  */
         IntDefaultHandler,                      /* Reserved                  */
         IntDefaultHandler,                      /* USB ISR                   */
         IntDefaultHandler,                      /* UDMA_SW ISR               */
         IntDefaultHandler,                      /* UDMA_ERR ISR              */
         IntDefaultHandler,                      /* Reserved                  */
         IntDefaultHandler,                      /* Reserved                  */
         IntDefaultHandler,                      /* CPU1TOCMIPC0 ISR          */
         IntDefaultHandler,                      /* CPU1TOCMIPC1 ISR          */
         IntDefaultHandler,                      /* CPU1TOCMIPC2 ISR          */
         IntDefaultHandler,                      /* CPU1TOCMIPC3 ISR          */
         IntDefaultHandler,                      /* CPU1TOCMIPC4 ISR          */
         IntDefaultHandler,                      /* CPU1TOCMIPC5 ISR          */
         IntDefaultHandler,                      /* CPU1TOCMIPC6 ISR          */
         IntDefaultHandler,                      /* CPU1TOCMIPC7 ISR          */
         IntDefaultHandler,                      /* CPU2TOCMIPC0 ISR          */
         IntDefaultHandler,                      /* CPU2TOCMIPC1 ISR          */
         IntDefaultHandler,                      /* CPU2TOCMIPC2 ISR          */
         IntDefaultHandler,                      /* CPU2TOCMIPC3 ISR          */
         IntDefaultHandler,                      /* CPU2TOCMIPC4 ISR          */
         IntDefaultHandler,                      /* CPU2TOCMIPC5 ISR          */
         IntDefaultHandler,                      /* CPU2TOCMIPC6 ISR          */
         IntDefaultHandler,                      /* CPU2TOCMIPC7 ISR          */
         IntDefaultHandler,                      /* FMC ISR                   */
         IntDefaultHandler,                      /* FMC_CORR_ERR ISR          */
         IntDefaultHandler,                      /* AES Interrupt ISR         */
         IntDefaultHandler,                      /* TIMER0 ISR                */
         IntDefaultHandler,                      /* TIMER1 ISR                */
         IntDefaultHandler,                      /* TIMER2 ISR                */
         IntDefaultHandler,                      /* CMRAM_TESTERROR_LOG ISR   */
         IntDefaultHandler,                      /* Reserved 52               */
         IntDefaultHandler,                      /* Reserved 53               */
         IntDefaultHandler,                      /* Reserved 54               */
         IntDefaultHandler,                      /* Reserved 55               */
         IntDefaultHandler,                      /* Reserved 56               */
         IntDefaultHandler,                      /* Reserved 57               */
         IntDefaultHandler,                      /* Reserved 58               */
         IntDefaultHandler,                      /* Reserved 59               */
         IntDefaultHandler,                      /* Reserved 60               */
         IntDefaultHandler,                      /* Reserved 61               */
         IntDefaultHandler,                      /* Reserved 62               */
         IntDefaultHandler                       /* Reserved 63               */
    };
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor first starts execution
    // following a reset event.  Only the absolutely necessary set is performed,
    // after which the application supplied entry() routine is called.  Any fancy
    // actions (such as making decisions based on the reset cause register, and
    // resetting the bits in that register) are left solely in the hands of the
    // application.
    //
    //*****************************************************************************
    #pragma CODE_SECTION(ResetISR, ".resetisr")
    void
    ResetISR(void)
    {
        // Jump to the CCS C Initialization Routine.
        __asm("    .global _c_int00\n"
              "    b.w     _c_int00");
    }
    
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives a NMI.  This
    // simply enters an infinite loop, preserving the system state for examination
    // by a debugger.
    //
    //*****************************************************************************
    static void
    NmiSR(void)
    {
        //
        // Enter an infinite loop.
        //
        while(1)
        {
        }
    }
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives a fault
    // interrupt.  This simply enters an infinite loop, preserving the system state
    // for examination by a debugger.
    //
    //*****************************************************************************
    static void
    FaultISR(void)
    {
        //
        // Enter an infinite loop.
        //
        while(1)
        {
        }
    }
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor receives an unexpected
    // interrupt.  This simply enters an infinite loop, preserving the system state
    // for examination by a debugger.
    //
    //*****************************************************************************
    static void
    IntDefaultHandler(void)
    {
        //
        // Go into an infinite loop.
        //
        while(1)
        {
        }
    }
    
    

    2838x_flash_lnk_cm_lwip_cmd.txt
    MEMORY
    {
       /* Flash sectors */
       CMBANK0_RESETISR : origin = 0x00200000, length = 0x00000008 /* Boot to Flash Entry Point */
       CMBANK0_SECTOR0  : origin = 0x00200008, length = 0x00003FF7
       CMBANK0_SECTOR1  : origin = 0x00204000, length = 0x00004000
       CMBANK0_SECTOR2  : origin = 0x00208000, length = 0x00004000
       CMBANK0_SECTOR3  : origin = 0x0020C000, length = 0x00004000
       CMBANK0_SECTOR4  : origin = 0x00210000, length = 0x00010000
       CMBANK0_SECTOR5  : origin = 0x00220000, length = 0x00010000
       CMBANK0_SECTOR6  : origin = 0x00230000, length = 0x00010000
       CMBANK0_SECTOR7  : origin = 0x00240000, length = 0x00010000
       CMBANK0_SECTOR8  : origin = 0x00250000, length = 0x00010000
       CMBANK0_SECTOR9  : origin = 0x00260000, length = 0x00010000
       CMBANK0_SECTOR10 : origin = 0x00270000, length = 0x00004000
       CMBANK0_SECTOR11 : origin = 0x00274000, length = 0x00004000
       CMBANK0_SECTOR12 : origin = 0x00278000, length = 0x00004000
       CMBANK0_SECTOR13 : origin = 0x0027C000, length = 0x00004000
    
       C1RAM            : origin = 0x1FFFC000, length = 0x00001FFF
       C0RAM            : origin = 0x1FFFE000, length = 0x00001FFF
    
       BOOT_RSVD        : origin = 0x20000000, length = 0x00000800 /* Part of S0, BOOT rom will use this for stack */
       SRAM             : origin = 0x20000800, length = 0x0000F7FF
       E0RAM            : origin = 0x20010000, length = 0x00003FFF
    
       CPU1TOCMMSGRAM0  : origin = 0x20080000, length = 0x00000800
       CPU1TOCMMSGRAM1  : origin = 0x20080800, length = 0x00000800
       CMTOCPU1MSGRAM0  : origin = 0x20082000, length = 0x00000800
       CMTOCPU1MSGRAM1  : origin = 0x20082800, length = 0x00000800
       CPU2TOCMMSGRAM0  : origin = 0x20084000, length = 0x00000800
       CPU2TOCMMSGRAM1  : origin = 0x20084800, length = 0x00000800
       CMTOCPU2MSGRAM0  : origin = 0x20086000, length = 0x00000800
       CMTOCPU2MSGRAM1  : origin = 0x20086800, length = 0x00000800
    }
    
    SECTIONS
    {
       .resetisr        : > CMBANK0_RESETISR
       .vftable         : > CMBANK0_SECTOR0   /* Application placed vector table in Flash*/
       .vtable          : > SRAM             /* Application placed vector table in RAM*/
       .text            : >> CMBANK0_SECTOR4
       .cinit           : > CMBANK0_SECTOR0
       .pinit           : >> CMBANK0_SECTOR0 | CMBANK0_SECTOR1
       .switch          : >> CMBANK0_SECTOR0 | CMBANK0_SECTOR1
       .sysmem          : > SRAM
    
       .stack           : > C1RAM
       .ebss            : > C1RAM
       .econst          : >> CMBANK0_SECTOR0 | CMBANK0_SECTOR1
       .esysmem         : > C1RAM
       .data            : > SRAM
       .bss             : > SRAM
       .const           : {} LOAD = CMBANK0_SECTOR0 | CMBANK0_SECTOR1 ,
       							RUN = SRAM,
       							LOAD_START(constLoadStart),
       							LOAD_SIZE(constLoadSize),
       							LOAD_END(constLoadEnd),
       							RUN_START(constRunStart),
       							RUN_SIZE(constRunSize),
       							RUN_END(constRunEnd)
    
        MSGRAM_CM_TO_CPU1 : > CMTOCPU1MSGRAM0, type=NOINIT
        MSGRAM_CM_TO_CPU2 : > CMTOCPU2MSGRAM0, type=NOINIT
        MSGRAM_CPU1_TO_CM : > CPU1TOCMMSGRAM0, type=NOINIT
        MSGRAM_CPU2_TO_CM : > CPU2TOCMMSGRAM0, type=NOINIT
    
        .TI.ramfunc : {} LOAD = CMBANK0_SECTOR0 | CMBANK0_SECTOR1 | CMBANK0_SECTOR4,
                               RUN = SRAM,
                               LOAD_START(RamfuncsLoadStart),
                               LOAD_SIZE(RamfuncsLoadSize),
                               LOAD_END(RamfuncsLoadEnd),
                               RUN_START(RamfuncsRunStart),
                               RUN_SIZE(RamfuncsRunSize),
                               RUN_END(RamfuncsRunEnd),
                               ALIGN(8)
    }
    
    /*
    //===========================================================================
    // End of file.
    //===========================================================================
    */
    

    Thanks,

    Yashwant

  • Yashwant,

    Do I need an updated driverlib_cm for this?

    Can't seem to find the "Ethernet_disableDmaInterrupt" and "Ethernet_enableMTLInterrupt" functions.

    Also, where do you want me to look for those "self explanatory" comments?

    Regards,

    Beat

  • Beat,

    You can define the following functions in the enet_lwip.c file. These are planned for next release.

    void Ethernet_disableDmaInterrupt(
    uint32_t base,
    uint32_t channelNum,
    uint32_t flags)
    {
    HWREG(base + (channelNum * ETHERNET_CHANNEL_OFFSET) +
    ETHERNET_O_DMA_CH0_INTERRUPT_ENABLE) &= ~flags;
    }
    void Ethernet_enableMTLInterrupt(
    uint32_t base,
    uint32_t queueNum,
    uint32_t flags)
    {
    HWREG(base + (queueNum * ETHERNET_QUEUE_OFFSET) +
    ETHERNET_O_MTL_Q0_INTERRUPT_CONTROL_STATUS) |= flags;
    }

    Thanks,

    Yashwant

  • Yashwant,

    Where do you want me to look for those "self explanatory" comments?

    Thanks,

    Beat

  • Beat,

    For the protocols enabled you can refer to Readme.txt at location C2000Ware_3_03_00_00\libraries\communications\Ethernet\third_party\lwip\examples\enet_lwip\cm.

    To try out other feature look into the defines in lwipopts.h file.

    Thanks,

    Yashwant

  • Yashwant,

    I am also trying to get lwip example to run standalone (from flash) on the TMS320F28388D evaluation board with C2000Ware_3_03_00_00.

    I followed your latest notes:

    1. replaced the files (5556.f2838xif.c, 3731.enet_lwip.c, 2352.startup_ccs.c, 2838x_flash_lnk_cm_lwip_cmd.txt).

    2. added the functions (Ethernet_disableDmaInterrupt, Ethernet_enableMTLInterrupt).

    With those modifications i got the program to run from flash (also after power cycle and without CCS) but i still have some problem .

    When running from CCS (through JTAG), the program runs completely fine but when running from flash after power cycle the connection is not stable.

    Especially, if i press the button "getDataFromServer" on the web server, the answer is delayed (2-5 seconds) and it causes the pings to fail for that time. When i am running from CCS the answer from the server is immediate (the number that the server sends updates immediately) and pings never miss.

    If i just ping the board, when running from CCS it never miss a ping but when running from flash once in while a ping is missed (once in ~20seconds)

    Any idea why?

    Thanks,

    Timor

  • Timor,

    When you are running from CCS are you using RAM configuration or FLASH configuration?

    When resetting the device for power cycle try doing it after disconnecting the ethernet cable then reset it and connect it back. 

    To narrow down the issue. 

    Regards,

    Yashwant 

  • I am using FLASH configuration.

    I tried resetting with the cable disconnected. No difference.

    p.s. my laptop is connected directly to the board. no ethernet switch in between.

    Anything else to check?

  • I presume you have taken following updates from the latest source files:

    1) Linker cmd file changes .const subsection load from FLASH and run from RAM.

    2) startup_ccs generic ethernet interrupt function added to vector table.

    3) enet_lwip.c Added cm_init which copies the the FLASH section to RAM to run. Definition of Generic Ethernet interrupt function.

    Regards,

    Yashwant

  • Yes I am using all these updates. Without these updates the program does not run in standalone at all.

  • A small update:

    I don't think its the cause of the problems but i think that lwIPTimer is not triggered correctly in the example that you sent.

    in SysTickIntHandler it is called with lwIPTimer(systickPeriodValue) while systickPeriodValue=15000000.

    lwIPTimer should be called with value of msec passed from the last call.

    i made the following changes:

    1. systickPeriodValue=1250000

    2. In SysTickIntHandler: lwIPTimer(100);

    This updates the lwip timer every 100msec

    It didn't seem to help but maybe its a lead...

    In addition, i also changed ETHERNET_NO_OF_RX_PACKETS from 2U to 5U. This helped a bit bit didn't solve the problem.

    It looks like something is running very slow when running standalone vs running with debugger connected (from CCS). This causes requests to be handled very slow so response is delayed and pings are missed. I can say that its not the main clock because i added LED blinking (both for CPU1 and CM) and the blink rate does not change between standalone and CCS.

  • We are looking into the problem and will update you once we have leads.

    Regards,

    Yashwant

  • Hi. Any progress?

  • Hi Timor,

    I tried recreating the issue but was unsuccessful at it. At my side the ping and getDataFromWebServer are working perfectly in the standalone(FLASH) mode. 

    In the image attached you can see the button clicked 345 times along with ICMP request.

    Are there any other Interrupt Service Routines in your application?

    You can also try adding VLAN to your application to restrict the packets tranferred to device. You can search the e2e for doubts on VLAN.

    Regards,

    Yashwant