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.

tm4c129encpdt: Experiences with lwIP and TivaWare?

Part Number: TM4C129ENCPDT
Other Parts Discussed in Thread: EK-TM4C129EXL, SYSBIOS

Hi all,

I'm starting to get into the networking aspect of my project and looking into the various options: lwIP, uIP, TI's NDK that is part of TI-RTOS. Currently I'm working with a EK-TM4C129EXL (Crypto Connected LaunchPad) but this firmware is destined for a custom board.

Regarding lwIP, what experiences have you had with it?

I'm looking for both a general "feel" in a subjective sense and I have some specific objective questions.

From a subjective standpoint: Is it easy to work with? Is performance "good"? Is it "reliable"? I know that these questions depend heavily on the context, what you're trying to do with it, etc. We're going to use it as the communication interface to our board, through which we will monitor live I/O data and status, send commands and receive replies, send and receive user settings / preferences, etc. I would say our use-case creates low to medium traffic. What does that mean? I'm guesstimating 5 to 50 packets a second, with about 100 to 200 bytes of payload data in a packet. It's not intended to be a massively busy server or anything like that, but it has to work continuously without getting "stuck."

My objective questions:

1. Is it difficult or impossible to avoid blocking function calls? That is, am I likely to find it necessary to switch from our simple polled superloop to a much more complex TI-RTOS based firmware? I'm trying to avoid going full RTOS (code size, execution overhead, simplicity, etc) but our firmware must be polled continuously and cannot block waiting for a network event outside of its control.

2. TivaWare_C_Series-2.1.4.178 comes with lwip-1.4.1. The newest at this time is lwip-2.0.2, though the code distributed at savannah.nongnu.org/.../ seems to lack any TM4C-specific code. I am starting with 1.4.1 because the example programs are based on that, but would like to use the newest code if possible. Has anyone done that and if so, was it relatively quick and easy to substitute the newer code, or was it a difficult and time-consuming task?

I guess that's it for now. I'm sure I'll have more questions (and more specific ones) later. Any additional information that anyone wishes to share is greatly appreciated.

  • Hello twelve12pm,

    twelve12pm said:
    That is, am I likely to find it necessary to switch from our simple polled superloop to a much more complex TI-RTOS based firmware?

    I don't know enough about lwIP to say one way or another, but just as a general TI support statement, all our lwIP examples for TM4C use TI-RTOS and are supported by the TI RTOS team who aren't likely to support non-RTOS implementations.

    twelve12pm said:
    TivaWare_C_Series-2.1.4.178 comes with lwip-1.4.1. The newest at this time is lwip-2.0.2, though the code distributed at savannah.nongnu.org/.../ seems to lack any TM4C-specific code. I am starting with 1.4.1 because the example programs are based on that, but would like to use the newest code if possible. Has anyone done that and if so, was it relatively quick and easy to substitute the newer code, or was it a difficult and time-consuming task?

    This hasn't been done yet and I am not currently aware of plans to add this support to TM4C, but again that is usually handled by the TI-RTOS team. As far as easier route goes, I'll see if I can ping the team to see if they have any helpful feedback on that.

  • Hi,

    I'm on the TI-RTOS team. Internally we ported lwIP to TI-RTOS on a chip that is similar to the TM4C129 device several years ago as a science project. We found that the footprint is slightly smaller for lwIP, but the NDK had slightly better performance. At that time the IPv6 support was much better in the NDK. This was a couple years ago, so the lwIP IPv6 support might have been improved now.

    Regarding an RTOS being "much more complex", while I agree there is a learning curve for any new software, I think the move to an RTOS is not that hard. Instead of a super-loop in main, have a super-loop in a single task. Then when you feel the super-loop is too complicated, you can peel off a higher or low priority piece into it's own task.

    The biggest change really is letting the RTOS manage the interrupts instead of handling the vector table yourself. You need to use the Hwi module in TI-RTOS instead of driverlib. So instead of filling in an array, you call Hwi_create to plug it.

    In general an RTOS attempts to give a structured and deterministic framework to work with. I find that meeting real-time is easier in an RTOS as opposed to a super-loop in complex applications. Also you are getting a chunk of tested and documented code for free (along with free support).

    At the end of the day, it's obviously your chance. If I was making a product with minimal memory and simple functionality...would I use an RTOS...I doubt it. It's when marketing starts asking for more features though (e.g. add a file system and BLE and XYZ) that an RTOS makes the application easier to manage...IMHO

    Todd
  • Thanks for your replies.

    Ralph Jacobi said:

    I don't know enough about lwIP to say one way or another, but just as a general TI support statement, all our lwIP examples for TM4C use TI-RTOS and are supported by the TI RTOS team who aren't likely to support non-RTOS implementations.

    Just fyi, lwIP does install with bare metal TivaWare (as well as with TI-RTOS). In the newest TivaWare, lwip-1.4.1 is found under C:\ti\TivaWare_C_Series-2.1.4.178\third_party. Before I posted my questions, I found the following TivaWare lwIP examples. I've been studying these and I built and ran enet_io. Unless I've missed something, these all appear to run "bare bones" -- no dependencies on TI-RTOS.

    C:\ti\TivaWare_C_Series-2.1.4.178\examples\boards\ek-tm4c129exl\enet_io

    C:\ti\TivaWare_C_Series-2.1.4.178\examples\boards\ek-tm4c129exl\enet_lwip

    C:\ti\TivaWare_C_Series-2.1.4.178\examples\boards\ek-tm4c129exl\enet_weather

    The only thing that isn't clear to me at this time without further study is whether lwIP, when used in this manner, will avoid blocking execution while awaiting network events. Currently I believe it should be okay. The file C:\ti\TivaWare_C_Series-2.1.4.178\third_party\lwip-1.4.1\doc\rawapi.txt describes the interfaces to lwIP, including this text:

    "The raw TCP/IP interface allows the application program to integrate better with the TCP/IP code. Program execution is event based by having callback functions being called from within the TCP/IP code. The TCP/IP code and the application program both run in the same
    thread."

    That sounds promising. Has anyone had experience with that and whether it truly avoids blocking?


    ToddMullanix said:

    I'm on the TI-RTOS team. Internally we ported lwIP to TI-RTOS on a chip that is similar to the TM4C129 device several years ago as a science project. We found that the footprint is slightly smaller for lwIP, but the NDK had slightly better performance. At that time the IPv6 support was much better in the NDK. This was a couple years ago, so the lwIP IPv6 support might have been improved now.

    Thank you for mentioning that. I'll definitely look into NDK.

    ToddMullanix said:

    Regarding an RTOS being "much more complex", while I agree there is a learning curve for any new software, I think the move to an RTOS is not that hard. Instead of a super-loop in main, have a super-loop in a single task. Then when you feel the super-loop is too complicated, you can peel off a higher or low priority piece into it's own task.

    We're certainly open to using TI-RTOS, provided it doesn't interfere with our interrupts (such as our highest priority interrupt to sample the QEI) and it doesn't get in the way of configuring peripherals (and reconfiguring them differently, on the fly) exactly as we want.

    I like your idea of putting our ordinary superloop in a thread. In this case, I would probably run TCP/IP networking in a separate thread, to avoid any potential blocking of the superloop.

    The caveat is that our board is multiprocessor and they run a shared codebase, but only one of the processors is a TM4C129 with networking. For purposes of maintenance and consistency, keeping everything in a shared codebase would mean running the smaller processors on TI-RTOS as well. Their resources are more limited. Or we would have to rethink some things.

    ToddMullanix said:

    The biggest change really is letting the RTOS manage the interrupts instead of handling the vector table yourself. You need to use the Hwi module in TI-RTOS instead of driverlib. So instead of filling in an array, you call Hwi_create to plug it.

    Does this mean that under TI-RTOS, the vector table always resides in RAM? (With bare-bones TivaWare, the vector table resides in flash, unless someone calls IntRegister(), in which case the vector table is copied to RAM.) I prefer to keep it in flash, if possible. It saves memory and is less likely to be accidentally clobbered at runtime.

    I noticed that the TivaWare installed under TI-RTOS seems to be an older version, v2.1.1.71b (C:\ti\tirtos_tivac_2_16_01_14\products\TivaWare_C_Series-2.1.1.71b). Is there a reason why TI-RTOS seems to be using older code?

  • Easy ones first...

    twelve12pm said:
    I noticed that the TivaWare installed under TI-RTOS seems to be an older version, v2.1.1.71b (C:\ti\tirtos_tivac_2_16_01_14\products\TivaWare_C_Series-2.1.1.71b). Is there a reason why TI-RTOS seems to be using older code?

    We have not released a new TI-RTOS for TivaC for a while, thus the older TivaWare. The small enhancement request and small bug list has not warranted a new one.

    twelve12pm said:
    Does this mean that under TI-RTOS, the vector table always resides in RAM?

    No, we have an option to have the vector table only in flash. You lose the ability to change it during runtime. This would be an issue for the TI-RTOS drivers since they plug the vector table during runtime (e.g. UART_open would plug in the UART ISR). If you made your own drivers, you could plug them as needed.

    twelve12pm said:
    We're certainly open to using TI-RTOS, provided it doesn't interfere with our interrupts

    We also have an option to have an interrupt be a "zero-latency" interrupt. This means that the kernel does not interact with it....so the kernel adds zero-latency. The caveat with these type of interrupts is that they cannot make a kernel call the impacts scheduling (e.g. Semaphore_post, etc.). We also support priority for the managed interrupts.

    Todd

  • twelve12pm said:

    My objective questions:

    1. Is it difficult or impossible to avoid blocking function calls? That is, am I likely to find it necessary to switch from our simple polled superloop to a much more complex TI-RTOS based firmware? I'm trying to avoid going full RTOS (code size, execution overhead, simplicity, etc) but our firmware must be polled continuously and cannot block waiting for a network event outside of its control.

    In such an environment, I don't see how you can avoid either an RTOS or a structure that essentially re-invents the RTOS only less well.

    If you do move to an RTOS, I would suggest looking at FREE-RTOS as well. It's not tied to TI and from what I've seen of support requests and explanations of TI-RTOS here FREE-RTOS is  less restrictive.

    I think cb1 may have some experience with FREE-RTOS.

    Robert

  • ToddMullanix said:

    No, we have an option to have the vector table only in flash. You lose the ability to change it during runtime. This would be an issue for the TI-RTOS drivers since they plug the vector table during runtime (e.g. UART_open would plug in the UART ISR). If you made your own drivers, you could plug them as needed.

    ...

    We also have an option to have an interrupt be a "zero-latency" interrupt. This means that the kernel does not interact with it....so the kernel adds zero-latency. The caveat with these type of interrupts is that they cannot make a kernel call the impacts scheduling (e.g. Semaphore_post, etc.). We also support priority for the managed interrupts.

    This zero-latency interrupt looks like just the thing we need.

    Very important question: (Since you said that we cannot interact with the kernel or scheduler.) Can this zero-latency interrupt trigger another interrupt? Currently we are using IntTrigger() for this. It triggers an interrupt via SWTRIG. We are "stealing" the interrupt vector that belongs to an unused I2C peripheral and using that for a different purpose. The reason is to split our task into two parts. The high priority interrupt preempts anything else in the system to sample QEI on time. Then it triggers the low priority interrupt, which performs calculations. This solves the issue where the long-running calculations (long is a relative term here) would prevent other higher priority tasks such as servicing I/O, communication, and the like.

    By the way, if the QEI peripheral were designed with the ability to trigger a copy to a shadow register, in hardware, via a timer peripheral that also triggers an interrupt (that's how we did it on a different MCU platform), then none of the above would be necessary. Just food for thought when designing the next MCU.

    Is there a guide to moving an application from bare-bones TivaWare to TI-RTOS?

    Where can I find documentation on the difference between the older TivaWare v2.1.1.71b included in TI-RTOS and the newer TivaWare 2.1.4.178?

    We are using numerous MAP_ calls to use code in ROM. Which version is hard-coded in the chip's ROM?

    Has anyone attempted to use TI-RTOS with the newer TivaWare?

  • Hello twelve12pm,

    First of all, I do confess to forgetting that the bare bones enet examples do rely on lwIP. Sorry for that and thank you for correcting my commentary on that matter.

    Regarding a few of your questions:

    twelve12pm said:

    Where can I find documentation on the difference between the older TivaWare v2.1.1.71b included in TI-RTOS and the newer TivaWare 2.1.4.178?

    In the TivaWare 2.1.4.178 installation, you can find a "SW-TM4C-RLN-2.1.4.178.pdf" in the docs folder. This is the Release Notes for TivaWare and they go back far beyond just 2.1.1, so you can use this to see all that is available.

    twelve12pm said:

    We are using numerous MAP_ calls to use code in ROM. Which version is hard-coded in the chip's ROM?

    An older version than either of those. I don't know which, but it isn't important to know for reasons I will explain:The MAP calls are used because the rom_map.h file is what we update when a ROM API is no longer accurate for the newest TivaWare. So this means all API's in a particular version are accurately documented by the DriverLib User's Guide, and thus you don't need to go digging for an old document for years past to know what each API does.

    twelve12pm said:

    Has anyone attempted to use TI-RTOS with the newer TivaWare?

    I don't believe so, but we'll see if Todd has any feedback on that.

  • twelve12pm said:
    Can this zero-latency interrupt trigger another interrupt?

    Yes. If you need the zero-latency interrupt to communicate to the kernel, you can assert a different (and managed) ISR that can do the kernel calls. 

    twelve12pm said:
    Is there a guide to moving an application from bare-bones TivaWare to TI-RTOS?

    Always on my list of things to do, but I never get to it:( The main areas that need to be ported on a TM4C device are interrupts, timers and maybe exception handling (we have several options for that). By default TI-RTOS grabs one timerthat drives timing things (e.g. Task_sleep, Semaphore_pend with a timeout, etc.). By default it runs every 1ms (we call this a tick). You can plug functions that will be called at after N number of clock ticks. The functions can be periodic or one-shot. If you don't want the kernel to use a timer, you can drive the clock tick yourself.

    twelve12pm said:
    Has anyone attempted to use TI-RTOS with the newer TivaWare?

    Not that I know of. I have not tried it.

  • ToddMullanix said:
    twelve12pm
    Can this zero-latency interrupt trigger another interrupt?

    What is the additional management that the kernel performs for managed ISRs?

  • Probably easiest to just point you to the code in C:\ti\tirtos_tivac_2_16_01_14\products\bios_6_45_02_31\packages\ti\sysbios\family\arm\m3\Hwi_asm.sv7M. This is one of the few places we use assembly for performance reasons.

    We also publish timing and sizing benchmarks. Look at the Docs Overview html page (file:///C:/ti/tirtos_tivac_2_16_01_14/docs/Documentation_Overview_tivac.html) and go into the kernel's release notes. There you'll find a timing and sizing benchmark link. We have all the sizing and footprint values for all the devices we support here (e.g. M4F with TI compiler). For example:

    The Kernel's User Guide (link in the Docs Overview page also) talks about these values in more detail.

    Todd

  • Just FYI and in case this helps others in the future...

    As a proof-of-concept, we created a version of our application which includes lwIP, running bare bones using TivaWare. Currently we have not attempted to use TI-RTOS, but that may happen in the future.

    What I'm writing here is very preliminary as we have not conducted very much in the way of tests... In fact we *just* got the code working an hour ago. I'll have to return afterwards and post further details as we learn more.

    Although our firmware is destined for a custom board, we used EK-TM4C129EXL (Crypto Connected LaunchPad) for this test.

    We are using TivaWare version 2.1.4.178, the newest at this time.

    The version of lwIP is 1.4.1 and installs with TivaWare under C:\ti\TivaWare_C_Series-2.1.4.178\third_party\lwip-1.4.1.

    Our end application does not include an embedded web server, but to demonstrate that lwIP can work with our application in the easiest manner, we basically added the functionality of the enet_io example into our application. This is a TivaWare example found under C:\ti\TivaWare_C_Series-2.1.4.178\examples\boards\ek-tm4c129exl\enet_io. It connects the board to the network and presents a website, which displays text and images, and through which the user can toggle a LED and perform other functions.

    We first imported enet_io into our CCS workspace, built, and ran that program successfully (as we had fully expected) on our EK-TM4C129EXL.

    Having demonstrated that this program works, we returned to our firmware project and added a new module, Network.c, Network.h. This module's purpose is to initialize networking. To write the init function, we followed along in enet_io to see what it does, and we added relevant calls to our code, taking care not to conflict with our existing application. We copied several functions, tables, and defines out of enet_io, on which the httpd server depends for CGI, etc., again, taking care to fix issues that would conflict with our existing code. We copied in io.c, io.h, cgifuncs.c, cgifuncs.h, io_fs.c, io_fsdata.h. These files will not remain in our actual firmware but were needed to satisfy dependencies for this proof-of-concept.

    The enet_io example configures three interrupts of significance: SysTickIntHandler, lwIPEthernetIntHandler, and AnimTimerIntHandler. We eliminated AnimTimerIntHandler and rewrote io.c to deal with IOs in a manner that doesn't conflict with our application. lwIPEthernetIntHandler is the handler for the chip's Ethernet interrupt and is implemented in lwiplib.c, located under TivaWare's utils directory. This leaves SysTickIntHandler. Because our application already uses the Cortex M4's SysTick for other purposes, we configured Timer2A to generate this interrupt instead. We configured the priorities of these interrupts similarly to how it's done in enet_io (our Timer2A interrupt having a slightly higher priority than our Ethernet interrupt for reasons explained in a comment in enet_io.c).

    We added the necessary include directories and include headers to our project.

    Once dependencies were satisfied and the code built, we got stuck in the IntDefaultHandler(). We lost most of our time tracing the cause of that, only to discover that we had forgotten to actually set the Ethernet interrupt vector in the C startup file!

    The other error was that we forgot to turn off the Timer2A interrupt flag in our Timer2A ISR handler. This omission caused the code to get stuck in that interrupt.

    Other than these two mistakes, the process went pretty smoothly.

    Having done all of this, the program builds and runs. It displays the same webpage as the enet_io example, while the rest of our firmware code appears to operate normally and seems responsive. Of course, it will take quite some testing to determine if this configuration will work acceptably for our application.

    Regarding the previous discussions in this thread about TI-RTOS: We studied that possibility and decided to try working without the RTOS at this time for the following reasons:

    (1) Much of our application and board driver code is implemented. Leaving the important issue of networking to this late in the game was not a good idea on our part, but happened due to various circumstances. We were confident Ethernet would work and had to test other things to answer pressing questions from our designers as they designed our new board. Since the code is implemented, we would either have to reimplement it in terms of TI-RTOS, or leave it as is, calling the underlying TivaWare driver lib. The first option did not appeal to us; the second would necessitate protecting the driver lib calls for reentrancy.

    (2) There's the subtle issue that we have multiple board designs, which are multiprocessor from the TM4C129 and TM4C123 families. We have architected our software so that the same source modules with the same code build and run on all the processors. A configuration header sets numerous compile-time defines, depending on the target board and processor, which map everything to the proper hardware peripherals and I/O pins, etc. This is important for maintenance, implementation of new features, and reducing costs in general. But it means that if we adopt TI-RTOS for the TM4C129 for networking reasons, we would have to adopt it for our more limited TM4C123 processors, even though the code running on those processors works perfectly fine as bare metal and would not benefit.

    (3) Our project lead did not like that TI-RTOS uses an older version of TivaWare. I can easily fix that by backporting fixes from the newer TivaWare into the one used by TI-RTOS and rebuilding TI-RTOS, but that idea was shot down because of concern that our fixes would cause subtle breakage that would be hard to trace.

    (4) lwIP seems designed to work with or without a RTOS. When running without a RTOS, the TivaWare port of lwIP does everything in the Ethernet ISR handler. We have set this to the lowest priority so that most of our interrupts will preempt it. I have only to verify that nothing in the lwIP code is outright disabling interrupts, but if that's the case, we should be okay.

    I'll be back to report on what we find as we test further. Thanks to all for your help.

  • Just FYI and in case this helps others in the future...

    As a proof-of-concept, we created a version of our application which includes lwIP, running bare bones using TivaWare. Currently we have not attempted to use TI-RTOS, but that may happen in the future.

    What I'm writing here is very preliminary as we have not conducted very much in the way of tests... In fact we *just* got the code working an hour ago. I'll have to return afterwards and post further details as we learn more.

    Although our firmware is destined for a custom board, we used EK-TM4C129EXL (Crypto Connected LaunchPad) for this test.

    We are using TivaWare version 2.1.4.178, the newest at this time.

    The version of lwIP is 1.4.1 and installs with TivaWare under C:\ti\TivaWare_C_Series-2.1.4.178\third_party\lwip-1.4.1.

    Our end application does not include an embedded web server, but to demonstrate that lwIP can work with our application in the easiest manner, we basically added the functionality of the enet_io example into our application. This is a TivaWare example found under C:\ti\TivaWare_C_Series-2.1.4.178\examples\boards\ek-tm4c129exl\enet_io. It connects the board to the network and presents a website, which displays text and images, and through which the user can toggle a LED and perform other functions.

    We first imported enet_io into our CCS workspace, built, and ran that program successfully (as we had fully expected) on our EK-TM4C129EXL.

    Having demonstrated that this program works, we returned to our firmware project and added a new module, Network.c, Network.h. This module's purpose is to initialize networking. To write the init function, we followed along in enet_io to see what it does, and we added relevant calls to our code, taking care not to conflict with our existing application. We copied several functions, tables, and defines out of enet_io, on which the httpd server depends for CGI, etc., again, taking care to fix issues that would conflict with our existing code. We copied in io.c, io.h, cgifuncs.c, cgifuncs.h, io_fs.c, io_fsdata.h. These files will not remain in our actual firmware but were needed to satisfy dependencies for this proof-of-concept.

    The enet_io example configures three interrupts of significance: SysTickIntHandler, lwIPEthernetIntHandler, and AnimTimerIntHandler. We eliminated AnimTimerIntHandler and rewrote io.c to deal with IOs in a manner that doesn't conflict with our application. lwIPEthernetIntHandler is the handler for the chip's Ethernet interrupt and is implemented in lwiplib.c, located under TivaWare's utils directory. This leaves SysTickIntHandler. Because our application already uses the Cortex M4's SysTick for other purposes, we configured Timer2A to generate this interrupt instead. We configured the priorities of these interrupts similarly to how it's done in enet_io (our Timer2A interrupt having a slightly higher priority than our Ethernet interrupt for reasons explained in a comment in enet_io.c).

    We added the necessary include directories and include headers to our project.

    Once dependencies were satisfied and the code built, we got stuck in the IntDefaultHandler(). We lost most of our time tracing the cause of that, only to discover that we had forgotten to actually set the Ethernet interrupt vector in the C startup file!

    The other error was that we forgot to turn off the Timer2A interrupt flag in our Timer2A ISR handler. This omission caused the code to get stuck in that interrupt.

    Other than these two mistakes, the process went pretty smoothly.

    Having done all of this, the program builds and runs. It displays the same webpage as the enet_io example, while the rest of our firmware code appears to operate normally and seems responsive. Of course, it will take quite some testing to determine if this configuration will work acceptably for our application.

    Regarding the previous discussions in this thread about TI-RTOS: We studied that possibility and decided to try working without the RTOS at this time for the following reasons:

    (1) Much of our application and board driver code is implemented. Leaving the important issue of networking to this late in the game was not a good idea on our part, but happened due to various circumstances. We were confident Ethernet would work and had to test other things to answer pressing questions from our designers as they designed our new board. Since the code is implemented, we would either have to reimplement it in terms of TI-RTOS, or leave it as is, calling the underlying TivaWare driver lib. The first option did not appeal to us; the second would necessitate protecting the driver lib calls for reentrancy.

    (2) There's the subtle issue that we have multiple board designs, which are multiprocessor from the TM4C129 and TM4C123 families. We have architected our software so that the same source modules with the same code build and run on all the processors. A configuration header sets numerous compile-time defines, depending on the target board and processor, which map everything to the proper hardware peripherals and I/O pins, etc. This is important for maintenance, implementation of new features, and reducing costs in general. But it means that if we adopt TI-RTOS for the TM4C129 for networking reasons, we would have to adopt it for our more limited TM4C123 processors, even though the code running on those processors works perfectly fine as bare metal and would not benefit.

    (3) Our project lead did not like that TI-RTOS uses an older version of TivaWare. I can easily fix that by backporting fixes from the newer TivaWare into the one used by TI-RTOS and rebuilding TI-RTOS, but that idea was shot down because of concern that our fixes would cause subtle breakage that would be hard to trace.

    (4) lwIP seems designed to work with or without a RTOS. When running without a RTOS, the TivaWare port of lwIP does everything in the Ethernet ISR handler. We have set this to the lowest priority so that most of our interrupts will preempt it. I have only to verify that nothing in the lwIP code is outright disabling interrupts, but if that's the case, we should be okay.

    I'll be back to report on what we find as we test further. Thanks to all for your help.
  • In the hopes that this post helps anyone who arrives here when investigating lwIP for their own TivaWare application:

    Further to our earlier post about our experiences with lwIP (which evidently we posted twice -- oops)...

    We found that when used similarly to the enet_io example, the entire lwIP stack, httpd server, and basically everything related to the network interface, all runs in the Ethernet ISR handler. We had given this ISR the lowest priority, but nevertheless it seemed to interfere with our more critical interrupts whenever a web browser loaded the webpage served by the board firmware. Perhaps we did something wrong. Is it enough to call IntPrioritySet()? We gave the critical interrupts a priority of 0x00 and the Ethernet interrupt a priority of 0xe0. This may require a bit more investigation, but in the meantime...

    We did not make measurements with an oscilloscope but we know that something was amiss because our application has one critical interrupt handler that must execute every 833 us, and we have a timer peripheral configured to generate a different interrupt every 1 ms. The 833 us interrupt restarts the timer, preventing the 1 ms interrupt from being generated. This has the effect that if the 833 us interrupt is missed with by a margin of some 166 us, the 1 ms interrupt triggers, indicating the error condition and triggering the appropriate application logic. Obviously, this should never be allowed to happen. With our 833 us interrupt having the highest priority (unless we messed up?) we should be preempting the Ethernet interrupt. That is to say, the Ethernet interrupt should not cause interference.

    The first thing we investigated was whether IntMasterDisable() is called anywhere in the lwIP code, and sure enough, it is called in sys_arch.c in the implementation of sys_arch_protect(). This is called through a define, SYS_ARCH_PROTECT(), in various parts of the lwIP code, to protect the stack from reentrancy issues.

    A blanket interrupt disable is something we cannot allow. We came up with several alternatives to mitigate this:

    (Option 1) Change the sys_arch_protect() / sys_arch_unprotect() code to disable/reenable only the Ethernet interrupt, leaving all other interrupts enabled. Since we are not calling lwIP code from any of our other interrupts, we think this should have the desired effect. We have not tried this alternative yet.

    (Option 2) Go with TI-RTOS like several people have recommended. (But this experimentation is more fun!)

    (Option 3) Make all of the lwIP run in main context (polled in our superloop just like everything else), eliminating interrupts. This is the alternative we tried.

    A little background information: The previous generations of our product used a microcontroller from a different vendor; the IP stack provided for those parts was fully polled. This has worked great for six years.

    To try the same thing here, we performed the following steps:

    1. We copied the lwIP code to a new directory, leaving the original TivaWare code untouched. We also copied lwiplib.c, lwiplib.h, which are found in TivaWare's utils directory.

    2. In our copy of lwip-1.4.1/ports/tiva-tm4c129/sys_arch.c, we made sys_arch_protect() and sys_arch_unprotect() empty functions. Since all lwIP code will be called from main context, there should be no issue of reentrancy.

    3. In our copy of lwip-1.4.1/ports/tiva-tm4c129/netif/tiva-tm4c129.c, in tivaif_hwinit(), we removed the lines IntEnable(INT_EMAC0); and IntMasterEnable();. All other initialization is left as-is.

    4. In our copy of utils/lwiplib.c, in lwIPTimer() we removed the line HWREG(NVIC_SW_TRIG) |= INT_EMAC0 - 16; This was triggering the Ethernet interrupt via the SWTRIG register. This function now has the effect of only incrementing g_ui32LocalTimer by ui32TimeMS, required for servicing the IP stack's timed handlers. We call lwIPTimer() from our 10 ms Timer2A interrupt. This is the only code we call from interrupt context, and as explained all it does is increment a variable.

    5. We removed lwIPEthernetIntHandler from the vector table. Instead we are now polling it from our superloop.

    Besides these changes, we changed the project's include paths to use our modified lwIP.

    The program builds and runs. The webpage is served successfully. In Firefox there is a hotkey combination to force reload a webpage (bypassing the browser's cache) and we held down this key combination for some time, rapidly reloading the page. We saw no interference with our critical interrupts.

    This will, of course, require extensive additional testing. I'll be back to report on our experiences as they unfold...