#include <avr/io.h>
#include <avr/ina90.h>
#include <avr/signal.h>
#include "timer.h"
#include "rtk.h"
static struct Thread mainThread; // static because it doesn't need to
// leave this file
// initialize timer2 to interrupt at 5kHz, enable output compare interrupt
static void
setTimer2(void)
{
output(TIMSK, (input(TIMSK) & 0x3f) | 0x80);
output(TCNT2,0);
output(OCR2, 49);
output(TCCR2,0x0b);
}
// be sure to specify the following when you compile:
// -DTICKFREQ=1000 makes the tick frequencey matches milliseconds
// -DISR_FREQ=5000 makes the system know that the ISR interrupts at 5kHz
// -DTIMER_ISR=SIG_OUTPUT_COMPARE2 makes the system know that the ISR is
// defined elsewhere
// this file needs to link with rtk.S and timer.S
// because rtk.S provides the RTK implementation, while
// timer.S provides the preemption ability and time tracking ability
int main(void)
{
struct Tick wakeTime;
// ... code before rtk is active
rtkInitialize(&mainThread, &rtkQueues[0]);
// ... code after rtk is active
// let's start up the timer to provide timing
DDRG |= 0x18;
PORTG |= 0x18;
setTimer2();
_SEI(); // enable interrupts
while (1)
{
PORTG ^= 0x18;
// ... do something
rtkTickCountGet(&wakeTime); // take a snapshot of the current time
tickAdd4(&wakeTime, 100); // make the wake time 100 ticks from now
// while (rtkTime < wakeTime) rtkThreadYield();
rtkThreadSchedule(rtkCurrentThread, &wakeTime);
// now wait 100 tick
// when we "return" from rtkThreadSchedule, it's 100 ticks later
}
}
This program sets up PORTG to control two LEDs. This part is
only useful if two LEDs are connected to pin 3 and pin 4 of the
MCU (via current limiting resistors). The main subroutine
calls setTimer2 to initialize timer2 to interrupt 5,000 times
per second.
_SEI() enables global interrupt. This is necessary because
when main gets control, global interrupt is disabled. Until
_SEI() is executed, the timer does not interrupt.
The most critical parts of this program is explained as follows:
rtkTickCountGet(&wakeTime);
wakeTime, which is a variable of
struct Tick type.
tickAdd4(&wakeTime, 100);
wakeTime.
rtkThreadSchedule(rtkCurrentThread, &wakeTime);
wakeTime.
This sequence effectively schedules the thread to execute 100 kernel ticks
later. One can imagine that rtkThreadSchedule does not return until
100 ticks has passed.
Now, let us take a look at the make file for this program.
MMCU = -mmcu=atmega128
COMMONOPT = -g $(MMCU) \
-DTICK_FREQ=1000 -DISR_FREQ=5000 -DTIMER_ISR=SIG_OUTPUT_COMPARE2
ASFLAGS = $(COMMONOPT) -D__ASM__
CFLAGS = $(COMMONOPT) -O3 # don't forget, otherwise defaulted to 8515!
# the mmcu option also controls how the linker
# links (which linker script file to use)
LDFLAGS = -g $(MMCU)
MAIN_SRCFILE = onethread_sch.c
C_SRCFILES = $(MAIN_SRCFILE)
ASM_SRCFILES = rtk.S timer.S
include main.make
The most notably differences of COMMONOPT between this make file
and the previous one are listed as follows:
-DTICK_FREQ=1000
-DISR_FREQ=5000
-DTIMER_ISR=SIG_OUTPUT_COMPARE2
SIG_OUTPUT_COMPARE2. This macro is chosen because
setTimer2 configures the timer to interrupt whenever
it overflows the output compare value.
In addition, this make file include timer.S as a modules. This is
because timer.S provides the actual timer ISR code.
Copyright © 2008-10-25 by Tak Auyeung