]> the.earth.li Git - esp8266-clock.git/blob - max7219.c
Update for SDK 3.0.4
[esp8266-clock.git] / max7219.c
1 /*
2  * Copyright 2017 Jonathan McDowell <noodles@earth.li>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include <stdint.h>
18 #include <stdlib.h>
19
20 #include <ets_sys.h>
21 #include <osapi.h>
22 #include <os_type.h>
23 #include <gpio.h>
24
25 #include "max7219.h"
26 #include "spi.h"
27
28 /* This is a small 8x4 font */
29 #include "font-atari.h"
30
31 /* The number of 8x8 displays we have daisy chained together */
32 #define MAX7219_WIDTH 4
33
34 enum max7129_regs {
35         NOOP = 0,
36         ROW7 = 1,
37         ROW6 = 2,
38         ROW5 = 3,
39         ROW4 = 4,
40         ROW3 = 5,
41         ROW2 = 6,
42         ROW1 = 7,
43         ROW0 = 8,
44         DECODEMODE = 9,
45         INTENSITY = 10,
46         SCANLIMIT = 11,
47         SHUTDOWN = 12,
48         DISPLAYTEST = 15,
49 };
50
51 struct max7219_ctx {
52         unsigned int width;
53         unsigned int cs;
54         uint8_t buf[8 * MAX7219_WIDTH];
55 };
56
57 /* Runtime context */
58 static struct max7219_ctx ctx;
59
60 static void ICACHE_FLASH_ATTR max7219_write_reg(uint8_t reg, uint8_t data)
61 {
62         int block;
63
64         /* Set CS low */
65         gpio_output_set(0, ctx.cs, ctx.cs, 0);
66         for (block = 0; block < ctx.width; block++) {
67                 spi_write(1, &reg);
68                 spi_write(1, &data);
69         }
70         /* Set CS high to latch data into MAX7219 */
71         gpio_output_set(ctx.cs, 0, ctx.cs, 0);
72         ets_delay_us(10);
73 }
74
75 void ICACHE_FLASH_ATTR max7219_set_pixel(unsigned int x, unsigned int y,
76         bool set)
77 {
78         unsigned int block;
79
80         block = x & 0x38;
81         x = x & 7;
82
83         if (set) {
84                 ctx.buf[y + block] |= 1 << x;
85         } else {
86                 ctx.buf[y + block] &= ~(1 << x);
87         }
88 }
89
90 void ICACHE_FLASH_ATTR max7219_blit(unsigned int x, unsigned int y,
91         const uint8_t *data, unsigned int width, unsigned int height)
92 {
93         unsigned int block = x & 0x38;
94         unsigned int left_shift = x & 7;
95         bool twoblocks = ((left_shift + width) > 8) &&
96                 ((x + width) < (ctx.width * 8));
97         unsigned int right_shift;
98         unsigned int row;
99
100         if (block >= (ctx.width << 3)) {
101                 /* We're off the right hand side; do nothing */
102                 return;
103         }
104
105         if (twoblocks) {
106                 if (block > (ctx.width << 3)) {
107                         /* 2nd block is off the edge; ignore it */
108                         twoblocks = false;
109                 } else {
110                         right_shift = (8 - left_shift);
111                 }
112         }
113
114         for (row = 0; row < height; row++)
115         {
116                 if ((y + row) > 7) {
117                         break;
118                 }
119                 ctx.buf[y + row + block] |= ((data[row] << left_shift) & 0xFF);
120                 if (twoblocks) {
121                         ctx.buf[y + row + (block + 8)] |=
122                                 (data[row] >> right_shift);
123                 }
124         }
125 }
126
127 void ICACHE_FLASH_ATTR max7219_clear(void)
128 {
129         int i;
130
131         for (i = 0; i < ctx.width * 8;i++)
132                 ctx.buf[i] = 0;
133 }
134
135 void ICACHE_FLASH_ATTR max7219_show(void)
136 {
137         int y, block;
138         uint8_t data[2];
139
140         for (y = 0; y < 8; y++) {
141                 /* Set CS low */
142                 gpio_output_set(0, ctx.cs, ctx.cs, 0);
143                 for (block = ctx.width - 1; block >= 0; block--) {
144                         data[0] = 8 - y;                        /* Row reg */
145                         data[1] = ctx.buf[y + (block << 3)];    /* Pixel val */
146                         spi_write(2, data);
147                 }
148                 /* Set CS high to latch data into MAX7219 */
149                 gpio_output_set(ctx.cs, 0, ctx.cs, 0);
150                 ets_delay_us(10);
151         }
152 }
153
154 void ICACHE_FLASH_ATTR max7219_print(const char *str)
155 {
156         int x = 0;
157         unsigned char cur;
158
159         while ((cur = (unsigned char) *str++) && x < (ctx.width * 8)) {
160                 if ((cur > 31) && (cur < 127)) {
161                         cur -= 32;
162                         max7219_blit(x, 0, font[cur].bitmap,
163                                 font[cur].width, 8);
164                         x += font[cur].width + 1;
165                 }
166         }
167 }
168
169 void ICACHE_FLASH_ATTR max7219_init(unsigned int cs)
170 {
171         ctx.width = MAX7219_WIDTH;
172         ctx.cs = cs;
173
174         max7219_write_reg(SHUTDOWN, 0);
175         max7219_write_reg(DISPLAYTEST, 0);
176         max7219_write_reg(SCANLIMIT, 7);
177         max7219_write_reg(DECODEMODE, 0);
178         max7219_write_reg(INTENSITY, 0);
179         max7219_write_reg(SHUTDOWN, 1);
180
181         max7219_clear();
182         max7219_show();
183 }