Welcome to the Modern Embedded Systems Programming course. I'm sorry for my long absence since posting lesson 20, but I'd like to make it up to you by announcing a new group of lessons about the architecture and design of embedded software. Today I am going to introduce the ubiquitous foreground-background architecture, also known as the super-loop or main+interrupts. Apart from being interesting in its own right, foreground/background is the starting point for all embedded software architectures and, among others, is an important stepping stone to understanding a Real-Time Operating System (RTOS), which was perhaps the most requested subject for me to explain. So, you can view this lesson as a prerequisite for the upcoming lessons about the RTOS as well as other architectures. To follow along today's lesson you need to download two pieces of code from the companion website to this course at state-machine.com/quickstart. The first is the lesson21 project that I prepared in advance, and the second piece is the 'qpc' framework, which you will use in most of the upcoming lessons in this group. You need to unzip these two downloads into the embedded-programming directory on your disk. This lesson also uses the ARM-Keil MDK toolset from the ARM company instead the Eclipse-based Code Composer Studio from Texas Instruments. The reason for this change is that I ran into problems with the latest CCS 7.3, which was simply blocked by my anti-virus software. I made all sorts of attempts to reconcile the CCS with my anti-virus, but I ultimately failed. This is, among others, one reason why this group of lessons took longer to prepare. In the end, I decided to treat this setback as an opportunity to introduce you to the third, very popular and excellent ARM-Keil MDK toolset, which is just as good as the IAR toolset, and in my option easier to use than Eclipse. To get Keil MDK, you can start from ARM.com and choose the "Development Tools -> Microcontroller and Embedded Development" menu. Alternatively, you can simply google for "Keil MDK". Either way, you will land on this main MDK page. As you can see in the comparison of available MDK editions, there is a free, code- size limited Lite version, which will be perfectly adequate for all projects in this video course. Click on the Download button and fill out the usual download form. Click the Submit button. While you install the Keil MDK toolset, you might want to familiarize yourself with the documentation. The toolset comes with the Getting Started videos and a guide in PDF. So, assuming that you have successfully installed ARM Keil MDK toolset, you can go to the lesson21 directory you have just downloaded and click on the provided uVision project file. When you run the Keil uVision IDE for the first time, you might need to register the license, which in my case is MDK-Lite Evaluation Version. You can get this license online by clicking on "Get LIC via Internet". Also, the first time you open a project for the TivaC LaunchPad board, you might need to install the so called "Software Pack". You open the Pack Installer and select the Texas Instruments, TivaC Series, TM4C123x Series pack, which includes your specific microcontroller. OK, so finally you can get to the code for today's lesson that is actually very similar to what you had back in lesson 8 in that it simply blinks the green LED on your TivaC LauchPad board. The only difference from the previous version is the delay() function, now called BSP_delay(), because it is defined in the Board Support Package (BSP), which you first encountered in lesson-15. In this lesson you will see how to take the concept of the Board Support Package to the next level. Before you go any further, let's just build this version of the Blinky program and check that it still works by opening it in the micro-Vision debugger. When you run the program, you can see that the Green LED blinks by staying on for about a quarter of a second and off for about three quarters of a second. Now, going back to the editing mode, let me explain a few things about the BSP_delay() function. Unlike the previous crude delay() implementation from lesson-8, BSP_delay() is based on the SysTick interrupt, which delivers more precise timing, because it does not depend on the speed of the compiler-generated code. In this new implementation, the SysTick interrupt is programmed to fire at a rate of BSP_TICKS_PER_SEC, which is defined as a hundred times per second in the bsp.h header file. This BSP_TICKS_PER_SEC constant is subsequently used to configure the SysTick interrupt. The SysTick interrupt handler simply increments the local l_tickCtr variable, which is declared both static and volatile. The 'volatilie' qualifier has been introduced back in lesson-5, but here let me quickly remind you that when you declare a variable to be "volatile", you are telling the compiler that the variable might change unexpectedly even though no currently performed program instructions change it, which is exactly what can happen when a variable is modified in an interrupt. The BSP_tickCtr() function simply reads and returns the current value of l_tickCtr variable. But as you surely remember from the last lesson-20, to avoid any race conditions between the SysTick interrupt and the code that calls BSP_tickCtr(), the access to such a variable must occur in a critical section, that is, with interrupts disabled. Finally, the BSP_delay() function first reads the tick counter and stores it in the automatic variable 'start'. Next, it enters a polling while-loop, which constantly reads the tick counter value and computes the difference from the start. The loop continues as long as the difference is smaller than the specified number of clock ticks. Please note that the 2's complement arithmetic, which I discussed in lesson 2, handles properly the discontinuity when the tick counter rolls over from all-Fs to 0. At the end of the day, however, the BSP_delay() implementation, just like the previous, crude delay() function, is based on the same primitive idea of polling, so it ends up wasting all the CPU cycles until the specified number of clock ticks elapse. However, for this lesson, the most important point is that the software structure of the Blinky program has all the characteristics of the so called *foreground/background architecture* also known as "main+ISRs", which is very common in smaller embedded systems. As the name suggests, the architecture consists of two main parts: the endless *background* loop inside the main() function and the interrupt handlers, like your SysTick_Handler() and possibly others, comprising the *foreground*. The interrupts running in the foreground preempt the background loop, but they always return to the point of preemption. The two parts of the system communicate with each other by means of shared variables, like l_tickCtr. To avoid race conditions due to preemption of the background loop by the foreground interrupts, these shared variables should be defined as volatile and must be protected by briefly disabling interrupts around any access to them from the background. The timing of the execution of the various functions called from the background loop is not well defined, because it depends on the time spent inside the loop that typically varies from one pass through the loop to another due to conditional branching in the code and interrupt activity. For these reasons, any operations with strict time constraints cannot be reliably performed from the background loop and must be pushed to the interrupt level running in the foreground. However, this tends to make the interrupts longer and they might start to interfere with the background loop and with each other. Still, due to its simplicity, the foreground/background architecture is very popular in high-volume embedded applications, such as consumer electronics, home appliances, toys, remote controllers, and countless others. Foreground/background is also exactly the architecture used in various maker platforms, such as Arduino. Here, for example is the Arduino version of the Blinky program. At the first glance, you might not recognize it as a foreground/background, because Arduino hides it inside its library. But if you take a look at the main function inside the Arduino library, you should immediately recognize the familiar background architecture consisting of initialization, the setup() function, and the endless loop, repetitively, calling the loop() function. Note that the for-loop with empty control is equivalent to the while(1) loop and is a C-language idiom that means for-ever. Arduino has, of course, also the foreground level consisting of interrupt handlers. Here, for example, is the system clock tick Interrupt Service Routine (ISR), which increments some counters, just like your SysTick handler. There is also, of course, the matching polling delay(), which is perhaps the most frequently used function in Arduino programs. Now, let's go back to your Blinky background code and notice that you can still organize it a bit better. For example, the initialization part is board-specific, so it logically belongs to the Board Support Package (BSP). So, let's make a BSP_init() function inside the BSP module, place all the initialization code there, and call it from main. Next, notice that switching the LEDs on and off is also board-specific, meaning that the code will need to change if you used a different board with LEDs attached to different pins. Therefore, you should move this code to the BSP as well. Specifically, inside the BSP module you can create BSP functions to turn LEDs of various colors on and off. Once the functions are defined, you can simply call them from the background loop. Of course, you need to add the prototypes of all the new BSP functions to the BSP header file. An finally, notice that now you can now remove all board-specific stuff from the main code, such as the MCU header file, the LEDs pin numbers, etc. You can move all this stuff into bsp.c, because your background loop no longer depends on any of these details. As you can see the code compiles and links error-free. The end effect is that your main code is completely insulated from the board. The background code only specifies WHAT needs to be done, while the BSP code specifies HOW to do it. This way of separating concerns (the WHAT from the HOW) has many advantages. First, your main code is smaller and self-explanatory. You really don't need comments to understand what's going on. The second advantage is that you could run this main code on a different board or you could use a different development toolchain. Of course, you would need to provide a different BSP implementation in the bsp.c file, but you don't need to change a single line of your main application code. It is even possible to run your main application on a desktop PC, which is not an embedded board at all. Now, let's check experimentally where your Blinky program spends the most of its time by simply breaking into the running code. As you can see, the program stops in BSP_tickCtr() function. When you inspect the call stack view, you can see that BSP_tickCtr() is called from BSP_delay(), which in turn is called from main at the shown location. In fact, you have almost no chance at all to find this program doing anything else than delaying its execution. When you draw a flowchart of this background code you can see arrows going *backwards* the flow of control. These are the pooling loops where the code spends the most of its time, and therefore they are shown with thick lines. I will call this type of code both *blocking* and *sequential*. The code is *blocking*, because it waits for events (such as a timeout event after expiration of a delay) in-line and does not progress until the expected event arrives. Once the event arrives, however, the code naturally progresses directly to handling the event because the code downstream the blocking call provides the right context for the expected event. The code is *sequential*, because the sequence of expected events is hard-coded in the sequence of instructions. For example, the Blinky program expects a timeout event of a duration of 1/4 second after turning the Green LED on, and another timeout event of duration 3/4 of a second after turning the Green LED off. But it is also possible to arrange the background code differently in a non- blocking fashion, without the polling loops that busy-wait for specific events. To show this alternative, I make the sequential implementation inactive by surrounding it with #if 0 ... #endif. Now, I add the new non-blocking version of the background loop. When you build and debug this version, you can see that it blinks exactly as before. But when you break into the code, you can see that it always stops inside the main loop rather than inside some other function. When you look at the flowchart of the non-blocking background code, you can see that no arrows in the flowchart go backwards. Instead, all arrows point forwards without blocking the main background loop, so the program spends the most of its time right in the main loop, as indicated by the heavy lines. Compared to the sequential and blocking version, the non-blocking main loop spins hundreds of thousand times per second instead of only once per second in the sequential code. This means that the main loop can handle events as soon as they arrive in the order in which they arrive. In other words, the non-blocking code is driven by events, and therefore I will call it *event-driven*. Of course, there is a price to pay for this increased flexibility and timeliness of such non-blocking code, and that is the apparent higher complexity. The event- driven code is more complex, because the sequence of events this code can accept is no longer hard-coded in the sequence of instructions. By the way, the non-blocking code is structured here as a polling state machine. This is unfortunately not the norm. In the majority of real-life projects, you will see rather convoluted and deeply nested IF-THEN-ELSE branching based on the value of many global variables, also known as the "spaghetti code" or a "big ball of mud". I cannot go into details of state machine in this lesson about foreground/background systems. But I promise to come back to state machines, in several upcoming lessons, actually, as they are fundamentally important in embedded systems programming. This concludes this lesson about the foreground/background architecture, which is fundamental to understanding all other architectures used in embedded software. You saw that foreground/background can be implemented either using the sequential paradigm with blocking, or with the event-driven and non-blocking paradigm. In the upcoming lessons I will explore all these options, starting with the introduction to Real-Time Operating Systems in the very next lesson! If you like this channel, please subscribe to stay tuned. You can also visit state- machine.com/quickstart for the class notes and project file downloads.