ESPHome 2026.1.5
Loading...
Searching...
No Matches
max7219.cpp
Go to the documentation of this file.
1#include "max7219.h"
2#include "esphome/core/hal.h"
4#include "esphome/core/log.h"
5
6namespace esphome::max7219 {
7
8static const char *const TAG = "max7219";
9
10static const uint8_t MAX7219_REGISTER_NOOP = 0x00;
11static const uint8_t MAX7219_REGISTER_DECODE_MODE = 0x09;
12static const uint8_t MAX7219_REGISTER_INTENSITY = 0x0A;
13static const uint8_t MAX7219_REGISTER_SCAN_LIMIT = 0x0B;
14static const uint8_t MAX7219_REGISTER_SHUTDOWN = 0x0C;
15static const uint8_t MAX7219_REGISTER_TEST = 0x0F;
16static const uint8_t MAX7219_UNKNOWN_CHAR = 0b11111111;
17
18const uint8_t MAX7219_ASCII_TO_RAW[95] PROGMEM = {
19 0b00000000, // ' ', ord 0x20
20 0b10110000, // '!', ord 0x21
21 0b00100010, // '"', ord 0x22
22 MAX7219_UNKNOWN_CHAR, // '#', ord 0x23
23 MAX7219_UNKNOWN_CHAR, // '$', ord 0x24
24 0b01001001, // '%', ord 0x25
25 MAX7219_UNKNOWN_CHAR, // '&', ord 0x26
26 0b00000010, // ''', ord 0x27
27 0b01001110, // '(', ord 0x28
28 0b01111000, // ')', ord 0x29
29 0b01000000, // '*', ord 0x2A
30 MAX7219_UNKNOWN_CHAR, // '+', ord 0x2B
31 0b00010000, // ',', ord 0x2C
32 0b00000001, // '-', ord 0x2D
33 0b10000000, // '.', ord 0x2E
34 MAX7219_UNKNOWN_CHAR, // '/', ord 0x2F
35 0b01111110, // '0', ord 0x30
36 0b00110000, // '1', ord 0x31
37 0b01101101, // '2', ord 0x32
38 0b01111001, // '3', ord 0x33
39 0b00110011, // '4', ord 0x34
40 0b01011011, // '5', ord 0x35
41 0b01011111, // '6', ord 0x36
42 0b01110000, // '7', ord 0x37
43 0b01111111, // '8', ord 0x38
44 0b01111011, // '9', ord 0x39
45 0b01001000, // ':', ord 0x3A
46 0b01011000, // ';', ord 0x3B
47 MAX7219_UNKNOWN_CHAR, // '<', ord 0x3C
48 0b00001001, // '=', ord 0x3D
49 MAX7219_UNKNOWN_CHAR, // '>', ord 0x3E
50 0b01100101, // '?', ord 0x3F
51 0b01101111, // '@', ord 0x40
52 0b01110111, // 'A', ord 0x41
53 0b00011111, // 'B', ord 0x42
54 0b01001110, // 'C', ord 0x43
55 0b00111101, // 'D', ord 0x44
56 0b01001111, // 'E', ord 0x45
57 0b01000111, // 'F', ord 0x46
58 0b01011110, // 'G', ord 0x47
59 0b00110111, // 'H', ord 0x48
60 0b00110000, // 'I', ord 0x49
61 0b00111100, // 'J', ord 0x4A
62 MAX7219_UNKNOWN_CHAR, // 'K', ord 0x4B
63 0b00001110, // 'L', ord 0x4C
64 MAX7219_UNKNOWN_CHAR, // 'M', ord 0x4D
65 0b00010101, // 'N', ord 0x4E
66 0b01111110, // 'O', ord 0x4F
67 0b01100111, // 'P', ord 0x50
68 0b11111110, // 'Q', ord 0x51
69 0b00000101, // 'R', ord 0x52
70 0b01011011, // 'S', ord 0x53
71 0b00000111, // 'T', ord 0x54
72 0b00111110, // 'U', ord 0x55
73 0b00111110, // 'V', ord 0x56
74 0b00111111, // 'W', ord 0x57
75 MAX7219_UNKNOWN_CHAR, // 'X', ord 0x58
76 0b00100111, // 'Y', ord 0x59
77 0b01101101, // 'Z', ord 0x5A
78 0b01001110, // '[', ord 0x5B
79 MAX7219_UNKNOWN_CHAR, // '\', ord 0x5C
80 0b01111000, // ']', ord 0x5D
81 MAX7219_UNKNOWN_CHAR, // '^', ord 0x5E
82 0b00001000, // '_', ord 0x5F
83 0b00100000, // '`', ord 0x60
84 0b01110111, // 'a', ord 0x61
85 0b00011111, // 'b', ord 0x62
86 0b00001101, // 'c', ord 0x63
87 0b00111101, // 'd', ord 0x64
88 0b01001111, // 'e', ord 0x65
89 0b01000111, // 'f', ord 0x66
90 0b01011110, // 'g', ord 0x67
91 0b00010111, // 'h', ord 0x68
92 0b00010000, // 'i', ord 0x69
93 0b00111100, // 'j', ord 0x6A
94 MAX7219_UNKNOWN_CHAR, // 'k', ord 0x6B
95 0b00001110, // 'l', ord 0x6C
96 MAX7219_UNKNOWN_CHAR, // 'm', ord 0x6D
97 0b00010101, // 'n', ord 0x6E
98 0b00011101, // 'o', ord 0x6F
99 0b01100111, // 'p', ord 0x70
100 MAX7219_UNKNOWN_CHAR, // 'q', ord 0x71
101 0b00000101, // 'r', ord 0x72
102 0b01011011, // 's', ord 0x73
103 0b00000111, // 't', ord 0x74
104 0b00011100, // 'u', ord 0x75
105 0b00011100, // 'v', ord 0x76
106 MAX7219_UNKNOWN_CHAR, // 'w', ord 0x77
107 MAX7219_UNKNOWN_CHAR, // 'x', ord 0x78
108 0b00100111, // 'y', ord 0x79
109 MAX7219_UNKNOWN_CHAR, // 'z', ord 0x7A
110 0b00110001, // '{', ord 0x7B
111 0b00000110, // '|', ord 0x7C
112 0b00000111, // '}', ord 0x7D
113 0b01100011, // '~', ord 0x7E (degree symbol)
114};
115
117
118MAX7219Component::MAX7219Component(uint8_t num_chips) : num_chips_(num_chips) {
119 this->buffer_ = new uint8_t[this->num_chips_ * 8]; // NOLINT
120 memset(this->buffer_, 0, this->num_chips_ * 8);
121}
122
124 this->spi_setup();
125 // let's assume the user has all 8 digits connected, only important in daisy chained setups anyway
126 this->send_to_all_(MAX7219_REGISTER_SCAN_LIMIT, 7);
127 // let's use our own ASCII -> led pattern encoding
128 this->send_to_all_(MAX7219_REGISTER_DECODE_MODE, 0);
129 this->send_to_all_(MAX7219_REGISTER_INTENSITY, this->intensity_);
130 this->display();
131 // power up
132 this->send_to_all_(MAX7219_REGISTER_TEST, 0);
133 this->send_to_all_(MAX7219_REGISTER_SHUTDOWN, 1);
134}
136 ESP_LOGCONFIG(TAG,
137 "MAX7219:\n"
138 " Number of Chips: %u\n"
139 " Intensity: %u",
140 this->num_chips_, this->intensity_);
141 LOG_PIN(" CS Pin: ", this->cs_);
142 LOG_UPDATE_INTERVAL(this);
143}
144
146 for (uint8_t i = 0; i < 8; i++) {
147 this->enable();
148 for (uint8_t j = 0; j < this->num_chips_; j++) {
149 if (reverse_) {
150 this->send_byte_(8 - i, buffer_[(num_chips_ - j - 1) * 8 + i]);
151 } else {
152 this->send_byte_(8 - i, buffer_[j * 8 + i]);
153 }
154 }
155 this->disable();
156 }
157}
158void MAX7219Component::send_byte_(uint8_t a_register, uint8_t data) {
159 this->write_byte(a_register);
160 this->write_byte(data);
161}
162void MAX7219Component::send_to_all_(uint8_t a_register, uint8_t data) {
163 this->enable();
164 for (uint8_t i = 0; i < this->num_chips_; i++)
165 this->send_byte_(a_register, data);
166 this->disable();
167}
169 if (this->intensity_changed_) {
170 this->send_to_all_(MAX7219_REGISTER_INTENSITY, this->intensity_);
171 this->intensity_changed_ = false;
172 }
173 for (uint8_t i = 0; i < this->num_chips_ * 8; i++)
174 this->buffer_[i] = 0;
175 if (this->writer_.has_value())
176 (*this->writer_)(*this);
177 this->display();
178}
179uint8_t MAX7219Component::print(uint8_t start_pos, const char *str) {
180 uint8_t pos = start_pos;
181 for (; *str != '\0'; str++) {
182 uint8_t data = MAX7219_UNKNOWN_CHAR;
183 if (*str >= ' ' && *str <= '~')
184 data = progmem_read_byte(&MAX7219_ASCII_TO_RAW[*str - ' ']);
185
186 if (data == MAX7219_UNKNOWN_CHAR) {
187 ESP_LOGW(TAG, "Encountered character '%c' with no MAX7219 representation while translating string!", *str);
188 }
189 if (*str == '.') {
190 if (pos != start_pos)
191 pos--;
192 this->buffer_[pos] |= 0b10000000;
193 } else {
194 if (pos >= this->num_chips_ * 8) {
195 ESP_LOGE(TAG, "MAX7219 String is too long for the display!");
196 break;
197 }
198 this->buffer_[pos] = data;
199 }
200 pos++;
201 }
202 return pos - start_pos;
203}
204uint8_t MAX7219Component::print(const char *str) { return this->print(0, str); }
205uint8_t MAX7219Component::printf(uint8_t pos, const char *format, ...) {
206 va_list arg;
207 va_start(arg, format);
208 char buffer[64];
209 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
210 va_end(arg);
211 if (ret > 0)
212 return this->print(pos, buffer);
213 return 0;
214}
215uint8_t MAX7219Component::printf(const char *format, ...) {
216 va_list arg;
217 va_start(arg, format);
218 char buffer[64];
219 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
220 va_end(arg);
221 if (ret > 0)
222 return this->print(buffer);
223 return 0;
224}
225void MAX7219Component::set_writer(max7219_writer_t &&writer) { this->writer_ = writer; }
226void MAX7219Component::set_intensity(uint8_t intensity) {
227 intensity &= 0xF;
228 if (intensity != this->intensity_) {
229 this->intensity_changed_ = true;
230 this->intensity_ = intensity;
231 }
232}
233
234uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, ESPTime time) {
235 char buffer[64];
236 size_t ret = time.strftime(buffer, sizeof(buffer), format);
237 if (ret > 0)
238 return this->print(pos, buffer);
239 return 0;
240}
241uint8_t MAX7219Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
242
243} // namespace esphome::max7219
uint8_t printf(uint8_t pos, const char *format,...) __attribute__((format(printf
Evaluate the printf-format and print the result at the given position.
Definition max7219.cpp:205
void set_intensity(uint8_t intensity)
Definition max7219.cpp:226
uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime
Evaluate the strftime-format and print the result at the given position.
Definition max7219.cpp:234
MAX7219Component(uint8_t num_chips)
Definition max7219.cpp:118
void send_to_all_(uint8_t a_register, uint8_t data)
Definition max7219.cpp:162
uint8_t uint8_t uint8_t print(uint8_t pos, const char *str)
Print str at the given position.
Definition max7219.cpp:179
void set_writer(max7219_writer_t &&writer)
Definition max7219.cpp:225
float get_setup_priority() const override
Definition max7219.cpp:116
void send_byte_(uint8_t a_register, uint8_t data)
Definition max7219.cpp:158
const uint8_t MAX7219_ASCII_TO_RAW[95] PROGMEM
Definition max7219.cpp:18
const float PROCESSOR
For components that use data from sensors like displays.
Definition component.cpp:82
uint8_t progmem_read_byte(const uint8_t *addr)
Definition core.cpp:49
A more user-friendly version of struct tm from time.h.
Definition time.h:16
size_t strftime(char *buffer, size_t buffer_len, const char *format)
Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument.
Definition time.cpp:16
std::string print()