ALERT: A Light Embedded Real-Time Operating System
ALERT_C5131 (v3.0) features...
The kernel module (kernel.c) contains support code and AT89c5131 peripheral interface functions for:
ALERT v3.0 provides additional code to support these options...
ALERT is easily scalable to include required features and to exclude unwanted features.
ALERT will run on other 80c51 core microcontrollers, e.g. Atmel AT89C51, with very little modification (built without the USB support modules).
ALERT will allow you to implement small embedded applications with many of the benefits of a more sophisticated RTOS, e.g. a rich set of system calls, robustness and reliability of execution, ease of code maintenance and extension, but with minimal overheads on processor and memory.
Characteristics of ALERT
ALERT supports simple "Foreground/Background" processing, where background tasks may be interrupted by foreground tasks. (A "foreground" task, in the ALERT context, is any interrupting task.) The kernel provides a task scheduler for invokation of periodic background tasks. Simplicity is achieved by compromise... of course.
The overall philosophy is to put as much as possible of the application code into background processes, i.e. scheduled tasks and the (optional) Command Line Interface (CLI). Background tasks are best implemented using a "state machine" model of some sort, because they are not permitted to cause delays. In this minimal RTOS design, background tasks have only two possible "status" values: ACTIVE and SUSPENDED. Active tasks are executed in a round-robin sequence. When a task is complete, it sets its own status to Suspended.
Background tasks are not time-critical, but must have short execution times on each call, so that the sum of all B/G tasks execution times is normally less than the minimum B/G task period. Occasional overruns can be tolerated, as long as not excessive in duration or frequency. (The definitions of "occasional" and "excessive" depend on the application and the watchdog time-out interval!) Background task overruns are monitored by the kernel, for diagnostic purposes.
Background tasks may be scheduled periodically by the Task Scheduler, or they may be invoked on an 'ad hoc' basis, as required, e.g. by a CLI command function or by another task.
Tasks are not permitted to contain "wait loops". If a process involves waiting for some external event to happen, e.g. a delay timer to expire, or another task to complete, or whatever, the process should be implemented as a "state machine". While a task is "stuck" in the same state, waiting for an event to occur before it can advance to a subsequent state, it should return immediately but remain in the ACTIVE state. This has the effect of allowing all other Active tasks to execute without disruption.
In any RTOS, care must be taken to prevent data corruption during data transfers between tasks. More sophisticated RTOS's use semaphores, message queues, etc, to control inter-task data communications. ALERT uses a simpler, more efficient approach...
There is no difficulty with data transfers between background tasks, since they are inherently prevented from "interrupting" each other at inconvenient times. As the majority of processing occurs in background, inter-task communications will rarely require special handling. Similarly, assuming the application disallows nesting of interrupts (with possible exemptions), there is no need to control data transfers among foreground tasks. In a nutshell, while a task (foreground or background) is processing data that another task needs to read, the data is never available for reading until the update is complete. Shared data simply cannot be modified by one task while it is being read by another.
ALERT does not provide generic mechanisms for synchronisation of inter-task data communications. There are two reasons for this: 1) Such mechanisms can add significant overheads to processor load and memory requirements; 2) Mechanisms developed specifically to suit the application are likely to be more efficient and less obscure than a generalised set of system calls.
Data transfers between background and foreground need to be carefully controlled to prevent errors due to one ground reading data while the same data is being modified by another. Background tasks must disable interrupts during multi-word data transfers and then restore the interrupt status afterwards. Double-buffering is a reliable technique for managing data transfers. (For example, see ReadRTCdateTime(). )
Nesting of foreground tasks which share multi-word data structures with other F/G tasks is prohibited, i.e. such tasks must be prevented from interrupting each other. F/G tasks that do not share multi-word data structures with other F/G tasks may interrupt freely.
Applying these guidelines to firmware based on ALERT will help you to implement reliable error-free applications.
How to incorporate ALERT into a firmware application
The best approach is to design the application around ALERT from the beginning. Incorporate the application into ALERT, not the other way around. Attempting to adapt an existing application to ALERT or any other 3rd-party RTOS, with minimal restructuring, is probably not going to be easy.
Step 1:
Understand how ALERT works and how best to build your
application code around it. ALERT has been designed to be largely
"self-documenting", i.e. the source code and
comprehensive annotation therein should give the developer
sufficient understanding of its workings. The sample program (AT89c5131
debug monitor) shows how application-specific code is best
incorporated, i.e. as a number of background tasks which
interface with ALERT by means of "system calls"...
(System calls are functions which the RTOS provides to facilitate
interfacing of the application code with system resources such as
the real-time clock, timers, serial data communications devices,
digital inputs and outputs, analog inputs, control surface
switches and indicators, displays, non-volatile memory, etc.)
Step 2: Decide which of ALERT's kernel features are required. Customise the kernel module accordingly.
Step 3: Decide which of the additional modules are required, i.e. CLI facility (with Debug Monitor).
Step 4. Flesh out the kernel with I/O device drivers to suit your particular MCU type and peripheral hardware (in module rtos.c). Use the sample I/O drivers (as provided for the AT89c5131 evaluation board) as a guide, substituting code to suit your target hardware platform.
Step 5: Extend the kernel module, if necessary, to provide support for additional resources, e.g. LCD panel, LED 7-segment display, keypad, analog I/O, SPI digital I/O port registers, DataFlash memory, audio codec, etc.
Step 6: Design and code application-specific tasks, making the most out of available system calls in the ALERT kernel and CLI modules. Stick to the guidelines in the Overview section above.
Command Line Interface (CLI) and Debug Monitor
A command string is composed of a 2-letter command "mnemonic" and a number of user-supplied "arguments" (parameters). Some commands have no arguments. A single space must be inserted between command line arguments, where there is more than one (including the 2-letter command name). CLI input is generally not case-sensitive. There is no provision for command-line editing.
A list of available commands is output by entering the "help" command, 'HE'. In the listing, square brackets enclosing a command argument mean that the argument is optional. (Don't type the brackets!) Refer to "help" listing for command syntax details.
USB Comm's Build Option (AT89c5131 firmware example)
The CLI is accessible from either the USB port or the "RS-232" async serial port (UART). This is a "build option" (meaning that the option is selected in a header file, before compilation) and cannot be swapped at run-time. The ALERT_C5131 download package includes four object code files, ready to load into your development board. The variants are: CLI on USB with 16MHz MCU clock; CLI on USB with 24MHz MCU clock; CLI on UART with 16MHz MCU clock; CLI on UART with 24MHz MCU clock.
Whether using USB or UART to acces the CLI, the UART port can be used to output "trace" information for diagnostics. The UART is configured to use 38400 Baud, 1 stop bit, 8 data bits, and no parity bit, by default. Of course, these defaults can be altered in the source code to suit your application.
If your application needs the USB port for a dedicated purpose, e.g. to implement a USB-to-Serial converter, or data logger, etc, choose a build-option which uses the UART for access to the CLI (for debugging). Your application can then use the CDC "USB Vuart" library functions to greatly simplify USB comm's.
Installing the Windows USB driver.
The Windows USB driver is "usbser.sys", normally included with Windows XP, and normally found in local directory C: \Windows\system32\drivers. The custom driver information file required for this firmware is "cdc5131.inf". This should be copied to local directory C: \Windows.
When the board is first powered up with the ALERT 'C5131 firmware installed, Windows "Found New Hardware Wizard" should appear and prompt for these files. It's better not to let the wizard search automatically for a suitable driver. Browse to the location of each file when prompted (cdc5131.inf comes first). If the Wizard asks for a hardware device type or category, select "Ports".
If the driver installed properly, the Windows "Device Manager" will show a new device "AT89C5131 CDC" under "Ports (COM & LPT)". It will also show the port number of the virtual COM port assigned to the device. Use this port number when configuring HyperTerminal.
Using the CLI when configured for USB comm's.
Connect the 'C5131 developement board to the host PC before starting HyperTerminal.
A second terminal emulator, e.g. TeraTerm, can be used to access the RS232 serial "debug" port, with UART settings: 38400Bd, n, 8, 1.
When the board is powered up and running, start HyperTerminal.
The 'C5131 board USB port appears to the host PC as a "virtual COM port". From File menu in HyperTerminal, select "Properties". In the dialog box, in the field "Connect Using:", select the COM port assigned to the device. (This is usually the highest numbered virtual COM port, which will be COM5 or above on PCs having physical ports on COM1 thru COM4.) Other serial port settings (Baud rate, etc) are irrelevant for USB comm's, except for devices implementing a USB-to-Serial converter, or such like.
Click "OK" to close the "Properties" dialog box.
Next, click the "Call Connect" button (or select "Call/Connect" from the menu). With the HyperTerminal window active, hit [Enter] once or twice on your keyboard. The ALERT CLI prompt should appear (:-->).
Click the "Disconnect" button in HyperTerminal before resetting or unplugging the board. Click the "Call Connect" button to resume communications. If HyperTerminal fails to respond, close it, reset the board, then open it again. In some cases, it might be necessary to reconfigure the COM port (as above).
Copyright 2008++ Michael J Bauer