Project

General

Profile

Statistics
| Revision:

root / branches / library_refactor / projects / libdragonfly / lights.c @ 1100

History | View | Annotate | Download (14.7 KB)

1
/**
2
 * Copyright (c) 2007 Colony Project
3
 * 
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 * 
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 * 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

    
26
/**
27
 * @file ligths.c
28
 * @brief Orbs
29
 *
30
 * Implemenation for the orbs (tri-colored LEDs)
31
 *
32
 * @author Colony Project, CMU Robotics Club
33
 * @bug Unfinished
34
 **/
35

    
36
/*
37
lights.c
38
Controls orb1 and orb2. Can be extended for a software PWM that may be used
39
for servos in the future.
40

41
author: CMU Robotics Club, Colony Project
42

43
Change Log:
44
3/31/2009 - Martin
45
    Rewritten from scratch (mostly), fixes some code duplication, long ISRs,
46
        bugs, unnecessary synchronized code, memory waste
47
*/
48

    
49
/*
50
Operation:
51
On timer overflow:
52
  - switch on LEDs (where value>0, according to a pre-determined mask)
53
  - load the first output compare value
54
At compare match:
55
  - switch off LEDs (according to mask)
56
  - load the next output compare value
57

58
 */
59

    
60
#include "lights.h"
61
#include <avr/interrupt.h>
62
#include "dragonfly_lib.h"
63

    
64

    
65
// *********
66
// ** I/O **
67
// *********
68

    
69
#define NUM_ORBS 2   // Number or orbs
70
#define NUM_COLORS 3 // Number of colors per orb
71

    
72
// Orb port
73
#define ORBPORT PORTC
74
#define ORBDDR  DDRC
75

    
76
// Orb pins
77
#define ORB1_RED   0
78
#define ORB1_GREEN 1
79
#define ORB1_BLUE  2
80
#define ORB2_RED   4
81
#define ORB2_GREEN 5
82
#define ORB2_BLUE  6
83

    
84
// ***********
85
// ** Masks **
86
// ***********
87

    
88
// Some useful bit masks. All of them are are calculated from the I/O
89
// definitions above. The calculations should be done at compile time (even if
90
// they are not, they are only executed once at startup).
91

    
92
// Masks for the individual LEDs
93
#define orb1_red_mask    _BV (ORB1_RED  )
94
#define orb1_green_mask  _BV (ORB1_GREEN)
95
#define orb1_blue_mask   _BV (ORB1_BLUE )
96
#define orb2_red_mask    _BV (ORB2_RED  )
97
#define orb2_green_mask  _BV (ORB2_GREEN)
98
#define orb2_blue_mask   _BV (ORB2_BLUE )
99

    
100
// Mask for all LEDs
101
const uint8_t all_orbs_mask=
102
        orb1_red_mask | orb1_green_mask | orb1_blue_mask |
103
        orb2_red_mask | orb2_green_mask | orb2_blue_mask;
104

    
105
// Mask for the individual LEDs, organized as an array for programmatic access.
106
// The layout of this array is orb_mask[orb_num, color_num]
107
const uint8_t orb_mask[NUM_ORBS][NUM_COLORS]=
108
{
109
        { orb1_red_mask, orb1_green_mask, orb1_blue_mask },
110
        { orb2_red_mask, orb2_green_mask, orb2_blue_mask }
111
};
112

    
113

    
114
// ***********
115
// ** Types **
116
// ***********
117

    
118
struct pwm_channel
119
{
120
    uint8_t time;
121
    uint8_t mask;
122
};
123

    
124

    
125
// ***************
126
// ** Variables **
127
// ***************
128

    
129
struct pwm_channel channels[NUM_ORBS*NUM_COLORS];
130

    
131

    
132
// ********************
133
// ** Initialization **
134
// ********************
135

    
136
static void dset(uint8_t num)
137
{
138
        PORTF|=1<<num;
139
}
140

    
141
static void dclear(uint8_t num)
142
{
143
        PORTF&=~(1<<num);
144
}
145

    
146
/**
147
 * Initializes the PWM for Orb control. This must be called before 
148
 * the orbs are used for them to function.
149
 **/
150
void orb_init ()
151
{
152
        // Timer mode:
153
        //   OCRnx update "immediate" is required. This leaves "Normal" mode and the
154
        //   "CTC" modes. "Normal" doesn't allow setting a reload value, and the
155
        //   prescaler is too limited. So CTC is used. CTC can match to OCRnA and
156
        //   ICRn. For the motor, OCRnA is already in use for the compare match
157
        //   output unit. So ICRn is used.
158
        //   This leaves: WGMn3:0=1100.
159
        //   This mode does not provide an overflow interrupt, so Output Compare
160
        //   has to be used instead.
161
        
162
        // Enable the output ports and turn off the LEDs
163
        ORBDDR  |=  all_orbs_mask;
164
        ORBPORT &= ~all_orbs_mask;
165

    
166
        // Set all orbs to "off"
167
        orb_set (0, 0, 0);
168

    
169
    // Set up the timer
170
    // Prescaler 8 is 66 ms or 15 Hz (8 MHz/prescaler 8/2^16)
171
    
172
        
173
        
174
        TCCR3A=0;
175
    TCCR3B=_BV(CS31); // Prescaler 8
176
    //TCCR3B=_BV(CS31) | _BV(CS30); // Prescaler 64
177
    TCCR3C=0;
178
    ETIMSK |= _BV(TOIE3) | _BV(OCIE3C); // Enable Overflow Interrupt and Output compare 3 interrupt
179
    
180
    // Clear Timer on Compare match:
181
    // Either from OCR3A (WGM3 3:0=4) or from ICR3 (WGM3 3:0=12
182

    
183
        // DOING: Select a good reload so
184
        //   - there are 256 values (not so important)
185
        //   - the refresh rate is around 20..25 Hz
186
        // Then, check if it can be co-used w/ the compare match output unit.
187
        
188
    ICR3=10000; // Refresh rate (period): 10ms
189
        OCR3C=0;
190
    
191
        //TCCR3A |= _BV(WGM31);
192
    TCCR3B |= _BV(WGM33) | _BV(WGM32);
193
        
194
        // TOP is 6, counter counts 0 1 2 3 4 5 6 (7 intervals) => 8 possibilities
195
        // OCR=0 => 1/8, OCR=7 => 8/8
196
    
197
    //OCR3C=1; // Compare after (?) 1
198

    
199
    // Debug
200
    DDRF=6;
201

    
202
        // In PWM mode, the OCR is double buffered (updated at TOP or BOTTOM)
203

    
204
//        //init timer3
205
//        TCCR3A = 0; 
206
//        TCCR3B = _BV(CS31); //prescale = 8
207
//        TCCR3C = 0;
208
//        ETIMSK |= _BV(OCIE3C); //turn on oc3c interrupt
209
//        OCR3C = TCNT3+ORB_RESET;
210
}
211
//
212

    
213

    
214
// ****************
215
// ** Timer ISRs **
216
// ****************
217

    
218
volatile uint8_t x;
219
volatile uint8_t i;
220

    
221
void orb_tick (uint8_t t)
222
{
223
        x++;
224
}
225

    
226
SIGNAL (SIG_OVERFLOW3)
227
{
228
}
229

    
230
// Timer values: 0 1 2 3 4 5 6 7 8 9
231

    
232

    
233

    
234
SIGNAL (SIG_OUTPUT_COMPARE3C)
235
{
236
        if (i==0)
237
        {
238
                dset (1);
239
                dset (2);
240
                
241
                i=1;
242
                OCR3C=1000;
243
        }
244
        else if (i==1)
245
        {
246
                dclear (1);
247
                
248
                OCR3C=2000;
249
                i=2;
250
        }
251
        else if (i==2)
252
        {
253
                dclear (2);
254
                
255
                OCR3C=0;
256
                i=0;
257
        }
258
}
259

    
260

    
261
// ************************
262
// ** Setting RGB colors **
263
// ************************
264

    
265
static void orb_n_set (uint8_t num, uint8_t red, uint8_t green, uint8_t blue)
266
{
267
        // FIXME implement PWM code (this is only binary on/off)
268
        // FIXME Synchronization
269
        
270
        // Oh, and of course the outputs are inverted.
271
        if (!red)   ORBPORT|=orb_mask[num][0]; else ORBPORT&=~orb_mask[num][0];
272
        if (!green) ORBPORT|=orb_mask[num][1]; else ORBPORT&=~orb_mask[num][1];
273
        if (!blue)  ORBPORT|=orb_mask[num][2]; else ORBPORT&=~orb_mask[num][2];
274
}
275

    
276
/**
277
 * Set orb1 to the color specified. orb_init must be called before this function
278
 * may be used.
279
 *
280
 * @param red the red component of the color
281
 * @param green the green component of the color
282
 * @param blue the blue component of the color
283
 *
284
 * @see orb_init
285
 **/
286
void orb1_set (uint8_t red, uint8_t green, uint8_t blue)
287
{
288
        orb_n_set (0, red, green, blue);
289
}
290

    
291
/**
292
 * Set orb2 to the color specified. orb_init must be called before this function
293
 * may be used.
294
 *
295
 * @param red_led the red component of the color
296
 * @param green_led the green component of the color
297
 * @param blue_led the blue component of the color
298
 *
299
 * @see orb_init
300
 **/
301
void orb2_set (uint8_t red, uint8_t green, uint8_t blue)
302
{
303
        orb_n_set (1, red, green, blue);
304
}
305

    
306
/**
307
 * Set both orbs to the color specified. orb_init must be called before this
308
 * function may be used.
309
 *
310
 * @param red_led the red component of the color
311
 * @param green_led the green component of the color
312
 * @param blue_led the blue component of the color
313
 *
314
 * @see orb_init, orb1_set, orb2_set
315
 **/
316
void orb_set (uint8_t red, uint8_t green, uint8_t blue)
317
{
318
        orb1_set (red, green, blue);
319
        orb2_set (red, green, blue);
320
}
321

    
322

    
323

    
324

    
325
//////////////////////////////////////////////////////////////////////////////////////////////////////////
326

    
327
//#define ORB_RESET 1025
328
//#define ORBMASK 0x77
329
//
330
///***** Port and Pin Definitions ****/
331
//
332
//
333
//// an orb node
334
//struct ORB_NODE {
335
//   uint8_t num;
336
//   uint16_t angle;
337
//};
338
//
339
//the change in an orb
340
//struct ORB_CHANGE {
341
//   uint16_t port_val;
342
//   uint16_t split_time_period;
343
//};
344
//
345
//// the status of an orb
346
//struct ORB_STATUS_STRUCT {
347
//   struct ORB_NODE orbs[ORB_COUNT];
348
//   uint16_t orb_angles[ORB_COUNT];
349
//   struct ORB_CHANGE changes[ORB_COUNT+1];
350
//   uint8_t change_count;
351
//   uint8_t new_angles;
352
//   uint8_t current_orb;
353
//
354
//} ORB_STATUS;
355
//
356
//void orb_sort(void);
357
//void orb_setup_pulse(void);
358
//
359
//SIGNAL (SIG_OUTPUT_COMPARE3C){
360
//
361
//                //pull the correct ones down
362
//      ORBPORT &= (~ORBMASK)|(ORB_STATUS.changes[ORB_STATUS.current_orb].port_val);
363
//
364
//      ++ORB_STATUS.current_orb; //now look at next orb transition
365
//
366
//      if (ORB_STATUS.current_orb < ORB_STATUS.change_count) { //if it isnt the end...
367
//          
368
//                        //setup timer for next pull down
369
//         OCR3C = TCNT3+ORB_STATUS.changes[ORB_STATUS.current_orb].split_time_period;
370
//                 
371
//     }
372
//      else { //we are done with these pulses
373
//                orb_setup_pulse();
374
//      }
375
//
376
//}
377
//
378
//
379
////sets a channel to a value
380
//void orb_set_angle(uint16_t orb, uint16_t angle) {
381
//        uint8_t mysreg;
382
//        
383
//        orb=orb&0x07; //only have 8
384
//        angle=angle&0xff; //only accept 0-255
385
//        angle=255-angle; //inverse intensity
386
//        angle=angle<<2; //scale up so that we dont run it too often
387
//        angle+=3; //0 values dont really work
388
//   if (ORB_STATUS.orb_angles[orb] != angle) { //if the angle has changed
389
//          mysreg=SREG; 
390
//          cli(); //disable interrupts
391
//      ORB_STATUS.orb_angles[orb] = angle; //update angle
392
//      ORB_STATUS.new_angles = 1;
393
//          SREG=mysreg; //put interrupt status back
394
//   }
395
//}
396
//
397
//
398
//void orb_sort(void) {
399
//   uint16_t done = 0, i;
400
//   
401
//   while (! done) {
402
//      done = 1;
403
//
404
//      for (i = 0; i < ORB_COUNT - 1; ++i) {  //loop through all
405
//          
406
//                        //if they are out of order, swap them
407
//         if (ORB_STATUS.orbs[i].angle > ORB_STATUS.orbs[i+1].angle) {
408
//            ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
409
//            ORB_STATUS.orbs[i+1].angle ^= ORB_STATUS.orbs[i].angle;
410
//            ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
411
//
412
//            ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
413
//            ORB_STATUS.orbs[i+1].num ^= ORB_STATUS.orbs[i].num;
414
//            ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
415
//
416
//            done = 0;
417
//         }
418
//      }
419
//   }
420
//}
421
//
422
////calculate the split times
423
//void orb_setup_pulse(void) {
424
//   uint16_t i;
425
//   uint16_t my_port;
426
//   uint16_t sum = 0;
427
//   uint16_t split_time;
428
//
429
//   my_port = 0xff; //all on
430
//
431
//   if (ORB_STATUS.new_angles) {
432
//
433
//      ORB_STATUS.change_count = 0;
434
//          for (i = 0; i < ORB_COUNT; ++i) { //get the new values
435
//         ORB_STATUS.orbs[i].angle = ORB_STATUS.orb_angles[ORB_STATUS.orbs[i].num];
436
//      }
437
//
438
//      orb_sort(); //sort them
439
//      ORB_STATUS.new_angles = 0;
440
//
441
//      for (i = 0; i < ORB_COUNT; ++i) { //calculate split times
442
//         split_time = ORB_STATUS.orbs[i].angle - sum;
443
//         my_port &= ~_BV(ORB_STATUS.orbs[i].num);
444
//                 
445
//         for (; i < ORB_COUNT - 1 && ORB_STATUS.orbs[i].angle == ORB_STATUS.orbs[i+1].angle; ++i) {
446
//            my_port &= ~_BV(ORB_STATUS.orbs[i+1].num); //look for doups
447
//         }
448
//                 
449
//         ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port; //which pins are low
450
//         ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = split_time;
451
//         
452
//                 ++ORB_STATUS.change_count;
453
//                 
454
//         sum += split_time;
455
//      }
456
//
457
//      ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port;
458
//      ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = ORB_RESET - sum; //get a constant period
459
//
460
//      ++ORB_STATUS.change_count;
461
//
462
//   }
463
//
464
//
465
//
466
//   ORB_STATUS.current_orb = 0;
467
//
468
//    ORBPORT |= ORBMASK; //start with all high
469
//        OCR3C = TCNT3 + ORB_STATUS.changes[0].split_time_period; //wait for first split
470
//
471
//}
472
//
473
///**
474
// * @defgroup orbs Orbs
475
// * @brief Functions for controlling the color of the orbs.
476
// * 
477
// * Functions for controlling the color and lighting of the orbs.
478
// *
479
// * @{
480
// **/
481
//
482

    
483
/**
484
 * Set both orbs to the specified color. This function
485
 * is intended to be used with the predefined
486
 * colors. orb_init must be called before this
487
 * function may be used.
488
 *
489
 * @param col the color to set the orbs to
490
 *
491
 * @see orb_init
492
 **/
493
void orb_set_color(uint8_t col)
494
{
495
// uint16_t red, green, blue;
496
//
497
// red = ((col & 0xE0) >> 5) * 36;
498
// green = ((col & 0x1C) >> 2) * 36;
499
// blue = (col & 0x03) * 85;
500
//
501
// orb_set(red, green, blue);
502
}
503

    
504
/**
505
 * Set orb1 to the specified color. This function
506
 * is intended to be used with the predefined
507
 * colors. orb_init must be called before this
508
 * function may be used.
509
 *
510
 * @param col the color to set the orbs to
511
 *
512
 * @see orb_init
513
 **/
514
void orb1_set_color(uint8_t  col)
515
{
516
// uint16_t red, green, blue;
517
//
518
// red = ((col & 0xE0) >> 5) * 36;
519
// green = ((col & 0x1C) >> 2) * 36;
520
// blue = (col & 0x03) * 85;
521
//
522
// orb1_set(red, green, blue);
523
}
524

    
525
/**
526
 * Set orb2 to the specified color. This function
527
 * is intended to be used with the predefined
528
 * colors. orb_init must be called before this
529
 * function may be used.
530
 *
531
 * @param col the color to set the orbs to
532
 *
533
 * @see orb_init
534
 **/
535
void orb2_set_color(uint8_t  col)
536
{
537
// uint16_t red, green, blue;
538
//
539
// red = ((col & 0xE0) >> 5) * 36;
540
// green = ((col & 0x1C) >> 2) * 36;
541
// blue = (col & 0x03) * 85;
542
//
543
// orb2_set(red, green, blue);
544
}
545

    
546
//DOES THIS WORK?
547
// Disables the timer1 interrupt, disabling the Orb's color fading capabilities
548
// You can still turn the red, green, and blue leds on and off with set_orb_dio
549
/* If we use the PWM for anything else besides the ORB, this implementation needs to be done better */
550
/**
551
 * Disables the orb color fading capabilities
552
 * by disabling the timer1 interrupt.
553
 *
554
 * @see orb_init
555
 **/
556
void orb_disable()
557
{
558
//        TCCR3B &= 0;          //Turn off everything
559
//        ORB_PORT |= _BV(ORB1_RED);
560
//        ORB_PORT |= _BV(ORB1_GREEN);
561
//        ORB_PORT |= _BV(ORB1_BLUE);
562
//        ORB_PORT |= _BV(ORB2_RED);
563
//        ORB_PORT |= _BV(ORB2_GREEN);
564
//        ORB_PORT |= _BV(ORB2_BLUE);
565
}
566

    
567
//DOES THIS WORK?
568
// Enables the timer1 interrupt, enabling the Orb's color fading capabilities
569
/**
570
 * Enables the orb's color fading capabilities.
571
 *
572
 * @see orb_init
573
 **/
574
void orb_enable()
575
{
576
////        TCCR0 |= _BV(COM01) | _BV(COM00)  | _BV(WGM00) | _BV(CS01);        //Toggle OC Pin on match, FAST PWM Mode, clock/8
577
//        TCCR3B =_BV(CS31);
578
}
579

    
580
/** @} **/ //end group
581