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