Revision 1574

View differences:

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

Also available in: Unified diff