forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
w1_zephyr_serial.c
287 lines (240 loc) · 7.83 KB
/
w1_zephyr_serial.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/*
* Copyright (c) 2022 Thomas Stranger
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT zephyr_w1_serial
/**
* @brief 1-Wire Bus Master driver using Zephyr serial interface.
*
* This driver implements the 1-Wire interface using an uart.
* The driver uses a uart peripheral with a baudrate of 115.2 kBd to send
* and receive data bits and a baurade of 9.6 kBd for slave reset and
* presence detection as suggested for normal speed operating mode in:
* https://www.analog.com/en/resources/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html
* For overdrive speed communication baudrates of 1 MBd and 115.2 kBd
* are used, respectively.
*/
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/drivers/w1.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/__assert.h>
LOG_MODULE_REGISTER(w1_serial, CONFIG_W1_LOG_LEVEL);
#define W1_SERIAL_READ_REQ_BYTE 0xFF
#define W1_SERIAL_BIT_1 0xFF
#define W1_SERIAL_BIT_0 0x00
/* Standard speed signal parameters:
* RST: t_RSTL=520us; t_slot=1041us
* DATA: t_low1=8.68us; t_low0=78.1us; t_slot=86.8us
*/
#define W1_SERIAL_STD_RESET_BYTE 0xF0
#define W1_SERIAL_STD_RESET_BAUD 9600u
#define W1_SERIAL_STD_DATA_BAUD 115200u
/*
* Overdrive speed signal parameters:
* RST: t_RSTL=52.1us; t_slot=86.8us
* DATA: t_low1=1.0us; t_low0=9.0us; t_slot=10.0us
*/
#define W1_SERIAL_OD_RESET_BYTE 0xE0
#define W1_SERIAL_OD_RESET_BAUD 115200u
#define W1_SERIAL_OD_DATA_BAUD 1000000u
struct w1_serial_config {
/** w1 master config, common to all drivers */
struct w1_master_config master_config;
/** UART device used for 1-Wire communication */
const struct device *uart_dev;
};
struct w1_serial_data {
/** w1 master data, common to all drivers */
struct w1_master_data master_data;
struct uart_config uart_cfg;
bool overdrive_active;
};
/*
* Concurrently transmits and receives one 1-Wire bit
* by sending and receiving one uart byte
*/
static int serial_tx_rx(const struct device *dev, const uint8_t *tx_data,
uint8_t *rx_data, size_t len, uint32_t timeout)
{
const struct w1_serial_config *cfg = dev->config;
k_timepoint_t end;
uint8_t dummy;
int ret = 0;
__ASSERT_NO_MSG(tx_data != NULL);
__ASSERT_NO_MSG(rx_data != NULL);
for (int i = 0; i < len; ++i) {
while (uart_poll_in(cfg->uart_dev, &dummy) == 0) {
/* poll in any buffered data */
}
uart_poll_out(cfg->uart_dev, tx_data[i]);
end = sys_timepoint_calc(K_USEC(timeout));
do {
ret = uart_poll_in(cfg->uart_dev, &rx_data[i]);
} while (ret != 0 && !sys_timepoint_expired(end));
}
return ret;
}
/* Concurretly tranmits and receives one 1-Wire byte */
static int serial_tx_rx_byte(const struct device *dev, uint8_t tx_byte,
uint8_t *rx_byte)
{
__ASSERT_NO_MSG(rx_byte != NULL);
uint8_t byte_representation[8];
for (int i = 0; i < 8; ++i) {
/*
* Transmitting 0xFF the uart start bit pulls the line low to
* indicate either write Bit 1, or read low time.
* Write Bit 0 is represented as 0x00
*/
byte_representation[i] =
((tx_byte & (1 << i)) != 0) ? W1_SERIAL_BIT_1 : W1_SERIAL_BIT_0;
}
if (serial_tx_rx(dev, &byte_representation[0], &byte_representation[0],
8, CONFIG_W1_ZEPHYR_SERIAL_BIT_TIMEOUT) < 0) {
return -EIO;
}
*rx_byte = 0;
for (int i = 0; i < 8; ++i) {
/*
* rx-byte different from 0xFF indicates that a slave has
* pulled line low to transmit a 0 bit, otherwise a 1 bit.
*/
*rx_byte |= (uint8_t)(byte_representation[i] == 0xFF) << i;
}
return 0;
}
static int w1_serial_reset_bus(const struct device *dev)
{
const struct w1_serial_config *cfg = dev->config;
struct w1_serial_data *data = dev->data;
uint8_t reset_byte = data->overdrive_active ?
W1_SERIAL_OD_RESET_BYTE : W1_SERIAL_STD_RESET_BYTE;
/* reset uses 115200/9600=12 slower baudrate,
* adjust timeout accordingly, also valid for overdrive speed.
*/
const uint32_t reset_timeout = CONFIG_W1_ZEPHYR_SERIAL_BIT_TIMEOUT * 12;
data->uart_cfg.baudrate = data->overdrive_active ?
W1_SERIAL_OD_RESET_BAUD : W1_SERIAL_STD_RESET_BAUD;
if (uart_configure(cfg->uart_dev, &data->uart_cfg) != 0) {
LOG_ERR("Failed set baud rate for reset pulse");
return -EIO;
}
if (serial_tx_rx(dev, &reset_byte, &reset_byte, 1, reset_timeout) < 0) {
LOG_ERR("tx_rx_error reset_present");
return -EIO;
}
data->uart_cfg.baudrate = data->overdrive_active ?
W1_SERIAL_OD_DATA_BAUD : W1_SERIAL_STD_DATA_BAUD;
if (uart_configure(cfg->uart_dev, &data->uart_cfg) != 0) {
LOG_ERR("Failed set baud rate for data transfer");
return -EIO;
}
/* At least 1 device is present on bus, if reset_byte is different
* from 0xF0. But Bus probably shorted if reset_byte is 0x00.
*/
return (reset_byte != W1_SERIAL_STD_RESET_BYTE) && (reset_byte != 0x00);
}
static int w1_serial_read_bit(const struct device *dev)
{
uint8_t tx_bit = W1_SERIAL_READ_REQ_BYTE;
uint8_t rx_bit;
if (serial_tx_rx(dev, &tx_bit, &rx_bit, 1,
CONFIG_W1_ZEPHYR_SERIAL_BIT_TIMEOUT) != 0) {
return -EIO;
};
return rx_bit == W1_SERIAL_READ_REQ_BYTE;
}
static int w1_serial_write_bit(const struct device *dev, const bool bit)
{
uint8_t tx_bit;
uint8_t rx_bit;
tx_bit = bit ? W1_SERIAL_BIT_1 : W1_SERIAL_BIT_0;
if (serial_tx_rx(dev, &tx_bit, &rx_bit, 1,
CONFIG_W1_ZEPHYR_SERIAL_BIT_TIMEOUT) != 0) {
return -EIO;
}
return 0;
}
static int w1_serial_read_byte(const struct device *dev)
{
uint8_t tx_byte = 0xFF;
uint8_t rx_byte;
if (serial_tx_rx_byte(dev, tx_byte, &rx_byte) != 0) {
return -EIO;
}
return rx_byte;
}
static int w1_serial_write_byte(const struct device *dev, const uint8_t byte)
{
uint8_t rx_byte;
return serial_tx_rx_byte(dev, byte, &rx_byte);
}
static int w1_serial_configure(const struct device *dev,
enum w1_settings_type type, uint32_t value)
{
const struct w1_serial_config *cfg = dev->config;
struct w1_serial_data *data = dev->data;
int ret = 0;
bool temp;
switch (type) {
case W1_SETTING_SPEED:
temp = (bool)value;
if (temp == data->overdrive_active) {
break;
}
data->overdrive_active = temp;
data->uart_cfg.baudrate = data->overdrive_active ?
W1_SERIAL_OD_DATA_BAUD : W1_SERIAL_STD_DATA_BAUD;
if (uart_configure(cfg->uart_dev, &data->uart_cfg) != 0) {
LOG_ERR("Failed set baud rate for data transfer");
ret = -EIO;
}
break;
default:
ret = -ENOTSUP;
}
return ret;
}
static int w1_serial_init(const struct device *dev)
{
const struct w1_serial_config *cfg = dev->config;
struct w1_serial_data *data = dev->data;
if (!device_is_ready(cfg->uart_dev)) {
LOG_ERR("Serial device not ready");
return -ENODEV;
}
data->uart_cfg.baudrate = W1_SERIAL_STD_DATA_BAUD;
data->uart_cfg.parity = UART_CFG_PARITY_NONE;
data->uart_cfg.data_bits = UART_CFG_DATA_BITS_8;
data->uart_cfg.stop_bits = UART_CFG_STOP_BITS_1;
data->uart_cfg.flow_ctrl = UART_CFG_FLOW_CTRL_NONE;
if (uart_configure(cfg->uart_dev, &data->uart_cfg) != 0) {
LOG_ERR("Failed to configure UART");
return -EINVAL;
}
data->overdrive_active = false;
LOG_DBG("w1-serial initialized, with %d slave devices",
cfg->master_config.slave_count);
return 0;
}
static DEVICE_API(w1, w1_serial_driver_api) = {
.reset_bus = w1_serial_reset_bus,
.read_bit = w1_serial_read_bit,
.write_bit = w1_serial_write_bit,
.read_byte = w1_serial_read_byte,
.write_byte = w1_serial_write_byte,
.configure = w1_serial_configure,
};
#define W1_ZEPHYR_SERIAL_INIT(inst) \
static const struct w1_serial_config w1_serial_cfg_##inst = { \
.uart_dev = DEVICE_DT_GET(DT_INST_BUS(inst)), \
.master_config.slave_count = W1_INST_SLAVE_COUNT(inst) \
}; \
static struct w1_serial_data w1_serial_data_##inst = {}; \
DEVICE_DT_INST_DEFINE(inst, &w1_serial_init, NULL, &w1_serial_data_##inst, \
&w1_serial_cfg_##inst, POST_KERNEL, \
CONFIG_W1_INIT_PRIORITY, &w1_serial_driver_api); \
DT_INST_FOREACH_STATUS_OKAY(W1_ZEPHYR_SERIAL_INIT)