Firmware SDK
twr_onewire_gpio.c
1 #include <twr_onewire_gpio.h>
2 #include <twr_system.h>
3 #include <twr_timer.h>
4 #include <twr_irq.h>
5 #include <stm32l0xx.h>
6 
7 static bool _twr_onewire_gpio_init(void *ctx);
8 static bool _twr_onewire_gpio_enable(void *ctx);
9 static bool _twr_onewire_gpio_disable(void *ctx);
10 static bool _twr_onewire_gpio_reset(void *ctx);
11 static void _twr_onewire_gpio_write_bit(void *ctx, uint8_t bit);
12 static uint8_t _twr_onewire_gpio_read_bit(void *ctx);
13 static void _twr_onewire_gpio_write_byte(void *ctx, uint8_t byte);
14 static uint8_t _twr_onewire_gpio_read_byte(void *ctx);
15 static bool _twr_onewire_gpio_search_next(void *ctx, twr_onewire_t *onewire, uint64_t *device_number);
16 
17 static const twr_onewire_driver_t _twr_onewire_gpio_driver =
18 {
19  .init = _twr_onewire_gpio_init,
20  .enable = _twr_onewire_gpio_enable,
21  .disable = _twr_onewire_gpio_disable,
22  .reset = _twr_onewire_gpio_reset,
23  .write_bit = _twr_onewire_gpio_write_bit,
24  .read_bit = _twr_onewire_gpio_read_bit,
25  .write_byte = _twr_onewire_gpio_write_byte,
26  .read_byte = _twr_onewire_gpio_read_byte,
27  .search_next = _twr_onewire_gpio_search_next
28 };
29 
31 {
32  twr_onewire_init(onewire, &_twr_onewire_gpio_driver, (void *) channel);
33 }
34 
35 const twr_onewire_driver_t *twr_onewire_gpio_det_driver(void)
36 {
37  return &_twr_onewire_gpio_driver;
38 }
39 
40 static bool _twr_onewire_gpio_init(void *ctx)
41 {
42  twr_gpio_channel_t channel = (twr_gpio_channel_t) ctx;
43 
44  twr_gpio_init(channel);
45 
47 
49 
50  return true;
51 }
52 
53 static bool _twr_onewire_gpio_enable(void *ctx)
54 {
55  (void) ctx;
56  twr_system_pll_enable();
59  return true;
60 }
61 
62 static bool _twr_onewire_gpio_disable(void *ctx)
63 {
64  (void) ctx;
66  twr_system_pll_disable();
67  return true;
68 }
69 
70 static bool _twr_onewire_gpio_reset(void *ctx)
71 {
72  twr_gpio_channel_t channel = (twr_gpio_channel_t) ctx;
73 
74  int i;
75  uint8_t retries = 125;
76 
78 
79  do
80  {
81  if (retries-- == 0)
82  {
83  return false;
84  }
85  twr_timer_delay(2);
86  }
87  while (twr_gpio_get_input(channel) == 0);
88 
89  twr_gpio_set_output(channel, 0);
91 
92  twr_timer_delay(480);
93 
95 
96  // Some devices responds little bit later than expected 70us, be less strict in timing...
97  // Low state of data line (presence detect) should be definitely low between 60us and 75us from now
98  // According to datasheet: t_PDHIGH=15..60us ; t_PDLOW=60..240us
99  //
100  // t_PDHIGH t_PDLOW
101  // /----\ ... \ / ... /-----
102  // ___/ \ ... \____/ ... /
103  // ^ ^ ^ ^ ^
104  // now 15 60 75 300 us
105  //
106  twr_timer_delay(60);
107  retries = 4;
108  do {
109  i = twr_gpio_get_input(channel);
110  twr_timer_delay(4);
111  }
112  while (i && --retries);
113  twr_timer_delay(retries * 4);
114  //twr_log_debug("retries=%d",retries);
115 
116  twr_timer_delay(410);
117 
118  return i == 0;
119 }
120 
121 static void _twr_onewire_gpio_write_bit(void *ctx, uint8_t bit)
122 {
123  twr_gpio_channel_t channel = (twr_gpio_channel_t) ctx;
124 
125  twr_gpio_set_output(channel, 0);
127 
128  if (bit)
129  {
130  twr_irq_disable();
131 
132  twr_timer_delay(3);
133 
134  twr_irq_enable();
135 
137 
138  twr_timer_delay(60);
139  }
140  else
141  {
142  twr_timer_delay(55);
143 
145 
146  twr_timer_delay(8);
147  }
148 }
149 
150 static uint8_t _twr_onewire_gpio_read_bit(void *ctx)
151 {
152  twr_gpio_channel_t channel = (twr_gpio_channel_t) ctx;
153 
154  uint8_t bit = 0;
155 
156  twr_gpio_set_output(channel, 0);
157 
159 
160  twr_irq_disable();
161 
162  twr_timer_delay(3);
163 
164  twr_irq_enable();
165 
167 
168  twr_irq_disable();
169 
170  twr_timer_delay(8);
171 
172  twr_irq_enable();
173 
174  bit = twr_gpio_get_input(channel);
175 
176  twr_timer_delay(50);
177 
178  return bit;
179 }
180 
181 static void _twr_onewire_gpio_write_byte(void *ctx, uint8_t byte)
182 {
183  for (uint8_t i = 0; i < 8; i++)
184  {
185  _twr_onewire_gpio_write_bit(ctx, byte & 0x01);
186  byte >>= 1;
187  }
188 }
189 
190 static uint8_t _twr_onewire_gpio_read_byte(void *ctx)
191 {
192  uint8_t byte = 0;
193  for (uint8_t i = 0; i < 8; i++)
194  {
195  byte |= (_twr_onewire_gpio_read_bit(ctx) << i);
196  }
197  return byte;
198 }
199 
200 static bool _twr_onewire_gpio_search_next(void *ctx, twr_onewire_t *onewire, uint64_t *device_number)
201 {
202  bool search_result = false;
203  uint8_t id_bit_number;
204  uint8_t last_zero, rom_byte_number;
205  uint8_t id_bit, cmp_id_bit;
206  uint8_t rom_byte_mask, search_direction;
207 
208  /* Initialize for search */
209  id_bit_number = 1;
210  last_zero = 0;
211  rom_byte_number = 0;
212  rom_byte_mask = 1;
213 
214  if (!_twr_onewire_gpio_reset(ctx))
215  {
216  return false;
217  }
218 
219  // issue the search command
220  _twr_onewire_gpio_write_byte(ctx, 0xf0);
221 
222  // loop to do the search
223  do
224  {
225  id_bit = _twr_onewire_gpio_read_bit(ctx);
226  cmp_id_bit = _twr_onewire_gpio_read_bit(ctx);
227 
228  // check for no devices on 1-wire
229  if ((id_bit == 1) && (cmp_id_bit == 1))
230  {
231  break;
232  }
233  else
234  {
235  /* All devices coupled have 0 or 1 */
236  if (id_bit != cmp_id_bit)
237  {
238  /* Bit write value for search */
239  search_direction = id_bit;
240  }
241  else
242  {
243  /* If this discrepancy is before the Last Discrepancy on a previous next then pick the same as last time */
244  if (id_bit_number < onewire->_last_discrepancy)
245  {
246  search_direction = ((onewire->_last_rom_no[rom_byte_number] & rom_byte_mask) > 0);
247  }
248  else
249  {
250  /* If equal to last pick 1, if not then pick 0 */
251  search_direction = (id_bit_number == onewire->_last_discrepancy);
252  }
253 
254  /* If 0 was picked then record its position in LastZero */
255  if (search_direction == 0)
256  {
257  last_zero = id_bit_number;
258 
259  /* Check for Last discrepancy in family */
260  if (last_zero < 9)
261  {
262  onewire->_last_family_discrepancy = last_zero;
263  }
264  }
265  }
266 
267  /* Set or clear the bit in the ROM byte rom_byte_number with mask rom_byte_mask */
268  if (search_direction == 1)
269  {
270  onewire->_last_rom_no[rom_byte_number] |= rom_byte_mask;
271  }
272  else
273  {
274  onewire->_last_rom_no[rom_byte_number] &= ~rom_byte_mask;
275  }
276 
277  /* Serial number search direction write bit */
278  _twr_onewire_gpio_write_bit(ctx, search_direction);
279 
280  /* Increment the byte counter id_bit_number and shift the mask rom_byte_mask */
281  id_bit_number++;
282  rom_byte_mask <<= 1;
283 
284  /* If the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask */
285  if (rom_byte_mask == 0)
286  {
287  rom_byte_number++;
288  rom_byte_mask = 1;
289  }
290  }
291  }
292  while (rom_byte_number < 8);
293 
294  /* If the search was successful then */
295  if (!(id_bit_number < 65))
296  {
297  /* Search successful so set LastDiscrepancy, LastDeviceFlag, search_result */
298  onewire->_last_discrepancy = last_zero;
299 
300  /* Check for last device */
301  if (onewire->_last_discrepancy == 0)
302  {
303  onewire->_last_device_flag = true;
304  }
305 
306  search_result = !onewire->_last_rom_no[0] ? false : true;
307  }
308 
309  if (search_result && twr_onewire_crc8(onewire->_last_rom_no, sizeof(onewire->_last_rom_no), 0x00) != 0)
310  {
311  search_result = false;
312  }
313 
314  if (search_result)
315  {
316  memcpy(device_number, onewire->_last_rom_no, sizeof(onewire->_last_rom_no));
317  }
318  else
319  {
320  _twr_onewire_gpio_reset(ctx);
321  }
322 
323  return search_result;
324 }
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
void twr_irq_enable(void)
Enable interrupt requests globally (call can be nested)
Definition: twr_irq.c:21
int twr_gpio_get_input(twr_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: twr_gpio.c:465
GPIO channel operates as output.
Definition: twr_gpio.h:108
uint8_t twr_onewire_crc8(const void *buffer, size_t length, uint8_t crc)
Calculate 8-bit CRC.
Definition: twr_onewire.c:165
void twr_gpio_set_pull(twr_gpio_channel_t channel, twr_gpio_pull_t pull)
Set pull-up/pull-down configuration for GPIO channel.
Definition: twr_gpio.c:340
GPIO channel has no pull-up/pull-down.
Definition: twr_gpio.h:90
void twr_timer_stop(void)
Stop timer.
Definition: twr_timer.c:42
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
twr_gpio_channel_t
GPIO channels.
Definition: twr_gpio.h:12
struct twr_onewire_t twr_onewire_t
1-Wire instance
Definition: twr_onewire.h:14
void twr_timer_init(void)
Initialize timer.
Definition: twr_timer.c:23
void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: twr_gpio.c:471
bool twr_onewire_init(twr_onewire_t *self, const twr_onewire_driver_t *driver, void *driver_ctx)
Initialize 1-Wire.
Definition: twr_onewire.c:12
void twr_onewire_gpio_init(twr_onewire_t *onewire, twr_gpio_channel_t channel)
Initialize 1-Wire.
GPIO channel operates as input.
Definition: twr_gpio.h:105
void twr_irq_disable(void)
Disable interrupt requests globally (call can be nested)
Definition: twr_irq.c:7
void twr_timer_delay(uint16_t microseconds)
Relative delay.
Definition: twr_timer.c:59
void twr_timer_start(void)
Start timer.
Definition: twr_timer.c:28