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