Skip to content

Commit 557c703

Browse files
committed
Added a start to a basic 1-wire driver (still WIP)
1 parent c456b1a commit 557c703

File tree

1 file changed

+230
-0
lines changed

1 file changed

+230
-0
lines changed

klib/io/bus/1-wire.hpp

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
#ifndef KLIB_1_WIRE_HPP
2+
#define KLIB_1_WIRE_HPP
3+
4+
#include <cstdint>
5+
6+
#include <klib/klib.hpp>
7+
#include <klib/multispan.hpp>
8+
#include <klib/delay.hpp>
9+
10+
namespace klib::io {
11+
/**
12+
* @brief A basic 1 wire implementation
13+
*
14+
* @tparam Pin
15+
*/
16+
template <typename Pin, typename OneShotTimer>
17+
class wire_1 {
18+
protected:
19+
/**
20+
* @brief Start a oneshot timer with a specific delay
21+
*
22+
* @param microseconds
23+
*/
24+
static void delay_start(const uint32_t microseconds) {
25+
// start the oneshot timer
26+
OneShotTimer::init(nullptr, 1'000'000 / microseconds);
27+
OneShotTimer::enable();
28+
}
29+
30+
/**
31+
* @brief Helper function to start a oneshot timer and
32+
* wait until it is done
33+
*
34+
* @param microseconds
35+
* @return true
36+
* @return false
37+
*/
38+
static void delay(const uint32_t microseconds) {
39+
// start the oneshot timer
40+
delay_start(microseconds);
41+
42+
// wait until the timer is done
43+
while (!OneShotTimer::done()) {
44+
// do nothing
45+
}
46+
}
47+
48+
/**
49+
* @brief Read a single bit on the 1-wire bus
50+
*
51+
* @return true
52+
* @return false
53+
*/
54+
static bool read_bit() {
55+
// disable all interrupts
56+
target::disable_irq();
57+
58+
// set the pin low
59+
Pin::template set<false>();
60+
61+
// when writing we need to send a 1 - 15 microseconds low
62+
// pulse on the bus. If the device wants to send a '1' it
63+
// does nothing. If the device wants to send a '0' the
64+
// device pulls the data line to ground for 60 microseconds
65+
delay(3);
66+
67+
// set the pin to high (in open drain mode it doesnt
68+
// stops pulling the pin low)
69+
Pin::template set<true>();
70+
71+
// start a one shot timer for 10 microseconds
72+
delay(10);
73+
74+
// get the state
75+
const bool bit = Pin::get();
76+
77+
// disable all interrupts
78+
target::enable_irq();
79+
80+
// start a one shot timer for 53 microseconds
81+
delay(52);
82+
83+
// return the bit we just read
84+
return bit;
85+
}
86+
87+
/**
88+
* @brief Write a single bit on the 1-wire bus
89+
*
90+
* @param bit
91+
*/
92+
static void write_bit(bool bit) {
93+
// disable all interrupts
94+
target::disable_irq();
95+
96+
// set the pin low
97+
Pin::template set<false>();
98+
99+
// start a oneshot timer. A '1' needs a 1 - 15 microseconds
100+
// low pulse. A '0' has needs a 60 microseconds low pulse.
101+
//
102+
// The device reads the the data line about 30 microseconds
103+
// after the falling edge. Due to inexpencive timers in the
104+
// device the timing can be off.
105+
delay(bit ? 10 : 60);
106+
107+
// set the pin to high (in open drain mode it doesnt
108+
// stops pulling the pin low)
109+
Pin::template set<true>();
110+
111+
// disable all interrupts
112+
target::enable_irq();
113+
114+
// start a one shot timer for 55 or 5 microseconds
115+
// based on if the bit is set or not
116+
delay(bit ? 55 : 5);
117+
}
118+
119+
public:
120+
/**
121+
* @brief Init the bus and count the amount of devices on the bus
122+
*
123+
* @return uint32_t
124+
*/
125+
static uint32_t init() {
126+
// reset the bus.
127+
reset();
128+
129+
// amount of devices we found
130+
uint32_t count = 0;
131+
132+
// Wait for
133+
for (uint32_t i = 0; i < 8; i++) {
134+
// start a timer to check if we have
135+
delay(10);
136+
137+
// check if the pin is low
138+
if (Pin::get()) {
139+
continue;
140+
}
141+
142+
// increment the amount of devices
143+
// we have found
144+
count++;
145+
146+
// reset the index
147+
i = 0;
148+
149+
// start a timer to wait for a maximum
150+
// of 60 microseconds
151+
delay_start(65);
152+
153+
// wait until the pin is high again (or
154+
// until the timeout has reached)
155+
while (!Pin::get() && !OneShotTimer::done()) {
156+
// wait and do nothing
157+
}
158+
}
159+
160+
// return the count
161+
return count;
162+
}
163+
164+
/**
165+
* @brief Reset the 1-wire bus
166+
*
167+
*/
168+
static void reset() {
169+
// disable all interrupts
170+
target::disable_irq();
171+
172+
// set the pin low
173+
Pin::template set<false>();
174+
175+
// start a one shot timer for at least to 480
176+
// microseconds to reset all the devices on the
177+
// bus. Every device will pull the bus low for
178+
// at least 60 microseconds
179+
delay(500);
180+
181+
// set the pin to high (in open drain mode it doesnt
182+
// stops pulling the pin low)
183+
Pin::template set<true>();
184+
185+
// disable all interrupts
186+
target::enable_irq();
187+
}
188+
189+
/**
190+
* @brief Read a array of bytes from the 1-wire bus
191+
*
192+
* @param data
193+
*/
194+
static void read(std::span<uint8_t> data) {
195+
for (uint32_t i = 0; i < data.size(); i++) {
196+
uint8_t bits = 0;
197+
198+
// read all the bits
199+
for (uint32_t j = 0; j < 8; j++) {
200+
// read a bit
201+
const bool b = read_bit();
202+
203+
// set the bits
204+
bits <<= 1;
205+
bits |= b;
206+
}
207+
208+
data[i] = bits;
209+
}
210+
}
211+
212+
/**
213+
* @brief Write a array of bytes from the 1-wire bus
214+
*
215+
* @param data
216+
*/
217+
static void write(std::span<const uint8_t> data) {
218+
for (uint32_t i = 0; i < data.size(); i++) {
219+
const uint8_t bits = data[i];
220+
221+
// write all the bits
222+
for (uint32_t j = 0; j < 8; j++) {
223+
write_bit((bits >> j) & 0x1);
224+
}
225+
}
226+
}
227+
};
228+
}
229+
230+
#endif

0 commit comments

Comments
 (0)