Project

General

Profile

Revision 1106

View differences:

branches/library_refactor/lib/include/libdragonfly/dragonfly_lib.h
80 80
#include <util/delay.h>
81 81
#include <util/twi.h>
82 82

  
83
// This file is included from the libdragonfly directory because it seems to be
84
// missing from the AVR libc distribution.
85
#include "atomic.h"
86

  
83 87
#include <analog.h>
84 88
#include <dio.h>
85 89
#include <time.h>
......
96 100
#include <eeprom.h>
97 101
#include <stdbool.h>
98 102

  
103
/** @brief shortcut for ATOMIC_BLOCK(ATOMIC_RESTORESTATE) **/
104
#define SYNC ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
105

  
106

  
99 107
#endif
100 108

  
branches/library_refactor/projects/libdragonfly/dragonfly_lib.h
80 80
#include <util/delay.h>
81 81
#include <util/twi.h>
82 82

  
83
// This file is included from the libdragonfly directory because it seems to be
84
// missing from the AVR libc distribution.
85
#include "atomic.h"
86

  
83 87
#include <analog.h>
84 88
#include <dio.h>
85 89
#include <time.h>
......
96 100
#include <eeprom.h>
97 101
#include <stdbool.h>
98 102

  
103
/** @brief shortcut for ATOMIC_BLOCK(ATOMIC_RESTORESTATE) **/
104
#define SYNC ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
105

  
106

  
99 107
#endif
100 108

  
branches/library_refactor/projects/libdragonfly/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