Multitasking w mikrokontrolerach AVR [EN].pdf

(493 KB) Pobierz
Microsoft Word - Multitasking on an AVR.doc
MULTITASKING ON AN AVR
E X A M P L E C I M P L E M E N T A T I O N O F A M U L T I T A S K I N G K E R N E L F O R T H E A V R
RIC H ARD B ARRY
MARCH 2004
EXAMPLE C IMPLEMENTATION OF A MULTITASKING KERNEL FOR THE AVR, RICHARD BARRY - AVRFREAKS.NET
306548880.001.png
TABLE OF CONTENTS
INTRODUCTION ............................................................................................................ 2
THE RTOS TICK............................................................................................................. 2
GENERATING THE TICK INTERRUPT .......................................................................... 3
'EXECUTION CONTEXT' - A DEFINITION ..................................................................... 5
THE AVR CONTEXT ...................................................................................................... 6
WRITING THE ISR - THE GCC 'SIGNAL' ATTRIBUTE .................................................. 7
ORGANIZING THE CONTEXT - THE GCC 'NAKED' ATTRIBUTE ................................. 8
SAVING AND RESTORING THE CONTEXT ................................................................ 10
THE COMPLETE FREERTOS ISR ............................................................................... 11
PUTTING IT ALL TOGETHER - A STEP BY STEP EXAMPLE..................................... 12
EXAMPLE C IMPLEMENTATION OF A MULTITASKING KERNEL FOR THE AVR, RICHARD BARRY - AVRFREAKS.NET
1
Introduction
A real time operating system has to switch execution from one task to another to ensure each task is
given processing time in accordance with the tasks priority. How this switch is performed is dependent
on the microcontroller architecture. This article uses source code from FreeRTOS (an open source real
time scheduler) and the free GCC development tools to demonstrate how a task switch can be
implemented on an AVR.
The source code is explained from the bottom up. Topics covered include the setup of a periodic tick
interrupt, using GCC to write interrupt service routines in C, special GCC features used by FreeRTOS and
the AVR execution context.
The last pages demonstrates the source code operation with a detailed step by step guide to one
complete task switch.
Following the source code can be a good way of learning both the compiler and hardware - even if task
switching is not directly relevant to your application. I hope the topics will be of interest to those
wishing to learn how to write interrupts using AVR builds of GCC, people new to AVR microcontrollers, or
those who are just interested in RTOS implementation.
Readers should be familiar with the basic concepts of a real time operating system - such as tasks,
multitasking and context switching. A brief introduction to these topics along with the complete
FreeRTOS source code can be obtained from www.FreeRTOS.org .
The RTOS Tick
Applications that use a real time operating system (RTOS) are structured as a set of autonomous
tasks, with the operating system deciding which task should execute at any given time. The RTOS
kernel will suspend and resume tasks as necessary to ensure the task with the highest priority that is
ready to run is the task given processing time. In addition to being suspended by the RTOS kernel a
task can choose to suspend itself. It will do this if it either wants to sleep for a fixed period or wait (with
a timeout) for a resource to become available. See the FreeRTOS WEB site for a more detailed
explanation if you are not familiar with these concepts.
FreeRTOS measures time using a tick count variable. A timer interrupt (the RTOS tick interrupt)
increments the tick count with strict temporal accuracy - allowing time to be measured to a resolution
of the chosen timer interrupt frequency.
When a task suspends itself it specifies a delay (or "sleep") period. Each time the tick count is
incremented the RTOS kernel must check to see if the new tick value has caused a delay period to
expire. Any task found by the RTOS kernel to have an expired delay period is made ready to run. A
context switch will be required within the RTOS tick if a task made ready to run by the tick interrupt
service routine (ISR) has a priority higher than the task interrupted by the tick ISR. When this occurs
the RTOS tick will interrupt one task, but return to another. This is depicted below:
EXAMPLE C IMPLEMENTATION OF A MULTITASKING KERNEL FOR THE AVR, RICHARD BARRY - AVRFREAKS.NET
2
In this type of diagram time moves from left to right. The coloured lines show which task is executing at
any particular time. Referring to the numbers in the diagram above:
At (1) the idle task is executing.
At (2) the RTOS tick occurs, and control transfers to the tick ISR (3).
The tick ISR makes vControlTask ready to run, and as vControlTask has a higher priority than
the idle task, switches the context to that of vControlTask.
As the execution context is now that of vControlTask, exiting the ISR (4) returns control to
vControlTask, which starts executing (5).
Generating the Tick Interrupt
A compare match interrupt on the AVR timer 1 peripheral is used to generate the RTOS tick.
Timer 1 is set to increment at a known frequency which is the system clock input frequency divided by a
prescaler. The prescaler is required to ensure the timer count does not overflow too quickly. The
compare match value is calculated to be the value to which timer 1 will have incremented from 0 in the
required tick period. When the timer 1 value reaches the compare match value the compare match
interrupt will execute and the AVR will automatically reset the timer 1 count back to 0 - so the following
tick interrupt will occur after exactly the same interval.
/* Hardware constants for timer 1 on ATMega323. */
#define portCLEAR_COUNTER_ON_MATCH ( 0x08 )
#define portPRESCALE_256 ( 0x04 )
#define portCLOCK_PRESCALER ( 256 )
#define portCOMPARE_MATCH_A_INTERRUPT_ENABLE ( 0x10 )
/*
Setup timer 1 compare match A to generate a tick interrupt.
*/
static void prvSetupTimerInterrupt( void )
{
unsigned portLONG ulCompareMatch;
unsigned portCHAR ucHighByte, ucLowByte;
/* Generate the compare match value for our required tick
frequency. */
ulCompareMatch = portCPU_CLOCK_HZ / portTICK_RATE_HZ;
EXAMPLE C IMPLEMENTATION OF A MULTITASKING KERNEL FOR THE AVR, RICHARD BARRY - AVRFREAKS.NET
3
306548880.002.png
/* We only have 16 bits so have to scale to get our
required tick rate. */
ulCompareMatch /= portCLOCK_PRESCALER;
/* Setup compare match value for compare match A.
Interrupts are disabled before calling this function so
we need not bother here. [casting has been removed for
each of reading] */
ucLowByte = ulCompareMatch & 0xff;
ulCompareMatch >>= 8;
ucHighByte = ulCompareMatch & 0xff;
outb( OCR1AH, ucHighByte );
outb( OCR1AL, ucLowByte );
/* Setup clock source and compare match behaviour. */
ucLowByte = portCLEAR_COUNTER_ON_MATCH | portPRESCALE_256;
outb( TCCR1B, ucLowByte );
/* Enable the interrupt - this is okay as interrupt
are currently globally disabled. */
ucLowByte = inb( TIMSK );
ucLowByte |= portCOMPARE_MATCH_A_INTERRUPT_ENABLE;
outb( TIMSK, ucLowByte );
}
Source code to setup the tick interrupt
EXAMPLE C IMPLEMENTATION OF A MULTITASKING KERNEL FOR THE AVR, RICHARD BARRY - AVRFREAKS.NET
4
Zgłoś jeśli naruszono regulamin