Firmware SDK
twr_ds18b20.c
1 #include <twr_ds18b20.h>
2 #include <twr_onewire.h>
3 #include <twr_gpio.h>
4 #include <twr_i2c.h>
5 #include <twr_module_sensor.h>
6 #include <twr_log.h>
7 
8 #define _TWR_DS18B20_SCRATCHPAD_SIZE 9
9 #define _TWR_DS18B20_DELAY_RUN 5000
10 #define TWR_DS18B20_LOG 1
11 
12 static twr_tick_t _twr_ds18b20_lut_delay[] = {
13  [TWR_DS18B20_RESOLUTION_BITS_9] = 100,
14  [TWR_DS18B20_RESOLUTION_BITS_10] = 190,
15  [TWR_DS18B20_RESOLUTION_BITS_11] = 380,
16  [TWR_DS18B20_RESOLUTION_BITS_12] = 760
17 };
18 
19 static void _twr_ds18b20_task_interval(void *param);
20 
21 static void _twr_ds18b20_task_measure(void *param);
22 
23 void twr_ds18b20_init_single(twr_ds18b20_t *self, twr_ds18b20_resolution_bits_t resolution)
24 {
25  static twr_ds18b20_sensor_t sensors[1];
27  twr_ds18b20_init(self, twr_module_sensor_get_onewire(), sensors, 1, resolution);
28 }
29 
30 void twr_ds18b20_init_multiple(twr_ds18b20_t *self, twr_ds18b20_sensor_t *sensors, int sensor_count, twr_ds18b20_resolution_bits_t resolution)
31 {
33  twr_ds18b20_init(self, twr_module_sensor_get_onewire(), sensors, sensor_count, resolution);
34 }
35 
36 void twr_ds18b20_init(twr_ds18b20_t *self, twr_onewire_t *onewire, twr_ds18b20_sensor_t *sensors, int sensor_count, twr_ds18b20_resolution_bits_t resolution)
37 {
38  memset(self, 0, sizeof(*self));
39 
40  self->_onewire = onewire;
41 
42  self->_resolution = resolution;
43  self->_sensor = sensors;
44  self->_sensor_count = sensor_count;
45 
46  for (int i = 0; i < self->_sensor_count; i++)
47  {
48  self->_sensor[i]._device_address = 0;
49  self->_sensor[i]._temperature_valid = false;
50  }
51 
52  self->_task_id_interval = twr_scheduler_register(_twr_ds18b20_task_interval, self, TWR_TICK_INFINITY);
53  self->_task_id_measure = twr_scheduler_register(_twr_ds18b20_task_measure, self, _TWR_DS18B20_DELAY_RUN);
54 }
55 
57  void (*event_handler)(twr_ds18b20_t *, uint64_t _device_address, twr_ds18b20_event_t, void *), void *event_param)
58 {
59  self->_event_handler = event_handler;
60  self->_event_param = event_param;
61 }
62 
64 {
65  self->_update_interval = interval;
66 
67  if (self->_update_interval == TWR_TICK_INFINITY)
68  {
69  twr_scheduler_plan_absolute(self->_task_id_interval, TWR_TICK_INFINITY);
70  }
71  else
72  {
73  twr_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
74 
75  twr_ds18b20_measure(self);
76  }
77 }
78 
80 {
81  if (self->_measurement_active)
82  {
83  return false;
84  }
85 
86  self->_measurement_active = true;
87 
88  twr_scheduler_plan_absolute(self->_task_id_measure, _TWR_DS18B20_DELAY_RUN);
89 
90  return true;
91 }
92 
93 int twr_ds18b20_get_index_by_device_address(twr_ds18b20_t *self, uint64_t device_address)
94 {
95  for (int i = 0; i < self->_sensor_found; i++)
96  {
97  if (self->_sensor[i]._device_address == device_address)
98  {
99  return i;
100  }
101  }
102 
103  return -1;
104 }
105 
106 uint64_t twr_ds182b0_get_short_address(twr_ds18b20_t *self, uint8_t index)
107 {
108  if (index >= self->_sensor_found)
109  {
110  return 0;
111  }
112 
113  uint64_t short_address = self->_sensor[index]._device_address;
114  short_address &= ~(((uint64_t) 0xff) << 56);
115  short_address >>= 8;
116 
117  return short_address;
118 }
119 
121 {
122  return self->_sensor_found;
123 }
124 
126 {
127  for (int i = 0; i < self->_sensor_found; i++)
128  {
129  self->_sensor[i]._device_address = 0;
130  self->_sensor[i]._temperature_valid = false;
131  }
132 
133  self->_measurement_active = true;
134 
135  self->_state = self->_sensor_found = 0;
136 
137  self->_state = TWR_DS18B20_STATE_PREINITIALIZE;
138 
139  twr_scheduler_plan_absolute(self->_task_id_measure, _TWR_DS18B20_DELAY_RUN);
140 }
141 
143 {
144  self->_power_dynamic = on;
145 }
146 
147 bool twr_ds18b20_get_temperature_raw(twr_ds18b20_t *self, uint64_t device_address, int16_t *raw)
148 {
149  int sensor_index = twr_ds18b20_get_index_by_device_address(self, device_address);
150 
151  if (sensor_index == -1)
152  {
153  return false;
154  }
155 
156  if (!self->_sensor[sensor_index]._temperature_valid)
157  {
158  return false;
159  }
160 
161  *raw = self->_sensor[sensor_index]._temperature_raw;
162 
163  return true;
164 }
165 
166 bool twr_ds18b20_get_temperature_celsius(twr_ds18b20_t *self, uint64_t device_address, float *celsius)
167 {
168  int sensor_index = twr_ds18b20_get_index_by_device_address(self, device_address);
169 
170  if (sensor_index == -1)
171  {
172  return false;
173  }
174 
175  if (!self->_sensor[sensor_index]._temperature_valid)
176  {
177  *celsius = NAN;
178  return false;
179  }
180 
181  if ((device_address & 0xFF) == 0x10)
182  {
183  // If sensor is DS18S20 with family code 0x10, divide by 2 because it is only 9bit sensor
184  *celsius = (float) self->_sensor[sensor_index]._temperature_raw / 2;
185  }
186  else
187  {
188  *celsius = (float) self->_sensor[sensor_index]._temperature_raw / 16;
189  }
190 
191  return true;
192 }
193 
194 static void _twr_ds18b20_task_interval(void *param)
195 {
196  twr_ds18b20_t *self = param;
197 
198  twr_ds18b20_measure(self);
199 
200  twr_scheduler_plan_current_relative(self->_update_interval);
201 }
202 
203 static bool _twr_ds18b20_power_up(twr_ds18b20_t *self)
204 {
205  if (self->_power)
206  {
207  return true;
208  }
209 
210  self->_power = true;
211 
212  #ifdef TWR_DS18B20_LOG
213  twr_log_debug("twr_ds18b20: Power UP");
214  #endif
215 
217  #ifdef TWR_DS18B20_LOG
218  twr_log_error("twr_ds18b20: call twr_module_sensor_onewire_power_up");
219  #endif
220  return false;
221  }
222 
223  return true;
224 }
225 
226 static bool _twr_ds18b20_power_down(twr_ds18b20_t *self)
227 {
228  if (!self->_power)
229  {
230  return true;
231  }
232 
233  self->_power = false;
234 
235  #ifdef TWR_DS18B20_LOG
236  twr_log_debug("twr_ds18b20: Power: OFF");
237  #endif
238 
240  #ifdef TWR_DS18B20_LOG
241  twr_log_error("twr_ds18b20: call twr_module_sensor_onewire_power_down");
242  #endif
243  return false;
244  }
245 
246  return true;
247 }
248 
249 static bool _twr_ds18b20_is_scratchpad_valid(uint8_t *scratchpad)
250 {
251  #ifdef TWR_DS18B20_STRICT_VALIDATION
252  if (scratchpad[5] != 0xff)
253  {
254  return false;
255  }
256 
257  if (scratchpad[7] != 0x10)
258  {
259  return false;
260  }
261  #endif
262 
263  if (twr_onewire_crc8(scratchpad, _TWR_DS18B20_SCRATCHPAD_SIZE, 0) != 0)
264  {
265  return false;
266  }
267 
268  return true;
269 }
270 
271 static void _twr_ds18b20_task_measure(void *param)
272 {
273  twr_ds18b20_t *self = param;
274 
275  start:
276 
277  switch (self->_state)
278  {
279  case TWR_DS18B20_STATE_ERROR:
280  {
281  #ifdef TWR_DS18B20_LOG
282  twr_log_error("twr_ds18b20: State Error");
283  #endif
284 
285  for (int i = 0; i < self->_sensor_found; i++)
286  {
287  self->_sensor[i]._temperature_valid = false;
288  }
289 
290  self->_measurement_active = false;
291 
292  _twr_ds18b20_power_down(self);
293 
294  if (self->_event_handler != NULL)
295  {
296  self->_event_handler(self, 0, TWR_DS18B20_EVENT_ERROR, self->_event_param);
297  }
298 
299  self->_state = self->_sensor_found > 0 ? TWR_DS18B20_STATE_READY : TWR_DS18B20_STATE_PREINITIALIZE;
300 
301  return;
302  }
303  case TWR_DS18B20_STATE_PREINITIALIZE:
304  {
305  #ifdef TWR_DS18B20_LOG
306  twr_log_debug("twr_ds18b20: State Preinitialize");
307  #endif
308 
309  self->_state = TWR_DS18B20_STATE_ERROR;
310 
311  if (!_twr_ds18b20_power_up(self))
312  {
313  goto start;
314  }
315 
316  self->_state = TWR_DS18B20_STATE_INITIALIZE;
317 
319 
320  break;
321  }
322  case TWR_DS18B20_STATE_INITIALIZE:
323  {
324  #ifdef TWR_DS18B20_LOG
325  twr_log_debug("twr_ds18b20: State Initialize");
326  #endif
327 
328  self->_state = TWR_DS18B20_STATE_ERROR;
329 
330  uint64_t _device_address = 0;
331  self->_sensor_found = 0;
332 
333  twr_onewire_search_start(self->_onewire, 0);
334  while ((self->_sensor_found < self->_sensor_count) && twr_onewire_search_next(self->_onewire, &_device_address))
335  {
336  self->_sensor[self->_sensor_found]._device_address = _device_address;
337  self->_sensor[self->_sensor_found]._temperature_valid = false;
338 
339  _device_address++;
340  self->_sensor_found++;
341 
342  #ifdef TWR_DS18B20_LOG
343  twr_log_debug("twr_ds18b20: Found 0x%08llx", _device_address);
344  #endif
345  }
346 
347  if (self->_sensor_found == 0)
348  {
349  goto start;
350  }
351 
352  twr_onewire_transaction_start(self->_onewire);
353 
354  // Write Scratchpad
355  if (!twr_onewire_reset(self->_onewire))
356  {
357  twr_onewire_transaction_stop(self->_onewire);
358  goto start;
359  }
360 
361  twr_onewire_skip_rom(self->_onewire);
362 
363  uint8_t buffer[] = {0x4e, 0x75, 0x70, self->_resolution << 5 | 0x1f};
364 
365  twr_onewire_write(self->_onewire, buffer, sizeof(buffer));
366 
367  twr_onewire_transaction_stop(self->_onewire);
368 
369  if (self->_measurement_active)
370  {
372  }
373  else if (self->_power_dynamic)
374  {
375  if (!_twr_ds18b20_power_down(self))
376  {
377  goto start;
378  }
379  }
380 
381  self->_state = TWR_DS18B20_STATE_READY;
382 
383  return;
384  }
385  case TWR_DS18B20_STATE_READY:
386  {
387  #ifdef TWR_DS18B20_LOG
388  twr_log_debug("twr_ds18b20: State Ready");
389  #endif
390 
391  self->_state = TWR_DS18B20_STATE_ERROR;
392 
393  if (!_twr_ds18b20_power_up(self))
394  {
395  goto start;
396  }
397 
398  self->_state = TWR_DS18B20_STATE_MEASURE;
399 
401 
402  return;
403  }
404  case TWR_DS18B20_STATE_MEASURE:
405  {
406  #ifdef TWR_DS18B20_LOG
407  twr_log_debug("twr_ds18b20: State Measure");
408  #endif
409  twr_onewire_transaction_start(self->_onewire);
410 
411  if (!twr_onewire_reset(self->_onewire))
412  {
413  // If no detect preset sensor set all sensor to invalid value, and call handler
414  twr_onewire_transaction_stop(self->_onewire);
415 
416  for (int i = 0; i < self->_sensor_found; i++)
417  {
418  self->_sensor[i]._temperature_valid = false;
419  }
420 
421  if (self->_power_dynamic) {
422  if (!_twr_ds18b20_power_down(self))
423  {
424  self->_state = TWR_DS18B20_STATE_ERROR;
425  goto start;
426  }
427  }
428 
429  self->_state = TWR_DS18B20_STATE_RESULTS;
431  return;
432  }
433 
434  twr_onewire_skip_rom(self->_onewire);
435 
436  twr_onewire_write_byte(self->_onewire, 0x44);
437 
438  twr_onewire_transaction_stop(self->_onewire);
439 
440  self->_state = TWR_DS18B20_STATE_READ;
441 
442  twr_scheduler_plan_current_from_now(_twr_ds18b20_lut_delay[self->_resolution]);
443 
444  return;
445  }
446  case TWR_DS18B20_STATE_READ:
447  {
448  #ifdef TWR_DS18B20_LOG
449  twr_log_debug("twr_ds18b20: State Read");
450  #endif
451 
452  self->_state = TWR_DS18B20_STATE_ERROR;
453 
454  uint8_t scratchpad[_TWR_DS18B20_SCRATCHPAD_SIZE];
455  int i = 0;
456 
457  for (; i < self->_sensor_found; i++)
458  {
459  twr_onewire_transaction_start(self->_onewire);
460 
461  if (!twr_onewire_reset(self->_onewire))
462  {
463  twr_onewire_transaction_stop(self->_onewire);
464  self->_sensor[i]._temperature_valid = false;
465  break;
466  }
467 
468  twr_onewire_select(self->_onewire, &self->_sensor[i]._device_address);
469 
470  twr_onewire_write_byte(self->_onewire, 0xBE);
471 
472  twr_onewire_read(self->_onewire, scratchpad, sizeof(scratchpad));
473 
474  twr_onewire_transaction_stop(self->_onewire);
475 
476  self->_sensor[i]._temperature_valid = _twr_ds18b20_is_scratchpad_valid(scratchpad);
477 
478  if (self->_sensor[i]._temperature_valid)
479  {
480  self->_sensor[i]._temperature_raw = ((int16_t) scratchpad[1]) << 8 | ((int16_t) scratchpad[0]);
481  } else {
482  #ifdef TWR_DS18B20_LOG
483  twr_log_warning("twr_ds18b20: invalid scratchpad 0x%08llx", self->_sensor[i]._device_address);
484  #endif
485  }
486  }
487 
488  for (; i < self->_sensor_found; i++)
489  {
490  self->_sensor[i]._temperature_valid = false;
491  }
492 
493  if (self->_power_dynamic) {
494  if (!_twr_ds18b20_power_down(self))
495  {
496  goto start;
497  }
498  }
499 
500  self->_state = TWR_DS18B20_STATE_RESULTS;
502  return;
503  }
504  case TWR_DS18B20_STATE_RESULTS:
505  {
506  #ifdef TWR_DS18B20_LOG
507  twr_log_debug("twr_ds18b20: State Results");
508  #endif
509 
510  self->_measurement_active = false;
511 
512  self->_state = TWR_DS18B20_STATE_READY;
513 
514  for (int i = 0; i < self->_sensor_found; i++)
515  {
516  if (self->_event_handler != NULL)
517  {
518  twr_ds18b20_event_t event = self->_sensor[i]._temperature_valid ? TWR_DS18B20_EVENT_UPDATE : TWR_DS18B20_EVENT_ERROR;
519 
520  self->_event_handler(self, self->_sensor[i]._device_address, event, self->_event_param);
521  }
522  }
523 
524  return;
525  }
526  default:
527  {
528  self->_state = TWR_DS18B20_STATE_ERROR;
529 
530  goto start;
531  }
532  }
533 }
534 
int twr_ds18b20_get_sensor_found(twr_ds18b20_t *self)
Get number of found sensor.
Definition: twr_ds18b20.c:120
void twr_ds18b20_set_event_handler(twr_ds18b20_t *self, void(*event_handler)(twr_ds18b20_t *, uint64_t _device_address, twr_ds18b20_event_t, void *), void *event_param)
Set callback function.
Definition: twr_ds18b20.c:56
void twr_ds18b20_init_single(twr_ds18b20_t *self, twr_ds18b20_resolution_bits_t resolution)
Initialize single ds18b20 over channel B on Sensor Module.
Definition: twr_ds18b20.c:23
void twr_ds18b20_set_update_interval(twr_ds18b20_t *self, twr_tick_t interval)
Set measurement interval.
Definition: twr_ds18b20.c:63
void twr_ds18b20_set_power_dynamic(twr_ds18b20_t *self, bool on)
Set power dynamic, Turns VDD on and pull 4k7 only for measurement.
Definition: twr_ds18b20.c:142
void twr_ds18b20_rescan(twr_ds18b20_t *self)
Request to rescan the bus.
Definition: twr_ds18b20.c:125
bool twr_ds18b20_get_temperature_celsius(twr_ds18b20_t *self, uint64_t device_address, float *celsius)
Get measured temperature in degrees of Celsius.
Definition: twr_ds18b20.c:166
void twr_ds18b20_init(twr_ds18b20_t *self, twr_onewire_t *onewire, twr_ds18b20_sensor_t *sensors, int sensor_count, twr_ds18b20_resolution_bits_t resolution)
Initialize ds18b20.
Definition: twr_ds18b20.c:36
twr_ds18b20_event_t
Callback events.
Definition: twr_ds18b20.h:16
int twr_ds18b20_get_index_by_device_address(twr_ds18b20_t *self, uint64_t device_address)
Get device index by its device address.
Definition: twr_ds18b20.c:93
struct twr_ds18b20_t twr_ds18b20_t
BigClown ds18b20 instance.
Definition: twr_ds18b20.h:27
bool twr_ds18b20_get_temperature_raw(twr_ds18b20_t *self, uint64_t device_address, int16_t *raw)
Get measured temperature in degrees of Celsius.
Definition: twr_ds18b20.c:147
bool twr_ds18b20_measure(twr_ds18b20_t *self)
Start measurement manually.
Definition: twr_ds18b20.c:79
uint64_t twr_ds182b0_get_short_address(twr_ds18b20_t *self, uint8_t index)
Get device index by its device address.
Definition: twr_ds18b20.c:106
void twr_ds18b20_init_multiple(twr_ds18b20_t *self, twr_ds18b20_sensor_t *sensors, int sensor_count, twr_ds18b20_resolution_bits_t resolution)
Initialize multiple ds18b20 over channel B on Sensor Module.
Definition: twr_ds18b20.c:30
@ TWR_DS18B20_EVENT_UPDATE
Update event.
Definition: twr_ds18b20.h:21
@ TWR_DS18B20_EVENT_ERROR
Error event.
Definition: twr_ds18b20.h:18
void void void void void twr_log_error(const char *format,...) __attribute__((format(printf
Log ERROR message (annotated in log as <E>)
void void void void twr_log_warning(const char *format,...) __attribute__((format(printf
Log WARNING message (annotated in log as <W>)
void void twr_log_debug(const char *format,...) __attribute__((format(printf
Log DEBUG message (annotated in log as <D>)
twr_onewire_t * twr_module_sensor_get_onewire(void)
Initialize and get Instance 1-Wire for channel B.
bool twr_module_sensor_onewire_power_down(void)
Semaphore for 1Wire Power down: for R1.1 set VDD Off, for R1.0 pull none on channel A.
bool twr_module_sensor_onewire_power_up(void)
Semaphore for 1Wire Power up: for R1.1 set VDD On, for R1.0 pull up 56R on channel A.
bool twr_module_sensor_init(void)
Initialize Sensor Module.
void twr_onewire_write(twr_onewire_t *self, const void *buffer, size_t length)
Select device.
Definition: twr_onewire.c:96
void twr_onewire_write_byte(twr_onewire_t *self, uint8_t data)
Select device.
Definition: twr_onewire.c:116
void twr_onewire_search_start(twr_onewire_t *self, uint8_t family_code)
Start of manual search, see also twr_onewire_search_next.
Definition: twr_onewire.c:214
struct twr_onewire_t twr_onewire_t
1-Wire instance
Definition: twr_onewire.h:14
void twr_onewire_skip_rom(twr_onewire_t *self)
Skip ROM.
Definition: twr_onewire.c:89
bool twr_onewire_transaction_start(twr_onewire_t *self)
Start transaction, enable pll and run timer.
Definition: twr_onewire.c:31
bool twr_onewire_reset(twr_onewire_t *self)
Reset the 1-Wire bus and return the presence of any device.
Definition: twr_onewire.c:55
void twr_onewire_read(twr_onewire_t *self, void *buffer, size_t length)
Select device.
Definition: twr_onewire.c:106
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_onewire_select(twr_onewire_t *self, uint64_t *device_number)
Select device.
Definition: twr_onewire.c:68
bool twr_onewire_transaction_stop(twr_onewire_t *self)
Stop transaction.
Definition: twr_onewire.c:43
bool twr_onewire_search_next(twr_onewire_t *self, uint64_t *device_number)
Manual search of next device.
Definition: twr_onewire.c:226
void twr_scheduler_plan_current_from_now(twr_tick_t tick)
Schedule current task to tick relative from now.
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
void twr_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
void twr_scheduler_plan_relative(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to tick relative from current spin.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16