Chris O'Byrne - YAVRTOS

In this example, we will flash two LEDs connected to port A at different rates.

#include "task.h"

#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>

// A semaphore that we will increment at every tick
static semaphore_t tick;
// We will also create a mutex for port A, as both tasks will be using it potentially "simultaneously"
static mutex_t porta_mutex;

// This is our first task - blinking port A bit 0 once every 200 ticks
void blink1(void *p) {
        while (1) {
                // Obtain a lock on the port A mutex
                lock_on(&porta_mutex);
                // OK - port A is now all ours, so blink the LED
                PORTA ^= 0x01;
                // Release our hold on the port A mutex
                lock_off(&porta_mutex);
                // Now, suspend this task for another 200 ticks
                wait_for_increment_of(&tick, 200);
        }
}

// This is our second task - blinking port A bit 1 once every 280 ticks
void blink2(void *p) {
        while (1) {
                // Obtain a lock on the port A mutex
                lock_on(&porta_mutex);
                // OK - port A is now all ours, so blink the LED
                PORTA ^= 0x02;
                // Release our hold on the port A mutex
                lock_off(&porta_mutex);
                // Now, suspend this task for another 280 ticks
                wait_for_increment_of(&tick, 280);
        }
}

// This is our idle task - the task that runs when all others are suspended.
// We sleep the CPU - the CPU will automatically awake when the tick interrupt occurs
void idle_task(void *p) {
        sleep_enable();
        sei();
        sleep_cpu();
        // This task cannot be stopped, so it is automatically re-started whenever it tries to exit
}

// This is a function that runs every tick interrupt - we use it to increment the tick semaphore value by one
uint8_t tick_interrupt() {
        increment_semaphore_by(&tick,1);
        // We want a task switch to ALWAYS occur - it is part of the definition of the tick interrupt!
        return 1;
}

// Setup the TIMER1_COMPA interrupt - it will be our tick interrupt
TASK_ISR(TIMER1_COMPA_vect, tick_interrupt())

// Our entry point
int main(void) {
        // Interrupts should remain disabled - they will be enabled as soon as the first task starts executing
        cli();
        // Set up port A for output
        DDRA = 0xFF;
        // Our idle task sleeps the CPU - set the sleep mode to IDLE, as we need the sleep to be
        // interruptable by the tick interrupt
        set_sleep_mode(SLEEP_MODE_IDLE);
        // Create our two tasks
        create_task(blink1, 0, 0, 55, 100, 0);
        create_task(blink2, 0, 0, 55, 100, 0);
        // Set up our TIMER1_COMPA interrupt to tick every 80,000 clock cycles
        TCCR1B = 0x0A;
        OCR1A = 9999;
        TIFR = _BV(OCF1A);
        TIMSK |= _BV(OCIE1A);
        // Start the RTOS - note that this function will never return
        task_switcher_start(idle_task, 0, 55, 55);
        return 0;
}

YAVRTOS and YAVRTOS documentation Copyright © 2007-2008 Chris O'Byrne. Email - chris <at> obyrne <dot> com