[3] A word of caution about waitfor : this implementation spins its wheels waiting for the software timer to change to the done state.. Putting It All Together 9.1 Application Overvi
Trang 1[1] Specifically, it represents the number of clock ticks remaining after all of the timers ahead of it in the list have expired
[2] Astute readers might recall that in Chapter 5, I stated that the PCB was located
in the I/O space of the 80188EB processor However, because memory-mapped registers are more likely in a device driver situation, I've relocated the entire PCB
to physical address 72000h, in the memory space This new location will be
assumed for the rest of the book To see how this relocation was performed, take a look at the constructor for the i8018xEB class
[3] A word of caution about waitfor : this implementation spins its wheels waiting for the software timer to change to the done state This technique is called busy-waiting, and it is neither elegant nor an efficient use of the processor In Chapter 8, we'll see how the introduction of an operating system allows us to improve upon this implementation
Chapter 9 Putting It All Together
9.1 Application Overview
9.2 Flashing the LED
9.3 Printing "Hello, World!"
9.4 Working with Serial Ports
9.5 The Zilog 85230 Serial Controller
A sufficiently high level of technology is indistinguishable from magic
—Arthur C Clarke
In this chapter, I'll attempt to bring all of the elements we've discussed so far
together into a complete embedded application I don't have much new material to add to the discussion at this point, so the body of the chapter is mainly a
description of the code presented herein My goal is to describe the structure of this application and its source code in such a way that there is no magic remaining for you You should leave this chapter with a complete understanding of the example program and the ability to develop useful embedded applications of your own
9.1 Application Overview
The application we're going to discuss is not much more complicated than the
"Hello, World!" example found in most other programming books It is a testament
Trang 2to the complexity of embedded software development that this example comes near the end of this book, rather than at its beginning We've had to gradually build our way up to the computing platform that most books, and even high-level language compilers, take for granted
Once you're able to write the "Hello, World!" program, your embedded platform starts to look a lot like any other programming environment The hardest parts of the embedded software development process—familiarizing yourself with the hardware, establishing a software development process for it, and interfacing to the individual hardware devices—are behind you You are finally able to focus your efforts on the algorithms and user interfaces that are specific to the product you're developing In many cases, these higher-level aspects of the program can be
developed on another computer platform, in parallel with the lower-level
embedded software development we've been discussing, and merely ported to the embedded system once both are complete
Figure 9-1 contains a high-level representation of the "Hello, World!" application This application includes three device drivers, the ADEOS operating system, and two ADEOS tasks The first task toggles the Arcom board's red LED at a rate of 10
Hz The second prints the string "Hello, World!" at 10 second intervals to a host computer or dumb terminal connected to one of the board's serial ports
Figure 9-1 The "Hello, World!" application
In addition to the two tasks, there are three device drivers shown in the figure These control the Arcom board's LEDs, timers, and serial ports, respectively
Although it is customary to draw device drivers below the operating system, I chose to place these three on the same level as the operating system to emphasize that they actually depend more on ADEOS than it does on them In fact, the
embedded operating system doesn't even know (or care) that these drivers are present in the system This is a common feature of the device drivers and other hardware-specific software in an embedded system
Trang 3The implementation of main is shown below This code simply creates the two
tasks and starts the operating system's scheduler At such a high level the code should speak for itself In fact, we've already discussed a similar code listing in the previous chapter
#include "adeos.h"
void flashRed(void);
void helloWorld(void);
/*
* Create the two tasks
*/
Task taskA(flashRed, 150, 512);
Task taskB(helloWorld, 200, 512);
/******************************************************************
***
*
* Function: main()
*
* Description: This function is responsible for starting the ADEOS
* scheduler only
*
* Notes:
*
* Returns: This function will never return!
*
******************************************************************
***/
void
main(void)
{
os.start();
// This point will never be reached
} /* main() */
9.2 Flashing the LED
As I said earlier, one of two things this application does is blink the red LED This
is done by the code shown below Here the function flashRed is executed as a task
However, ignoring that and the new function name, this is almost exactly the same
Trang 4Blinking LED function we studied in Chapter 7 The only differences at this level are the new frequency (10 Hz) and LED color (red)
#include "led.h"
#include "timer.h"
/******************************************************************
****
*
* Function: flashRed()
*
* Description: Blink the red LED ten times a second
*
* Notes: This outer loop is hardware-independent However, it
* calls the hardware-dependent function toggleLed()
*
* Returns: This routine contains an infinite loop
*
******************************************************************
****/
void
flashRed(void)
{
Timer timer;
timer.start(50, Periodic); // Start a periodic 50ms timer
while (1)
{
toggleLed(LED_RED); // Toggle the red LED
timer.waitfor(); // Wait for the timer to expire
}
} /* flashRed() */
The most significant changes to the Blinking LED program are not visible in this
code These are changes made to the toggleLed function and the Timer class to make them compatible with a multitasking environment The toggleLed function is
what I am now calling the LED driver Once you start thinking about it this way, it might make sense to consider rewriting the driver as a C++ class and add new
methods to set and clear an LED explicitly However, it is sufficient to leave our
implementation as it was in Chapter 7 and simply use a mutex to protect the
P2LTCH register from simultaneous access by more than one task.[1]
Trang 5Here is the modified code:
#include "i8018xEB.h"
#include "adeos.h"
static Mutex gLedMutex;
/******************************************************************
****
*
* Function: toggleLed()
*
* Description: Toggle the state of one or both LEDs
*
* Notes: This version is ready for multitasking
*
* Returns: None defined
*
******************************************************************
****/
void
toggleLed(unsigned char ledMask)
{
gLedMutex.take();
// Read P2LTCH, modify its value, and write the result
//
gProcessor.pPCB->ioPort[1].latch ^= ledMask;
gLedMutex.release();
} /* toggleLed() */
A similar change must be made to the timer driver from Chapter 7 before it can be used in a multitasking environment However, in this case there is no race
condition.[2] Rather, we need to use a mutex to eliminate the polling in the waitfor
method By associating a mutex with each software timer, we can put any task that
is waiting for a timer to sleep and, thereby, free up the processor for the execution
of lower-priority ready tasks When the awaited timer expires, the sleeping task will be reawakened by the operating system
Toward this end, a pointer to a mutex object, called pMutex, will be added to the class definition:
class Timer