/
multitasking_framework.c
219 lines (195 loc) · 4.35 KB
/
multitasking_framework.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*
Multitasking Framework Example
http://elegantcircuits.com/2014/09/22/implementing-a-multitasking-framework-for-an-avr-microcontroller/
LED -> PORTC[4]
LED -> PORTC[5]
Credit To/Based off of:
Co-operative multitasking framework tutorial code
(c)Russell Bull 2010. Free for any use.
Code built for a Atmega328P @ 8MHz
flash two outputs (PORTD.4,PORTD.5) at different speeds - blinky#2.
*/
#include <avr/io.h>
#include <avr/delay.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
void init_devices(void);
void timer0_init(void);
void reset_task(char tsk);
void set_task(char tsk);
void task_dispatch(void);
void task0(void);
void task1(void);
void task2(void);
void task3(void);
void task4(void);
void task5(void);
void task6(void);
void task7(void);
#define NUM_TASKS 8
char task_bits = 0; /* lsb is hi priority task */
volatile char tick_flag = 0; /* if non-zero, a tick has elapsed */
unsigned int task_timers[NUM_TASKS]={0,0,0,0,0,0,0,0}; /* init the timers to 0 on startup */
static const char bit_mask[] PROGMEM={1,2,4,8,16,32,64,128}; /* value -> bit mask xlate table */
int main(void){
init_devices();
//
// start at least one task here
//
set_task(7); //task7 runs
set_task(6); //task6 runs
// main loop
while(1){
if (tick_flag){
tick_flag = 0;
task_dispatch(); // well....
}
}
return 0;
}
//
// a task gets dispatched on every tick_flag tick (10ms)
//
void task_dispatch(void)
{
/* scan the task bits for an active task and execute it */
char task;
/* take care of the task timers. if the value ==0 skip it
else decrement it. If it decrements to zero, activate the task associated with it */
task=0;
while (task < NUM_TASKS )
{
if (task_timers[task])
{
task_timers[task]--; /* dec the timer */
if (task_timers[task] == 0 )
{
set_task(task); /* if ==0 activate the task bit */
}
}
task++;
}
task = 0; /* start at the most significant task */
while (task <= NUM_TASKS )
{
if ((task_bits & pgm_read_byte(&bit_mask[task])))
{
break; /* if activate task found..*/
}
task++; /* else try the next one */
}
switch(task) /* if task bit is active..execute the task */
{
case 0:
task0();
break;
case 1:
task1();
break;
case 2:
task2();
break;
case 3:
task3();
break;
case 4:
task4();
break;
case 5:
task5();
break;
case 6:
task6();
break;
case 7:
task7();
break;
default:
break; /* no task was active!! */
}
}
// enable a task for execution
void set_task(char tsk)
{
task_bits |= pgm_read_byte(&bit_mask[tsk]); /* sets a task bit */
}
// disable a task from executing
void reset_task(char tsk)
{
task_bits &= (~pgm_read_byte(&bit_mask[tsk])); /* resets a task bit */
}
void task0(void)
{
reset_task(0);
}
void task1(void)
{
reset_task(1);
}
void task2(void)
{
reset_task(2);
}
void task3(void)
{
reset_task(3);
}
void task4(void)
{
reset_task(4);
}
void task5(void)
{
reset_task(5);
}
//
// flash PORTD.4 at 2hz
//
void task6(void)
{
PORTD ^= (1<<4);
task_timers[6] = 25; //every 250ms
reset_task(6);
}
//
// flash PORTD.5 at 1hz
//
void task7(void)
{
PORTD ^= (1<<5);
task_timers[7] = 50; //every 500ms
reset_task(7);
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
cli(); //disable all interrupts
DDRD = 0x30; //port 4 & 5 as outputs
timer0_init();
MCUCR = 0x00;
EICRA = 0x00; //extended ext ints
EIMSK = 0x00;
TIMSK0 = 0x02; //timer 0 interrupt sources
PRR = 0x00; //power controller
sei(); //re-enable interrupts
//all peripherals are now initialized
}
//TIMER0 initialize - prescale:1024
// WGM: CTC
// desired value: 10mSec
// actual value: 10.048mSec (-0.5%)
void timer0_init(void)
{
TCCR0B = 0x00; //stop
TCNT0 = 0x00; //set count
TCCR0A = 0x02; //CTC mode
OCR0A = 0x9C;
TCCR0B = 0x05; //start timer
}
ISR(TIMER0_COMPA_vect)
{
//TIMER0 has overflowed
tick_flag = 1;
}