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