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; } } }