Revision 1574
Working scheduler.
Booyakasha.
trunk/code/projects/scheduler/scheduler.c | ||
---|---|---|
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 |
|
131 |
current_task = task_i; |
|
132 |
PCB[current_task].next += PCB[current_task].period; |
|
133 |
PCB[current_task].running = 1; |
|
134 |
|
|
148 | 135 |
task_i++; |
136 |
if(task_i >= nactive_tasks) |
|
137 |
task_i = 1; |
|
149 | 138 |
|
150 |
current_task = task_i; |
|
151 |
PCB[task_i].next += PCB[task_i].period; |
|
152 |
|
|
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 |
|
trunk/code/projects/scheduler/scheduler.h | ||
---|---|---|
13 | 13 |
#define _SCHEDULER_H_ |
14 | 14 |
|
15 | 15 |
#define STACKSIZE 128 |
16 |
#define MAXTASKS 3
|
|
16 |
#define MAXTASKS 4
|
|
17 | 17 |
|
18 | 18 |
#include <stdint.h> |
19 | 19 |
|
trunk/code/projects/scheduler/main.c | ||
---|---|---|
14 | 14 |
usb_puts("Oh no!!! Reset!!\n\r"); |
15 | 15 |
|
16 | 16 |
scheduler_init(); |
17 |
register_task(task0, 22);
|
|
18 |
//register_task(task1, 2);
|
|
19 |
//register_task(task2, 3);
|
|
17 |
register_task(task0, 48);
|
|
18 |
register_task(task1, 20);
|
|
19 |
register_task(task2, 80);
|
|
20 | 20 |
|
21 | 21 |
while (1) { |
22 | 22 |
//usb_puti(time_now()); |
23 | 23 |
usb_puts("main\n\r"); |
24 |
delay_ms(200);
|
|
24 |
delay_ms(20); |
|
25 | 25 |
} |
26 | 26 |
|
27 | 27 |
return 0; |
28 | 28 |
} |
29 | 29 |
|
30 | 30 |
void task0() { |
31 |
sei(); |
|
32 |
usb_puts("0\n\r"); |
|
33 |
|
|
34 |
cli(); |
|
31 |
int i = 0; |
|
32 |
while(1) { |
|
33 |
usb_puts("Task 0-"); |
|
34 |
usb_puti(i++); |
|
35 |
usb_puts("\n\r"); |
|
36 |
delay_ms(20); |
|
37 |
} |
|
35 | 38 |
} |
36 | 39 |
|
37 | 40 |
void task1() { |
41 |
cli(); |
|
42 |
usb_puts("Hello from task 1\n\r"); |
|
38 | 43 |
sei(); |
39 |
usb_puts("1\n\r"); |
|
40 |
cli(); |
|
41 | 44 |
} |
42 | 45 |
|
43 | 46 |
void task2() { |
47 |
cli(); |
|
48 |
usb_puts("Hello from task 2\n\r"); |
|
44 | 49 |
sei(); |
45 |
usb_puts("2\n\r"); |
|
46 |
cli(); |
|
47 | 50 |
} |
trunk/code/projects/scheduler/Makefile | ||
---|---|---|
5 | 5 |
COLONYROOT := .. |
6 | 6 |
|
7 | 7 |
# Target file name (without extension). |
8 |
TARGET = main
|
|
8 |
TARGET=main
|
|
9 | 9 |
|
10 | 10 |
# Uncomment this to use the wireless library |
11 | 11 |
USE_WIRELESS = 1 |
12 | 12 |
|
13 | 13 |
# com1 = serial port. Use lpt1 to connect to parallel port. |
14 | 14 |
AVRDUDE_PORT = $(shell if uname -s |grep -i w32 >/dev/null; then echo 'COM4:'; else echo '/dev/ttyUSB0'; fi) |
15 |
AVRDUDE_PORT = /dev/tty.usbserial-A4001hAG |
|
15 | 16 |
|
17 |
|
|
16 | 18 |
else |
17 | 19 |
COLONYROOT := ../$(COLONYROOT) |
18 | 20 |
endif |
19 | 21 |
|
20 |
include $(COLONYROOT)/Makefile |
|
22 |
include $(COLONYROOT)/Makefile |
Also available in: Unified diff