]> the.earth.li Git - esp8266-clock.git/blob - max7219.c
Update for SDK 2.2.1 with system compiler
[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 <stdbool.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20
21 #include <ets_sys.h>
22 #include <osapi.h>
23 #include <os_type.h>
24 #include <gpio.h>
25
26 #include "max7219.h"
27 #include "spi.h"
28
29 /* This is a small 8x4 font */
30 #include "font-atari.h"
31
32 /* The number of 8x8 displays we have daisy chained together */
33 #define MAX7219_WIDTH 4
34
35 enum max7129_regs {
36         NOOP = 0,
37         ROW7 = 1,
38         ROW6 = 2,
39         ROW5 = 3,
40         ROW4 = 4,
41         ROW3 = 5,
42         ROW2 = 6,
43         ROW1 = 7,
44         ROW0 = 8,
45         DECODEMODE = 9,
46         INTENSITY = 10,
47         SCANLIMIT = 11,
48         SHUTDOWN = 12,
49         DISPLAYTEST = 15,
50 };
51
52 struct max7219_ctx {
53         unsigned int width;
54         unsigned int cs;
55         uint8_t buf[8 * MAX7219_WIDTH];
56 };
57
58 /* Runtime context */
59 static struct max7219_ctx ctx;
60
61 static void ICACHE_FLASH_ATTR max7219_write_reg(uint8_t reg, uint8_t data)
62 {
63         int block;
64
65         /* Set CS low */
66         gpio_output_set(0, ctx.cs, ctx.cs, 0);
67         for (block = 0; block < ctx.width; block++) {
68                 spi_write(1, &reg);
69                 spi_write(1, &data);
70         }
71         /* Set CS high to latch data into MAX7219 */
72         gpio_output_set(ctx.cs, 0, ctx.cs, 0);
73         ets_delay_us(10);
74 }
75
76 void ICACHE_FLASH_ATTR max7219_set_pixel(unsigned int x, unsigned int y,
77         bool set)
78 {
79         unsigned int block;
80
81         block = x & 0x38;
82         x = x & 7;
83
84         if (set) {
85                 ctx.buf[y + block] |= 1 << x;
86         } else {
87                 ctx.buf[y + block] &= ~(1 << x);
88         }
89 }
90
91 void ICACHE_FLASH_ATTR max7219_blit(unsigned int x, unsigned int y,
92         const uint8_t *data, unsigned int width, unsigned int height)
93 {
94         unsigned int block = x & 0x38;
95         unsigned int left_shift = x & 7;
96         bool twoblocks = ((left_shift + width) > 8) &&
97                 ((x + width) < (ctx.width * 8));
98         unsigned int right_shift;
99         unsigned int row;
100
101         if (block >= (ctx.width << 3)) {
102                 /* We're off the right hand side; do nothing */
103                 return;
104         }
105
106         if (twoblocks) {
107                 if (block > (ctx.width << 3)) {
108                         /* 2nd block is off the edge; ignore it */
109                         twoblocks = false;
110                 } else {
111                         right_shift = (8 - left_shift);
112                 }
113         }
114
115         for (row = 0; row < height; row++)
116         {
117                 if ((y + row) > 7) {
118                         break;
119                 }
120                 ctx.buf[y + row + block] |= ((data[row] << left_shift) & 0xFF);
121                 if (twoblocks) {
122                         ctx.buf[y + row + (block + 8)] |=
123                                 (data[row] >> right_shift);
124                 }
125         }
126 }
127
128 void ICACHE_FLASH_ATTR max7219_clear(void)
129 {
130         int i;
131
132         for (i = 0; i < ctx.width * 8;i++)
133                 ctx.buf[i] = 0;
134 }
135
136 void ICACHE_FLASH_ATTR max7219_show(void)
137 {
138         int y, block;
139         uint8_t data[2];
140
141         for (y = 0; y < 8; y++) {
142                 /* Set CS low */
143                 gpio_output_set(0, ctx.cs, ctx.cs, 0);
144                 for (block = ctx.width - 1; block >= 0; block--) {
145                         data[0] = 8 - y;                        /* Row reg */
146                         data[1] = ctx.buf[y + (block << 3)];    /* Pixel val */
147                         spi_write(2, data);
148                 }
149                 /* Set CS high to latch data into MAX7219 */
150                 gpio_output_set(ctx.cs, 0, ctx.cs, 0);
151                 ets_delay_us(10);
152         }
153 }
154
155 void ICACHE_FLASH_ATTR max7219_print(const char *str)
156 {
157         int x = 0;
158         unsigned char cur;
159
160         while ((cur = (unsigned char) *str++) && x < (ctx.width * 8)) {
161                 if ((cur > 31) && (cur < 127)) {
162                         cur -= 32;
163                         max7219_blit(x, 0, font[cur].bitmap,
164                                 font[cur].width, 8);
165                         x += font[cur].width + 1;
166                 }
167         }
168 }
169
170 void ICACHE_FLASH_ATTR max7219_init(unsigned int cs)
171 {
172         ctx.width = MAX7219_WIDTH;
173         ctx.cs = cs;
174
175         max7219_write_reg(SHUTDOWN, 0);
176         max7219_write_reg(DISPLAYTEST, 0);
177         max7219_write_reg(SCANLIMIT, 7);
178         max7219_write_reg(DECODEMODE, 0);
179         max7219_write_reg(INTENSITY, 0);
180         max7219_write_reg(SHUTDOWN, 1);
181
182         max7219_clear();
183         max7219_show();
184 }