Category Archives: EbayCheapies

Ebay Cheapies: Arduino Mega and 8×8 LED Matrix w/MAX7219 + ‘Saleae’ Logic Analyzer

 Ebay Cheapies 001

A couple of my ebay cheap buys have arrived. I have an Arduino Mega for $12, and a 8×8 LED Matrix with a (fake) MAX7219 driver for $3. To test them out, i’ve hooked them both up, and wrote some Arduino code to show what they can do.

I usually don’t use Arduino for Projects, but for testing out some parts it works great! Don’t even have to get my MKII programmer out fo the drawer.

Also as a bonus, my knock off Saleae Logic Anayzler ($10) has arrived. I’ve used it to plot out the logic of shifting the data from the Arduino to the MAX7219.

Not much else to say here, so lets get into some pictures, code, and a video!

MAX7219 kit: Pretty simple setup here, the MAX7219 provides 3 data lines to the arduino, which allows the 8×8 matrix to set which leds are to be lit.

ledmatrix_partsledmatrix

Arduino Mega: The back and front of the Arduino Mega. Amazing value at $10, considering the retail price of the non-clone is like $70. The only difference i could tell is the back of the PCB looks to say ‘ROARD’ instead of ‘BOARD’.

mega_frontmega_reverse

‘Saleae’ Logic Anazlyer: A $10 rip off of the Saleae system. Looks nothing like the quite refined Saleae logic, but does the job quite well. Uses the official software form Saleae. Read somewhere that this can be reconfigured to use the USBee software also, but havn’t had a chance to look at that yet.

saleae_clone03

 

saleae_clone02

 

Here is a screen shot showing the analyzer in use, channel description:

  1. MAX7219 Clock line
  2. MAX7219 Load line
  3. MAX7219 Data line
  4. Custom line to show pushing out an entire 8×8 led update

saleae_logic

Here is the video showing a quick demostration of using the MAX7219 kit and the Arduino Mega

 

And finally, the code for doing this. The MAX7219 code has been ripped from the arduino.cc website. The rotary code is my own, which you can read more about in this post here. This will also work on a standard Arduino (clones available on the net form $8!)

You can also find the lastest version of this code on my SVN repo here.

** RECOMMEND using the above WebSVN link until i sort out my Syntax Highligter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include <Encoder.h>
 
// Delays for certain events in ms
const int ROTARY_DELAY = 100;    // Time between checking for rotary turns
const int BUTTON_DELAY = 800;    // Button debouncing, and repeating
const int FLASH_DELAY = 600;     // How long to flash the entire row after button press
const int CURSOR_DELAY = 200;    // How quickly to flash the cursor led
 
// Pin Assignments
uint8_t rota = 2;
uint8_t rotb = 3;
uint8_t button = 4;
uint8_t dataIn = 5;
uint8_t load = 6;
uint8_t clock = 7;
uint8_t trigger = 12;
 
int maxInUse = 1; 
uint8_t x = 0;
 
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;
 
 
Encoder knobLeft(rota, rotb);
 
 
char id=0;
 
void putByte(byte data) {
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask){            // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    }else{
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}
 
void maxSingle( byte reg, byte col) {    
//maxSingle is the "easy"  function to use for a     //single max7219
 
  digitalWrite(load, LOW);       // begin    
  putByte(reg);                  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data  
  digitalWrite(load, LOW);       // and load da shit
  digitalWrite(load,HIGH);
}
 
void maxAll (byte reg, byte col) {    // initialize  all  MAX7219's in the system
  int c = 0;
  digitalWrite(load, LOW);  // begin    
  for ( c =1; c<= maxInUse; c++) {
  putByte(reg);  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data
    }
  digitalWrite(load, LOW);
  digitalWrite(load,HIGH);
}
 
void maxOne(byte maxNr, byte reg, byte col) {    
//maxOne is for adressing different MAX7219's,
//whilele having a couple of them cascaded
 
  int c = 0;
  digitalWrite(load, LOW);  // begin    
 
  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means no operation
  }
 
  putByte(reg);  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data
 
  for ( c =maxNr-1; c >= 1; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means no operation
  }
 
  digitalWrite(load, LOW); // and load da shit
  digitalWrite(load,HIGH);
}
 
 
void setup () {
  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);
  pinMode(button, INPUT);
  pinMode(trigger, OUTPUT);
  digitalWrite(button, HIGH);
  digitalWrite(13, LOW);  
  digitalWrite(trigger, LOW);
 
  //initiation of the max 7219
  maxAll(max7219_reg_scanLimit, 0x07);      
  maxAll(max7219_reg_decodeMode, 0x00);  // using an led matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  for (x=1; x<=8; x++) {    // empty registers, turn all LEDs off
    maxAll(x,0);
  }
  maxAll(max7219_reg_intensity, 0x01 & 0x0f);  // the first 0x0f is the value you can set range: 0x00 to 0x0f
 
}  
 
// Value to display a single LED on a row
uint8_t values[9] = {0, 1, 2, 4, 8, 16, 32, 64, 128};
// Array with all rows, indicating which 'value' to show
uint8_t line[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 
// What row we are current working with
uint8_t idx = 0;
// Our delay counters (in ms)
int delayButton = 0;
int delayRotary = ROTARY_DELAY;
int delayFlash = 0;
int delayCursor = CURSOR_DELAY;
int cursorState = 0;
 
// Rotary position, reset after each loop
long pos = 0;
// Do we update the matrix this run?
uint8_t update = 1;
 
void loop () { 
 
  // Flash the row after a button press
  if (delayFlash && idx != 8) {
    maxSingle(idx+1, 255);
 
    if (delayFlash == 1) {
      maxSingle(idx+1, values[line[idx+1]]);
    }
 
    delayFlash--;
    if (delayButton) delayButton--;
 
    return;
  } 
 
  // Check for button press
  if (delayButton) delayButton--;
  if (!digitalRead(4) && delayButton == 0) { 
    if (idx == 8) 
      idx = 0;
     else
       idx++;
     delayButton = BUTTON_DELAY;
     delayFlash = FLASH_DELAY;
  }
 
 
  // Checks for rotary turning, and update
  //  the matrix buffer
  // My rotary encoder had '2 turns' per detent, making
  //  it awkward to move a single position. This is why
  //  the check is for > 1 and < -1 to make it a full detent.
  if (delayRotary) delayRotary--;
  if (delayRotary == 0 && idx != 8) {
    pos = knobLeft.read();
    if (pos > 1) {
      if (line[idx] != 0)
        line[idx]--;
      else
        line[idx] = 8;
      update = 1;
    } else if (pos < -1) {
      if (line[idx] != 8)
        line[idx]++;
      else
        line[idx]= 0;
      update = 1;
    }
 
    if (update) { 
      knobLeft.write(0);
      delayRotary = ROTARY_DELAY;
 
      if (pos) {
        cursorState = 1;
        delayCursor = CURSOR_DELAY;
      }
    }
  }
 
 
  // Toggle the state of the cursor after the
  //  cursor delay (in ms) has been reached
  if (delayCursor) delayCursor--; 
  if (delayCursor == 0 && idx != 8) {
    delayCursor = CURSOR_DELAY;
    cursorState = 1 - cursorState;
    update = 1; 
  }
 
  // Update the matrix only if a change has been made
  if (update) {
    for (x = 0; x<8; x++) {
       if (x == idx) {
         if (cursorState && line[x] != 0)
             maxSingle(x+1, values[line[x]]);
         else
             maxSingle(x+1, 0);
       } else {
         if (line[x] == 0) continue;
         digitalWrite(trigger, HIGH);
         maxSingle(x+1, values[line[x]]);
         digitalWrite(trigger, LOW);
       }
    }
    update = 0;
  }
 
  delay(1);
 
}