ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
tm1621.cpp
Go to the documentation of this file.
1#include "tm1621.h"
2#include "esphome/core/hal.h"
4#include "esphome/core/log.h"
5
6namespace esphome::tm1621 {
7
8static const char *const TAG = "tm1621";
9
10const uint8_t TM1621_PULSE_WIDTH = 10; // microseconds (Sonoff = 100)
11
12const uint8_t TM1621_SYS_EN = 0x01; // 0b00000001
13const uint8_t TM1621_LCD_ON = 0x03; // 0b00000011
14const uint8_t TM1621_TIMER_DIS = 0x04; // 0b00000100
15const uint8_t TM1621_WDT_DIS = 0x05; // 0b00000101
16const uint8_t TM1621_TONE_OFF = 0x08; // 0b00001000
17const uint8_t TM1621_BIAS = 0x29; // 0b00101001 = LCD 1/3 bias 4 commons option
18const uint8_t TM1621_IRQ_DIS = 0x80; // 0b100x0xxx
19
21
24
25constexpr char TM1621_KCHAR[] PROGMEM = {"0|1|2|3|4|5|6|7|8|9|-| "};
26// 0 1 2 3 4 5 6 7 8 9 - off
27const uint8_t TM1621_DIGIT_ROW[2][12] = {{0x5F, 0x50, 0x3D, 0x79, 0x72, 0x6B, 0x6F, 0x51, 0x7F, 0x7B, 0x20, 0x00},
28 {0xF5, 0x05, 0xB6, 0x97, 0x47, 0xD3, 0xF3, 0x85, 0xF7, 0xD7, 0x02, 0x00}};
29
31 this->cs_pin_->setup(); // OUTPUT
32 this->cs_pin_->digital_write(true);
33 this->data_pin_->setup(); // OUTPUT
34 this->data_pin_->digital_write(true);
35 this->read_pin_->setup(); // OUTPUT
36 this->read_pin_->digital_write(true);
37 this->write_pin_->setup(); // OUTPUT
38 this->write_pin_->digital_write(true);
39
40 this->state_ = 100;
41
42 this->cs_pin_->digital_write(false);
44 this->read_pin_->digital_write(false);
46 this->write_pin_->digital_write(false);
48 this->data_pin_->digital_write(false);
49 delayMicroseconds(TM1621_PULSE_WIDTH);
50 this->data_pin_->digital_write(true);
51
52 for (uint8_t tm1621_command : TM1621_COMMANDS) {
53 this->send_command_(tm1621_command);
54 }
55
56 this->send_address_(0x00);
57 for (uint32_t segment = 0; segment < 16; segment++) {
58 this->send_common_(0);
59 }
60 this->stop_();
61
62 snprintf(this->row_[0], sizeof(this->row_[0]), "----");
63 snprintf(this->row_[1], sizeof(this->row_[1]), "----");
64
65 this->display();
66}
68 ESP_LOGCONFIG(TAG, "TM1621:");
69 LOG_PIN(" CS Pin: ", this->cs_pin_);
70 LOG_PIN(" DATA Pin: ", this->data_pin_);
71 LOG_PIN(" READ Pin: ", this->read_pin_);
72 LOG_PIN(" WRITE Pin: ", this->write_pin_);
73 LOG_UPDATE_INTERVAL(this);
74}
75
77 // memset(this->row, 0, sizeof(this->row));
78 if (this->writer_.has_value())
79 (*this->writer_)(*this);
80 this->display();
81}
82
85
87 this->cs_pin_->digital_write(true); // Stop command sequence
88 delayMicroseconds(TM1621_PULSE_WIDTH / 2);
89 this->data_pin_->digital_write(true); // Reset data
90}
91
93 // Tm1621.row[x] = "text", "----", " " or a number with one decimal like "0.4", "237.5", "123456.7"
94 // "123456.7" will be shown as "9999" being a four digit overflow
95
96 // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1: Row1 '%s', Row2 '%s'"), Tm1621.row[0], Tm1621.row[1]);
97
98 uint8_t buffer[8] = {0}; // TM1621 16-segment 4-bit common buffer
99 char row[4];
100 for (uint32_t j = 0; j < 2; j++) {
101 // 0.4V => " 04", 0.0A => " ", 1234.5V => "1234"
102 uint32_t len = strlen(this->row_[j]);
103 char *dp = nullptr; // Expect number larger than "123"
104 int row_idx = len - 3; // "1234.5"
105 if (len <= 5) { // "----", " ", "0.4", "237.5"
106 dp = strchr(this->row_[j], '.');
107 row_idx = len - 1;
108 } else if (len > 6) { // "12345.6"
109 snprintf(this->row_[j], sizeof(this->row_[j]), "9999");
110 row_idx = 3;
111 }
112 row[3] = (row_idx >= 0) ? this->row_[j][row_idx--] : ' ';
113 if ((row_idx >= 0) && dp) {
114 row_idx--;
115 }
116 row[2] = (row_idx >= 0) ? this->row_[j][row_idx--] : ' ';
117 row[1] = (row_idx >= 0) ? this->row_[j][row_idx--] : ' ';
118 row[0] = (row_idx >= 0) ? this->row_[j][row_idx--] : ' ';
119
120 // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1: Dump%d %4_H"), j +1, row);
121
122 char command[10];
123 char needle[2] = {0};
124 for (uint32_t i = 0; i < 4; i++) {
125 needle[0] = row[i];
126 int index = this->get_command_code_(command, sizeof(command), (const char *) needle, TM1621_KCHAR);
127 if (-1 == index) {
128 index = 11;
129 }
130 uint32_t bidx = (0 == j) ? i : 7 - i;
131 buffer[bidx] = TM1621_DIGIT_ROW[j][index];
132 }
133 if (dp) {
134 if (0 == j) {
135 buffer[2] |= 0x80; // Row 1 decimal point
136 } else {
137 buffer[5] |= 0x08; // Row 2 decimal point
138 }
139 }
140 }
141
142 if (this->fahrenheit_) {
143 buffer[1] |= 0x80;
144 }
145 if (this->celsius_) {
146 buffer[3] |= 0x80;
147 }
148 if (this->kwh_) {
149 buffer[4] |= 0x08;
150 }
151 if (this->humidity_) {
152 buffer[6] |= 0x08;
153 }
154 if (this->voltage_) {
155 buffer[7] |= 0x08;
156 }
157
158 // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1: Dump3 %8_H"), buffer);
159
160 this->send_address_(0x10); // Sonoff only uses the upper 16 Segments
161 for (uint8_t i : buffer) {
162 this->send_common_(i);
163 }
164 this->stop_();
165}
166
167bool TM1621Display::send_command_(uint16_t command) {
168 uint16_t full_command = (0x0400 | command) << 5; // 0b100cccccccc00000
169 this->cs_pin_->digital_write(false); // Start command sequence
170 delayMicroseconds(TM1621_PULSE_WIDTH / 2);
171 for (uint32_t i = 0; i < 12; i++) {
172 this->write_pin_->digital_write(false); // Start write sequence
173 if (full_command & 0x8000) {
174 this->data_pin_->digital_write(true); // Set data
175 } else {
176 this->data_pin_->digital_write(false); // Set data
177 }
178 delayMicroseconds(TM1621_PULSE_WIDTH);
179 this->write_pin_->digital_write(true); // Read data
180 delayMicroseconds(TM1621_PULSE_WIDTH);
181 full_command <<= 1;
182 }
183 this->stop_();
184 return true;
185}
186
187bool TM1621Display::send_common_(uint8_t common) {
188 for (uint32_t i = 0; i < 8; i++) {
189 this->write_pin_->digital_write(false); // Start write sequence
190 if (common & 1) {
191 this->data_pin_->digital_write(true); // Set data
192 } else {
193 this->data_pin_->digital_write(false); // Set data
194 }
195 delayMicroseconds(TM1621_PULSE_WIDTH);
196 this->write_pin_->digital_write(true); // Read data
197 delayMicroseconds(TM1621_PULSE_WIDTH);
198 common >>= 1;
199 }
200 return true;
201}
202
204 uint16_t full_address = (address | 0x0140) << 7; // 0b101aaaaaa0000000
205 this->cs_pin_->digital_write(false); // Start command sequence
206 delayMicroseconds(TM1621_PULSE_WIDTH / 2);
207 for (uint32_t i = 0; i < 9; i++) {
208 this->write_pin_->digital_write(false); // Start write sequence
209 if (full_address & 0x8000) {
210 this->data_pin_->digital_write(true); // Set data
211 } else {
212 this->data_pin_->digital_write(false); // Set data
213 }
214 delayMicroseconds(TM1621_PULSE_WIDTH);
215 this->write_pin_->digital_write(true); // Read data
216 delayMicroseconds(TM1621_PULSE_WIDTH);
217 full_address <<= 1;
218 }
219 return true;
220}
221
222uint8_t TM1621Display::print(uint8_t start_pos, const char *str) {
223 // ESP_LOGD(TAG, "Print at %d: %s", start_pos, str);
224 return snprintf(this->row_[start_pos], sizeof(this->row_[start_pos]), "%s", str);
225}
226uint8_t TM1621Display::print(const char *str) { return this->print(0, str); }
227uint8_t TM1621Display::printf(uint8_t pos, const char *format, ...) {
228 va_list arg;
229 va_start(arg, format);
230 char buffer[64];
231 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
232 va_end(arg);
233 if (ret > 0)
234 return this->print(pos, buffer);
235 return 0;
236}
237uint8_t TM1621Display::printf(const char *format, ...) {
238 va_list arg;
239 va_start(arg, format);
240 char buffer[64];
241 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
242 va_end(arg);
243 if (ret > 0)
244 return this->print(buffer);
245 return 0;
246}
247
248int TM1621Display::get_command_code_(char *destination, size_t destination_size, const char *needle,
249 const char *haystack) {
250 // Returns -1 of not found
251 // Returns index and command if found
252 int result = -1;
253 const char *read = haystack;
254 char *write = destination;
255
256 while (true) {
257 result++;
258 size_t size = destination_size - 1;
259 write = destination;
260 char ch = '.';
261 while ((ch != '\0') && (ch != '|')) {
262 ch = *(read++);
263 if (size && (ch != '|')) {
264 *write++ = ch;
265 size--;
266 }
267 }
268 *write = '\0';
269 if (!strcasecmp(needle, destination)) {
270 break;
271 }
272 if (0 == ch) {
273 result = -1;
274 break;
275 }
276 }
277 return result;
278}
279} // namespace esphome::tm1621
uint8_t address
Definition bl0906.h:4
virtual void setup()=0
virtual void digital_write(bool value)=0
int get_command_code_(char *destination, size_t destination_size, const char *needle, const char *haystack)
Definition tm1621.cpp:248
void dump_config() override
Definition tm1621.cpp:67
bool send_command_(uint16_t command)
Definition tm1621.cpp:167
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 tm1621.cpp:227
uint8_t uint8_t uint8_t print(uint8_t pos, const char *str)
Print str at the given position.
Definition tm1621.cpp:222
bool send_common_(uint8_t common)
Definition tm1621.cpp:187
tm1621_writer_t writer_
Definition tm1621.h:62
bool send_address_(uint16_t address)
Definition tm1621.cpp:203
float get_setup_priority() const override
Definition tm1621.cpp:83
constexpr float PROCESSOR
For components that use data from sensors like displays.
Definition component.h:45
const uint8_t TM1621_LCD_ON
Definition tm1621.cpp:13
const uint8_t TM1621_WDT_DIS
Definition tm1621.cpp:15
const uint8_t TM1621_SYS_EN
Definition tm1621.cpp:12
const uint8_t TM1621_TONE_OFF
Definition tm1621.cpp:16
const uint8_t TM1621_TIMER_DIS
Definition tm1621.cpp:14
const uint8_t TM1621_PULSE_WIDTH
Definition tm1621.cpp:10
const uint8_t TM1621_BIAS
Definition tm1621.cpp:17
const uint8_t TM1621_IRQ_DIS
Definition tm1621.cpp:18
const uint8_t TM1621_DIGIT_ROW[2][12]
Definition tm1621.cpp:27
constexpr char TM1621_KCHAR[] PROGMEM
Definition tm1621.cpp:25
const uint8_t TM1621_COMMANDS[]
Definition tm1621.cpp:22
const char int const __FlashStringHelper * format
Definition log.h:74
va_end(args)
const void size_t len
Definition hal.h:64
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition hal.cpp:48
uint16_t size
Definition helpers.cpp:25
size_t size_t pos
Definition helpers.h:1038
size_t size_t const char va_start(args, fmt)
static void uint32_t
std::string print()