7.2 onethread_sch

This program only uses one thread, but it is a bit different from the previous one.

#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:

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:

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