ESPHome 2025.5.0
Loading...
Searching...
No Matches
sx1509.cpp
Go to the documentation of this file.
1#include "sx1509.h"
3#include "esphome/core/log.h"
4
5namespace esphome {
6namespace sx1509 {
7
8static const char *const TAG = "sx1509";
9
11 ESP_LOGCONFIG(TAG, "Setting up SX1509Component...");
12
13 ESP_LOGV(TAG, " Resetting devices...");
14 if (!this->write_byte(REG_RESET, 0x12)) {
15 this->mark_failed();
16 return;
17 }
18 this->write_byte(REG_RESET, 0x34);
19
20 uint16_t data;
21 if (!this->read_byte_16(REG_INTERRUPT_MASK_A, &data)) {
22 this->mark_failed();
23 return;
24 }
25 if (data != 0xFF00) {
26 this->mark_failed();
27 return;
28 }
31 if (this->has_keypad_)
32 this->setup_keypad_();
33}
34
36 ESP_LOGCONFIG(TAG, "SX1509:");
37 if (this->is_failed()) {
38 ESP_LOGE(TAG, "Setting up SX1509 failed!");
39 }
40 LOG_I2C_DEVICE(this);
41}
42
44 if (this->has_keypad_) {
46 return;
48 uint16_t key_data = this->read_key_data();
49 for (auto *binary_sensor : this->keypad_binary_sensors_)
50 binary_sensor->process(key_data);
51 }
52}
53
55 if (this->ddr_mask_ & (1 << pin)) {
56 uint16_t temp_reg_data;
57 if (!this->read_byte_16(REG_DATA_B, &temp_reg_data))
58 return false;
59 if (temp_reg_data & (1 << pin))
60 return true;
61 }
62 return false;
63}
64
65void SX1509Component::digital_write(uint8_t pin, bool bit_value) {
66 if ((~this->ddr_mask_) & (1 << pin)) {
67 // If the pin is an output, write high/low
68 uint16_t temp_reg_data = 0;
69 this->read_byte_16(REG_DATA_B, &temp_reg_data);
70 if (bit_value) {
71 output_state_ |= (1 << pin); // set bit in shadow register
72 } else {
73 output_state_ &= ~(1 << pin); // reset bit shadow register
74 }
75 for (uint16_t b = 0x8000; b; b >>= 1) {
76 if ((~ddr_mask_) & b) { // transfer bits of outputs, but don't mess with inputs
77 if (output_state_ & b) {
78 temp_reg_data |= b;
79 } else {
80 temp_reg_data &= ~b;
81 }
82 }
83 }
84 this->write_byte_16(REG_DATA_B, temp_reg_data);
85 }
86}
87
88void SX1509Component::pin_mode(uint8_t pin, gpio::Flags flags) {
89 ESP_LOGI(TAG, "Configuring pin %u with flags %x", pin, flags);
90
91 uint16_t temp_word = 0;
92
93 this->read_byte_16(REG_DIR_B, &this->ddr_mask_);
94 if (flags & gpio::FLAG_OUTPUT) {
95 // Always disable input buffer
96 this->read_byte_16(REG_INPUT_DISABLE_B, &temp_word);
97 temp_word |= (1 << pin);
98 this->write_byte_16(REG_INPUT_DISABLE_B, temp_word);
99
100 if (flags & gpio::FLAG_OPEN_DRAIN) {
101 // Pullup must be disabled for open drain mode
102 this->read_byte_16(REG_PULL_UP_B, &temp_word);
103 temp_word &= ~(1 << pin);
104 this->write_byte_16(REG_PULL_UP_B, temp_word);
105 this->read_byte_16(REG_OPEN_DRAIN_B, &temp_word);
106 temp_word |= (1 << pin);
107 this->write_byte_16(REG_OPEN_DRAIN_B, temp_word);
108 ESP_LOGD(TAG, "Open drain output mode set for %u", pin);
109 } else {
110 ESP_LOGD(TAG, "Output Mode for %u", pin);
111 }
112
113 // Set direction to output
114 this->ddr_mask_ &= ~(1 << pin);
115 this->write_byte_16(REG_DIR_B, this->ddr_mask_);
116 } else {
117 ESP_LOGD(TAG, "Input Mode for %u", pin);
118
119 // Always enable input buffer
120 this->read_byte_16(REG_INPUT_DISABLE_B, &temp_word);
121 temp_word &= ~(1 << pin);
122 this->write_byte_16(REG_INPUT_DISABLE_B, temp_word);
123
124 // Pullup
125 this->read_byte_16(REG_PULL_UP_B, &temp_word);
126 if (flags & gpio::FLAG_PULLUP) {
127 temp_word |= (1 << pin);
128 } else {
129 temp_word &= ~(1 << pin);
130 }
131 this->write_byte_16(REG_PULL_UP_B, temp_word);
132
133 // Pulldown
134 this->read_byte_16(REG_PULL_DOWN_B, &temp_word);
135 if (flags & gpio::FLAG_PULLDOWN) {
136 temp_word |= (1 << pin);
137 } else {
138 temp_word &= ~(1 << pin);
139 }
140 this->write_byte_16(REG_PULL_DOWN_B, temp_word);
141
142 // Set direction to input
143 this->ddr_mask_ |= (1 << pin);
144 this->write_byte_16(REG_DIR_B, this->ddr_mask_);
145 }
146}
147
149 uint16_t temp_word = 0;
150 uint8_t temp_byte = 0;
151
152 this->read_byte_16(REG_INPUT_DISABLE_B, &temp_word);
153 temp_word |= (1 << pin);
154 this->write_byte_16(REG_INPUT_DISABLE_B, temp_word);
155
156 this->ddr_mask_ &= ~(1 << pin); // 0=output
157 this->write_byte_16(REG_DIR_B, this->ddr_mask_);
158
159 this->read_byte(REG_CLOCK, &temp_byte);
160 temp_byte |= (1 << 6); // Internal 2MHz oscillator part 1 (set bit 6)
161 temp_byte &= ~(1 << 5); // Internal 2MHz oscillator part 2 (clear bit 5)
162 this->write_byte(REG_CLOCK, temp_byte);
163
164 this->read_byte(REG_MISC, &temp_byte);
165 temp_byte &= ~(1 << 7); // set linear mode bank B
166 temp_byte &= ~(1 << 3); // set linear mode bank A
167 temp_byte |= 0x70; // Frequency of the LED Driver clock ClkX of all IOs:
168 this->write_byte(REG_MISC, temp_byte);
169
170 this->read_byte_16(REG_LED_DRIVER_ENABLE_B, &temp_word);
171 temp_word |= (1 << pin);
172 this->write_byte_16(REG_LED_DRIVER_ENABLE_B, temp_word);
173
174 this->read_byte_16(REG_DATA_B, &temp_word);
175 temp_word &= ~(1 << pin);
176 output_state_ &= ~(1 << pin);
177 this->write_byte_16(REG_DATA_B, temp_word);
178}
179
180void SX1509Component::clock_(uint8_t osc_source, uint8_t osc_pin_function, uint8_t osc_freq_out, uint8_t osc_divider) {
181 osc_source = (osc_source & 0b11) << 5; // 2-bit value, bits 6:5
182 osc_pin_function = (osc_pin_function & 1) << 4; // 1-bit value bit 4
183 osc_freq_out = (osc_freq_out & 0b1111); // 4-bit value, bits 3:0
184 uint8_t reg_clock = osc_source | osc_pin_function | osc_freq_out;
185 this->write_byte(REG_CLOCK, reg_clock);
186
187 osc_divider = clamp<uint8_t>(osc_divider, 1, 7u);
188 this->clk_x_ = 2000000;
189 osc_divider = (osc_divider & 0b111) << 4; // 3-bit value, bits 6:4
190
191 uint8_t reg_misc = 0;
192 this->read_byte(REG_MISC, &reg_misc);
193 reg_misc &= ~(0b111 << 4);
194 reg_misc |= osc_divider;
195 this->write_byte(REG_MISC, reg_misc);
196}
197
199 uint8_t temp_byte = 0;
200
201 // setup row/col pins for INPUT OUTPUT
202 this->read_byte_16(REG_DIR_B, &this->ddr_mask_);
203 for (int i = 0; i < this->rows_; i++)
204 this->ddr_mask_ &= ~(1 << i);
205 for (int i = 8; i < (this->cols_ * 2); i++)
206 this->ddr_mask_ |= (1 << i);
207 this->write_byte_16(REG_DIR_B, this->ddr_mask_);
208
209 this->read_byte(REG_OPEN_DRAIN_A, &temp_byte);
210 for (int i = 0; i < this->rows_; i++)
211 temp_byte |= (1 << i);
212 this->write_byte(REG_OPEN_DRAIN_A, temp_byte);
213
214 this->read_byte(REG_PULL_UP_B, &temp_byte);
215 for (int i = 0; i < this->cols_; i++)
216 temp_byte |= (1 << i);
217 this->write_byte(REG_PULL_UP_B, temp_byte);
218
219 if (debounce_time_ >= scan_time_) {
220 debounce_time_ = scan_time_ >> 1; // Force debounce_time to be less than scan_time
221 }
223 uint8_t scan_time_bits = 0;
224 for (uint8_t i = 7; i > 0; i--) {
225 if (scan_time_ & (1 << i)) {
226 scan_time_bits = i;
227 break;
228 }
229 }
230 scan_time_bits &= 0b111; // Scan time is bits 2:0
231 temp_byte = sleep_time_ | scan_time_bits;
232 this->write_byte(REG_KEY_CONFIG_1, temp_byte);
233 rows_ = (rows_ - 1) & 0b111; // 0 = off, 0b001 = 2 rows, 0b111 = 8 rows, etc.
234 cols_ = (cols_ - 1) & 0b111; // 0b000 = 1 column, ob111 = 8 columns, etc.
235 this->write_byte(REG_KEY_CONFIG_2, (rows_ << 3) | cols_);
236}
237
239 uint16_t key_data = 0;
240 this->read_byte_16(REG_KEY_DATA_1, &key_data);
241 return (0xFFFF ^ key_data);
242}
243
244void SX1509Component::set_debounce_config_(uint8_t config_value) {
245 // First make sure clock is configured
246 uint8_t temp_byte = 0;
247 this->read_byte(REG_MISC, &temp_byte);
248 temp_byte |= (1 << 4); // Just default to no divider if not set
249 this->write_byte(REG_MISC, temp_byte);
250 this->read_byte(REG_CLOCK, &temp_byte);
251 temp_byte |= (1 << 6); // default to internal osc.
252 this->write_byte(REG_CLOCK, temp_byte);
253
254 config_value &= 0b111; // 3-bit value
255 this->write_byte(REG_DEBOUNCE_CONFIG, config_value);
256}
257
259 uint8_t config_value = 0;
260
261 for (int i = 7; i >= 0; i--) {
262 if (time & (1 << i)) {
263 config_value = i + 1;
264 break;
265 }
266 }
267 config_value = clamp<uint8_t>(config_value, 0, 7);
268
269 set_debounce_config_(config_value);
270}
271
273 uint16_t debounce_enable = 0;
274 this->read_byte_16(REG_DEBOUNCE_ENABLE_B, &debounce_enable);
275 debounce_enable |= (1 << pin);
276 this->write_byte_16(REG_DEBOUNCE_ENABLE_B, debounce_enable);
277}
278
280
281void SX1509Component::set_debounce_keypad_(uint8_t time, uint8_t num_rows, uint8_t num_cols) {
282 set_debounce_time_(time);
283 for (uint16_t i = 0; i < num_rows; i++)
285 for (uint16_t i = 0; i < (8 + num_cols); i++)
287}
288
289} // namespace sx1509
290} // namespace esphome
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
bool write_byte(uint8_t a_register, uint8_t data, bool stop=true)
Definition i2c.h:266
bool read_byte_16(uint8_t a_register, uint16_t *data)
Definition i2c.h:250
bool read_byte(uint8_t a_register, uint8_t *data, bool stop=true)
Definition i2c.h:239
bool write_byte_16(uint8_t a_register, uint16_t data)
Definition i2c.h:270
void clock_(uint8_t osc_source=2, uint8_t osc_pin_function=1, uint8_t osc_freq_out=0, uint8_t osc_divider=0)
Definition sx1509.cpp:180
bool digital_read(uint8_t pin)
Definition sx1509.cpp:54
void set_debounce_pin_(uint8_t pin)
Definition sx1509.cpp:279
void set_debounce_config_(uint8_t config_value)
Definition sx1509.cpp:244
void digital_write(uint8_t pin, bool bit_value)
Definition sx1509.cpp:65
void set_debounce_time_(uint8_t time)
Definition sx1509.cpp:258
void set_debounce_keypad_(uint8_t time, uint8_t num_rows, uint8_t num_cols)
Definition sx1509.cpp:281
void pin_mode(uint8_t pin, gpio::Flags flags)
Definition sx1509.cpp:88
std::vector< SX1509Processor * > keypad_binary_sensors_
Definition sx1509.h:71
void setup_led_driver(uint8_t pin)
Definition sx1509.cpp:148
void set_debounce_enable_(uint8_t pin)
Definition sx1509.cpp:272
const uint32_t min_loop_period_
Definition sx1509.h:74
@ FLAG_OUTPUT
Definition gpio.h:19
@ FLAG_OPEN_DRAIN
Definition gpio.h:20
@ FLAG_PULLUP
Definition gpio.h:21
@ FLAG_PULLDOWN
Definition gpio.h:22
const char *const TAG
Definition spi.cpp:8
const uint8_t REG_DEBOUNCE_CONFIG
const uint8_t REG_MISC
const uint8_t REG_CLOCK
const uint8_t REG_KEY_CONFIG_2
const uint8_t REG_DATA_B
const uint8_t REG_LED_DRIVER_ENABLE_B
const uint8_t REG_KEY_CONFIG_1
const uint8_t REG_OPEN_DRAIN_B
const uint8_t REG_PULL_UP_B
const uint8_t REG_INPUT_DISABLE_B
const uint8_t REG_RESET
const uint8_t REG_DEBOUNCE_ENABLE_B
const uint8_t REG_INTERRUPT_MASK_A
const uint8_t REG_PULL_DOWN_B
const uint8_t REG_DIR_B
const uint8_t INTERNAL_CLOCK_2MHZ
Definition sx1509.h:15
const uint8_t REG_OPEN_DRAIN_A
const uint8_t REG_KEY_DATA_1
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:30
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:27
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
Definition helpers.h:101