NiosII GCC with MicroC/OS (original) (raw)
To find out more generally about MicroC/OS, read the book listed below by Labrosse. There is also a partial API summary by Nancy Minderman at the University of Alberta and a terse summary from Micrium. There is a very complete list of functions from Departamento de Arquitectura de Computadores (DAC) en la Escola Politècnica Superior de Castelldefels (EPSC) (campus de la Universitat Politècnica de Catalunya). There is a good MicroC/OS summary at Zworld, but you will have to filter out the device-specific material.
MicroC/OS allows you to define several functions in C, each of which can execute as an independent thread or task. Each task runs at a different priority, and thinks that it owns the CPU. Lower priority tasks can be prempted by higher priority tasks at any time. Higher priority tasks use operating system services (such as a delay or event) to allow lower priority tasks to execute. There are operating system services provided for task managment, inter-task communication, memory managment, and for timing.
MicroC/OS services include:
- Semaphores and Mutual Exclusion Semaphores (to reduce priority inversions)
- Event Flags
- Message Mailboxes and Queues
- Task Management (Create, Delete, Change Priority, Suspend/Resume etc.)
- Fixed Sized Memory Block management
- Time and Timer Management
Interrupt service routines can be integrated into MicroC/OS programs as long as the OS is informed of the interrupt. ISRs should be short and essentially just signal a normal (high priority) task to execute. See example 3 below.
Examples:
Three MicroC/OS tasks with DDS, semaphore, and message passing.
The first example uses a NiosII cpu with JTAG UART, interval timer, two input and two output ports, and an LCD port. The timer was set to default to 1 mSec in the SOPC. This setting seems to be picked up by the OS library builder in the IDE program. For real applications, it should probably be set to 10 mSec. Changing the timer in the SOPC to 10 mSec, rebuilding the hardware, then recompiling the GCC program automatically sets the MicroC/OS system tick to 10 mSec. The[sof](TestBigNios%5Ftime%5Flimited.sof)
and[ptf](bigNios.ptf)
files define the system.
The top level module connectsOut0
to a DDS (direct digital synthesis) unit for sine wave production.In0
is connected to the DE2 switches and the 8-bitIn1
connected to the pushbuttons. See NiosII C examples, example #3 for more information on the DDS. Note that in<system.h>
(generated by the library builder) that the names of the i/o ports are UPPERCASED. After the workspace is defined in the IDE, the system library properties need to be set up for the RTOS as shown below. Clicking theRTOS Options
button allows you to choose exactly what OS modules you want to include. The default is to include every module, which results in a minimum 120 kByte executable. The Altera Tutorial gives more detail on setting up the system library.
The GCC program structure is very simple:- The
main
defines OS data structures and tasks. OS data structures (in this example, a message queue and a semaphore) used by more than one task need to be global. - Each task is written so that it never terminates. This implies that task local variables are effectively static. The task stack must be made big enough to hold all local variables (including those defined in functions within tasks) and the task context when another task is running.
- Task 1 controls a hardware DDS unit running in the top level Verilog module. The DE2 toggle switches control which octave is played.
- Task 1 sends a message to Task 2, which prints the message.
- Task 1 controls Task 3 via a semaphore so that Task 3 runs every time Task 1 does, unless Task 1 suspends Task 3 using a pushbutton.
- Task 2 waits for a message, prints it and waits again
- Task 3 waits for a semaphore, prints the system time, and waits again
Note that several system calls in the program cause a context change. The callOSTimeDlyHMSM
causes Task 1 to block for a time interval, but does not affect the execution of other tasks.OSQPend
causes Task 2 to wait for a message in the queue, whileOSSemPend
causes Task 2 to wait for a signal from Task 1. If a task does not call an OS service which causes it to wait, then no lower priority task will ever execute!
A slight modification to the top-level Verilog module connects output port Out1 to the green LEDs. The GCC program was modified to include a fourth, low priority task, which does not block using OS calls, but runs at full speed. With task 1 pacing the first three tasks at one/sec, the LED blink rate suggests that task 4 is running about a million times/sec. When task 1 is running at about 140/sec (OSTimeDly
set to 7 mSec), task 4 never gets a chance to run because task processing, context switches and OS overhead is eating the cpu.
- The
Using the LCD.
The example uses the same cpu as above, but the last two lines of the top-level Verilog module were modified to turn on the LCD alphanumeric display. The device driver for the LCD is named in <system.h> and seems to be recognized as a UNIX-style stream file device by the GCC librarystdio.h
. Using it is just a matter of opening a device usingfopen
and writing to it usingfprintf
. The device driver recognizes ansi escape codes to control the cursor position. This GCC program is a modification of example 1. Task 1 can clear the LCD when KEY1 is pushed and Task 3 prints its stack size tostdout
and the OS tick time to the LCD. The LCD file device is opened inmain
. The frequency accuracy of the DDS was reduced to increase its dynamic range in frequency. As shown, the DDS can reproduce sine waves from DC to over one MHz with an accuracy of about .012 Hz at low frequencies and an accuracy limited by the crystal at high frequencies.Interrupt Service Routine (ISR) in MicroC/OS.
This example uses the same cpu as above, but with the addition of a second timer (timer1). Timer0 cannot be touched because it is used by the internal OS time-tick function. The GCC program was modified so that task 4 runs at highest priority, but waits for a semaphore which is signaled by the timer1 ISR. MicroC/OS needs to know you are in an interrupt, but it turns out that the necessary MicroC/OS bookkeeping is encapsulated in the Altera interrupt handler, so that only user code needs to be in the ISR. This means that you don't need to save context or includeOSIntEnter()
orOSIntExit()
in the ISR because the interrupt handler is aware of the operating system and handles it. The details can be found in the main interrupt handler,alt_irq_handler()
(To find the source file, open the tabs in the left-most IDE panel:syslib / DeviceDrivers[nios] / altera_hal / HAL / src)
. More details on saving context are inalt_irq_entry.S
(To find the source file, open the tabs:syslib / DeviceDrivers[nios] / altera_nios2 / HAL / src
). The whole project is zipped here.
How fast can we make it interrupt before the multitasking messes up? You can set the optimization level by right-clicking the project icon and going toproperties
. From there, choose NiosII complier options. With optimization set to-O0
(the default setting), reducing the number of ticks to timeout for timer1 to 0x1800 causes the system to crash. Setting the number of ticks to timeout for timer1 to 0x2000 allows multitasking of all four tasks to work. Setting the number of ticks to timeout for timer1 to 0x1d00 allows task 4 and task 1 to run, but not the lower priority tasks 2 and 3. With optimization set to-O3
(the highest) and no debugging, multitasking works with a setting of 0x1900, but fails at 0x1800. Thus, it looks like it takes about 6100 cycles for the ISR handling, internal timer0 functions, and context switching, so we can sustain (with these simple tasks) perhaps 7800 interrupts/second in MicroC/OS. Very fast functions, such as DDS, should be put in hardware, but button push detection and other sporadic events can be interrupt-driven.LCD written from 3 tasks, with Mutex protection
This example uses the same cpu as in example 3 above. The GCC program was modified so that tasks 2, 3 and 4 all write to the LCD. A mutex is used to give each task sole control of the LCD until it is finished writing its string. The task owning the mutex has its priority temporarily boosted to avoid priority inversion.
References
Micrium is the MicroC/OS vendor
MicroC/OS-II The Real Time Kernel, by Jean Labrosse, RD books, second edition, 2002
MicroC/OS function summary and API (linked from http://www.ece.ualberta.ca/~cmpe401/fall2004/labs/docs/uC_Functions.html)
- AN3000 TCP/IP on NiosII
- AN5001 µC/GUI and the Altera Nios II Soft Core Processor
- AN6000 µC/FS and the Altera Nios II Soft Core Processor
MicroC/OS info from EPSC
- Summary slides
- Function Reference This appears to be Chapter 16 of Labrosse's book.
Copyright Cornell University June 2006