Project

General

Profile

Revision 1102

Basic orb PWM functionality on Timer0

View differences:

branches/library_refactor/behaviors/library_test/main.c
78 78

  
79 79
	//DDRF=2;
80 80

  
81
	//motors_init ();
82
	//motor2_set (FORWARD, 64);
83

  
81 84
	//orb_init ();
82 85
	//orb_enable ();
83 86

  
......
85 88
	//delay_ms (1000);
86 89
	while (1)
87 90
	{
88
		orb_tick (0);
89 91
		delay_ms (1000);
90 92
	}
91 93
	
branches/library_refactor/projects/libdragonfly/lights.c
57 57

  
58 58
 */
59 59

  
60
/*
61
 * Random notes:
62
 *   - Current motor frequency is 32 us/30 KHz
63
 *   - AVR suckage: there is not timer mode with immediate OCR update and 
64
 *     overflow interrupt at TOP (CTC value)
65
 *   - AVR suckage: Set on compare match/Clear on overflow not available with
66
 *     non-PWM modes (especially not with immediate OCR update)
67
 */
68
 
60 69
#include "lights.h"
61 70
#include <avr/interrupt.h>
62 71
#include "dragonfly_lib.h"
......
81 90
#define ORB2_GREEN 5
82 91
#define ORB2_BLUE  6
83 92

  
93

  
84 94
// ***********
85 95
// ** Masks **
86 96
// ***********
......
115 125
// ** Types **
116 126
// ***********
117 127

  
118
struct pwm_channel
128
struct pwm_channel_t
119 129
{
120 130
    uint8_t time;
121 131
    uint8_t mask;
......
126 136
// ** Variables **
127 137
// ***************
128 138

  
129
struct pwm_channel channels[NUM_ORBS*NUM_COLORS];
139
#define num_pwm_channels NUM_ORBS*NUM_COLORS
140
struct pwm_channel_t pwm_channels[num_pwm_channels];
141
uint8_t pwm_init_mask;
130 142

  
131 143

  
132 144
// ********************
133 145
// ** Initialization **
134 146
// ********************
135 147

  
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 148
/**
147 149
 * Initializes the PWM for Orb control. This must be called before 
148 150
 * the orbs are used for them to function.
149 151
 **/
150 152
void orb_init ()
151 153
{
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.
154
	// Use 8 bit TC0. Timer mode:
155
	//   We cannot use CTC mode because it can only clear on OCR0 (in contrast
156
	//   to the 16 bit timers which can also use the ICR for that) and OCR0 is
157
	//   already used for generating output compare interrupts. We also need
158
	//   immediate (non double buffered) update of OCR0, so the only mode left
159
	//   is "Normal".
160
	//   Note that for a timer counting from 0 to 255, there are 256 states and
161
	//   thus 257 output possibilities (0/256...256/256)! Possible ways to deal
162
	//   with that:
163
	//     1. use a 16 bit variable for the PWM value (memory waste, overhead)
164
	//     2. use an additional flag for the 257th value (inconvenient)
165
	//     3. use 1/256...256/256 (skip 0, never complete off)
166
	//     4. use 0/256...256/256 (skip 256, never complete on)
167
	//     5. skip a value somewhere in the middle
168
	//   For this implementation, variant 4 was chosen.
161 169
	
162 170
	// Enable the output ports and turn off the LEDs
163 171
	ORBDDR  |=  all_orbs_mask;
164
	ORBPORT &= ~all_orbs_mask;
172
	ORBPORT |=  all_orbs_mask;
165 173

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

  
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
177
	// *** Set up the timer
182 178

  
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
179
	// Normal mode, Compare match output off, Prescaler 1024
180
	TCCR0=_BV(CS02) | _BV(CS01) | _BV(CS00);
198 181

  
182
	// Enable compare match and overflow interrupts
183
	TIMSK=_BV(OCIE0) | _BV(TOIE0);
184

  
199 185
    // Debug
200 186
    DDRF=6;
201 187

  
202
	// In PWM mode, the OCR is double buffered (updated at TOP or BOTTOM)
188
	
189
	// The output compare flag (and interrupt) is set at the next timer clock
190
	// cycle after compare match. So time=pwm_value-1 (for pwm_value==0: don't
191
	// switch on at all)
192
	// ORB1: 255/127/1
193
	// ORB2: 0/126/254
203 194

  
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;
195
	// Init mask: all masks where value>0
196
	pwm_init_mask=
197
		orb1_red_mask |
198
		orb1_green_mask |
199
		orb1_blue_mask |
200
		orb2_green_mask |
201
		orb2_blue_mask
202
		;
203
	
204
	// Channels: value-1
205
	pwm_channels[0].mask=orb2_red_mask   ; pwm_channels[0].time= 10-1;//0
206
	pwm_channels[1].mask=orb1_blue_mask  ; pwm_channels[1].time= 20-1;//1
207
	pwm_channels[2].mask=orb2_green_mask ; pwm_channels[2].time= 30-1;//126
208
	pwm_channels[3].mask=orb1_green_mask ; pwm_channels[3].time=200-1;//127
209
	pwm_channels[4].mask=orb2_blue_mask  ; pwm_channels[4].time=220-1;//254
210
	pwm_channels[5].mask=orb1_red_mask   ; pwm_channels[5].time=230-1;//255
210 211
}
211
//
212 212

  
213 213

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

  
218
volatile uint8_t x;
219
volatile uint8_t i;
218
volatile uint8_t current_pwm_channel=0;
220 219

  
221
void orb_tick (uint8_t t)
220
SIGNAL (SIG_OVERFLOW0)
222 221
{
223
	x++;
222
	// Turn all appropriate PWM channels on
223
	// TODO invert earlier
224
	ORBPORT&=~pwm_init_mask;
225
	
226
	// Start at the first channel
227
	current_pwm_channel=0;
228
	
229
	// Load the first OCR
230
	OCR0=pwm_channels[current_pwm_channel].time;
224 231
}
225 232

  
226
SIGNAL (SIG_OVERFLOW3)
233
SIGNAL(SIG_OUTPUT_COMPARE0)
227 234
{
228
}
235
	// TODO:
236
	//   - delayed interrupt
237
	//   - identical values
238
	
239
	// Turn the current channel off
240
	// TODO invert earlier
241
	ORBPORT|=pwm_channels[current_pwm_channel].mask;
229 242

  
230
// Timer values: 0 1 2 3 4 5 6 7 8 9
243
	// Increment the channel
244
	current_pwm_channel++;
231 245

  
246
	// If there is a next channel, load its OCR value
247
	if (current_pwm_channel<=(num_pwm_channels-1))
248
		if (pwm_channels[current_pwm_channel].time<255)
249
			OCR0=pwm_channels[current_pwm_channel].time;
250
}
232 251

  
233 252

  
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 253

  
260

  
261 254
// ************************
262 255
// ** Setting RGB colors **
263 256
// ************************

Also available in: Unified diff