Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / scheduler / scheduler.c @ 1574

History | View | Annotate | Download (4 KB)

1 1479 jsexton
/**
2
 * @file scheduler.c
3
 * @brief Scheduler
4
 *
5
 * Implementation of functions for scheduler
6 1573 justin
 * Currently relies on avr-gcc's interrupt call convention.
7 1479 jsexton
 *
8
 * @author Colony Project, CMU Robotics Club
9 1544 justin
 * Based on avrOS and 18348 Lab9 code
10 1479 jsexton
 **/
11 16 bcoltin
12 1574 justin
#include <avr/interrupt.h>
13
#include <util/delay.h>
14 1479 jsexton
#include "scheduler.h"
15 1544 justin
16 1573 justin
#define DEBUG
17
18
#ifdef DEBUG
19
#include <serial.h>
20 1574 justin
#endif
21 1573 justin
22
static uint8_t STACK[MAXTASKS + 1][STACKSIZE];
23 1544 justin
static uint8_t nactive_tasks = 1;
24
static uint8_t current_task = 0; //Default to main.
25
26
//Internal functions
27 1573 justin
static void task_terminate(void);
28 1544 justin
29 1573 justin
//TODO Use a context struct instead of pushing onto the stack.
30
//so we don't need to worry so much about stack overflow.
31
typedef struct context_t {
32
        uint8_t reg[32];
33
        uint8_t sreg;
34
} context_t;
35 1544 justin
36 1573 justin
//Define some PCB's
37 1544 justin
typedef struct PCB_t
38
{
39
        void (*exec)(void);
40
        uint8_t* sp;
41
        uint16_t period; //Interval in clock cycles.
42
        uint32_t next;
43 1574 justin
        char running;
44 1544 justin
} PCB_t;
45
46
PCB_t PCB[MAXTASKS + 1];
47
48 1573 justin
//Keep track of global time.
49
static uint32_t current_time = 0;
50 1544 justin
51 1573 justin
unsigned int time_now() {
52
        return current_time;
53
}
54
55
void scheduler_init() {
56
        //Set the counter to 0.
57
        TCNT3 = 0;
58
59
        //Clear timer on compare (CTC) mode.
60
        TCCR3B |= _BV(WGM32);
61
62
        //Set a prescalar of 8. 8 / (8MHz) = 1us per tick.
63
        TCCR3B |= _BV(CS31);
64
65
        //Trigger an interrupt every 16th second for now.
66
        OCR3A = 0xF424;
67
68
        //Enable Output Compare A Interrupt. (Begins immediately).
69
          ETIMSK |= _BV(OCIE3A);
70
71
        sei();
72
}
73
74
static void task_terminate(void) {
75 1544 justin
        PCB[current_task].running = 0;
76
        yield();
77
}
78
79
void yield() {
80
        //TODO Actually implement.
81
        for(;;){}
82
}
83
84
int register_task(void (*exec)(void), uint16_t period)
85
{
86
        if(nactive_tasks >= MAXTASKS) {
87
                return -1;
88
        }
89
90
        PCB[nactive_tasks].exec = exec;
91
        PCB[nactive_tasks].period = period;
92 1574 justin
93
        cli();
94 1573 justin
        PCB[nactive_tasks].next = current_time + period;
95 1574 justin
        sei();
96
97 1544 justin
        PCB[nactive_tasks].running = 0;
98
99
        //Don't need to initialize SP, it will get done later.
100
        nactive_tasks++;
101
        return nactive_tasks - 1;
102
}
103
104 1573 justin
//I need a timer to do the rest.  Thinking about stealing it from rtc.
105
SIGNAL(TIMER3_COMPA_vect) {
106
        static uint8_t task_i = 1;
107
        volatile uint8_t* sp;
108 1544 justin
109 1573 justin
        uint8_t i;
110 1544 justin
111 1573 justin
        //Store sp.
112 1574 justin
        sp = (uint8_t*)&(PCB[current_task].sp);
113 1573 justin
114
        asm volatile( \
115
                "in r0, __SP_L__ \n" \
116
                   "st %a0+, r0 \n" \
117
            "in r0, __SP_H__ \n" \
118 1574 justin
                "st %a0, r0 \n"  : : "e" (sp));
119 1573 justin
120
        //Keep track of the number of 1/16 second's that have passed.
121
        current_time++;
122
123
        /******** scheduler ********/
124 1544 justin
125
        //Loop over registered tasks, like in round robin order.
126 1573 justin
        for(i = nactive_tasks - 1; i > 0; i--) {
127
                //Launch a new task if it is due to run.
128
                if(        !PCB[task_i].running
129
                  && PCB[task_i].next <= current_time) {
130 1544 justin
131 1574 justin
                        current_task = task_i;
132
                        PCB[current_task].next += PCB[current_task].period;
133
                        PCB[current_task].running = 1;
134
135 1573 justin
                        task_i++;
136 1574 justin
                        if(task_i >= nactive_tasks)
137
                                task_i = 1;
138 1573 justin
139
                        /***** create launch stack ***/
140
141 1574 justin
                        sp = (void*)((uint16_t)&STACK[current_task][STACKSIZE - 1]);
142 1573 justin
143
                        //Put task terminate  and the task to execute on the stack.
144 1574 justin
                        *(sp--) = (uint8_t)(uint16_t)*task_terminate;
145
                        *(sp--) = (uint8_t)((uint16_t)*task_terminate >> 8);
146 1573 justin
147 1574 justin
                        *(sp--) = (uint8_t)(uint16_t)PCB[current_task].exec;
148
                        *(sp--) = (uint8_t)((uint16_t)PCB[current_task].exec >> 8);
149
150 1573 justin
                        //The current state of the registers is what the tasks will
151
                        //see on entry (shouldn't matter).
152
153
                        asm volatile( \
154
                                "out __SP_L__, %A0 \n" \
155
                                "out __SP_H__, %B0 \n" : : "d" (sp));
156
157
                         /* start process and enable interrupts */
158
                         asm volatile("reti \n");
159 1545 justin
                        break;
160
                }
161 1573 justin
162
                //Continue an old task.
163 1574 justin
                if(PCB[task_i].running == 1) {
164 1573 justin
                        current_task = task_i;
165 1546 justin
                        task_i++;
166 1574 justin
                        if(task_i >= nactive_tasks)
167
                                task_i = 1;
168 1544 justin
                        break;
169
                }
170
171
                task_i++;
172 1574 justin
                if(task_i >= nactive_tasks)
173 1545 justin
                        task_i = 1;
174 1544 justin
        }
175 1545 justin
176 1573 justin
        //If no task was selected to run, go to main
177 1574 justin
        if(i == 0)
178 1545 justin
                current_task = 0;
179 1573 justin
180 1574 justin
        //Reset the stack pointer.
181
        sp = PCB[current_task].sp;
182
        asm volatile( \
183
                "out __SP_L__, %A0 \n" \
184
                "out __SP_H__, %B0 \n" : : "d" (sp));
185
186 1573 justin
        //Set the running task.*/
187
        PCB[current_task].running = 1;
188 1544 justin
189 1573 justin
        //avr-gcc inserts all of the necessary pops and the reti here.
190 1544 justin
}