Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (19.6 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
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!
71
 */
72

    
73
/*
74
  TODO:
75
        - Find out the interrupt time
76
        - Optimize the OC interrupt
77
    - enable_orb_pwm use everywhere, add methods to switch on/off, add init
78
          function
79
        - test old code: continuously setting the orbs
80
        - fix sync/volatile
81
 */
82

    
83
/*
84
 * Random notes:
85
 *   - Current motor frequency is 32 us/30 KHz
86
 *   - AVR suckage: there is not timer mode with immediate OCR update and 
87
 *     overflow interrupt at TOP (CTC value)
88
 *   - AVR suckage: Set on compare match/Clear on overflow not available with
89
 *     non-PWM modes (especially not with immediate OCR update)
90
 *   - Frequency is 120 Hz (8 ms) next lower (prescaler) is 30 Hz which flickers
91
 *     Not that we could still use the slower prescaler and manually reload
92
 *     after 127. This would still cost resolution, but 128 steps should be
93
 *     enough.
94
 *   - Overflow interrupt 2.5 us (0.03%), compare interrupts are 6*10us (when
95
 *     using all different values) (0.75%) or 1*26 us (when using all same
96
 *     values)
97
 *   - Where to put the time base?
98
 *     - buzzer => doesn't work because of varying frequency
99
 *     - motors => possible? would trigger often (?)
100
 *     - lights => must put lights on 16 bit timer (no OCR left)
101
 *   - Syncronization test case: set orb A to 1,1,1 (not 0 because they will
102
 *     not be turned on) and orb B to 254,254,254. Do this in a loop, with
103
 *     some delay d between.
104
 *      * d=1ms => occasional flickering
105
 *      * d=400us => frequent flickering
106
 *      * d=0 => no usable orb output
107
 *     Without syncronization, both LEDs flicker (because the wrong values are
108
 *     in the channels array while sorting). When the sorting code ist
109
 *     synchronized, only orb A flickers, because the timing is disrupted by the
110
 *     large synchronized block.
111
 */
112
 
113
#include "lights.h"
114

    
115
#include <avr/interrupt.h>
116

    
117
#include "dragonfly_lib.h"
118

    
119

    
120
// ***************
121
// ** Constants **
122
// ***************
123

    
124
#define NUM_ORBS 2   // Number or orbs
125
#define NUM_COLORS 3 // Number of colors per orb
126
#define num_pwm_channels NUM_ORBS*NUM_COLORS
127

    
128

    
129
// *********
130
// ** I/O **
131
// *********
132

    
133
// Orb port
134
#define ORBPORT PORTC
135
#define ORBDDR  DDRC
136

    
137
// Orb pins
138
#define ORB1_RED   0
139
#define ORB1_GREEN 1
140
#define ORB1_BLUE  2
141
#define ORB2_RED   4
142
#define ORB2_GREEN 5
143
#define ORB2_BLUE  6
144

    
145

    
146
// ***********
147
// ** Masks **
148
// ***********
149

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

    
154
// Masks for the individual LEDs
155
#define orb1_red_mask    _BV (ORB1_RED  )
156
#define orb1_green_mask  _BV (ORB1_GREEN)
157
#define orb1_blue_mask   _BV (ORB1_BLUE )
158
#define orb2_red_mask    _BV (ORB2_RED  )
159
#define orb2_green_mask  _BV (ORB2_GREEN)
160
#define orb2_blue_mask   _BV (ORB2_BLUE )
161

    
162
// Mask for all LEDs
163
const uint8_t all_orbs_mask=
164
        orb1_red_mask | orb1_green_mask | orb1_blue_mask |
165
        orb2_red_mask | orb2_green_mask | orb2_blue_mask;
166

    
167
// Mask for the individual LEDs, organized as an array for programmatic access.
168
// The layout of this array is orb_mask[orb_num, color_num]
169
const uint8_t orb_mask[NUM_ORBS][NUM_COLORS]=
170
{
171
        { orb1_red_mask, orb1_green_mask, orb1_blue_mask },
172
        { orb2_red_mask, orb2_green_mask, orb2_blue_mask }
173
};
174

    
175
// ***********
176
// ** Types **
177
// ***********
178

    
179
struct pwm_channel_t
180
{
181
    uint8_t time;
182
    uint8_t mask;
183
};
184

    
185
struct pwm_t
186
{
187
        uint8_t init_mask;
188
        struct pwm_channel_t channel[num_pwm_channels];
189
};
190

    
191

    
192
// ***************
193
// ** Variables **
194
// ***************
195

    
196
// Whether to use PWM (true) or binary (false) orb mode
197
bool enable_orb_pwm=true;
198

    
199
// The PWM channels and the buffer pointers. This data structure is triple
200
// buffered, see above for the reasons.
201
struct pwm_t pwm_buffer[3];
202
// TODO using pointers might be faster (or might be slower because pointers are
203
// 16 bit long).
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
208

    
209

    
210
// The orb value array. Orb values are written here to be sorted into
211
// pwm_channels.
212
uint8_t orb_values[NUM_ORBS][NUM_COLORS];
213

    
214
// TODO: random note: what happens if the main process is sorting and a different
215
// interrupt calls set_orb?
216

    
217

    
218
// ****************
219
// ** Timer ISRs **
220
// ****************
221

    
222
// Not volatile - only accessed in the interrupt handler
223
uint8_t current_pwm_channel=0;
224

    
225
uint8_t lastim=0;
226

    
227
SIGNAL (SIG_OVERFLOW0)
228
{
229
PORTF|=4;
230

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

    
241
        // Turn only the appropriate PWM channels on
242
        // TODO: why do we have to turn them off? It should be done in the oc isr.
243
        // Test code: set (0); set (255); delay (100ms); set (0) => blu/green is on
244
        // Does it also happen with 254 instead of 255? But isn't it turned off with
245
        // 255? Better turn them off anyway.
246
        ORBPORT|=all_orbs_mask;
247
        ORBPORT&=pwm_read_buffer->init_mask;
248
        
249
        // Start at the first channel (TODO faster w/ pointers?)
250
        current_pwm_channel=0;
251
        
252
        // Load the first OCR
253
        OCR0=pwm_read_buffer->channel[current_pwm_channel].time;
254
PORTF&=~4;
255
}
256

    
257
SIGNAL(SIG_OUTPUT_COMPARE0)
258
{
259
PORTF|=4;
260
        // TODO:
261
        //   - delayed interrupt
262
        //   - synchronization OK?
263
        
264
        // If the interrupt is executed w/o delay, TCNT0 == time+1 (and TIME=OCR0)
265

    
266
        // TODO improve (check overflow; maybe use return after last, maybe use
267
        // pointers instead of indicies)
268
        while (TCNT0==pwm_read_buffer->channel[current_pwm_channel].time+1)
269
        {
270
                // Turn the current channel off
271
                ORBPORT|=pwm_read_buffer->channel[current_pwm_channel].mask;
272

    
273
                // Increment the channel
274
                current_pwm_channel++;
275

    
276
                // If there is a next channel, load its OCR value
277
                if (current_pwm_channel<=(num_pwm_channels-1))
278
                        if (pwm_read_buffer->channel[current_pwm_channel].time<255)
279
                                OCR0=pwm_read_buffer->channel[current_pwm_channel].time;
280
        }
281
PORTF&=~4;
282
}
283

    
284

    
285

    
286
// ************************************
287
// ** Internal orb setting functions **
288
// ************************************
289

    
290
#define SYNC_START uint8_t tmp_sreg; do { tmp_sreg=SREG; cli (); } while (false)
291
#define SYNC_RESTART                 do { tmp_sreg=SREG; cli (); } while (false)
292
#define SYNC_END                     do { SREG=tmp_sreg; } while (false)
293

    
294
static void apply_orbs (void)
295
{
296
        if (enable_orb_pwm)
297
        {
298
                // PWM mode
299
                
300
                // Sort the orb values.
301

    
302
PORTF|=2;
303
                pwm_write_buffer->init_mask=~0;
304
        
305
                // 1. Write the orb values and corresponding masks to the pwm channels
306
                // array unsorted
307
                
308
                for (uint8_t orb=0; orb<2; ++orb)
309
                {
310
                        for (uint8_t color=0; color<3; ++color)
311
                        {
312
                                // TODO this should be faster w/o multiplication
313
                                uint8_t index=NUM_COLORS*orb+color;
314
                                uint8_t time=orb_values[orb][color];
315
                                uint8_t mask=orb_mask[orb][color];
316
                                
317
                                pwm_write_buffer->channel[index].time=time-1;
318
                                pwm_write_buffer->channel[index].mask=mask;
319
                                
320
                                // If the channel is not off (0), it has to be turned on
321
                                // (low) at the beginning of the PWM cycle.
322
                                if (time!=0)
323
                                        pwm_write_buffer->init_mask &= ~mask;
324
                        }
325
                }
326

    
327
                // 2. Sort the values. Use bubble sort.
328
                // Considering the low number of data points, more
329
                // sophisticated algorithms are unlikely to be faster.
330
                bool done;
331
                // For 6 channels, we count i=0..4 and compare i with i+1
332
                uint8_t top=num_pwm_channels-1;
333
                do
334
                {
335
                        done=true; // We are done unless we do some swapping
336
                        
337
                        for (uint8_t i=0; i<top; ++i)
338
                        {
339
                                #define channel_a pwm_write_buffer->channel[i]
340
                                #define channel_b pwm_write_buffer->channel[i+1]
341

    
342
                                if (channel_a.time>channel_b.time)
343
                                {
344
                                        uint8_t temp;
345
                                        
346

    
347
                                        // Swap the times
348
                                        temp           = channel_a.time;
349
                                        channel_a.time = channel_b.time;
350
                                        channel_b.time = temp;
351
                                        
352
                                        // Swap the masks
353
                                        temp           = channel_a.mask;
354
                                        channel_a.mask = channel_b.mask;
355
                                        channel_b.mask = temp;
356
                                        
357
                                        done=false; // No, we're not done yet.
358
                                }
359
                                
360
                                #undef channel_a
361
                                #undef channel_b
362
                        }
363
                        
364
                        // On the next iteration, we need one less comparison
365
                        top--;
366
                } while (!done);
367
                
368
                // Flip the write buffer with the free buffer
369
                SYNC
370
                {
371
                        struct pwm_t *temp = pwm_write_buffer;
372
                        pwm_write_buffer   = pwm_free_buffer;
373
                        pwm_free_buffer    = temp;
374
                }
375
                
376
                // On the next overflow, do the page flip.
377
                pwm_page_flip=true;
378
                
379
PORTF&=~2;
380
        }
381
        else
382
        {
383
                // Binary mode.
384
                // Don't do anything, the orbs pins are set in orb_n_set.
385
                // It would be more consistent to set them here (because you could
386
                // update them independently and then apply the changes at once), but it
387
                // is faster this way, and being fast is the whole point of using the
388
                // binary orb mode anyway.
389
        }
390
}
391

    
392
// TODO: make a public version of this one, but keep a private one which does
393
// not sort them so you can update both sides and update only once.
394

    
395
static void orb_n_set (uint8_t num, uint8_t red, uint8_t green, uint8_t blue)
396
{
397
        if (enable_orb_pwm)
398
        {
399
                // PWM mode
400
                orb_values[num][0]=red;
401
                orb_values[num][1]=green;
402
                orb_values[num][2]=blue;
403
        }
404
        else
405
        {
406
                // Binary mode
407
                // The outputs are inverted.
408
                if (!red)   ORBPORT|=orb_mask[num][0]; else ORBPORT&=~orb_mask[num][0];
409
                if (!green) ORBPORT|=orb_mask[num][1]; else ORBPORT&=~orb_mask[num][1];
410
                if (!blue)  ORBPORT|=orb_mask[num][2]; else ORBPORT&=~orb_mask[num][2];
411
        }
412
}
413

    
414
// ************************************
415
// ** Frontend orb setting functions **
416
// ************************************
417

    
418
// All of these functions use orb_n_set to set the actual values, and then call
419
// apply_orbs() to apply the changes. orb_n_set should be used (although it
420
// would be faster to set the array directly) because the binary/pwm mode has
421
// to be handled.
422

    
423
/**
424
 * Set orb1 to the color specified. orb_init must be called before this function
425
 * may be used.
426
 *
427
 * @param red the red component of the color
428
 * @param green the green component of the color
429
 * @param blue the blue component of the color
430
 *
431
 * @see orb_init
432
 **/
433
void orb1_set (uint8_t red, uint8_t green, uint8_t blue)
434
{
435
        orb_n_set (0, red, green, blue);
436
        apply_orbs ();
437
}
438

    
439
/**
440
 * Set orb2 to the color specified. orb_init must be called before this function
441
 * may be used.
442
 *
443
 * @param red_led the red component of the color
444
 * @param green_led the green component of the color
445
 * @param blue_led the blue component of the color
446
 *
447
 * @see orb_init
448
 **/
449
void orb2_set (uint8_t red, uint8_t green, uint8_t blue)
450
{
451
        orb_n_set (1, red, green, blue);
452
        apply_orbs ();
453
}
454

    
455
/**
456
 * Set both orbs to the color specified. orb_init must be called before this
457
 * function may be used.
458
 *
459
 * @param red_led the red component of the color
460
 * @param green_led the green component of the color
461
 * @param blue_led the blue component of the color
462
 *
463
 * @see orb_init, orb1_set, orb2_set
464
 **/
465
void orb_set (uint8_t red, uint8_t green, uint8_t blue)
466
{
467
        orb_n_set (0, red, green, blue);
468
        orb_n_set (1, red, green, blue);
469
        apply_orbs ();
470
}
471

    
472
void orbs_set (
473
        uint8_t red1, uint8_t green1, uint8_t blue1,
474
        uint8_t red2, uint8_t green2, uint8_t blue2)
475
{
476
        orb_n_set (0, red1, green1, blue1);
477
        orb_n_set (1, red2, green2, blue2);
478
        apply_orbs ();
479
}
480

    
481

    
482

    
483

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

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

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

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

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

    
581
/** @} **/ //end group
582

    
583

    
584
// ********************
585
// ** Initialization **
586
// ********************
587

    
588
/**
589
 * Initializes the PWM for Orb control. This must be called before 
590
 * the orbs are used for them to function.
591
 **/
592
void orb_init ()
593
{
594
        // Use 8 bit TC0. Timer mode:
595
        //   We cannot use CTC mode because it can only clear on OCR0 (in contrast
596
        //   to the 16 bit timers which can also use the ICR for that) and OCR0 is
597
        //   already used for generating output compare interrupts. We also need
598
        //   immediate (non double buffered) update of OCR0, so the only mode left
599
        //   is "Normal".
600
        //   Note that for a timer counting from 0 to 255, there are 256 states and
601
        //   thus 257 output possibilities (0/256...256/256)! Possible ways to deal
602
        //   with that:
603
        //     1. use a 16 bit variable for the PWM value (memory waste, overhead)
604
        //     2. use an additional flag for the 257th value (inconvenient)
605
        //     3. use 1/256...256/256 (skip 0, never complete off)
606
        //     4. use 0/256...256/256 (skip 256, never complete on)
607
        //     5. skip a value somewhere in the middle
608
        //     6. reload the timer after 254
609
        //   For this implementation, variant 4 was chosen.
610
        // Using and 8 bit timer has the added advantage that all the comparisons
611
        // are faster.
612
        
613
        // Enable the output ports and turn off the LEDs
614
        ORBDDR  |=  all_orbs_mask;
615
        ORBPORT |=  all_orbs_mask;
616

    
617
        // Set all orbs to "off"
618
        orb_set (0, 0, 0);
619

    
620
        // *** Set up the timer
621

    
622
        // Normal mode, Compare match output off, Prescaler
623
        TCCR0=_BV(CS02) | _BV(CS01) | _BV(CS00); // 1024, 30 Hz
624
        TCCR0=_BV(CS02) | _BV(CS01); // 1024, 30 Hz
625

    
626
        // Enable compare match and overflow interrupts
627
        TIMSK=_BV(OCIE0) | _BV(TOIE0);
628

    
629
    // Debug
630
    DDRF=6;
631

    
632
        
633
        // The output compare flag (and interrupt) is set at the next timer clock
634
        // cycle after compare match. So time=pwm_value-1 (for pwm_value==0: don't
635
        // switch on at all)
636
        // ORB1: red
637
        // ORB2: green
638

    
639
        // Left: greenish red, Right: greenish blue
640
        // For testing, set some pretty colors
641
        //orbs_set (250, 127, 3, 3, 127, 250); // Pretty colors
642
        //orbs_set (255, 127, 0, 0, 127, 255); // Pretty colors with extreme values
643
        //orbs_set (0, 1, 2, 253, 254, 255); // Timing tests
644

    
645
//        orbs_set (255, 255, 255, 0, 0, 0);
646
//        delay_ms (1000);
647

    
648
        //while (1)
649
        //{
650
        //        orbs_set (250, 127, 3, 3, 127, 250); // Pretty colors
651
        //        //orbs_set (255, 255, 255, 1, 1, 1);
652
        //        //_delay_us(400);
653
        //}
654

    
655
        // Test the time of the sorting routine
656
//        while (1)
657
//        {
658
//                orbs_set (10, 20, 30, 40, 50, 60);        // Correct order
659
//                //orbs_set (60, 50, 40, 30, 20, 10); // Reverse order
660
//                delay_ms (10);
661
//        }
662
}
663

    
664
// Pure sorting time/us (interrupts disabled!) (difference to naive bs):
665
//                        Correct order    Reverse order
666
// Naive bubble sort:     147              216
667
// Aborting bubble sort:   70 (-52%)       231 (+7%)
668
// Aborting w/ top:        72 (-51%)       188 (-13%)