-
Notifications
You must be signed in to change notification settings - Fork 0
/
Max72xxPanel.cpp
195 lines (155 loc) · 5.39 KB
/
Max72xxPanel.cpp
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
/******************************************************************
A library for controling a set of 8x8 LEDs with a MAX7219 or
MAX7221 displays.
This is a plugin for Adafruit's core graphics library, providing
basic graphics primitives (points, lines, circles, etc.).
You need to download and install Adafruit_GFX to use this library.
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source hardware
by purchasing products from Adafruit!
Written by Mark Ruys.
BSD license, check license.txt for more information.
All text above must be included in any redistribution.
******************************************************************/
#include <Adafruit_GFX.h>
#include "Max72xxPanel.h"
#include <SPI.h>
// The opcodes for the MAX7221 and MAX7219
#define OP_NOOP 0
#define OP_DIGIT0 1
#define OP_DIGIT1 2
#define OP_DIGIT2 3
#define OP_DIGIT3 4
#define OP_DIGIT4 5
#define OP_DIGIT5 6
#define OP_DIGIT6 7
#define OP_DIGIT7 8
#define OP_DECODEMODE 9
#define OP_INTENSITY 10
#define OP_SCANLIMIT 11
#define OP_SHUTDOWN 12
#define OP_DISPLAYTEST 15
Max72xxPanel::Max72xxPanel(byte csPin, byte hDisplays, byte vDisplays) : Adafruit_GFX(hDisplays << 3, vDisplays << 3) {
Max72xxPanel::SPI_CS = csPin;
byte displays = hDisplays * vDisplays;
Max72xxPanel::hDisplays = hDisplays;
Max72xxPanel::bitmapSize = displays << 3;
Max72xxPanel::bitmap = (byte*)malloc(bitmapSize);
Max72xxPanel::matrixRotation = (byte*)malloc(displays);
Max72xxPanel::matrixPosition = (byte*)malloc(displays);
for ( byte display = 0; display < displays; display++ ) {
matrixPosition[display] = display;
matrixRotation[display] = 0;
}
SPI.begin();
//SPI.setBitOrder(MSBFIRST);
//SPI.setDataMode(SPI_MODE0);
pinMode(SPI_CS, OUTPUT);
// Clear the screen
fillScreen(0);
// Make sure we are not in test mode
spiTransfer(OP_DISPLAYTEST, 0);
// We need the multiplexer to scan all segments
spiTransfer(OP_SCANLIMIT, 7);
// We don't want the multiplexer to decode segments for us
spiTransfer(OP_DECODEMODE, 0);
// Enable display
shutdown(false);
// Set the brightness to a medium value
setIntensity(7);
}
void Max72xxPanel::setPosition(byte display, byte x, byte y) {
matrixPosition[x + hDisplays * y] = display;
}
void Max72xxPanel::setRotation(byte display, byte rotation) {
matrixRotation[display] = rotation;
}
void Max72xxPanel::setRotation(uint8_t rotation) {
Adafruit_GFX::setRotation(rotation);
}
void Max72xxPanel::shutdown(boolean b) {
spiTransfer(OP_SHUTDOWN, b ? 0 : 1);
}
void Max72xxPanel::setIntensity(byte intensity) {
spiTransfer(OP_INTENSITY, intensity);
}
void Max72xxPanel::fillScreen(uint16_t color) {
memset(bitmap, color ? 0xff : 0, bitmapSize);
}
void Max72xxPanel::drawPixel(int16_t xx, int16_t yy, uint16_t color) {
// Operating in bytes is faster and takes less code to run. We don't
// need values above 200, so switch from 16 bit ints to 8 bit unsigned
// ints (bytes).
// Keep xx as int16_t so fix 16 panel limit
int16_t x = xx;
byte y = yy;
byte tmp;
if ( rotation ) {
// Implement Adafruit's rotation.
if ( rotation >= 2 ) { // rotation == 2 || rotation == 3
x = _width - 1 - x;
}
if ( rotation == 1 || rotation == 2 ) { // rotation == 1 || rotation == 2
y = _height - 1 - y;
}
if ( rotation & 1 ) { // rotation == 1 || rotation == 3
tmp = x; x = y; y = tmp;
}
}
if ( x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT ) {
// Ignore pixels outside the canvas.
return;
}
// Translate the x, y coordinate according to the layout of the
// displays. They can be ordered and rotated (0, 90, 180, 270).
byte display = matrixPosition[(x >> 3) + hDisplays * (y >> 3)];
x &= 0b111;
y &= 0b111;
byte r = matrixRotation[display];
if ( r >= 2 ) { // 180 or 270 degrees
x = 7 - x;
}
if ( r == 1 || r == 2 ) { // 90 or 180 degrees
y = 7 - y;
}
if ( r & 1 ) { // 90 or 270 degrees
tmp = x; x = y; y = tmp;
}
byte d = display / hDisplays;
x += (display - d * hDisplays) << 3; // x += (display % hDisplays) * 8
y += d << 3; // y += (display / hDisplays) * 8
// Update the color bit in our bitmap buffer.
byte *ptr = bitmap + x + WIDTH * (y >> 3);
byte val = 1 << (y & 0b111);
if ( color ) {
*ptr |= val;
}
else {
*ptr &= ~val;
}
}
void Max72xxPanel::write() {
// Send the bitmap buffer to the displays.
for ( byte row = OP_DIGIT7; row >= OP_DIGIT0; row-- ) {
spiTransfer(row);
}
}
void Max72xxPanel::spiTransfer(byte opcode, byte data) {
// If opcode > OP_DIGIT7, send the opcode and data to all displays.
// If opcode <= OP_DIGIT7, display the column with data in our buffer for all displays.
// We do not support (nor need) to use the OP_NOOP opcode.
// Enable the line
digitalWrite(SPI_CS, LOW);
// Now shift out the data, two bytes per display. The first byte is the opcode,
// the second byte the data.
byte end = opcode - OP_DIGIT0;
byte start = bitmapSize + end;
do {
start -= 8;
SPI.transfer(opcode);
SPI.transfer(opcode <= OP_DIGIT7 ? bitmap[start] : data);
}
while ( start > end );
// Latch the data onto the display(s)
digitalWrite(SPI_CS, HIGH);
}