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 
7 #define _TWR_DS18B20_SCRATCHPAD_SIZE 9
8 #define _TWR_DS18B20_DELAY_RUN 5000
9 
10 static twr_tick_t _twr_ds18b20_lut_delay[] = {
11  [TWR_DS18B20_RESOLUTION_BITS_9] = 100,
12  [TWR_DS18B20_RESOLUTION_BITS_10] = 190,
13  [TWR_DS18B20_RESOLUTION_BITS_11] = 380,
14  [TWR_DS18B20_RESOLUTION_BITS_12] = 760
15 };
16 
17 static void _twr_ds18b20_task_interval(void *param);
18 
19 static void _twr_ds18b20_task_measure(void *param);
20 
21 static int _twr_ds18b20_power_semaphore = 0;
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  self->_power = true;
29 }
30 
31 void twr_ds18b20_init_multiple(twr_ds18b20_t *self, twr_ds18b20_sensor_t *sensors, int sensor_count, twr_ds18b20_resolution_bits_t resolution)
32 {
34  twr_ds18b20_init(self, twr_module_sensor_get_onewire(), sensors, sensor_count, resolution);
35  self->_power = true;
36 }
37 
38 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)
39 {
40  memset(self, 0, sizeof(*self));
41 
42  self->_onewire = onewire;
43 
44  self->_resolution = resolution;
45  self->_sensor = sensors;
46  self->_sensor_count = sensor_count;
47 
48  self->_task_id_interval = twr_scheduler_register(_twr_ds18b20_task_interval, self, TWR_TICK_INFINITY);
49  self->_task_id_measure = twr_scheduler_register(_twr_ds18b20_task_measure, self, _TWR_DS18B20_DELAY_RUN);
50 }
51 
53  void (*event_handler)(twr_ds18b20_t *, uint64_t _device_address, twr_ds18b20_event_t, void *), void *event_param)
54 {
55  self->_event_handler = event_handler;
56  self->_event_param = event_param;
57 }
58 
60 {
61  self->_update_interval = interval;
62 
63  if (self->_update_interval == TWR_TICK_INFINITY)
64  {
65  twr_scheduler_plan_absolute(self->_task_id_interval, TWR_TICK_INFINITY);
66  }
67  else
68  {
69  twr_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
70 
71  twr_ds18b20_measure(self);
72  }
73 }
74 
76 {
77  if (self->_measurement_active)
78  {
79  return false;
80  }
81 
82  self->_measurement_active = true;
83 
84  twr_scheduler_plan_absolute(self->_task_id_measure, _TWR_DS18B20_DELAY_RUN);
85 
86  return true;
87 }
88 
89 int twr_ds18b20_get_index_by_device_address(twr_ds18b20_t *self, uint64_t device_address)
90 {
91  for (int i = 0; i < self->_sensor_found; i++)
92  {
93  if (self->_sensor[i]._device_address == device_address)
94  {
95  return i;
96  }
97  }
98 
99  return -1;
100 }
101 
102 uint64_t twr_ds182b0_get_short_address(twr_ds18b20_t *self, uint8_t index)
103 {
104  if (index >= self->_sensor_found)
105  {
106  return 0;
107  }
108 
109  uint64_t short_address = self->_sensor[index]._device_address;
110  short_address &= ~(((uint64_t) 0xff) << 56);
111  short_address >>= 8;
112 
113  return short_address;
114 }
115 
117 {
118  return self->_sensor_found;
119 }
120 
122 {
123  self->_power_dynamic = on;
124 }
125 
126 bool twr_ds18b20_get_temperature_raw(twr_ds18b20_t *self, uint64_t device_address, int16_t *raw)
127 {
128  int sensor_index = twr_ds18b20_get_index_by_device_address(self, device_address);
129 
130  if (sensor_index == -1)
131  {
132  return false;
133  }
134 
135  if (!self->_sensor[sensor_index]._temperature_valid)
136  {
137  return false;
138  }
139 
140  *raw = self->_sensor[sensor_index]._temperature_raw;
141 
142  return true;
143 }
144 
145 bool twr_ds18b20_get_temperature_celsius(twr_ds18b20_t *self, uint64_t device_address, float *celsius)
146 {
147  int sensor_index = twr_ds18b20_get_index_by_device_address(self, device_address);
148 
149  if (sensor_index == -1)
150  {
151  return false;
152  }
153 
154  if (!self->_sensor[sensor_index]._temperature_valid)
155  {
156  return false;
157  }
158 
159  if ((device_address & 0xFF) == 0x10)
160  {
161  // If sensor is DS18S20 with family code 0x10, divide by 2 because it is only 9bit sensor
162  *celsius = (float) self->_sensor[sensor_index]._temperature_raw / 2;
163  }
164  else
165  {
166  *celsius = (float) self->_sensor[sensor_index]._temperature_raw / 16;
167  }
168 
169  return true;
170 }
171 
172 static void _twr_ds18b20_task_interval(void *param)
173 {
174  twr_ds18b20_t *self = param;
175 
176  twr_ds18b20_measure(self);
177 
178  twr_scheduler_plan_current_relative(self->_update_interval);
179 }
180 
181 static bool _twr_ds18b20_power_up(twr_ds18b20_t *self)
182 {
183  if (!self->_power_dynamic) // If power dynamic equal False, can't power down
184  {
185  return true;
186  }
187 
188  if (self->_power)
189  {
190  return true;
191  }
192 
193  if (_twr_ds18b20_power_semaphore == 0)
194  {
196 
198  {
200  }
201  else
202  {
204  }
205 
207  {
208  return false;
209  }
210  }
211 
212  _twr_ds18b20_power_semaphore++;
213 
214  self->_power = true;
215 
216  return true;
217 }
218 
219 static bool _twr_ds18b20_power_down(twr_ds18b20_t *self)
220 {
221  if (!self->_power_dynamic) // If power dynamic equal False, can't power down
222  {
223  return true;
224  }
225 
226  if (!self->_power)
227  {
228  return true;
229  }
230 
231  if (_twr_ds18b20_power_semaphore == 1)
232  {
234 
236  {
238  }
239  else
240  {
242  }
243 
245  {
246  return false;
247  }
248  }
249 
250  _twr_ds18b20_power_semaphore--;
251 
252  self->_power = false;
253 
254  return true;
255 }
256 
257 static bool _twr_ds18b20_is_scratchpad_valid(uint8_t *scratchpad)
258 {
259  #ifdef TWR_DS18B20_STRICT_VALIDATION
260  if (scratchpad[5] != 0xff)
261  {
262  return false;
263  }
264 
265  if (scratchpad[7] != 0x10)
266  {
267  return false;
268  }
269  #endif
270 
271  if (twr_onewire_crc8(scratchpad, _TWR_DS18B20_SCRATCHPAD_SIZE, 0) != 0)
272  {
273  return false;
274  }
275 
276  return true;
277 }
278 
279 static void _twr_ds18b20_task_measure(void *param)
280 {
281  twr_ds18b20_t *self = param;
282 
283  start:
284 
285  switch (self->_state)
286  {
287  case TWR_DS18B20_STATE_ERROR:
288  {
289  for (int i = 0; i < self->_sensor_found; i++)
290  {
291  self->_sensor[i]._temperature_valid = false;
292  }
293 
294  self->_measurement_active = false;
295 
296  _twr_ds18b20_power_down(self);
297 
298  if (self->_event_handler != NULL)
299  {
300  self->_event_handler(self, 0, TWR_DS18B20_EVENT_ERROR, self->_event_param);
301  }
302 
303  self->_state = TWR_DS18B20_STATE_PREINITIALIZE;
304 
305  return;
306  }
307  case TWR_DS18B20_STATE_PREINITIALIZE:
308  {
309  self->_state = TWR_DS18B20_STATE_ERROR;
310 
311  if (self->_power_dynamic)
312  {
314 
315  if (!_twr_ds18b20_power_up(self))
316  {
317  goto start;
318  }
319  }
320 
321  self->_state = TWR_DS18B20_STATE_INITIALIZE;
322 
324 
325  break;
326  }
327  case TWR_DS18B20_STATE_INITIALIZE:
328  {
329  self->_state = TWR_DS18B20_STATE_ERROR;
330 
331  uint64_t _device_address = 0;
332  self->_sensor_found = 0;
333 
334 
335  twr_onewire_search_start(self->_onewire, 0);
336  while ((self->_sensor_found < self->_sensor_count) && twr_onewire_search_next(self->_onewire, &_device_address))
337  {
338  self->_sensor[self->_sensor_found]._device_address = _device_address;
339 
340  _device_address++;
341  self->_sensor_found++;
342  }
343 
344  if (self->_sensor_found == 0)
345  {
346  // twr_onewire_transaction_stop(self->_onewire);
347  goto start;
348  }
349 
350  twr_onewire_transaction_start(self->_onewire);
351 
352  // Write Scratchpad
353  if (!twr_onewire_reset(self->_onewire))
354  {
355  twr_onewire_transaction_stop(self->_onewire);
356 
357  goto start;
358  }
359 
360  twr_onewire_skip_rom(self->_onewire);
361 
362  uint8_t buffer[] = {0x4e, 0x75, 0x70, self->_resolution << 5 | 0x1f};
363 
364  twr_onewire_write(self->_onewire, buffer, sizeof(buffer));
365 
366  twr_onewire_transaction_stop(self->_onewire);
367 
368  if (self->_measurement_active)
369  {
371  }
372  else
373  {
374  if (!_twr_ds18b20_power_down(self))
375  {
376  goto start;
377  }
378  }
379 
380  self->_state = TWR_DS18B20_STATE_READY;
381 
382  return;
383  }
384  case TWR_DS18B20_STATE_READY:
385  {
386  self->_state = TWR_DS18B20_STATE_ERROR;
387 
388  if (!_twr_ds18b20_power_up(self))
389  {
390  goto start;
391  }
392 
393  self->_state = TWR_DS18B20_STATE_MEASURE;
394 
396 
397  return;
398  }
399  case TWR_DS18B20_STATE_MEASURE:
400  {
401  self->_state = TWR_DS18B20_STATE_ERROR;
402 
403  twr_onewire_transaction_start(self->_onewire);
404 
405  if (!twr_onewire_reset(self->_onewire))
406  {
407  twr_onewire_transaction_stop(self->_onewire);
408  goto start;
409  }
410 
411  //twr_onewire_select(self->_onewire, &self->_device_address);
412  twr_onewire_skip_rom(self->_onewire);
413 
414  twr_onewire_write_byte(self->_onewire, 0x44);
415 
416  twr_onewire_transaction_stop(self->_onewire);
417 
418  self->_state = TWR_DS18B20_STATE_READ;
419 
420  twr_scheduler_plan_current_from_now(_twr_ds18b20_lut_delay[self->_resolution]);
421 
422  return;
423  }
424  case TWR_DS18B20_STATE_READ:
425  {
426  self->_state = TWR_DS18B20_STATE_ERROR;
427 
428  uint8_t scratchpad[_TWR_DS18B20_SCRATCHPAD_SIZE];
429 
430  for (int i = 0; i < self->_sensor_found; i++)
431  {
432  twr_onewire_transaction_start(self->_onewire);
433 
434  if (!twr_onewire_reset(self->_onewire))
435  {
436  twr_onewire_transaction_stop(self->_onewire);
437 
438  goto start;
439  }
440 
441  twr_onewire_select(self->_onewire, &self->_sensor[i]._device_address);
442 
443  twr_onewire_write_byte(self->_onewire, 0xBE);
444 
445  twr_onewire_read(self->_onewire, scratchpad, sizeof(scratchpad));
446 
447  twr_onewire_transaction_stop(self->_onewire);
448 
449 
450  if (!_twr_ds18b20_is_scratchpad_valid(scratchpad))
451  {
452  goto start;
453  }
454 
455  self->_sensor[i]._temperature_raw = ((int16_t) scratchpad[1]) << 8 | ((int16_t) scratchpad[0]);
456  self->_sensor[i]._temperature_valid = true;
457  }
458 
459  if (!_twr_ds18b20_power_down(self))
460  {
461  goto start;
462  }
463 
464  self->_state = TWR_DS18B20_STATE_UPDATE;
465 
466  goto start;
467  }
468  case TWR_DS18B20_STATE_UPDATE:
469  {
470  self->_measurement_active = false;
471 
472  self->_state = TWR_DS18B20_STATE_READY;
473 
474  for (int i = 0; i < self->_sensor_found; i++)
475  {
476  if (self->_event_handler != NULL)
477  {
478  self->_event_handler(self, self->_sensor[i]._device_address, TWR_DS18B20_EVENT_UPDATE, self->_event_param);
479  }
480  }
481 
482  return;
483  }
484  default:
485  {
486  self->_state = TWR_DS18B20_STATE_ERROR;
487 
488  goto start;
489  }
490  }
491 }
492 
Channel has pull-up 4k7.
Channel operates as input.
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.
bool twr_ds18b20_measure(twr_ds18b20_t *self)
Start measurement manually.
Definition: twr_ds18b20.c:75
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:31
void twr_ds18b20_set_update_interval(twr_ds18b20_t *self, twr_tick_t interval)
Set measurement interval.
Definition: twr_ds18b20.c:59
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
bool twr_onewire_transaction_stop(twr_onewire_t *self)
Stop transaction.
Definition: twr_onewire.c:43
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
bool twr_onewire_search_next(twr_onewire_t *self, uint64_t *device_number)
Manual search of next device.
Definition: twr_onewire.c:226
bool twr_module_sensor_init(void)
Initialize Sensor Module.
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_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:38
bool twr_onewire_transaction_start(twr_onewire_t *self)
Start transaction, enable pll and run timer.
Definition: twr_onewire.c:31
twr_module_sensor_revision_t twr_module_sensor_get_revision(void)
Get Sensor Module revision.
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
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:145
void twr_module_sensor_set_mode(twr_module_sensor_channel_t channel, twr_module_sensor_mode_t mode)
Set output mode of Sensor Module channel.
int twr_ds18b20_get_sensor_found(twr_ds18b20_t *self)
Get number of found sensor.
Definition: twr_ds18b20.c:116
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:121
bool twr_module_sensor_set_pull(twr_module_sensor_channel_t channel, twr_module_sensor_pull_t pull)
Set pull of Sensor Module channel.
void twr_onewire_write_byte(twr_onewire_t *self, uint8_t data)
Select device.
Definition: twr_onewire.c:116
void twr_onewire_read(twr_onewire_t *self, void *buffer, size_t length)
Select device.
Definition: twr_onewire.c:106
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:52
void twr_scheduler_plan_current_from_now(twr_tick_t tick)
Schedule current task to tick relative from now.
void twr_onewire_select(twr_onewire_t *self, uint64_t *device_number)
Select device.
Definition: twr_onewire.c:68
void twr_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
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...
struct twr_onewire_t twr_onewire_t
1-Wire instance
Definition: twr_onewire.h:14
Channel has pull-up 56R.
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
void twr_onewire_skip_rom(twr_onewire_t *self)
Skip ROM.
Definition: twr_onewire.c:89
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:126
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
Hardware revision R1.1.
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:102
bool twr_module_sensor_set_vdd(bool on)
Set VDD On / Off.
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:89
Channel has no pull.
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
twr_ds18b20_event_t
Callback events.
Definition: twr_ds18b20.h:15
void twr_onewire_write(twr_onewire_t *self, const void *buffer, size_t length)
Select device.
Definition: twr_onewire.c:96
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
twr_onewire_t * twr_module_sensor_get_onewire(void)
Initialize and get Instance 1-Wire for channel B.
struct twr_ds18b20_t twr_ds18b20_t
BigClown ds18b20 instance.
Definition: twr_ds18b20.h:27