Project

General

Profile

Revision 1107

Implemented triple buffering
Optimized sorting

View differences:

lights.c
72 72

  
73 73
/*
74 74
  TODO:
75
	- test the timing
76
	- Determine sorting time, possibly improve sorting algorithm (111 us sorted,
77
	  143 us reverse sorted)
78
	- stop sorting when finished (no change made) (and measure performance gain)
75
	- Find out the interrupt time
76
	- Optimize the OC interrupt
79 77
    - enable_orb_pwm use everywhere, add methods to switch on/off, add init
80 78
	  function
81 79
	- test old code: continuously setting the orbs
82
	- n-buffering
83 80
	- fix sync/volatile
84 81
 */
85 82

  
......
185 182
    uint8_t mask;
186 183
};
187 184

  
188
sutrct pwm_t
185
struct pwm_t
189 186
{
190 187
	uint8_t init_mask;
191
	pwm_channels_t channel[num_pwm_channels];
192
}
188
	struct pwm_channel_t channel[num_pwm_channels];
189
};
193 190

  
194 191

  
195 192
// ***************
......
204 201
struct pwm_t pwm_buffer[3];
205 202
// TODO using pointers might be faster (or might be slower because pointers are
206 203
// 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;
204
struct pwm_t *pwm_read_buffer =&pwm_buffer[0]; // The front buffer the ISR reads from. Other thread may not touch this pointer or the buffer it points to.
205
struct pwm_t *pwm_write_buffer=&pwm_buffer[1]; // The back buffer we can write to. The ISR may not touch this pointer or the buffer it points to.
206
struct pwm_t *pwm_free_buffer =&pwm_buffer[2]; // The back buffer to flip with.
207
bool pwm_page_flip=false; // Whether to do a page flip on the next overflow
211 208

  
212 209

  
213

  
214 210
// The orb value array. Orb values are written here to be sorted into
215 211
// pwm_channels.
216 212
uint8_t orb_values[NUM_ORBS][NUM_COLORS];
......
228 224
SIGNAL (SIG_OVERFLOW0)
229 225
{
230 226
PORTF|=4;
227

  
228
	if (pwm_page_flip)
229
	{
230
		// Flip the read buffer with the free buffer
231
		// We are in an ISR, so we don't have to synchronize explicitly.
232
		struct pwm_t *temp = pwm_read_buffer;
233
		pwm_read_buffer    = pwm_free_buffer;
234
		pwm_free_buffer    = temp;
235
		pwm_page_flip=false;
236
	}
237

  
231 238
	// Turn all appropriate PWM channels on
232
	ORBPORT&=pwm_init_mask;
239
	ORBPORT&=pwm_read_buffer->init_mask;
233 240
	
234
	// Start at the first channel
241
	// Start at the first channel (TODO faster w/ pointers?)
235 242
	current_pwm_channel=0;
236 243
	
237 244
	// Load the first OCR
238
	OCR0=pwm_channels[current_pwm_channel].time;
245
	OCR0=pwm_read_buffer->channel[current_pwm_channel].time;
239 246
PORTF&=~4;
240 247
}
241 248

  
......
250 257

  
251 258
	// TODO improve (check overflow; maybe use return after last, maybe use
252 259
	// pointers instead of indicies)
253
	while (TCNT0==pwm_channels[current_pwm_channel].time+1)
260
	while (TCNT0==pwm_read_buffer->channel[current_pwm_channel].time+1)
254 261
	{
255 262
		// Turn the current channel off
256
		ORBPORT|=pwm_channels[current_pwm_channel].mask;
263
		ORBPORT|=pwm_read_buffer->channel[current_pwm_channel].mask;
257 264

  
258 265
		// Increment the channel
259 266
		current_pwm_channel++;
260 267

  
261 268
		// If there is a next channel, load its OCR value
262 269
		if (current_pwm_channel<=(num_pwm_channels-1))
263
			if (pwm_channels[current_pwm_channel].time<255)
264
				OCR0=pwm_channels[current_pwm_channel].time;
270
			if (pwm_read_buffer->channel[current_pwm_channel].time<255)
271
				OCR0=pwm_read_buffer->channel[current_pwm_channel].time;
265 272
	}
266 273
PORTF&=~4;
267 274
}
......
288 295
		// Sort the orb values.
289 296

  
290 297
PORTF|=2;
291
SYNC
292
{
293
		pwm_init_mask=~0;
298
		pwm_write_buffer->init_mask=~0;
294 299
	
295 300
		// 1. Write the orb values and corresponding masks to the pwm channels
296 301
		// array unsorted
302
		
297 303
		for (uint8_t orb=0; orb<2; ++orb)
298 304
		{
299 305
			for (uint8_t color=0; color<3; ++color)
......
303 309
				uint8_t time=orb_values[orb][color];
304 310
				uint8_t mask=orb_mask[orb][color];
305 311
				
306
				pwm_channels[index].time=time-1;
307
				pwm_channels[index].mask=mask;
312
				pwm_write_buffer->channel[index].time=time-1;
313
				pwm_write_buffer->channel[index].mask=mask;
308 314
				
309 315
				if (time!=0)
310
					pwm_init_mask &= ~mask;
316
					pwm_write_buffer->init_mask &= ~mask;
311 317
			}
312 318
		}
313 319

  
314
		// 2. Sort the values. Use bubble sort for now.
315
		for (uint8_t count=num_pwm_channels-1; count>0; --count)
320
		// 2. Sort the values. Use bubble sort.
321
		// Considering the low number of data points, more
322
		// sophisticated algorithms are unlikely to be faster.
323
		bool done;
324
		// For 6 channels, we count i=0..4 and compare i with i+1
325
		uint8_t top=num_pwm_channels-1;
326
		do
316 327
		{
317
			for (uint8_t i=num_pwm_channels-1; i>0; --i)
328
			done=true; // We are done unless we do some swapping
329
			
330
			for (uint8_t i=0; i<top; ++i)
318 331
			{
319
				if (pwm_channels[i].time<pwm_channels[i-1].time)
332
				#define channel_a pwm_write_buffer->channel[i]
333
				#define channel_b pwm_write_buffer->channel[i+1]
334

  
335
				if (channel_a.time>channel_b.time)
320 336
				{
321 337
					uint8_t temp;
322 338
					
339

  
323 340
					// Swap the times
324
					temp=pwm_channels[i].time;
325
					pwm_channels[i].time=pwm_channels[i-1].time;
326
					pwm_channels[i-1].time=temp;
341
					temp           = channel_a.time;
342
					channel_a.time = channel_b.time;
343
					channel_b.time = temp;
327 344
					
328 345
					// Swap the masks
329
					temp=pwm_channels[i].mask;
330
					pwm_channels[i].mask=pwm_channels[i-1].mask;
331
					pwm_channels[i-1].mask=temp;
346
					temp           = channel_a.mask;
347
					channel_a.mask = channel_b.mask;
348
					channel_b.mask = temp;
349
					
350
					done=false; // No, we're not done yet.
332 351
				}
352
				
353
				#undef channel_a
354
				#undef channel_b
333 355
			}
356
			
357
			// On the next iteration, we need one less comparison
358
			top--;
359
		} while (!done);
360
		
361
		// Flip the write buffer with the free buffer
362
		SYNC
363
		{
364
			struct pwm_t *temp = pwm_write_buffer;
365
			pwm_write_buffer   = pwm_free_buffer;
366
			pwm_free_buffer    = temp;
334 367
		}
335
}
336
//SYNC_END;
368
		
369
		// On the next overflow, do the page flip.
370
		pwm_page_flip=true;
371
		
337 372
PORTF&=~2;
338

  
339 373
	}
340 374
	else
341 375
	{
......
598 632
	//orbs_set (255, 127, 0, 0, 127, 255); // Pretty colors with extreme values
599 633
	//orbs_set (0, 1, 2, 253, 254, 255); // Timing tests
600 634

  
601
	orbs_set (255, 255, 255, 0, 0, 0);
602
	delay_ms (1000);
635
//	orbs_set (255, 255, 255, 0, 0, 0);
636
//	delay_ms (1000);
603 637

  
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

  
611
	// Test the time of the sorting routine
612 638
	//while (1)
613 639
	//{
614
	//	orbs_set (10, 20, 30, 40, 50, 60);	// Correct order
615
	//	//orbs_set (60, 50, 40, 30, 20, 10); // Reverse order
616
	//	delay_ms (10);
640
	//	orbs_set (250, 127, 3, 3, 127, 250); // Pretty colors
641
	//	//orbs_set (255, 255, 255, 1, 1, 1);
642
	//	//_delay_us(400);
617 643
	//}
644

  
645
	// Test the time of the sorting routine
646
//	while (1)
647
//	{
648
//		orbs_set (10, 20, 30, 40, 50, 60);	// Correct order
649
//		//orbs_set (60, 50, 40, 30, 20, 10); // Reverse order
650
//		delay_ms (10);
651
//	}
618 652
}
619 653

  
620

  
654
// Pure sorting time/us (interrupts disabled!) (difference to naive bs):
655
//                        Correct order    Reverse order
656
// Naive bubble sort:     147              216
657
// Aborting bubble sort:   70 (-52%)       231 (+7%)
658
// Aborting w/ top:        72 (-51%)       188 (-13%)

Also available in: Unified diff