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