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.

Tiva Ethernet speed/data rate problems.



Hi,

My application involves implimenting a couple control systems using a couple TIVA micro-controllers being commanded by a main micro-controller over an Ethernet bus.  Telemetry data and other various commands will also be sent around on the Ethernet bus all using UDP.  I have modified the lwip example to send udp packets to a static IP. (my computer at the moment) and am only transmitting from within the lwip timer interrupt loop. In order to simulate me sending data whenever I want and not just when the loop runs I am calling the timer interrupt method from within my main. This makes sure that lwip doesnt crash over a long time because I am calling the send from a place that is not within the loop. 

The problem I have reached though is no matter what values I change I cant get the micro controller to send more than 100 packets a second (each one containing around 100 bytes). For my application to work I need that rate to be at least 100 times what it is now. 

The data sheet for the TM4C1294NCPDT micro controller which I plan on using for all the nodes of this system says it can do 10/100 Ethernet or at least it says its Mac and Phy can so it can. 

My question is, Is there something wrong with my code or some value I forgot to modify thats limiting my write speed or can the microcontroller just not handle that much communication at once or is the problem with LWIP and I should look into the third party industrial Ethernet stacks instead? 

I am getting the 100 packets a second number by inspecting the communication over wireshark and a custom python program both gave me the same results. 

My code has been copied and pasted below. 

//*****************************************************************************
//
// enet_lwip.c - Sample WebServer Application using lwIP.
//
// Copyright (c) 2013-2014 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
// 
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 2.1.0.12573 of the EK-TM4C1294XL Firmware Package.
//
//*****************************************************************************

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/flash.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "utils/locator.h"
#include "utils/lwiplib.h"
#include "utils/ustdlib.h"
#include "utils/uartstdio.h"
#include "httpserver_raw/httpd.h"
#include "drivers/pinout.h"

//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>Ethernet with lwIP (enet_lwip)</h1>
//!
//! This example application demonstrates the operation of the Tiva
//! Ethernet controller using the lwIP TCP/IP Stack.  DHCP is used to obtain
//! an Ethernet address.  If DHCP times out without obtaining an address,
//! AutoIP will be used to obtain a link-local address.  The address that is
//! selected will be shown on the UART.
//!
//! UART0, connected to the ICDI virtual COM port and running at 115,200,
//! 8-N-1, is used to display messages from this application. Use the
//! following command to re-build the any file system files that change.
//!
//!     ../../../../tools/bin/makefsfile -i fs -o enet_fsdata.h -r -h -q
//!
//! For additional details on lwIP, refer to the lwIP web page at:
//! savannah.nongnu.org/.../lwip
//
//*****************************************************************************

//*****************************************************************************
//
// Defines for setting up the system clock.
//
//*****************************************************************************
#define SYSTICKHZ               100
#define SYSTICKMS               (1000 / SYSTICKHZ)

//*****************************************************************************
//
// Interrupt priority definitions.  The top 3 bits of these values are
// significant with lower values indicating higher priority interrupts.
//
//*****************************************************************************
#define SYSTICK_INT_PRIORITY    0x80
#define ETHERNET_INT_PRIORITY   0xC0


//#define USE_DHCP                 0
//
//#define STATIC_IP_ADDRESS            	  0xC0A85A96  /* 192.168.90.150 */
//#define STATIC_NETMASK                    0xFFFFFF00  /* 255.255.255.0 */
//#define STATIC_GATEWAY                    0xC0A85AFE  /* 192.168.90.254 */



//*****************************************************************************
//
// The current IP address.
//
//*****************************************************************************
uint32_t g_ui32IPAddress;

//*****************************************************************************
//
// The system clock frequency.
//
//*****************************************************************************
uint32_t g_ui32SysClock;


struct udp_pcb *remote_pcb;
struct pbuf* pbuf1;
char buf [120];

static int n = 0;

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

//*****************************************************************************
//
// Display an lwIP type IP Address.
//
//*****************************************************************************
void
DisplayIPAddress(uint32_t ui32Addr)
{
    char pcBuf[16];

    //
    // Convert the IP Address into a string.
    //
    usprintf(pcBuf, "%d.%d.%d.%d", ui32Addr & 0xff, (ui32Addr >> 8) & 0xff,
            (ui32Addr >> 16) & 0xff, (ui32Addr >> 24) & 0xff);

    //
    // Display the string.
    //
    UARTprintf(pcBuf);
}

//*****************************************************************************
//
// Required by lwIP library to support any host-related timer functions.
//
//*****************************************************************************
void
lwIPHostTimerHandler(void)
{
    uint32_t ui32Idx, ui32NewIPAddress;

    //
    // Get the current IP address.
    //
    ui32NewIPAddress = lwIPLocalIPAddrGet();

    //
    // See if the IP address has changed.
    //
    if(ui32NewIPAddress != g_ui32IPAddress)
    {
        //
        // See if there is an IP address assigned.
        //
        if(ui32NewIPAddress == 0xffffffff)
        {
            //
            // Indicate that there is no link.
            //
            UARTprintf("Waiting for link.\n");
        }
        else if(ui32NewIPAddress == 0)
        {
            //
            // There is no IP address, so indicate that the DHCP process is
            // running.
            //
            UARTprintf("Waiting for IP address.\n");
        }
        else
        {
            //
            // Display the new IP address.
            //
            UARTprintf("IP Address: ");
            DisplayIPAddress(ui32NewIPAddress);
            UARTprintf("\nOpen a browser and enter the IP address.\n");
        }

        //
        // Save the new IP address.
        //
        g_ui32IPAddress = ui32NewIPAddress;

        //
        // Turn GPIO off.
        //
        MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, ~GPIO_PIN_1);
    }

    //
    // If there is not an IP address.
    //
    if((ui32NewIPAddress == 0) || (ui32NewIPAddress == 0xffffffff))
    {
        //
        // Loop through the LED animation.
        //
    	UARTprintf("no ip address");
        for(ui32Idx = 1; ui32Idx < 17; ui32Idx++)
        {

            //
            // Toggle the GPIO
            //
            MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1,
                    (MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_1) ^
                     GPIO_PIN_1));

            SysCtlDelay(g_ui32SysClock/(ui32Idx << 1));
        }
    } else {

    	UARTprintf("I have an IP");

        //
        // Transmit to UDP
        //

    	//static int n = 0;

    	pbuf1 = pbuf_alloc(PBUF_TRANSPORT, 100, PBUF_RAM);
        pbuf1->payload = (void*)buf;
        pbuf1->tot_len = 15;
        pbuf1->len = 15;

        n++;

        //buf[0] = 0x10;
        buf[0] = n;
        buf[1] = n-1;

        //buf[1] = 0;

        if(n>= 55){
        	n=0;
        }

        //usprintf(&buf[4], " test %d", n++);
        //udp_send(remote_pcb, pbuf1);
        //pbuf_free(pbuf1);

        //udp_send(mypcb, pbuf1);  //this works


        struct ip_addr udpDestIpAddr;
        IP4_ADDR(&udpDestIpAddr, 192, 168, 7, 1);
        udp_sendto(remote_pcb, pbuf1, &udpDestIpAddr, 1234); // this does not work

        pbuf_free(pbuf1);

    }


}

//*****************************************************************************
//
// The interrupt handler for the SysTick interrupt.
//
//*****************************************************************************
void
SysTickIntHandler(void)
{
    //
    // Call the lwIP timer handler.
    //
    lwIPTimer(SYSTICKMS);
}

//*****************************************************************************
//
// This example demonstrates the use of the Ethernet Controller.
//
//*****************************************************************************
int
main(void)
{
    uint32_t ui32User0, ui32User1;
    uint8_t pui8MACArray[8];

    //
    // Make sure the main oscillator is enabled because this is required by
    // the PHY.  The system must have a 25MHz crystal attached to the OSC
    // pins. The SYSCTL_MOSC_HIGHFREQ parameter is used when the crystal
    // frequency is 10MHz or higher.
    //
    SysCtlMOSCConfigSet(SYSCTL_MOSC_HIGHFREQ);

    //
    // Run from the PLL at 120 MHz.
    //
    g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                             SYSCTL_OSC_MAIN |
                                             SYSCTL_USE_PLL |
                                             SYSCTL_CFG_VCO_480), 120000000);

    //
    // Configure the device pins.
    //
    PinoutSet(true, false);

    //
    // Configure UART.
    //
    UARTStdioConfig(0, 115200, g_ui32SysClock);

    //
    // Clear the terminal and print banner.
    //
    UARTprintf("\033[2J\033[H");
    UARTprintf("Ethernet lwIP example\n\n");

    //
    // Configure Port N1 for as an output for the animation LED.
    //
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1);

    //
    // Initialize LED to OFF (0)
    //
    MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, ~GPIO_PIN_1);

    //
    // Configure SysTick for a periodic interrupt.
    //
    MAP_SysTickPeriodSet(g_ui32SysClock / SYSTICKHZ);
    MAP_SysTickEnable();
    MAP_SysTickIntEnable();

    //
    // Configure the hardware MAC address for Ethernet Controller filtering of
    // incoming packets.  The MAC address will be stored in the non-volatile
    // USER0 and USER1 registers.
    //
    MAP_FlashUserGet(&ui32User0, &ui32User1);
    if((ui32User0 == 0xffffffff) || (ui32User1 == 0xffffffff))
    {
        //
        // We should never get here.  This is an error if the MAC address has
        // not been programmed into the device.  Exit the program.
        // Let the user know there is no MAC address
        //
        UARTprintf("No MAC programmed!\n");
        while(1)
        {
        }
    }

    //
    // Tell the user what we are doing just now.
    //
    UARTprintf("Waiting for IP.\n");

    //
    // 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.
    //
    pui8MACArray[0] = ((ui32User0 >>  0) & 0xff);
    pui8MACArray[1] = ((ui32User0 >>  8) & 0xff);
    pui8MACArray[2] = ((ui32User0 >> 16) & 0xff);
    pui8MACArray[3] = ((ui32User1 >>  0) & 0xff);
    pui8MACArray[4] = ((ui32User1 >>  8) & 0xff);
    pui8MACArray[5] = ((ui32User1 >> 16) & 0xff);

    //
    // Initialize the lwIP library, using DHCP.
    //
    //lwIPInit(g_ui32SysClock, pui8MACArray, 0, 0, 0, IPADDR_USE_DHCP);


    //IP address - 192.168.7.2 = 0xC0A80702 // own device IP address
    //Gateway - 192.168.7.1 = 0xC0A80701
    //subnet mask - 255.255.255.0 = 0xFFFFFF00

    lwIPInit(g_ui32SysClock, pui8MACArray, 0xC0A80702, 0xFFFFFF00, 0xC0A80701, IPADDR_USE_STATIC);
    //lwIPInit(pucMACAddr, DEFAULT_IPADDR, DEFAULT_NET_MASK, DEFAULT_GATEWAY_ADDR, IPADDR_USE_STATIC);


    //
    // Setup the device locator service.
    //
    LocatorInit();
    LocatorMACAddrSet(pui8MACArray);
    LocatorAppTitleSet("EK-TM4C1294XL enet_io");

    //
    // Initialize a sample httpd server.
    //
    httpd_init();


    udp_init();

    struct udp_pcb * mypcb;
    mypcb = udp_new();
    if (mypcb == NULL)
    {
        UARTprintf("udp failed.\n");
    }
    else
    {
        UARTprintf("udp up.\n");
    }

    if (udp_bind(mypcb, IP_ADDR_ANY, 8760) != ERR_OK)
    {
        UARTprintf("udp bind failed.\n");
    }



    //
    // Set the interrupt priorities.  We set the SysTick interrupt to a higher
    // priority than the Ethernet interrupt to ensure that the file system
    // tick is processed if SysTick occurs while the Ethernet handler is being
    // processed.  This is very likely since all the TCP/IP and HTTP work is
    // done in the context of the Ethernet interrupt.
    //
    MAP_IntPrioritySet(INT_EMAC0, ETHERNET_INT_PRIORITY);
    MAP_IntPrioritySet(FAULT_SYSTICK, SYSTICK_INT_PRIORITY);

    //
    // Loop forever.  All the work is done in interrupt handlers.
    //

    int loopCount = 0;

    while(1)
    {

    	uint32_t ui32Idx, ui32NewIPAddress;

//    	loopCount++;


        // Get the current IP address.
        //

        ui32NewIPAddress = lwIPLocalIPAddrGet();

        //UARTprintf("IP Address: ");
        //DisplayIPAddress(ui32NewIPAddress);


        if(loopCount%200 == 0){
        	lwIPHostTimerHandler();
        }

        if(loopCount >= 250){
        	loopCount = 0;
        }





    }
}

  • Feel your pain - and hate to see your nicely detailed post - "just sit."

    I've no background w/this vendor's Enet issues - but our small tech firm, "lives/breathes" diagnostics.

    How have you established that this, "unacceptably slow speed" is entirely the fault of these Tiva MCUs?   Might your "main controller" - be at least (even partially) to blame?    How (or have you) tested - so that "what you're attempting" really can work?   (I'm speaking here of a Tiva replacement/alternative - NOT wireshark!)
     
    May I suggest a (temporary - 2nd vendor/board) replacement device - so that you can confirm that the issue resides (in whole - or mostly) w/in vendor's device?

    Only other potential issue I sense is your, "timer method" of launch.    Suggest you "stick w/mainstream" (assuming they differ) - and at minimum - see if results change...

  • Roy,
    I saw your post earlier but hadn't enough time just then to answer - then forgot. I've recently implemented a bare-bones UDP/IP stack on the Tiva, which I believe is somewhat lighter, thus hopefully faster, than either of lwIP or uIP that both have the burden of TCP on them. The stack is not yet packaged so that it would be ready to be shared - publicly at least, but I can give you pointers on how to get something similar done. Especially if you can lock all of your MAC addresses during your tests (so no need for ARP), you don't really need much more than the example code in the TivaWare manual.
    Also, what cb1 said. 10 kilopackets per second is quite a lot already, especially for a non-realtime OS. The minimum would be to have a non-GUI tool (say bare-bones C command line program using the socket API) on the receiving end. Perhaps netcat would work, too.
  • Jabber Disable
    When this bit is set, the MAC disables the jabber counter on the
    transmitter. The MAC can transfer frames of up to 16,384 bytes.
    When this bit is clear, the MAC stops transmission if the application
    sends out more than 2,048 bytes of data (10,240 if JFEN is set to 1).
    Value Description
    0 Jabber counter enabled.
    1 Jabber counter disabled.
  • Let the record show that poster (alone) "Likes" both his opening & bump post!    Helpful that!

    Perhaps a self-anointed, "Verify Answer" could more properly close the loop - and put "helper crue" out of their misery....

  • Bump? = inferred to be asking a question "what is bump?" Have no idea what Bump is asking. Order to get more throughput settings have to be changed on the DMA.

    Additional EMAC DMA tweaks will help others in the forum Burst larger number of words in TXD packets & set priority 4:1 or {4 TXD to 1 RXD}. Then we get more packets leaving the PHY at any given time in a continuous transmit cycle loop.

        //
        // Initialize the MAC and set the DMA mode.
        //
        MAP_EMACInit(EMAC0_BASE, ui32SysClkHz,
                     EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_TX_PRIORITY |
                     EMAC_BCONFIG_DMA_PRIO_WEIGHT_4 | EMAC_BCONFIG_PRIORITY_4_1 ,  //default EMAC_BCONFIG_PRIORITY_FIXED,
                     8, 8 , 0) // was 4, 4, 0);
    
    
    //! The \e ui32RxBurst and \e ui32TxBurst parameters indicate the maximum
    //! number of words that the relevant DMA should transfer in a single
    //! transaction.  Valid values are 1, 2, 4, 8, 16 and 32.  Any other value
    //! results in undefined behavior.

  • Roy Cohen1 said:
    Bump?

    If the source of "bump" is your target - voila!     (this appeared 2nd post - this thread)

    Such usually is a (neglected) poster's, "Request for (some) Service."

  • We verified that the slow down was being caused by Lwip itself and are currently writing our own implementation based on the example provided to us in the Tivaware manual. Ill post the implementation here when we finish it to help anyone else thats having the same problem.
  • We have implemented Ethernet in our boards using the lwip solution and we have achieved more than 70Mb/s in a constant udp connection with a 1100bytes per frame.

    You may need to play a little bit with configuration of timers and lwip flags, but it is pretty straight forward.

    Just changing HOST_TMR_INTERVAL (in lwipopts.h) and SYSTICKHZ probably will do the trick easier. With those you can get more interrupts on the lwip stack, and then attend them properly in the lwIPHostTimerHandler function.

    Regards
  • Greetings friend PAk - been awhile - many opportunities your (tech services) this side of the pond...
    Suspect your guidance here will help many (including o.p.) and (as always) we love your, "do the trick, easier" defined methodology.
  • Yet with jabber counter clear all frames are restricted to 2048 bytes tops.

    We are seeing issues with PCBs possibly corrupted RX/TX descriptors @Systick 2.5us, LWIP count increment at 12.5us or (5x) LWIP interval timer.

    Seems TI only tested TCP stack with a Systick 120mhz/100, LWIP timer increment x (10) Oddly said to be in milliseconds. LWIP can not pass the litmus test, guessing it falters at the abstraction layer (tiva-tm4c129.c) after hours of working great with only 2 TCP ports 80 & 23 and DNS UDP broadcasts.

    Have discovered the abstraction layer configured interrupts handler is not servicing but only a few of the possible (13) EMAC interrupt conditions that may arise or occur on the transport layer should it also falter. Faltering seems to be related to DMA transfer timing out of the EMAC into SRAM that randomly either corrupts the memory pool or Heap, resets the MPU or merely stops all IP traffic on only 1 of the 2 IP port struct list.  

    We have tested Systcik 120mHz/100, 200, 300 and 100 is the most stable @1.2Mhz (8.3e-7) also the slowest TCP stack speed on earth.

    BTW: Discovered the link interrupt was never configured or properly enabled yet the handler was written for the interrupt. When a disconnect of the link state in a frame changes or link down the EMAC had no knowledge and kept transmitting data.

    The abstraction layer code is brilliantly written yet not fully debugged and lacks ability to handle all the TCP stack complexities that surround (pbuf.c) invoking mem_free() when returning closed PCB to the memory pool Heap after being stripped of DMA descriptors.

    Fix for link interrupt enable: 

      EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1, (EPHY_MISR1_LINKSTATEN | EPHY_MISR1_LINKSTAT | //Added Link;staten/stat
                   EPHY_MISR1_SPEEDEN | EPHY_MISR1_DUPLEXMEN | EPHY_MISR1_ANCEN));

  • Yes, frame size is restricted, but you can send multiple frames (as we do to achieve the data rate). This is a microcontroller not a PC, so you have to "handle" your resources.

    You dont need a LWIP interrupt every 12.5us, you can do it every 1or 2ms, and then let you room to take all the actions required (multiple frames tx, attend rx, etc).
    Again, in the uC world, you need "to handle" memory calls as well.

  • Looking forward to hear more from you and those opportunities.

    About theses issues, as you know, our group is pretty focused on real time applicattions so mastering timing is the issue, and as I often see, stepping from a simple application to realtime world is a struggle in uC world.
    Regards
  • Merci mon ami - c'est tres bien. Insure your "conversation" light glows - writing arrives in few hours...
  • Unfortunately real time data transport of variables requires very fast LWIP timing. Case our GUI scope widgets horizontal scroll speed would run at turtle speed. 

    Wireshark presently confirms 11kbyte/sec transmit data rate on TCP port 23 - (Systick 120mhz/300) 400kHz @2.5us Systick interrupt period / (5) = 80kHz LWIP timer interval 12.5us. Very fast indeed.

    That text in LWIP timer handler seems to incorrectly claim milliseconds. Systick interrupt cycle call to LWIP timer only bumps the timers variable ++ (value). That seems to infer variable delay/div of the caller LWIP timer interval value. It may concatenate into a millisecond value inside LWIP service timers function math but at the Systick interrupt level every 2.5us * ++(5) = 12.5us call to LWIP timer function itself @80kHz. After all we are frame casting at 100mbps with a 25Mhz PHY clock.

    The opposite far slower (Systick 120mHz/100) = 1.2mHz / (10) or 800Hz @125us LWIP timer increment.  In that case PCBs can not de-allocated quick enough, similar for PBUF returned to the heap so the memory pool runs dry. Heap corruption then results as LWIP mem_free() is running far to slow to keep pace with the client PCB interval. Abstraction layer DMA descriptors are challenged to keep up, all frame packet receive errors drop roll into pbuf_free(). Making DMA priority Q changes & scatter word size reduction helped to keep the PBUF pool free from error far longer than without making any changes.

    Perhaps TI has some more work to do in the etharp linked output return error handling in tivaif_init(). STAT tracking is registering 100's of cache hit errors. The only receive error handling relies on OR'd DMA descriptor error returns.

    Must say DMA default configuration and OR'd descriptor error returns are intuitive yet not exactly full proof, seemingly is still passing packet errors up the stack into LWI.

     

  • Love to see if (past) regular poster PAk confirms - such far (over) this reporter's simple head.

    BP101 said:
    error returns are intuitive yet not exactly full proof

    Those returns are more likely, "Fool proof."    

  • BP101 said:
    That text in LWIP timer handler seems to incorrectly claim milliseconds. Systick interrupt cycle call to LWIP timer only bumps the timers variable ++ (value). That seems to infer variable delay/div of the caller LWIP timer interval value. It may concatenate into a millisecond value inside LWIP service timers function math but at the Systick interrupt level every 2.5us * ++(5) = 12.5us call to LWIP timer function itself @80kHz. After all we are frame casting at 100mbps with a 25Mhz PHY clock.

    I don't know what you are tryint to achieve but, indeed, as  posted, this is a Fool proof.

    Try to define SYSTICKHZ as 500, then SYSTICKMS at (1000 / SYSTICKHZ) and HOST_TMR_INTERVAL as 2.That will give you an interrupt every 2ms (500Hz as you call it).

    That gap of time is the "space" you have to send your data, if another LWIP timer handler is called before you are finished, then you will lose data (or simply won't send it).

    If you need to send a big amount of data, in the lwIPHostTimerHandler function, just call as many times as frames you are going to send, this block: (we are using UDP):

    {
    pbuf1_tx = pbuf_alloc(PBUF_TRANSPORT, LENGTH, PBUF_RAM);
    pbuf1_tx->payload = (void*)buf_msx_eth;
    pbuf1_tx->tot_len = LENGTH;
    pbuf1_tx->len = LENGTH;
    
    udp_send(g_upcb, pbuf1_tx);
    pbuf_free(pbuf1_tx);
    
    while (EMACStatusGet(EMAC0_BASE) & EMAC_STATUS_TX_NOT_EMPTY){};
    }   			      

    Hence , try to measure the time it takes to send the frames, and then CONSEQUENTLY  adjust your program. Be careful and thoughtful in your calculations. This is a bare metal device, it will do what you program in it.

     

  • Telnet real time client with TCP nagle disabled transmits constant frames no larger than TCP_WND= 2400 bytes. We have two unique named pcb lists each restricted by 600 byte MSS, PBUF pool size. Other words separate tcp port bindings serviced on the LWIP stack all in the same interrupt context during 2 LWIP timer intervals in (lwiplib.c): IntervalTimer1, IntervalTimer2.

    That 1000/ 500 makes SYSCLK 120mHz/3 = 40Mhz, 25ns Systick interrupt vector period call into LWIP timer function. How that equates into a 2ms interval timer is suspect. At 4.8mHz Systick interval LWIP is smoking TCP stack, the Telnet client scopes widgets are moving so fast they immediately lock the Windows client just after launching it. Here we use F = 1/P or P=1/F to determine frequency from the period or period from the frequency. Data sheet suggest Systick interval is the entire period cycle time up to reset of its' timer divided by SYSCLK. LWIP interval time is not equating ms, behaves more like us and ns.

    The telnet client best burst rate on Wireshark is 25mbytes/sec with (Rx/Tx DMA descriptors set 8,8,0 TX priority 2, mixed burst rate, 2:1 ratio) 2 transmits 1 receive. Betting since UDP uses connectionless Broad Cast transport it may have different transmit aspects from that of TCP connection. Perhaps LWIP is more forgiving with UDP but the TI abstraction layer appears to have some sort of DMA related issue, perhaps with Runts or Giants. EMAC crash seems related to something in DMA that goes haywire when both clients are being serviced for around 10-15k seconds. The Telnet client only receives data and the Exosite client is bidirectional into the cloud. Each client will run almost forever without incident most testing times but not always. A slow memory leak in the PBUF pool would behave like that.
  • Suspect the LWIP callback errors  in  macro (output) asserting etharp_output() are being truncated in the static pipe links used to pass data vectored into Netif via pointers to Etharp IP routes.  That might be causing orphaned callback returns to build on the stack at the lowest level of LWIP.

    Find it very odd nothing in LWIP tweaked, enable, disable in etharp settings lowers the number of errors etharp typically reports on netif.

    Today tried to add call back error variable just after (if) test in etharp_ouput() to capture the call back (ERR_RTE) if it should flag, transmit routing error. Even though the function that calls etharp_otput() states function type err_t that is no guarantee the error call backs will be serviced by an error handler that doesn't exist in the module. Struct (err_t) can be used to link any of 13 LWIP error call backs into the user provide API error handler.

    Question is do transmit routing packet errors linked to PBUFS get flushed by the EMAC?  Suspect maybe not and may cause CSMACD collision at some point so bad the EMAC crashes the PHY. Seems plausible fewer transmit error frames might result in longer EMAC wire time prior to crashing.

    err_t
    tivaif_init(struct netif *psNetif)
    {
    
      LWIP_ASSERT("psNetif != NULL", (psNetif != NULL));
    
    #if LWIP_NETIF_HOSTNAME
      /* Initialize interface hostname */
      psNetif->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(psNetif, snmp_ifType_ethernet_csmacd, 1000000);
    
      psNetif->state = &g_StellarisIFData;
      psNetif->name[0] = IFNAME0;
      psNetif->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...) */
      psNetif->output = etharp_output;
      psNetif->linkoutput = tivaif_transmit;
    
      /* Remember our MAC address. */
      g_StellarisIFData.ethaddr = (struct eth_addr *)&(psNetif->hwaddr[0]);
    
      /* Initialize the hardware */
      tivaif_hwinit(psNetif);
    
      return ERR_OK;
    }
  • Here something more interesting discovered about DAM DMA configuration settings. :)

    (Rx/Tx DMA descriptor word lengths set 8,12,0 - TX priority 2, mixed burst rate, 2:1 ratio)

    Being 8 receive & 12 transmit DMA Burst size words in a scatter gather copied to/from SRAM.

     MPU didn't reset, Telnet client kept receiving but the http Cloud client stopped transmitting at 31k seconds online.

    Noticed when that happens; try to enter a manual command at console (connect) to Cloud the client reports to still be Online. That (bOnline) is Boolean switch that gets set when a valid IP address is initially returned to the client or the sock is validated as being connected to Host server during a connect cycle. The last message reported on the console is always (Reading Metadata).

    So we added an error call back into the EEROM read meta data function. Meta data read now returns an error to the server connect function prior to transmitting to Cloud http header just returned from EEROM. That is if the EEROM could be read without error, on error we return -1 from host server connect.

    There is EEROM errata condition also seems to effect revision 3 EMAC DMA writes to SRAM besides what has been discovered. 

    MEM#12Code Jumps from Flash to ROM when EEPROM is Active may Never Return

    Revision(s) Affected: 1 and 2.

    Description:

    ROM function calls may never return when the EEPROM is active (when the WORKING bit in the EEPROM Done Status (EEDONE) register is set or when an EEPROM register is read) and the user application is executing from Flash memory.

    Workaround(s):

    Replace ROM functions with the Flash-based equivalent functions.

  • BP101 said:
    discovered about DAM configuration settings.

    Nothing I can add - yet note that famed "Hoover Dam" - on occasion - overflows - damning its "configuration settings..."

  • Need to go see the DAM one day stead sitting here trying to make the horse eat that dang carrot and like it. : )~

    Rx value 12 was an (unknown results #) AKA datasheet warning 1,2,4,8,16,32. Yet great results rendered DAM Rx descriptor lasted for 70k seconds before dropping infamous payload bomb. Confirms bug bombs worse than cockroach kitchen cabinet, in water glass at night. Least we can shake out the bug during rinse cycle!