ESPHome 2025.5.0
Loading...
Searching...
No Matches
gpio_one_wire.cpp
Go to the documentation of this file.
1#include "gpio_one_wire.h"
2#include "esphome/core/log.h"
4
5namespace esphome {
6namespace gpio {
7
8static const char *const TAG = "gpio.one_wire";
9
11 ESP_LOGCONFIG(TAG, "Setting up 1-wire bus...");
12 this->t_pin_->setup();
14 // clear bus with 480µs high, otherwise initial reset in search might fail
15 this->pin_.digital_write(true);
18 this->search();
19}
20
22 ESP_LOGCONFIG(TAG, "GPIO 1-wire bus:");
23 LOG_PIN(" Pin: ", this->t_pin_);
24 this->dump_devices_(TAG);
25}
26
27int HOT IRAM_ATTR GPIOOneWireBus::reset_int() {
28 InterruptLock lock;
29 // See reset here:
30 // https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
31 // Wait for communication to clear (delay G)
33 uint8_t retries = 125;
34 do {
35 if (--retries == 0)
36 return -1;
38 } while (!this->pin_.digital_read());
39
40 bool r = false;
41
42 // Send 480µs LOW TX reset pulse (drive bus low, delay H)
43 this->pin_.digital_write(false);
46
47 // Release the bus, delay I
49 uint32_t start = micros();
51
52 while (micros() - start < 300) {
53 // sample bus, 0=device(s) present, 1=no device present
54 r = !this->pin_.digital_read();
55 if (r)
56 break;
58 }
59
60 // delay J
61 delayMicroseconds(start + 480 - micros());
62 this->pin_.digital_write(true);
64 return r ? 1 : 0;
65}
66
67void HOT IRAM_ATTR GPIOOneWireBus::write_bit_(bool bit) {
68 // drive bus low
69 this->pin_.digital_write(false);
70
71 // from datasheet:
72 // write 0 low time: t_low0: min=60µs, max=120µs
73 // write 1 low time: t_low1: min=1µs, max=15µs
74 // time slot: t_slot: min=60µs, max=120µs
75 // recovery time: t_rec: min=1µs
76 // ds18b20 appears to read the bus after roughly 14µs
77 uint32_t delay0 = bit ? 6 : 60;
78 uint32_t delay1 = bit ? 64 : 10;
79
80 // delay A/C
81 delayMicroseconds(delay0);
82 // release bus
83 this->pin_.digital_write(true);
84 // delay B/D
85 delayMicroseconds(delay1);
86}
87
88bool HOT IRAM_ATTR GPIOOneWireBus::read_bit_() {
89 // drive bus low
90 this->pin_.digital_write(false);
91
92 // datasheet says >= 1µs
94
95 // release bus, delay E
97
99 // sample bus to read bit from peer
100 bool r = this->pin_.digital_read();
101
102 // read slot is at least 60µs
104
105 this->pin_.digital_write(true);
107 return r;
108}
109
110void IRAM_ATTR GPIOOneWireBus::write8(uint8_t val) {
111 InterruptLock lock;
112 for (uint8_t i = 0; i < 8; i++) {
113 this->write_bit_(bool((1u << i) & val));
114 }
115}
116
117void IRAM_ATTR GPIOOneWireBus::write64(uint64_t val) {
118 InterruptLock lock;
119 for (uint8_t i = 0; i < 64; i++) {
120 this->write_bit_(bool((1ULL << i) & val));
121 }
122}
123
124uint8_t IRAM_ATTR GPIOOneWireBus::read8() {
125 InterruptLock lock;
126 uint8_t ret = 0;
127 for (uint8_t i = 0; i < 8; i++)
128 ret |= (uint8_t(this->read_bit_()) << i);
129 return ret;
130}
131
132uint64_t IRAM_ATTR GPIOOneWireBus::read64() {
133 InterruptLock lock;
134 uint64_t ret = 0;
135 for (uint8_t i = 0; i < 8; i++) {
136 ret |= (uint64_t(this->read_bit_()) << i);
137 }
138 return ret;
139}
140
142 this->last_discrepancy_ = 0;
143 this->last_device_flag_ = false;
144 this->address_ = 0;
145}
146
147uint64_t IRAM_ATTR GPIOOneWireBus::search_int() {
148 InterruptLock lock;
149 if (this->last_device_flag_)
150 return 0u;
151
152 uint8_t last_zero = 0;
153 uint64_t bit_mask = 1;
154 uint64_t address = this->address_;
155
156 // Initiate search
157 for (int bit_number = 1; bit_number <= 64; bit_number++, bit_mask <<= 1) {
158 // read bit
159 bool id_bit = this->read_bit_();
160 // read its complement
161 bool cmp_id_bit = this->read_bit_();
162
163 if (id_bit && cmp_id_bit) {
164 // No devices participating in search
165 return 0;
166 }
167
168 bool branch;
169
170 if (id_bit != cmp_id_bit) {
171 // only chose one branch, the other one doesn't have any devices.
172 branch = id_bit;
173 } else {
174 // there are devices with both 0s and 1s at this bit
175 if (bit_number < this->last_discrepancy_) {
176 branch = (address & bit_mask) > 0;
177 } else {
178 branch = bit_number == this->last_discrepancy_;
179 }
180
181 if (!branch) {
182 last_zero = bit_number;
183 }
184 }
185
186 if (branch) {
187 address |= bit_mask;
188 } else {
189 address &= ~bit_mask;
190 }
191
192 // choose/announce branch
193 this->write_bit_(branch);
194 }
195
196 this->last_discrepancy_ = last_zero;
197 if (this->last_discrepancy_ == 0) {
198 // we're at root and have no choices left, so this was the last one.
199 this->last_device_flag_ = true;
200 }
201
202 this->address_ = address;
203 return address;
204}
205
206} // namespace gpio
207} // namespace esphome
uint8_t address
Definition bl0906.h:4
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
void digital_write(bool value)
Definition gpio.cpp:147
void pin_mode(gpio::Flags flags)
Definition gpio.cpp:156
Helper class to disable interrupts.
Definition helpers.h:614
void write64(uint64_t val) override
void write8(uint8_t val) override
void dump_devices_(const char *tag)
log the found devices
void search()
Search for 1-Wire devices on the bus.
mopeka_std_values val[4]
@ FLAG_OUTPUT
Definition gpio.h:19
@ FLAG_PULLUP
Definition gpio.h:21
@ FLAG_INPUT
Definition gpio.h:18
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 micros()
Definition core.cpp:29