add hardware SPI support
[Arduino] / Hub08_LedMatrix / LEDMatrix.cpp
1 /**
2  * LED Matrix library for http://www.seeedstudio.com/depot/ultrathin-16x32-red-led-matrix-panel-p-1582.html
3  * The LED Matrix panel has 32x16 pixels. Several panel can be combined together as a large screen.
4  *
5  * Coordinate & Connection (Arduino -> panel 0 -> panel 1 -> ...)
6  *   (0, 0)                                     (0, 0)
7  *     +--------+--------+--------+               +--------+--------+
8  *     |   5    |    4   |    3   |               |    1   |    0   |
9  *     |        |        |        |               |        |        |<----- Arduino
10  *     +--------+--------+--------+               +--------+--------+
11  *     |   2    |    1   |    0   |                              (64, 16)
12  *     |        |        |        |<----- Arduino
13  *     +--------+--------+--------+
14  *                             (96, 32)
15  *  Copyright (c) 2013 Seeed Technology Inc.
16  *  @auther     Yihui Xiong
17  *  @date       Nov 8, 2013
18  *  @license    MIT
19  */
20
21 #include "LEDMatrix.h"
22 #include "Arduino.h"
23
24 #define USE_SPI 1
25
26 #if USE_SPI
27 #include <SPI.h>
28 #endif
29
30 #if 0
31 #define ASSERT(e)   if (!(e)) { Serial.println(#e); while (1); }
32 #else
33 #define ASSERT(e)
34 #endif
35
36 LEDMatrix::LEDMatrix(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t oe, uint8_t r1, uint8_t stb, uint8_t clk)
37 {
38     this->clk = clk;
39     this->r1 = r1;
40     this->stb = stb;
41     this->oe = oe;
42     this->a = a;
43     this->b = b;
44     this->c = c;
45     this->d = d;
46
47     mask = 0xff;
48     state = 0;
49 #if USE_SPI
50         SPI.begin();
51 #endif
52 }
53
54 void LEDMatrix::begin(uint8_t *displaybuf, uint16_t width, uint16_t height)
55 {
56     ASSERT(0 == (width % 32));
57     ASSERT(0 == (height % 16));
58
59     this->displaybuf = displaybuf;
60     this->width = width;
61     this->height = height;
62
63     pinMode(a, OUTPUT);
64     pinMode(b, OUTPUT);
65     pinMode(c, OUTPUT);
66     pinMode(d, OUTPUT);
67     pinMode(oe, OUTPUT);
68     pinMode(r1, OUTPUT);
69     pinMode(clk, OUTPUT);
70     pinMode(stb, OUTPUT);
71
72     state = 1;
73 }
74
75 void LEDMatrix::drawPoint(uint16_t x, uint16_t y, uint8_t pixel)
76 {
77     ASSERT(width > x);
78     ASSERT(height > y);
79
80     uint8_t *byte = displaybuf + x / 8 + y * width / 8;
81     uint8_t  bit = x % 8;
82
83     if (pixel) {
84         *byte |= 0x80 >> bit;
85     } else {
86         *byte &= ~(0x80 >> bit);
87     }
88 }
89
90 void LEDMatrix::drawRect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t pixel)
91 {
92     for (uint16_t x = x1; x < x2; x++) {
93         for (uint16_t y = y1; y < y2; y++) {
94             drawPoint(x, y, pixel);
95         }
96     }
97 }
98
99 void LEDMatrix::drawImage(uint16_t xoffset, uint16_t yoffset, uint16_t width, uint16_t height, const uint8_t *image)
100 {
101     for (uint16_t y = 0; y < height; y++) {
102         for (uint16_t x = 0; x < width; x++) {
103             const uint8_t *byte = image + (x + y * width) / 8;
104             uint8_t  bit = 7 - x % 8;
105             uint8_t  pixel = (*byte >> bit) & 1;
106
107             drawPoint(x + xoffset, y + yoffset, pixel);
108         }
109     }
110 }
111
112 void LEDMatrix::clear()
113 {
114     uint8_t *ptr = displaybuf;
115     for (uint16_t i = 0; i < (width * height / 8); i++) {
116         *ptr = 0x00;
117         ptr++;
118     }
119 }
120
121 void LEDMatrix::reverse()
122 {
123     mask = ~mask;
124 }
125
126 uint8_t LEDMatrix::isReversed()
127 {
128     return mask;
129 }
130
131 void LEDMatrix::scan()
132 {
133     static uint8_t row = 0;  // from 0 to 15
134
135     if (!state) {
136         return;
137     }
138
139     uint8_t *head = displaybuf + row * (width / 8);
140     for (uint8_t line = 0; line < (height / 16); line++) {
141         uint8_t *ptr = head;
142         head += width * 2;              // width * 16 / 8
143
144         for (uint8_t byte = 0; byte < (width / 8); byte++) {
145             uint8_t pixels = *ptr;
146             ptr++;
147             pixels = pixels ^ mask;     // reverse: mask = 0xff, normal: mask =0x00
148 #if USE_SPI
149                 SPI.transfer(pixels);
150 #else
151             for (uint8_t bit = 0; bit < 8; bit++) {
152                 digitalWrite(clk, LOW);
153                 digitalWrite(r1, pixels & (0x80 >> bit));
154                 digitalWrite(clk, HIGH);
155             }
156 #endif
157         }
158     }
159
160     digitalWrite(oe, HIGH);              // disable display
161
162     // select row
163     digitalWrite(a, (row & 0x01));
164     digitalWrite(b, (row & 0x02));
165     digitalWrite(c, (row & 0x04));
166     digitalWrite(d, (row & 0x08));
167
168     // latch data
169     digitalWrite(stb, LOW);
170     digitalWrite(stb, HIGH);
171     digitalWrite(stb, LOW);
172
173     digitalWrite(oe, LOW);              // enable display
174
175     row = (row + 1) & 0x0F;
176 }
177
178 void LEDMatrix::on()
179 {
180     state = 1;
181 }
182
183 void LEDMatrix::off()
184 {
185     state = 0;
186     digitalWrite(oe, HIGH);
187 }