Skip to content

Commit a53d78b

Browse files
Roxy-3Drpls
authored andcommitted
Add Max7219 LED Matrix Debug Support (MarlinFirmware#7563)
* Add Max7219 LED Matrix Debug Support The Max7219 8x8 LED Matrix's are very helpful for debugging new code. And for that matter, just trying to maximize printer settings without causing stuttering. The displays are very inexpensive (under $2.00 with shipping) and provide a lot of help when trying to debug complicated code. * Try to keep Makefile up to date.
1 parent 1e13470 commit a53d78b

File tree

32 files changed

+1090
-5
lines changed

32 files changed

+1090
-5
lines changed

Marlin/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ CXXSRC = WMath.cpp WString.cpp Print.cpp Marlin_main.cpp \
310310
temperature.cpp cardreader.cpp configuration_store.cpp \
311311
watchdog.cpp SPI.cpp servo.cpp Tone.cpp ultralcd.cpp digipot_mcp4451.cpp \
312312
dac_mcp4728.cpp vector_3.cpp least_squares_fit.cpp endstops.cpp stopwatch.cpp utility.cpp \
313-
printcounter.cpp nozzle.cpp serial.cpp gcode.cpp
313+
printcounter.cpp nozzle.cpp serial.cpp gcode.cpp Max7219_Debug_LEDs.cpp
314314
ifeq ($(NEOPIXEL), 1)
315315
CXXSRC += Adafruit_NeoPixel.cpp
316316
endif

Marlin/Marlin_main.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@
279279
#include "watchdog.h"
280280
#endif
281281

282+
#if ENABLED(MAX7219_DEBUG)
283+
#include "Max7219_Debug_LEDs.h"
284+
#endif
285+
282286
#if ENABLED(NEOPIXEL_RGBW_LED)
283287
#include <Adafruit_NeoPixel.h>
284288
#endif
@@ -10292,7 +10296,7 @@ inline void invalid_extruder_error(const uint8_t e) {
1029210296
SET_OUTPUT(FANMUX1_PIN);
1029310297
#if PIN_EXISTS(FANMUX2)
1029410298
SET_OUTPUT(FANMUX2_PIN);
10295-
#endif
10299+
#endif
1029610300
#endif
1029710301
fanmux_switch(0);
1029810302
}
@@ -13201,6 +13205,10 @@ void idle(
1320113205
bool no_stepper_sleep/*=false*/
1320213206
#endif
1320313207
) {
13208+
#if ENABLED(MAX7219_DEBUG)
13209+
Max7219_idle_tasks();
13210+
#endif // MAX7219_DEBUG
13211+
1320413212
lcd_update();
1320513213

1320613214
host_keepalive();
@@ -13316,6 +13324,10 @@ void stop() {
1331613324
*/
1331713325
void setup() {
1331813326

13327+
#if ENABLED(MAX7219_DEBUG)
13328+
Max7219_init();
13329+
#endif
13330+
1331913331
#ifdef DISABLE_JTAG
1332013332
// Disable JTAG on AT90USB chips to free up pins for IO
1332113333
MCUCR = 0x80;
@@ -13467,11 +13479,11 @@ void setup() {
1346713479
SET_OUTPUT(E_MUX1_PIN);
1346813480
SET_OUTPUT(E_MUX2_PIN);
1346913481
#endif
13470-
13482+
1347113483
#if HAS_FANMUX
1347213484
fanmux_init();
1347313485
#endif
13474-
13486+
1347513487
lcd_init();
1347613488

1347713489
#ifndef CUSTOM_BOOTSCREEN_TIMEOUT

Marlin/Max7219_Debug_LEDs.cpp

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
/**
2+
* Marlin 3D Printer Firmware
3+
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4+
*
5+
* Based on Sprinter and grbl.
6+
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License as published by
10+
* the Free Software Foundation, either version 3 of the License, or
11+
* (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
23+
/**
24+
* This module is normally not enabled. It can be enabled to facilitate
25+
* the display of extra debug information during code development.
26+
* It assumes the existance of a Max7219 LED Matrix. A suitable
27+
* device can be obtained on eBay similar to this: http://www.ebay.com/itm/191781645249
28+
* for under $2.00 including shipping.
29+
*
30+
* Just connect up +5v and Gnd to give it power. And then 3 wires declared in the
31+
* #define's below. Actual pin assignments can be changed in MAX7219_DEBUG section
32+
* of configuration_adv.h
33+
*
34+
* #define Max7219_clock 77
35+
* #define Max7219_data_in 78
36+
* #define Max7219_load 79
37+
*
38+
* First call Max7219_init() and then there are a number of support functions available
39+
* to control the LED's in the 8x8 grid.
40+
*
41+
* void Max7219_init();
42+
* void Max7219_PutByte(uint8_t data);
43+
* void Max7219(uint8_t reg, uint8_t data);
44+
* void Max7219_LED_On( int8_t row, int8_t col);
45+
* void Max7219_LED_Off( int8_t row, int8_t col);
46+
* void Max7219_LED_Toggle( int8_t row, int8_t col);
47+
* void Max7219_Clear_Row( int8_t row);
48+
* void Max7219_Clear_Column( int8_t col);
49+
*/
50+
51+
52+
#include "Marlin.h"
53+
54+
#if ENABLED(MAX7219_DEBUG)
55+
#include "planner.h"
56+
#include "stepper.h"
57+
#include "Max7219_Debug_LEDs.h"
58+
59+
static uint8_t LEDs[8] = {0};
60+
61+
void Max7219_PutByte(uint8_t data) {
62+
uint8_t i = 8;
63+
while(i > 0) {
64+
digitalWrite( Max7219_clock, LOW); // tick
65+
if (data & 0x80) // check bit
66+
digitalWrite(Max7219_data_in,HIGH); // send 1
67+
else
68+
digitalWrite(Max7219_data_in,LOW); // send 0
69+
digitalWrite(Max7219_clock, HIGH); // tock
70+
data = data << 0x01;
71+
--i; // move to lesser bit
72+
}
73+
}
74+
75+
void Max7219( uint8_t reg, uint8_t data) {
76+
digitalWrite(Max7219_load, LOW); // begin
77+
Max7219_PutByte(reg); // specify register
78+
Max7219_PutByte(data); // put data
79+
digitalWrite(Max7219_load, LOW); // and tell the chip to load the data
80+
digitalWrite(Max7219_load,HIGH);
81+
}
82+
83+
void Max7219_LED_On( int8_t row, int8_t col) {
84+
int x_index;
85+
if ( row>=8 || row<0 || col>=8 || col<0)
86+
return;
87+
if ( LEDs[row] & (0x01<<col) ) // if LED is already on, just leave
88+
return;
89+
90+
LEDs[row] |= (0x01<<col);
91+
x_index = 7-row;
92+
Max7219( x_index+1, LEDs[row] );
93+
}
94+
95+
void Max7219_LED_Off( int8_t row, int8_t col) {
96+
int x_index;
97+
if ( row>=8 || row<0 || col>=8 || col<0)
98+
return;
99+
if ( !(LEDs[row] & (0x01<<col)) ) // if LED is already off, just leave
100+
return;
101+
102+
LEDs[row] ^= (0x01<<col);
103+
x_index = 7-row;
104+
Max7219( x_index+1, LEDs[row] );
105+
}
106+
107+
void Max7219_LED_Toggle( int8_t row, int8_t col) {
108+
if ( row>=8 || row<0 || col>=8 || col<0)
109+
return;
110+
if ( (LEDs[row] & (0x01<<col)) )
111+
Max7219_LED_Off( row, col);
112+
else
113+
Max7219_LED_On( row, col);
114+
}
115+
116+
void Max7219_Clear_Column( int8_t col) {
117+
int x_index;
118+
if ( col>=8 || col<0 )
119+
return;
120+
LEDs[col] = 0;
121+
x_index = 7-col;
122+
Max7219( x_index+1, LEDs[col] );
123+
}
124+
125+
void Max7219_Clear_Row( int8_t row) {
126+
int c;
127+
if ( row>=8 || row<0 )
128+
return;
129+
130+
for(c=0; c<8; c++)
131+
Max7219_LED_Off( c, row);
132+
}
133+
134+
void Max7219_Set_Row( int8_t row, uint8_t val) {
135+
int b;
136+
137+
if ( row<0 || row>7 )
138+
return;
139+
140+
if ( val<0 || val>255 )
141+
return;
142+
143+
for(b=0; b<8; b++)
144+
if ( val & (0x01 << b) )
145+
Max7219_LED_On( 7-b, row);
146+
else
147+
Max7219_LED_Off( 7-b, row);
148+
}
149+
150+
void Max7219_Set_Column( int8_t col, uint8_t val) {
151+
int x_index;
152+
153+
if ( col>=8 || col<0 )
154+
return;
155+
156+
if ( val<0 || val>255 )
157+
return;
158+
159+
LEDs[col] = val;
160+
x_index = 7-col;
161+
Max7219( x_index+1, LEDs[col] );
162+
}
163+
164+
165+
void Max7219_init() {
166+
int i, x, y;
167+
168+
pinMode(Max7219_data_in, OUTPUT);
169+
pinMode(Max7219_clock, OUTPUT);
170+
pinMode(Max7219_load, OUTPUT);
171+
172+
digitalWrite(Max7219_load, HIGH);
173+
174+
//initiation of the max 7219
175+
Max7219(max7219_reg_scanLimit, 0x07);
176+
Max7219(max7219_reg_decodeMode, 0x00); // using an led matrix (not digits)
177+
Max7219(max7219_reg_shutdown, 0x01); // not in shutdown mode
178+
Max7219(max7219_reg_displayTest, 0x00); // no display test
179+
Max7219(max7219_reg_intensity, 0x01 & 0x0f); // the first 0x0f is the value you can set
180+
// range: 0x00 to 0x0f
181+
for (i=0; i<8; i++) { // empty registers, turn all LEDs off
182+
LEDs[i] = 0x00;
183+
Max7219(i+1,0);
184+
}
185+
186+
for(x=0; x<8; x++) { // Do an austetically pleasing pattern to fully test
187+
for(y=0; y<8; y++) { // the Max7219 module and LED's. First, turn them
188+
Max7219_LED_On( x, y); // all on.
189+
delay(3);
190+
}
191+
}
192+
for(x=0; x<8; x++) { // Now, turn them all off.
193+
for(y=0; y<8; y++) {
194+
Max7219_LED_Off( x, y);
195+
delay(3); // delay() is OK here. Max7219_init() is only called from
196+
} // setup() and nothing is running yet.
197+
}
198+
199+
delay(150);
200+
201+
for(x=7; x>=0; x--) { // Now, do the same thing from the opposite direction
202+
for(y=0; y<8; y++) {
203+
Max7219_LED_On( x, y);
204+
delay(2);
205+
}
206+
}
207+
208+
for(x=7; x>=0; x--) {
209+
for(y=0; y<8; y++) {
210+
Max7219_LED_Off( x, y);
211+
delay(2);
212+
}
213+
}
214+
}
215+
216+
/*
217+
* These are sample debug features to demonstrate the usage of the 8x8 LED Matrix for debug purposes.
218+
* There is very little CPU burden added to the system by displaying information within the idle()
219+
* task.
220+
*
221+
* But with that said, if your debugging can be facilitated by making calls into the library from
222+
* other places in the code, feel free to do it. The CPU burden for a few calls to toggle an LED
223+
* or clear a row is not very significant.
224+
*/
225+
void Max7219_idle_tasks() {
226+
#ifdef MAX7219_DEBUG_PRINTER_ALIVE
227+
static int debug_cnt=0;
228+
if (debug_cnt++ > 100) {
229+
Max7219_LED_Toggle(7,7);
230+
debug_cnt = 0;
231+
}
232+
#endif
233+
234+
#ifdef MAX7219_DEBUG_STEPPER_HEAD
235+
Max7219_Clear_Row(MAX7219_DEBUG_STEPPER_HEAD);
236+
Max7219_Clear_Row(MAX7219_DEBUG_STEPPER_HEAD+1);
237+
if ( planner.block_buffer_head < 8)
238+
Max7219_LED_On( planner.block_buffer_head, MAX7219_DEBUG_STEPPER_HEAD);
239+
else
240+
Max7219_LED_On( planner.block_buffer_head-8, MAX7219_DEBUG_STEPPER_HEAD+1);
241+
#endif
242+
243+
#ifdef MAX7219_DEBUG_STEPPER_TAIL
244+
Max7219_Clear_Row(MAX7219_DEBUG_STEPPER_TAIL);
245+
Max7219_Clear_Row(MAX7219_DEBUG_STEPPER_TAIL+1);
246+
if ( planner.block_buffer_tail < 8)
247+
Max7219_LED_On( planner.block_buffer_tail, MAX7219_DEBUG_STEPPER_TAIL );
248+
else
249+
Max7219_LED_On( planner.block_buffer_tail-8, MAX7219_DEBUG_STEPPER_TAIL+1 );
250+
#endif
251+
252+
#ifdef MAX7219_DEBUG_STEPPER_QUEUE
253+
static int16_t last_depth=0, current_depth;
254+
uint8_t i;
255+
current_depth = planner.block_buffer_head - planner.block_buffer_tail;
256+
if (current_depth != last_depth) { // usually, no update will be needed.
257+
258+
if ( current_depth < 0 )
259+
current_depth += BLOCK_BUFFER_SIZE;
260+
261+
if ( current_depth >= BLOCK_BUFFER_SIZE )
262+
current_depth = BLOCK_BUFFER_SIZE;
263+
264+
if ( current_depth > 16 ) // if the BLOCK_BUFFER_SIZE is greater than 16 two lines
265+
current_depth = 16; // of LED's is enough to see if the buffer is draining
266+
267+
if ( current_depth < last_depth )
268+
for(i=current_depth; i<=last_depth; i++) { // clear the highest order LED's
269+
if ( i & 1)
270+
Max7219_LED_Off(i>>1, MAX7219_DEBUG_STEPPER_QUEUE+1);
271+
else
272+
Max7219_LED_Off(i>>1, MAX7219_DEBUG_STEPPER_QUEUE+0);
273+
}
274+
else
275+
for(i=last_depth; i<=current_depth; i++) { // light up the highest order LED's
276+
if ( i & 1)
277+
Max7219_LED_On(i>>1, MAX7219_DEBUG_STEPPER_QUEUE+1);
278+
else
279+
Max7219_LED_On(i>>1, MAX7219_DEBUG_STEPPER_QUEUE+0);
280+
}
281+
last_depth = current_depth;
282+
}
283+
#endif
284+
}
285+
#endif //MAX7219_DEBUG
286+

0 commit comments

Comments
 (0)