|
@@ -62,6 +62,15 @@
|
62
|
62
|
#error "MAX7219_ROTATE must be a multiple of +/- 90°."
|
63
|
63
|
#endif
|
64
|
64
|
|
|
65
|
+#ifdef MAX7219_DEBUG_PROFILE
|
|
66
|
+ CodeProfiler::Mode CodeProfiler::mode = ACCUMULATE_AVERAGE;
|
|
67
|
+ uint8_t CodeProfiler::instance_count = 0;
|
|
68
|
+ uint32_t CodeProfiler::last_calc_time = micros();
|
|
69
|
+ uint8_t CodeProfiler::time_fraction = 0;
|
|
70
|
+ uint32_t CodeProfiler::total_time = 0;
|
|
71
|
+ uint16_t CodeProfiler::call_count = 0;
|
|
72
|
+#endif
|
|
73
|
+
|
65
|
74
|
Max7219 max7219;
|
66
|
75
|
|
67
|
76
|
uint8_t Max7219::led_line[MAX7219_LINES]; // = { 0 };
|
|
@@ -69,7 +78,7 @@ uint8_t Max7219::suspended; // = 0;
|
69
|
78
|
|
70
|
79
|
#define LINE_REG(Q) (max7219_reg_digit0 + ((Q) & 0x7))
|
71
|
80
|
|
72
|
|
-#if _ROT == 0 || _ROT == 270
|
|
81
|
+#if (_ROT == 0 || _ROT == 270) == DISABLED(MAX7219_REVERSE_EACH)
|
73
|
82
|
#define _LED_BIT(Q) (7 - ((Q) & 0x7))
|
74
|
83
|
#else
|
75
|
84
|
#define _LED_BIT(Q) ((Q) & 0x7)
|
|
@@ -266,26 +275,27 @@ void Max7219::set(const uint8_t line, const uint8_t bits) {
|
266
|
275
|
#endif // MAX7219_NUMERIC
|
267
|
276
|
|
268
|
277
|
// Modify a single LED bit and send the changed line
|
269
|
|
-void Max7219::led_set(const uint8_t x, const uint8_t y, const bool on) {
|
|
278
|
+void Max7219::led_set(const uint8_t x, const uint8_t y, const bool on, uint8_t * const rcm/*=nullptr*/) {
|
270
|
279
|
if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_set"), x, y);
|
271
|
280
|
if (BIT_7219(x, y) == on) return;
|
272
|
281
|
XOR_7219(x, y);
|
273
|
282
|
refresh_unit_line(LED_IND(x, y));
|
|
283
|
+ if (rcm != nullptr) *rcm |= _BV(LED_IND(x, y) & 0x07);
|
274
|
284
|
}
|
275
|
285
|
|
276
|
|
-void Max7219::led_on(const uint8_t x, const uint8_t y) {
|
|
286
|
+void Max7219::led_on(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) {
|
277
|
287
|
if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_on"), x, y);
|
278
|
|
- led_set(x, y, true);
|
|
288
|
+ led_set(x, y, true, rcm);
|
279
|
289
|
}
|
280
|
290
|
|
281
|
|
-void Max7219::led_off(const uint8_t x, const uint8_t y) {
|
|
291
|
+void Max7219::led_off(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) {
|
282
|
292
|
if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_off"), x, y);
|
283
|
|
- led_set(x, y, false);
|
|
293
|
+ led_set(x, y, false, rcm);
|
284
|
294
|
}
|
285
|
295
|
|
286
|
|
-void Max7219::led_toggle(const uint8_t x, const uint8_t y) {
|
|
296
|
+void Max7219::led_toggle(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) {
|
287
|
297
|
if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_toggle"), x, y);
|
288
|
|
- led_set(x, y, !BIT_7219(x, y));
|
|
298
|
+ led_set(x, y, !BIT_7219(x, y), rcm);
|
289
|
299
|
}
|
290
|
300
|
|
291
|
301
|
void Max7219::send_row(const uint8_t row) {
|
|
@@ -448,7 +458,7 @@ void Max7219::register_setup() {
|
448
|
458
|
pulse_load(); // Tell the chips to load the clocked out data
|
449
|
459
|
}
|
450
|
460
|
|
451
|
|
-#ifdef MAX7219_INIT_TEST
|
|
461
|
+#if MAX7219_INIT_TEST
|
452
|
462
|
|
453
|
463
|
uint8_t test_mode = 0;
|
454
|
464
|
millis_t next_patt_ms;
|
|
@@ -536,13 +546,9 @@ void Max7219::init() {
|
536
|
546
|
|
537
|
547
|
register_setup();
|
538
|
548
|
|
539
|
|
- LOOP_LE_N(i, 7) { // Empty registers to turn all LEDs off
|
540
|
|
- led_line[i] = 0x00;
|
541
|
|
- send(max7219_reg_digit0 + i, 0);
|
542
|
|
- pulse_load(); // Tell the chips to load the clocked out data
|
543
|
|
- }
|
|
549
|
+ clear();
|
544
|
550
|
|
545
|
|
- #ifdef MAX7219_INIT_TEST
|
|
551
|
+ #if MAX7219_INIT_TEST
|
546
|
552
|
start_test_pattern();
|
547
|
553
|
#endif
|
548
|
554
|
}
|
|
@@ -554,41 +560,47 @@ void Max7219::init() {
|
554
|
560
|
*/
|
555
|
561
|
|
556
|
562
|
// Apply changes to update a marker
|
557
|
|
-void Max7219::mark16(const uint8_t pos, const uint8_t v1, const uint8_t v2) {
|
|
563
|
+void Max7219::mark16(const uint8_t pos, const uint8_t v1, const uint8_t v2, uint8_t * const rcm/*=nullptr*/) {
|
558
|
564
|
#if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line.
|
559
|
|
- led_off(v1 & 0xF, pos);
|
560
|
|
- led_on(v2 & 0xF, pos);
|
|
565
|
+ led_off(v1 & 0xF, pos, rcm);
|
|
566
|
+ led_on(v2 & 0xF, pos, rcm);
|
561
|
567
|
#elif MAX7219_Y_LEDS > 8 // At least 16 LEDs on the Y-Axis. Use a single column.
|
562
|
|
- led_off(pos, v1 & 0xF);
|
563
|
|
- led_on(pos, v2 & 0xF);
|
|
568
|
+ led_off(pos, v1 & 0xF, rcm);
|
|
569
|
+ led_on(pos, v2 & 0xF, rcm);
|
564
|
570
|
#else // Single 8x8 LED matrix. Use two lines to get 16 LEDs.
|
565
|
|
- led_off(v1 & 0x7, pos + (v1 >= 8));
|
566
|
|
- led_on(v2 & 0x7, pos + (v2 >= 8));
|
|
571
|
+ led_off(v1 & 0x7, pos + (v1 >= 8), rcm);
|
|
572
|
+ led_on(v2 & 0x7, pos + (v2 >= 8), rcm);
|
567
|
573
|
#endif
|
568
|
574
|
}
|
569
|
575
|
|
570
|
576
|
// Apply changes to update a tail-to-head range
|
571
|
|
-void Max7219::range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh) {
|
|
577
|
+void Max7219::range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh,
|
|
578
|
+ const uint8_t nh, uint8_t * const rcm/*=nullptr*/) {
|
572
|
579
|
#if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line.
|
573
|
580
|
if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF)
|
574
|
|
- led_off(n & 0xF, y);
|
|
581
|
+ led_off(n & 0xF, y, rcm);
|
575
|
582
|
if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF)
|
576
|
|
- led_on(n & 0xF, y);
|
|
583
|
+ led_on(n & 0xF, y, rcm);
|
577
|
584
|
#elif MAX7219_Y_LEDS > 8 // At least 16 LEDs on the Y-Axis. Use a single column.
|
578
|
585
|
if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF)
|
579
|
|
- led_off(y, n & 0xF);
|
|
586
|
+ led_off(y, n & 0xF, rcm);
|
580
|
587
|
if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF)
|
581
|
|
- led_on(y, n & 0xF);
|
|
588
|
+ led_on(y, n & 0xF, rcm);
|
582
|
589
|
#else // Single 8x8 LED matrix. Use two lines to get 16 LEDs.
|
583
|
590
|
if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF)
|
584
|
|
- led_off(n & 0x7, y + (n >= 8));
|
|
591
|
+ led_off(n & 0x7, y + (n >= 8), rcm);
|
585
|
592
|
if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF)
|
586
|
|
- led_on(n & 0x7, y + (n >= 8));
|
|
593
|
+ led_on(n & 0x7, y + (n >= 8), rcm);
|
587
|
594
|
#endif
|
588
|
595
|
}
|
589
|
596
|
|
590
|
597
|
// Apply changes to update a quantity
|
591
|
|
-void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv) {
|
|
598
|
+void Max7219::quantity(const uint8_t pos, const uint8_t ov, const uint8_t nv, uint8_t * const rcm/*=nullptr*/) {
|
|
599
|
+ for (uint8_t i = _MIN(nv, ov); i < _MAX(nv, ov); i++)
|
|
600
|
+ led_set(i, pos, nv >= ov, rcm);
|
|
601
|
+}
|
|
602
|
+
|
|
603
|
+void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv, uint8_t * const rcm/*=nullptr*/) {
|
592
|
604
|
for (uint8_t i = _MIN(nv, ov); i < _MAX(nv, ov); i++)
|
593
|
605
|
led_set(
|
594
|
606
|
#if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line.
|
|
@@ -599,6 +611,7 @@ void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv)
|
599
|
611
|
i >> 1, pos + (i & 1)
|
600
|
612
|
#endif
|
601
|
613
|
, nv >= ov
|
|
614
|
+ , rcm
|
602
|
615
|
);
|
603
|
616
|
}
|
604
|
617
|
|
|
@@ -636,16 +649,20 @@ void Max7219::idle_tasks() {
|
636
|
649
|
register_setup();
|
637
|
650
|
}
|
638
|
651
|
|
639
|
|
- #ifdef MAX7219_INIT_TEST
|
|
652
|
+ #if MAX7219_INIT_TEST
|
640
|
653
|
if (test_mode) {
|
641
|
654
|
run_test_pattern();
|
642
|
655
|
return;
|
643
|
656
|
}
|
644
|
657
|
#endif
|
645
|
658
|
|
|
659
|
+ // suspend updates and record which lines have changed for batching later
|
|
660
|
+ suspended++;
|
|
661
|
+ uint8_t row_change_mask = 0x00;
|
|
662
|
+
|
646
|
663
|
#if ENABLED(MAX7219_DEBUG_PRINTER_ALIVE)
|
647
|
664
|
if (do_blink) {
|
648
|
|
- led_toggle(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1);
|
|
665
|
+ led_toggle(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1, &row_change_mask);
|
649
|
666
|
next_blink = ms + 1000;
|
650
|
667
|
}
|
651
|
668
|
#endif
|
|
@@ -655,7 +672,7 @@ void Max7219::idle_tasks() {
|
655
|
672
|
static int16_t last_head_cnt = 0xF, last_tail_cnt = 0xF;
|
656
|
673
|
|
657
|
674
|
if (last_head_cnt != head || last_tail_cnt != tail) {
|
658
|
|
- range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head);
|
|
675
|
+ range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head, &row_change_mask);
|
659
|
676
|
last_head_cnt = head;
|
660
|
677
|
last_tail_cnt = tail;
|
661
|
678
|
}
|
|
@@ -665,7 +682,7 @@ void Max7219::idle_tasks() {
|
665
|
682
|
#ifdef MAX7219_DEBUG_PLANNER_HEAD
|
666
|
683
|
static int16_t last_head_cnt = 0x1;
|
667
|
684
|
if (last_head_cnt != head) {
|
668
|
|
- mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head);
|
|
685
|
+ mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head, &row_change_mask);
|
669
|
686
|
last_head_cnt = head;
|
670
|
687
|
}
|
671
|
688
|
#endif
|
|
@@ -673,7 +690,7 @@ void Max7219::idle_tasks() {
|
673
|
690
|
#ifdef MAX7219_DEBUG_PLANNER_TAIL
|
674
|
691
|
static int16_t last_tail_cnt = 0x1;
|
675
|
692
|
if (last_tail_cnt != tail) {
|
676
|
|
- mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail);
|
|
693
|
+ mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail, &row_change_mask);
|
677
|
694
|
last_tail_cnt = tail;
|
678
|
695
|
}
|
679
|
696
|
#endif
|
|
@@ -684,11 +701,26 @@ void Max7219::idle_tasks() {
|
684
|
701
|
static int16_t last_depth = 0;
|
685
|
702
|
const int16_t current_depth = (head - tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1) & 0xF;
|
686
|
703
|
if (current_depth != last_depth) {
|
687
|
|
- quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth);
|
|
704
|
+ quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth, &row_change_mask);
|
688
|
705
|
last_depth = current_depth;
|
689
|
706
|
}
|
690
|
707
|
#endif
|
691
|
708
|
|
|
709
|
+ #ifdef MAX7219_DEBUG_PROFILE
|
|
710
|
+ static uint8_t last_time_fraction = 0;
|
|
711
|
+ const uint8_t current_time_fraction = (uint16_t(CodeProfiler::get_time_fraction()) * MAX7219_NUMBER_UNITS + 8) / 16;
|
|
712
|
+ if (current_time_fraction != last_time_fraction) {
|
|
713
|
+ quantity(MAX7219_DEBUG_PROFILE, last_time_fraction, current_time_fraction, &row_change_mask);
|
|
714
|
+ last_time_fraction = current_time_fraction;
|
|
715
|
+ }
|
|
716
|
+ #endif
|
|
717
|
+
|
|
718
|
+ // batch line updates
|
|
719
|
+ suspended--;
|
|
720
|
+ if (!suspended)
|
|
721
|
+ LOOP_L_N(i, 8) if (row_change_mask & _BV(i))
|
|
722
|
+ refresh_line(i);
|
|
723
|
+
|
692
|
724
|
// After resume() automatically do a refresh()
|
693
|
725
|
if (suspended == 0x80) {
|
694
|
726
|
suspended = 0;
|