Revision 1574 trunk/code/projects/scheduler/scheduler.c

View differences:

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

Also available in: Unified diff