Revision 1106
lights.c | ||
---|---|---|
55 | 55 |
- switch off LEDs (according to mask) |
56 | 56 |
- load the next output compare value |
57 | 57 |
|
58 |
Ad triple buffering: |
|
59 |
- The buffer the ISR is reading from may only be changed at timer overflow, |
|
60 |
before the next PWM sequence is started, because otherwise, the next OCR |
|
61 |
value may be set to a value smaller than the current timer value, resulting |
|
62 |
in the remaining channels not being turned off in that PWM period (flash to |
|
63 |
on). |
|
64 |
- When using two buffers, the copying (or switching) would have to wait until |
|
65 |
the next timer overflow. During this time, neither of the buffers could be |
|
66 |
modified because one is used by the ISR and the other may be copied/switched |
|
67 |
at any time. Thus, the main thread would possibly be delayed by up to one |
|
68 |
full PWM period (8ms in the current implementation, but 20ms-50ms would be a |
|
69 |
reasonable value to expect here. |
|
70 |
- Triple buffering For Teh Win! |
|
58 | 71 |
*/ |
59 | 72 |
|
60 | 73 |
/* |
... | ... | |
62 | 75 |
- test the timing |
63 | 76 |
- Determine sorting time, possibly improve sorting algorithm (111 us sorted, |
64 | 77 |
143 us reverse sorted) |
78 |
- stop sorting when finished (no change made) (and measure performance gain) |
|
65 | 79 |
- enable_orb_pwm use everywhere, add methods to switch on/off, add init |
66 | 80 |
function |
81 |
- test old code: continuously setting the orbs |
|
82 |
- n-buffering |
|
83 |
- fix sync/volatile |
|
67 | 84 |
*/ |
68 | 85 |
|
69 | 86 |
/* |
... | ... | |
84 | 101 |
* - buzzer => doesn't work because of varying frequency |
85 | 102 |
* - motors => possible? would trigger often (?) |
86 | 103 |
* - lights => must put lights on 16 bit timer (no OCR left) |
104 |
* - Syncronization test case: set orb A to 1,1,1 (not 0 because they will |
|
105 |
* not be turned on) and orb B to 254,254,254. Do this in a loop, with |
|
106 |
* some delay d between. |
|
107 |
* * d=1ms => occasional flickering |
|
108 |
* * d=400us => frequent flickering |
|
109 |
* * d=0 => no usable orb output |
|
110 |
* Without syncronization, both LEDs flicker (because the wrong values are |
|
111 |
* in the channels array while sorting). When the sorting code ist |
|
112 |
* synchronized, only orb A flickers, because the timing is disrupted by the |
|
113 |
* large synchronized block. |
|
87 | 114 |
*/ |
88 | 115 |
|
89 | 116 |
#include "lights.h" |
117 |
|
|
90 | 118 |
#include <avr/interrupt.h> |
119 |
|
|
91 | 120 |
#include "dragonfly_lib.h" |
92 | 121 |
|
93 | 122 |
|
123 |
// *************** |
|
124 |
// ** Constants ** |
|
125 |
// *************** |
|
126 |
|
|
127 |
#define NUM_ORBS 2 // Number or orbs |
|
128 |
#define NUM_COLORS 3 // Number of colors per orb |
|
129 |
#define num_pwm_channels NUM_ORBS*NUM_COLORS |
|
130 |
|
|
131 |
|
|
94 | 132 |
// ********* |
95 | 133 |
// ** I/O ** |
96 | 134 |
// ********* |
97 | 135 |
|
98 |
#define NUM_ORBS 2 // Number or orbs |
|
99 |
#define NUM_COLORS 3 // Number of colors per orb |
|
100 |
|
|
101 | 136 |
// Orb port |
102 | 137 |
#define ORBPORT PORTC |
103 | 138 |
#define ORBDDR DDRC |
... | ... | |
150 | 185 |
uint8_t mask; |
151 | 186 |
}; |
152 | 187 |
|
188 |
sutrct pwm_t |
|
189 |
{ |
|
190 |
uint8_t init_mask; |
|
191 |
pwm_channels_t channel[num_pwm_channels]; |
|
192 |
} |
|
153 | 193 |
|
194 |
|
|
154 | 195 |
// *************** |
155 | 196 |
// ** Variables ** |
156 | 197 |
// *************** |
157 | 198 |
|
158 |
#define num_pwm_channels NUM_ORBS*NUM_COLORS |
|
159 |
struct pwm_channel_t pwm_channels[num_pwm_channels]; |
|
160 |
uint8_t orb_values[NUM_ORBS][NUM_COLORS]; |
|
161 |
uint8_t pwm_init_mask; |
|
199 |
// Whether to use PWM (true) or binary (false) orb mode |
|
162 | 200 |
bool enable_orb_pwm=true; |
163 | 201 |
|
202 |
// The PWM channels and the buffer pointers. This data structure is triple |
|
203 |
// buffered, see above for the reasons. |
|
204 |
struct pwm_t pwm_buffer[3]; |
|
205 |
// TODO using pointers might be faster (or might be slower because pointers are |
|
206 |
// 16 bit long). |
|
207 |
uint8_t read_buffer=0; // The buffer the ISR reads from |
|
208 |
uint8_t next_buffer=0; // The buffer the ISR will switch to on the next overflow |
|
209 |
uint8_t |
|
210 |
uint8_t inactive_buffer=2; |
|
164 | 211 |
|
212 |
|
|
213 |
|
|
214 |
// The orb value array. Orb values are written here to be sorted into |
|
215 |
// pwm_channels. |
|
216 |
uint8_t orb_values[NUM_ORBS][NUM_COLORS]; |
|
217 |
|
|
218 |
// TODO: random note: what happens if the main process is sorting and a different |
|
219 |
// interrupt calls set_orb? |
|
220 |
|
|
221 |
|
|
165 | 222 |
// **************** |
166 | 223 |
// ** Timer ISRs ** |
167 | 224 |
// **************** |
... | ... | |
170 | 227 |
|
171 | 228 |
SIGNAL (SIG_OVERFLOW0) |
172 | 229 |
{ |
173 |
//PORTF=2;
|
|
230 |
PORTF|=4;
|
|
174 | 231 |
// Turn all appropriate PWM channels on |
175 | 232 |
ORBPORT&=pwm_init_mask; |
176 | 233 |
|
... | ... | |
179 | 236 |
|
180 | 237 |
// Load the first OCR |
181 | 238 |
OCR0=pwm_channels[current_pwm_channel].time; |
182 |
//PORTF=0;
|
|
239 |
PORTF&=~4;
|
|
183 | 240 |
} |
184 | 241 |
|
185 | 242 |
SIGNAL(SIG_OUTPUT_COMPARE0) |
186 | 243 |
{ |
187 |
//PORTF=4;
|
|
244 |
PORTF|=4;
|
|
188 | 245 |
// TODO: |
189 | 246 |
// - delayed interrupt |
190 | 247 |
// - synchronization OK? |
191 | 248 |
|
192 | 249 |
// If the interrupt is executed w/o delay, TCNT0 == time+1 (and TIME=OCR0) |
193 | 250 |
|
194 |
// TODO improve (check overflow; maybe use return after last |
|
251 |
// TODO improve (check overflow; maybe use return after last, maybe use |
|
252 |
// pointers instead of indicies) |
|
195 | 253 |
while (TCNT0==pwm_channels[current_pwm_channel].time+1) |
196 | 254 |
{ |
197 | 255 |
// Turn the current channel off |
... | ... | |
205 | 263 |
if (pwm_channels[current_pwm_channel].time<255) |
206 | 264 |
OCR0=pwm_channels[current_pwm_channel].time; |
207 | 265 |
} |
208 |
//PORTF=0;
|
|
266 |
PORTF&=~4;
|
|
209 | 267 |
} |
210 | 268 |
|
211 | 269 |
|
... | ... | |
217 | 275 |
// TODO: make a public version of this one, but keep a private one which does |
218 | 276 |
// not sort them so you can update both sides and update only once. |
219 | 277 |
|
278 |
#define SYNC_START uint8_t tmp_sreg; do { tmp_sreg=SREG; cli (); } while (false) |
|
279 |
#define SYNC_RESTART do { tmp_sreg=SREG; cli (); } while (false) |
|
280 |
#define SYNC_END do { SREG=tmp_sreg; } while (false) |
|
281 |
|
|
220 | 282 |
static void apply_orbs (void) |
221 | 283 |
{ |
222 |
PORTF=2; |
|
223 | 284 |
if (enable_orb_pwm) |
224 | 285 |
{ |
225 | 286 |
// PWM mode |
226 | 287 |
|
227 | 288 |
// Sort the orb values. |
228 | 289 |
|
290 |
PORTF|=2; |
|
291 |
SYNC |
|
292 |
{ |
|
229 | 293 |
pwm_init_mask=~0; |
230 | 294 |
|
231 | 295 |
// 1. Write the orb values and corresponding masks to the pwm channels |
... | ... | |
268 | 332 |
} |
269 | 333 |
} |
270 | 334 |
} |
271 |
|
|
272 |
//pwm_init_mask=all_orbs_mask; // FIXME use real values |
|
273 |
|
|
274 |
// Sort the values from orb_values[NUM_ORBS][NUM_COLORS]. |
|
275 |
|
|
335 |
} |
|
336 |
//SYNC_END; |
|
337 |
PORTF&=~2; |
|
338 |
|
|
276 | 339 |
} |
277 | 340 |
else |
278 | 341 |
{ |
... | ... | |
283 | 346 |
// is faster this way, and being fast is the whole point of using the |
284 | 347 |
// binary orb mode anyway. |
285 | 348 |
} |
286 |
PORTF=0; |
|
287 | 349 |
} |
288 | 350 |
|
289 | 351 |
static void orb_n_set (uint8_t num, uint8_t red, uint8_t green, uint8_t blue) |
... | ... | |
375 | 437 |
|
376 | 438 |
|
377 | 439 |
|
378 |
////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
379 |
|
|
380 |
//#define ORB_RESET 1025 |
|
381 |
//#define ORBMASK 0x77 |
|
382 |
// |
|
383 |
///***** Port and Pin Definitions ****/ |
|
384 |
// |
|
385 |
// |
|
386 |
//// an orb node |
|
387 |
//struct ORB_NODE { |
|
388 |
// uint8_t num; |
|
389 |
// uint16_t angle; |
|
390 |
//}; |
|
391 |
// |
|
392 |
//the change in an orb |
|
393 |
//struct ORB_CHANGE { |
|
394 |
// uint16_t port_val; |
|
395 |
// uint16_t split_time_period; |
|
396 |
//}; |
|
397 |
// |
|
398 |
//// the status of an orb |
|
399 |
//struct ORB_STATUS_STRUCT { |
|
400 |
// struct ORB_NODE orbs[ORB_COUNT]; |
|
401 |
// uint16_t orb_angles[ORB_COUNT]; |
|
402 |
// struct ORB_CHANGE changes[ORB_COUNT+1]; |
|
403 |
// uint8_t change_count; |
|
404 |
// uint8_t new_angles; |
|
405 |
// uint8_t current_orb; |
|
406 |
// |
|
407 |
//} ORB_STATUS; |
|
408 |
// |
|
409 |
//void orb_sort(void); |
|
410 |
//void orb_setup_pulse(void); |
|
411 |
// |
|
412 |
//SIGNAL (SIG_OUTPUT_COMPARE3C){ |
|
413 |
// |
|
414 |
// //pull the correct ones down |
|
415 |
// ORBPORT &= (~ORBMASK)|(ORB_STATUS.changes[ORB_STATUS.current_orb].port_val); |
|
416 |
// |
|
417 |
// ++ORB_STATUS.current_orb; //now look at next orb transition |
|
418 |
// |
|
419 |
// if (ORB_STATUS.current_orb < ORB_STATUS.change_count) { //if it isnt the end... |
|
420 |
// |
|
421 |
// //setup timer for next pull down |
|
422 |
// OCR3C = TCNT3+ORB_STATUS.changes[ORB_STATUS.current_orb].split_time_period; |
|
423 |
// |
|
424 |
// } |
|
425 |
// else { //we are done with these pulses |
|
426 |
// orb_setup_pulse(); |
|
427 |
// } |
|
428 |
// |
|
429 |
//} |
|
430 |
// |
|
431 |
// |
|
432 |
////sets a channel to a value |
|
433 |
//void orb_set_angle(uint16_t orb, uint16_t angle) { |
|
434 |
// uint8_t mysreg; |
|
435 |
// |
|
436 |
// orb=orb&0x07; //only have 8 |
|
437 |
// angle=angle&0xff; //only accept 0-255 |
|
438 |
// angle=255-angle; //inverse intensity |
|
439 |
// angle=angle<<2; //scale up so that we dont run it too often |
|
440 |
// angle+=3; //0 values dont really work |
|
441 |
// if (ORB_STATUS.orb_angles[orb] != angle) { //if the angle has changed |
|
442 |
// mysreg=SREG; |
|
443 |
// cli(); //disable interrupts |
|
444 |
// ORB_STATUS.orb_angles[orb] = angle; //update angle |
|
445 |
// ORB_STATUS.new_angles = 1; |
|
446 |
// SREG=mysreg; //put interrupt status back |
|
447 |
// } |
|
448 |
//} |
|
449 |
// |
|
450 |
// |
|
451 |
//void orb_sort(void) { |
|
452 |
// uint16_t done = 0, i; |
|
453 |
// |
|
454 |
// while (! done) { |
|
455 |
// done = 1; |
|
456 |
// |
|
457 |
// for (i = 0; i < ORB_COUNT - 1; ++i) { //loop through all |
|
458 |
// |
|
459 |
// //if they are out of order, swap them |
|
460 |
// if (ORB_STATUS.orbs[i].angle > ORB_STATUS.orbs[i+1].angle) { |
|
461 |
// ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle; |
|
462 |
// ORB_STATUS.orbs[i+1].angle ^= ORB_STATUS.orbs[i].angle; |
|
463 |
// ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle; |
|
464 |
// |
|
465 |
// ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num; |
|
466 |
// ORB_STATUS.orbs[i+1].num ^= ORB_STATUS.orbs[i].num; |
|
467 |
// ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num; |
|
468 |
// |
|
469 |
// done = 0; |
|
470 |
// } |
|
471 |
// } |
|
472 |
// } |
|
473 |
//} |
|
474 |
// |
|
475 |
////calculate the split times |
|
476 |
//void orb_setup_pulse(void) { |
|
477 |
// uint16_t i; |
|
478 |
// uint16_t my_port; |
|
479 |
// uint16_t sum = 0; |
|
480 |
// uint16_t split_time; |
|
481 |
// |
|
482 |
// my_port = 0xff; //all on |
|
483 |
// |
|
484 |
// if (ORB_STATUS.new_angles) { |
|
485 |
// |
|
486 |
// ORB_STATUS.change_count = 0; |
|
487 |
// for (i = 0; i < ORB_COUNT; ++i) { //get the new values |
|
488 |
// ORB_STATUS.orbs[i].angle = ORB_STATUS.orb_angles[ORB_STATUS.orbs[i].num]; |
|
489 |
// } |
|
490 |
// |
|
491 |
// orb_sort(); //sort them |
|
492 |
// ORB_STATUS.new_angles = 0; |
|
493 |
// |
|
494 |
// for (i = 0; i < ORB_COUNT; ++i) { //calculate split times |
|
495 |
// split_time = ORB_STATUS.orbs[i].angle - sum; |
|
496 |
// my_port &= ~_BV(ORB_STATUS.orbs[i].num); |
|
497 |
// |
|
498 |
// for (; i < ORB_COUNT - 1 && ORB_STATUS.orbs[i].angle == ORB_STATUS.orbs[i+1].angle; ++i) { |
|
499 |
// my_port &= ~_BV(ORB_STATUS.orbs[i+1].num); //look for doups |
|
500 |
// } |
|
501 |
// |
|
502 |
// ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port; //which pins are low |
|
503 |
// ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = split_time; |
|
504 |
// |
|
505 |
// ++ORB_STATUS.change_count; |
|
506 |
// |
|
507 |
// sum += split_time; |
|
508 |
// } |
|
509 |
// |
|
510 |
// ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port; |
|
511 |
// ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = ORB_RESET - sum; //get a constant period |
|
512 |
// |
|
513 |
// ++ORB_STATUS.change_count; |
|
514 |
// |
|
515 |
// } |
|
516 |
// |
|
517 |
// |
|
518 |
// |
|
519 |
// ORB_STATUS.current_orb = 0; |
|
520 |
// |
|
521 |
// ORBPORT |= ORBMASK; //start with all high |
|
522 |
// OCR3C = TCNT3 + ORB_STATUS.changes[0].split_time_period; //wait for first split |
|
523 |
// |
|
524 |
//} |
|
525 |
// |
|
526 |
///** |
|
527 |
// * @defgroup orbs Orbs |
|
528 |
// * @brief Functions for controlling the color of the orbs. |
|
529 |
// * |
|
530 |
// * Functions for controlling the color and lighting of the orbs. |
|
531 |
// * |
|
532 |
// * @{ |
|
533 |
// **/ |
|
534 |
// |
|
535 |
|
|
536 | 440 |
/** |
537 | 441 |
* Set both orbs to the specified color. This function |
538 | 442 |
* is intended to be used with the predefined |
... | ... | |
694 | 598 |
//orbs_set (255, 127, 0, 0, 127, 255); // Pretty colors with extreme values |
695 | 599 |
//orbs_set (0, 1, 2, 253, 254, 255); // Timing tests |
696 | 600 |
|
601 |
orbs_set (255, 255, 255, 0, 0, 0); |
|
602 |
delay_ms (1000); |
|
603 |
|
|
604 |
while (1) |
|
605 |
{ |
|
606 |
//orbs_set (250, 127, 3, 3, 127, 250); // Pretty colors |
|
607 |
orbs_set (255, 255, 255, 1, 1, 1); |
|
608 |
_delay_us(400); |
|
609 |
} |
|
610 |
|
|
697 | 611 |
// Test the time of the sorting routine |
698 | 612 |
//while (1) |
699 | 613 |
//{ |
Also available in: Unified diff