| 9 |
9 |
* Based on avrOS and 18348 Lab9 code
|
| 10 |
10 |
**/
|
| 11 |
11 |
|
| 12 |
|
#include <avr/interrupt.h>
|
| 13 |
|
#include <util/delay.h>
|
|
12 |
#include <avr/interrupt.h>
|
|
13 |
#include <util/delay.h>
|
| 14 |
14 |
#include "scheduler.h"
|
| 15 |
15 |
|
| 16 |
16 |
#define DEBUG
|
| 17 |
17 |
|
| 18 |
18 |
#ifdef DEBUG
|
| 19 |
19 |
#include <serial.h>
|
| 20 |
|
#endif //DEBUG
|
|
20 |
#endif
|
| 21 |
21 |
|
| 22 |
22 |
static uint8_t STACK[MAXTASKS + 1][STACKSIZE];
|
| 23 |
23 |
static uint8_t nactive_tasks = 1;
|
| ... | ... | |
| 38 |
38 |
{
|
| 39 |
39 |
void (*exec)(void);
|
| 40 |
40 |
uint8_t* sp;
|
| 41 |
|
char running;
|
| 42 |
41 |
uint16_t period; //Interval in clock cycles.
|
| 43 |
42 |
uint32_t next;
|
|
43 |
char running;
|
| 44 |
44 |
} PCB_t;
|
| 45 |
45 |
|
| 46 |
46 |
PCB_t PCB[MAXTASKS + 1];
|
| ... | ... | |
| 68 |
68 |
//Enable Output Compare A Interrupt. (Begins immediately).
|
| 69 |
69 |
ETIMSK |= _BV(OCIE3A);
|
| 70 |
70 |
|
| 71 |
|
#ifdef DEBUG
|
| 72 |
|
usb_init();
|
| 73 |
|
#endif //DEBUG
|
| 74 |
|
|
| 75 |
71 |
sei();
|
| 76 |
72 |
}
|
| 77 |
73 |
|
| 78 |
74 |
static void task_terminate(void) {
|
| 79 |
|
#ifdef DEBUG
|
| 80 |
|
usb_puts("In task terminate!.\n\r");
|
| 81 |
|
#endif //DEBUG
|
| 82 |
75 |
PCB[current_task].running = 0;
|
| 83 |
76 |
yield();
|
| 84 |
77 |
}
|
| ... | ... | |
| 96 |
89 |
|
| 97 |
90 |
PCB[nactive_tasks].exec = exec;
|
| 98 |
91 |
PCB[nactive_tasks].period = period;
|
|
92 |
|
|
93 |
cli();
|
| 99 |
94 |
PCB[nactive_tasks].next = current_time + period;
|
|
95 |
sei();
|
|
96 |
|
| 100 |
97 |
PCB[nactive_tasks].running = 0;
|
| 101 |
98 |
|
| 102 |
99 |
//Don't need to initialize SP, it will get done later.
|
| ... | ... | |
| 107 |
104 |
//I need a timer to do the rest. Thinking about stealing it from rtc.
|
| 108 |
105 |
SIGNAL(TIMER3_COMPA_vect) {
|
| 109 |
106 |
static uint8_t task_i = 1;
|
| 110 |
|
volatile uint8_t** sploc;
|
| 111 |
107 |
volatile uint8_t* sp;
|
| 112 |
108 |
|
| 113 |
109 |
uint8_t i;
|
| 114 |
110 |
|
| 115 |
|
#ifdef DEBUG
|
| 116 |
|
char test_buf[128];
|
| 117 |
|
#endif //DEBUG
|
| 118 |
|
|
| 119 |
111 |
//Store sp.
|
| 120 |
|
sploc = &(PCB[current_task].sp);
|
|
112 |
sp = (uint8_t*)&(PCB[current_task].sp);
|
| 121 |
113 |
|
| 122 |
114 |
asm volatile( \
|
| 123 |
115 |
"in r0, __SP_L__ \n" \
|
| 124 |
116 |
"st %a0+, r0 \n" \
|
| 125 |
117 |
"in r0, __SP_H__ \n" \
|
| 126 |
|
"st %a0, r0 \n" : : "e" (sploc));
|
|
118 |
"st %a0, r0 \n" : : "e" (sp));
|
| 127 |
119 |
|
| 128 |
|
#ifdef DEBUG
|
| 129 |
|
sprintf(test_buf, "current_task = %d, current_time = %d, sp = %x\n\r", current_task, current_time, sploc);
|
| 130 |
|
usb_puts(test_buf);
|
| 131 |
|
#endif //DEBUG
|
| 132 |
|
|
| 133 |
|
//The current task may no longer be running when we exit.
|
| 134 |
|
PCB[current_task].running = 0;
|
| 135 |
|
|
| 136 |
120 |
//Keep track of the number of 1/16 second's that have passed.
|
| 137 |
121 |
current_time++;
|
| 138 |
122 |
|
| ... | ... | |
| 140 |
124 |
|
| 141 |
125 |
//Loop over registered tasks, like in round robin order.
|
| 142 |
126 |
for(i = nactive_tasks - 1; i > 0; i--) {
|
| 143 |
|
|
| 144 |
127 |
//Launch a new task if it is due to run.
|
| 145 |
128 |
if( !PCB[task_i].running
|
| 146 |
129 |
&& PCB[task_i].next <= current_time) {
|
| 147 |
130 |
|
| 148 |
|
task_i++;
|
| 149 |
|
|
| 150 |
131 |
current_task = task_i;
|
| 151 |
|
PCB[task_i].next += PCB[task_i].period;
|
|
132 |
PCB[current_task].next += PCB[current_task].period;
|
|
133 |
PCB[current_task].running = 1;
|
| 152 |
134 |
|
|
135 |
task_i++;
|
|
136 |
if(task_i >= nactive_tasks)
|
|
137 |
task_i = 1;
|
|
138 |
|
| 153 |
139 |
/***** create launch stack ***/
|
| 154 |
|
#ifdef DEBUG
|
| 155 |
|
usb_puts("Switching tasks..... (cross fingers)\n\r");
|
| 156 |
|
#endif //DEBUG
|
| 157 |
140 |
|
| 158 |
|
sp = &(STACK[task_i][STACKSIZE - 1]);
|
|
141 |
sp = (void*)((uint16_t)&STACK[current_task][STACKSIZE - 1]);
|
| 159 |
142 |
|
| 160 |
143 |
//Put task terminate and the task to execute on the stack.
|
| 161 |
|
*(sp--) = (uint8_t)(uint16_t) task_terminate;
|
| 162 |
|
*(sp--) = (uint8_t)(uint16_t) task_terminate >> 8;
|
| 163 |
|
*(sp--) = (uint8_t)(uint16_t) PCB[nactive_tasks].exec;
|
| 164 |
|
*(sp--) = (uint8_t)(uint16_t) PCB[nactive_tasks].exec >> 8;
|
|
144 |
*(sp--) = (uint8_t)(uint16_t)*task_terminate;
|
|
145 |
*(sp--) = (uint8_t)((uint16_t)*task_terminate >> 8);
|
| 165 |
146 |
|
|
147 |
*(sp--) = (uint8_t)(uint16_t)PCB[current_task].exec;
|
|
148 |
*(sp--) = (uint8_t)((uint16_t)PCB[current_task].exec >> 8);
|
|
149 |
|
| 166 |
150 |
//The current state of the registers is what the tasks will
|
| 167 |
151 |
//see on entry (shouldn't matter).
|
| 168 |
152 |
|
| ... | ... | |
| 170 |
154 |
"out __SP_L__, %A0 \n" \
|
| 171 |
155 |
"out __SP_H__, %B0 \n" : : "d" (sp));
|
| 172 |
156 |
|
| 173 |
|
#ifdef DEBUG
|
| 174 |
|
sprintf(test_buf, "Switching tasks, sp = %x\n\r", sp);
|
| 175 |
|
usb_puts(test_buf);
|
| 176 |
|
#endif //DEBUG
|
| 177 |
|
|
| 178 |
157 |
/* start process and enable interrupts */
|
| 179 |
158 |
asm volatile("reti \n");
|
| 180 |
159 |
break;
|
| 181 |
160 |
}
|
| 182 |
161 |
|
| 183 |
162 |
//Continue an old task.
|
| 184 |
|
if(PCB[task_i].running) {
|
|
163 |
if(PCB[task_i].running == 1) {
|
| 185 |
164 |
current_task = task_i;
|
| 186 |
|
|
| 187 |
|
//Reset the stack pointer.
|
| 188 |
|
sp = PCB[current_task].sp;
|
| 189 |
|
asm volatile( \
|
| 190 |
|
"out __SP_L__, %A0 \n" \
|
| 191 |
|
"out __SP_H__, %B0 \n" : : "d" (sp));
|
| 192 |
|
|
| 193 |
165 |
task_i++;
|
|
166 |
if(task_i >= nactive_tasks)
|
|
167 |
task_i = 1;
|
| 194 |
168 |
break;
|
| 195 |
169 |
}
|
| 196 |
170 |
|
| 197 |
|
//Loop back to 1 if necessary.
|
| 198 |
171 |
task_i++;
|
| 199 |
|
if(task_i >= nactive_tasks)
|
|
172 |
if(task_i >= nactive_tasks)
|
| 200 |
173 |
task_i = 1;
|
| 201 |
174 |
}
|
| 202 |
175 |
|
| 203 |
176 |
//If no task was selected to run, go to main
|
| 204 |
|
if(i == 0) {
|
| 205 |
|
#ifdef DEBUG
|
| 206 |
|
usb_puts("Resetting main.\n\r");
|
| 207 |
|
#endif //DEBUG
|
| 208 |
|
//Set the SP to the original stack.
|
| 209 |
|
sp = PCB[current_task].sp;
|
| 210 |
|
asm volatile( \
|
| 211 |
|
"out __SP_L__, %A0 \n" \
|
| 212 |
|
"out __SP_H__, %B0 \n" : : "d" (sp));
|
| 213 |
|
|
|
177 |
if(i == 0)
|
| 214 |
178 |
current_task = 0;
|
| 215 |
|
}
|
| 216 |
179 |
|
|
180 |
//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 |
|
| 217 |
186 |
//Set the running task.*/
|
| 218 |
187 |
PCB[current_task].running = 1;
|
| 219 |
188 |
|