Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_ds18b20.c
1 #include <bc_ds18b20.h>
2 #include <bc_onewire.h>
3 #include <bc_gpio.h>
4 #include <bc_i2c.h>
5 
6 #define _BC_DS18B20_SCRATCHPAD_SIZE 9
7 
8 static bc_tick_t _bc_ds18b20_lut_delay[] = {
9  [BC_DS18B20_RESOLUTION_BITS_9] = 100,
10  [BC_DS18B20_RESOLUTION_BITS_10] = 190,
11  [BC_DS18B20_RESOLUTION_BITS_11] = 380,
12  [BC_DS18B20_RESOLUTION_BITS_12] = 760
13 };
14 
15 static void _bc_ds18b20_task_interval(void *param);
16 
17 static void _bc_ds18b20_task_measure(void *param);
18 
19 static int _bc_ds18b20_power_semaphore = 0;
20 
21 void bc_ds18b20_init_single(bc_ds18b20_t *self, bc_ds18b20_resolution_bits_t resolution)
22 {
23  static bc_ds18b20_sensor_t sensor;
24  bc_ds18b20_init_multiple(self, &sensor, 1, resolution);
25 }
26 
27 void bc_ds18b20_init_multiple(bc_ds18b20_t *self, bc_ds18b20_sensor_t *sensors, int sensor_count, bc_ds18b20_resolution_bits_t resolution)
28 {
29  bc_ds18b20_init(self, BC_GPIO_P5, sensors, sensor_count, resolution);
30 }
31 
32 void bc_ds18b20_init(bc_ds18b20_t *self, bc_gpio_channel_t onewire_channel, bc_ds18b20_sensor_t *sensors, int sensor_count, bc_ds18b20_resolution_bits_t resolution)
33 {
34  memset(self, 0, sizeof(*self));
35 
36  self->_onewire_channel = onewire_channel;
37 
38  bc_onewire_init(self->_onewire_channel);
39 
40  self->_resolution = resolution;
41  self->_sensor = sensors;
42  self->_sensor_count = sensor_count;
43 
44  self->_task_id_interval = bc_scheduler_register(_bc_ds18b20_task_interval, self, BC_TICK_INFINITY);
45  self->_task_id_measure = bc_scheduler_register(_bc_ds18b20_task_measure, self, 10);
46 }
47 
49  void (*event_handler)(bc_ds18b20_t *, uint64_t _device_address, bc_ds18b20_event_t, void *), void *event_param)
50 {
51  self->_event_handler = event_handler;
52  self->_event_param = event_param;
53 }
54 
56 {
57  self->_update_interval = interval;
58 
59  if (self->_update_interval == BC_TICK_INFINITY)
60  {
61  bc_scheduler_plan_absolute(self->_task_id_interval, BC_TICK_INFINITY);
62  }
63  else
64  {
65  bc_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
66 
67  bc_ds18b20_measure(self);
68  }
69 }
70 
72 {
73  if (self->_measurement_active)
74  {
75  return false;
76  }
77 
78  self->_measurement_active = true;
79 
80  bc_scheduler_plan_now(self->_task_id_measure);
81 
82  return true;
83 }
84 
85 int bc_ds18b20_get_index_by_device_address(bc_ds18b20_t *self, uint64_t device_address)
86 {
87  for (int i = 0; i < self->_sensor_found; i++)
88  {
89  if (self->_sensor[i]._device_address == device_address)
90  {
91  return i;
92  }
93  }
94 
95  return -1;
96 }
97 
99 {
100  return self->_sensor_found;
101 }
102 
104 {
105  self->_power_dynamic = on;
106 }
107 
108 bool bc_ds18b20_get_temperature_raw(bc_ds18b20_t *self, uint64_t device_address, int16_t *raw)
109 {
110  int sensor_index = bc_ds18b20_get_index_by_device_address(self, device_address);
111 
112  if (sensor_index == -1)
113  {
114  return false;
115  }
116 
117  if (!self->_sensor[sensor_index]._temperature_valid)
118  {
119  return false;
120  }
121 
122  *raw = self->_sensor[sensor_index]._temperature_raw;
123 
124  return true;
125 }
126 
127 bool bc_ds18b20_get_temperature_celsius(bc_ds18b20_t *self, uint64_t device_address, float *celsius)
128 {
129  int sensor_index = bc_ds18b20_get_index_by_device_address(self, device_address);
130 
131  if (sensor_index == -1)
132  {
133  return false;
134  }
135 
136  if (!self->_sensor[sensor_index]._temperature_valid)
137  {
138  return false;
139  }
140 
141  if ((device_address & 0xFF) == 0x10)
142  {
143  // If sensor is DS18S20 with family code 0x10, divide by 2 because it is only 9bit sensor
144  *celsius = (float) self->_sensor[sensor_index]._temperature_raw / 2;
145  }
146  else
147  {
148  *celsius = (float) self->_sensor[sensor_index]._temperature_raw / 16;
149  }
150 
151  return true;
152 }
153 
154 static void _bc_ds18b20_task_interval(void *param)
155 {
156  bc_ds18b20_t *self = param;
157 
158  bc_ds18b20_measure(self);
159 
160  bc_scheduler_plan_current_relative(self->_update_interval);
161 }
162 
163 static bool _bc_ds18b20_power_up(bc_ds18b20_t *self)
164 {
165  if (self->_power)
166  {
167  return true;
168  }
169 
170  if (_bc_ds18b20_power_semaphore == 0)
171  {
172 
174 
176  {
178  }
179  else
180  {
182  }
183 
185  {
186  return false;
187  }
188  }
189 
190  _bc_ds18b20_power_semaphore++;
191 
192  self->_power = true;
193 
194  return true;
195 }
196 
197 static bool _bc_ds18b20_power_down(bc_ds18b20_t *self)
198 {
199  if (!self->_power_dynamic) // If power dynamic equal False, can't power down
200  {
201  return true;
202  }
203 
204  if (!self->_power)
205  {
206  return true;
207  }
208 
209  if (_bc_ds18b20_power_semaphore == 1)
210  {
212 
214  {
216  }
217  else
218  {
220  }
221 
223  {
224  return false;
225  }
226  }
227 
228  _bc_ds18b20_power_semaphore--;
229 
230  self->_power = false;
231 
232  return true;
233 }
234 
235 static bool _bc_ds18b20_is_scratchpad_valid(uint8_t *scratchpad)
236 {
237  #ifdef BC_DS18B20_STRICT_VALIDATION
238  if (scratchpad[5] != 0xff)
239  {
240  return false;
241  }
242 
243  if (scratchpad[7] != 0x10)
244  {
245  return false;
246  }
247  #endif
248 
249  if (bc_onewire_crc8(scratchpad, _BC_DS18B20_SCRATCHPAD_SIZE, 0) != 0)
250  {
251  return false;
252  }
253 
254  return true;
255 }
256 
257 static void _bc_ds18b20_task_measure(void *param)
258 {
259  bc_ds18b20_t *self = param;
260 
261  start:
262 
263  switch (self->_state)
264  {
265  case BC_DS18B20_STATE_ERROR:
266  {
267  for (int i = 0; i < self->_sensor_found; i++)
268  {
269  self->_sensor[i]._temperature_valid = false;
270  }
271 
272  self->_measurement_active = false;
273 
274  _bc_ds18b20_power_down(self);
275 
276  if (self->_event_handler != NULL)
277  {
278  self->_event_handler(self, 0, BC_DS18B20_EVENT_ERROR, self->_event_param);
279  }
280 
281  self->_state = BC_DS18B20_STATE_PREINITIALIZE;
282 
283  return;
284  }
285  case BC_DS18B20_STATE_PREINITIALIZE:
286  {
287  self->_state = BC_DS18B20_STATE_ERROR;
288 
289  if (!bc_module_sensor_init())
290  {
291  goto start;
292  }
293 
295 
296  if (!_bc_ds18b20_power_up(self))
297  {
298  goto start;
299  }
300 
301  self->_state = BC_DS18B20_STATE_INITIALIZE;
302 
304 
305  break;
306  }
307  case BC_DS18B20_STATE_INITIALIZE:
308  {
309  self->_state = BC_DS18B20_STATE_ERROR;
310 
311  uint64_t _device_address = 0;
312  self->_sensor_found = 0;
313 
315  while ((self->_sensor_found < self->_sensor_count) && bc_onewire_search_next(self->_onewire_channel, &_device_address))
316  {
317  self->_sensor[self->_sensor_found]._device_address = _device_address;
318 
319  _device_address++;
320  self->_sensor_found++;
321  }
322 
323  if (self->_sensor_found == 0)
324  {
325  goto start;
326  }
327 
328  bc_onewire_transaction_start(self->_onewire_channel);
329 
330  // Write Scratchpad
331  if (!bc_onewire_reset(self->_onewire_channel))
332  {
333  bc_onewire_transaction_stop(self->_onewire_channel);
334 
335  goto start;
336  }
337 
338  bc_onewire_skip_rom(self->_onewire_channel);
339 
340  uint8_t buffer[] = {0x4e, 0x75, 0x70, self->_resolution << 5 | 0x1f};
341 
342  bc_onewire_write(self->_onewire_channel, buffer, sizeof(buffer));
343 
344  bc_onewire_transaction_stop(self->_onewire_channel);
345 
346  if (self->_measurement_active)
347  {
349  }
350  else
351  {
352  if (!_bc_ds18b20_power_down(self))
353  {
354  goto start;
355  }
356  }
357 
358  self->_state = BC_DS18B20_STATE_READY;
359 
360  return;
361  }
362  case BC_DS18B20_STATE_READY:
363  {
364  self->_state = BC_DS18B20_STATE_ERROR;
365 
366  if (!_bc_ds18b20_power_up(self))
367  {
368  goto start;
369  }
370 
371  self->_state = BC_DS18B20_STATE_MEASURE;
372 
374 
375  return;
376  }
377  case BC_DS18B20_STATE_MEASURE:
378  {
379  self->_state = BC_DS18B20_STATE_ERROR;
380 
381  bc_onewire_transaction_start(self->_onewire_channel);
382 
383  if (!bc_onewire_reset(self->_onewire_channel))
384  {
385  bc_onewire_transaction_stop(self->_onewire_channel);
386  goto start;
387  }
388 
389  //bc_onewire_select(self->_onewire_channel, &self->_device_address);
390  bc_onewire_skip_rom(self->_onewire_channel);
391 
392  bc_onewire_write_8b(self->_onewire_channel, 0x44);
393 
394  bc_onewire_transaction_stop(self->_onewire_channel);
395 
396  self->_state = BC_DS18B20_STATE_READ;
397 
398  bc_scheduler_plan_current_from_now(_bc_ds18b20_lut_delay[self->_resolution]);
399 
400  return;
401  }
402  case BC_DS18B20_STATE_READ:
403  {
404  self->_state = BC_DS18B20_STATE_ERROR;
405 
406  uint8_t scratchpad[_BC_DS18B20_SCRATCHPAD_SIZE];
407 
408  for (int i = 0; i < self->_sensor_found; i++)
409  {
410  bc_onewire_transaction_start(self->_onewire_channel);
411 
412  if (!bc_onewire_reset(self->_onewire_channel))
413  {
414  bc_onewire_transaction_stop(self->_onewire_channel);
415 
416  goto start;
417  }
418 
419  bc_onewire_select(self->_onewire_channel, &self->_sensor[i]._device_address);
420 
421  bc_onewire_write_8b(self->_onewire_channel, 0xBE);
422 
423  bc_onewire_read(self->_onewire_channel, scratchpad, sizeof(scratchpad));
424 
425  bc_onewire_transaction_stop(self->_onewire_channel);
426 
427 
428  if (!_bc_ds18b20_is_scratchpad_valid(scratchpad))
429  {
430  goto start;
431  }
432 
433  self->_sensor[i]._temperature_raw = ((int16_t) scratchpad[1]) << 8 | ((int16_t) scratchpad[0]);
434  self->_sensor[i]._temperature_valid = true;
435  }
436 
437  if (!_bc_ds18b20_power_down(self))
438  {
439  goto start;
440  }
441 
442  self->_state = BC_DS18B20_STATE_UPDATE;
443 
444  goto start;
445  }
446  case BC_DS18B20_STATE_UPDATE:
447  {
448  self->_measurement_active = false;
449 
450  self->_state = BC_DS18B20_STATE_READY;
451 
452  for (int i = 0; i < self->_sensor_found; i++)
453  {
454  if (self->_event_handler != NULL)
455  {
456  self->_event_handler(self, self->_sensor[i]._device_address, BC_DS18B20_EVENT_UPDATE, self->_event_param);
457  }
458  }
459 
460  return;
461  }
462  default:
463  {
464  self->_state = BC_DS18B20_STATE_ERROR;
465 
466  goto start;
467  }
468  }
469 }
470 
void bc_ds18b20_init_multiple(bc_ds18b20_t *self, bc_ds18b20_sensor_t *sensors, int sensor_count, bc_ds18b20_resolution_bits_t resolution)
Initialize multiple ds18b20 over channel B on Sensor Module.
Definition: bc_ds18b20.c:27
int bc_ds18b20_get_index_by_device_address(bc_ds18b20_t *self, uint64_t device_address)
Get device index by its device address.
Definition: bc_ds18b20.c:85
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
GPIO channel P5.
Definition: bc_gpio.h:30
Channel has pull-up 4k7.
bool bc_module_sensor_set_pull(bc_module_sensor_channel_t channel, bc_module_sensor_pull_t pull)
Set pull of Sensor Module channel.
bool bc_onewire_search_next(bc_gpio_channel_t channel, uint64_t *device_number)
Manual search of next device.
Definition: bc_onewire.c:425
struct bc_ds18b20_t bc_ds18b20_t
BigClown ds18b20 instance.
Definition: bc_ds18b20.h:27
void bc_scheduler_plan_absolute(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to absolute tick.
Definition: bc_scheduler.c:124
void bc_ds18b20_init(bc_ds18b20_t *self, bc_gpio_channel_t onewire_channel, bc_ds18b20_sensor_t *sensors, int sensor_count, bc_ds18b20_resolution_bits_t resolution)
Initialize ds18b20.
Definition: bc_ds18b20.c:32
Update event.
Definition: bc_ds18b20.h:21
bc_ds18b20_event_t
Callback events.
Definition: bc_ds18b20.h:15
Channel has no pull.
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
bool bc_ds18b20_measure(bc_ds18b20_t *self)
Start measurement manually.
Definition: bc_ds18b20.c:71
bc_module_sensor_revision_t bc_module_sensor_get_revision(void)
Get Sensor Module revision.
bool bc_onewire_transaction_stop(bc_gpio_channel_t channel)
Stop transaction.
Definition: bc_onewire.c:67
void bc_ds18b20_set_power_dynamic(bc_ds18b20_t *self, bool on)
Set power dynamic, Turns VDD on and pull 4k7 only for measurement.
Definition: bc_ds18b20.c:103
bool bc_module_sensor_set_vdd(bool on)
Set VDD On / Off.
void bc_scheduler_plan_current_relative(bc_tick_t tick)
Schedule current task to tick relative from current spin.
Definition: bc_scheduler.c:149
void bc_ds18b20_init_single(bc_ds18b20_t *self, bc_ds18b20_resolution_bits_t resolution)
Initialize single ds18b20 over channel B on Sensor Module.
Definition: bc_ds18b20.c:21
int bc_ds18b20_get_sensor_found(bc_ds18b20_t *self)
Get number of found sensor.
Definition: bc_ds18b20.c:98
void bc_onewire_write_8b(bc_gpio_channel_t channel, uint8_t data)
Select device.
Definition: bc_onewire.c:152
void bc_onewire_search_start(uint8_t family_code)
Start of manual search, see also bc_onewire_search_next.
Definition: bc_onewire.c:413
bool bc_onewire_reset(bc_gpio_channel_t channel)
Reset the 1-Wire bus and return the presence of any device.
Definition: bc_onewire.c:91
void bc_onewire_init(bc_gpio_channel_t channel)
Initialize 1-Wire.
Definition: bc_onewire.c:35
void bc_scheduler_plan_relative(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to tick relative from current spin.
Definition: bc_scheduler.c:129
void bc_onewire_select(bc_gpio_channel_t channel, uint64_t *device_number)
Select device.
Definition: bc_onewire.c:104
bool bc_onewire_transaction_start(bc_gpio_channel_t channel)
Start transaction, enable pll and run timer.
Definition: bc_onewire.c:51
bool bc_ds18b20_get_temperature_celsius(bc_ds18b20_t *self, uint64_t device_address, float *celsius)
Get measured temperature in degrees of Celsius.
Definition: bc_ds18b20.c:127
Channel operates as input.
void bc_module_sensor_set_mode(bc_module_sensor_channel_t channel, bc_module_sensor_mode_t mode)
Set output mode of Sensor Module channel.
Error event.
Definition: bc_ds18b20.h:18
uint8_t bc_onewire_crc8(const void *buffer, size_t length, uint8_t crc)
Calculate 8-bit CRC.
Definition: bc_onewire.c:197
void bc_scheduler_plan_current_from_now(bc_tick_t tick)
Schedule current task to tick relative from now.
Definition: bc_scheduler.c:154
bool bc_ds18b20_get_temperature_raw(bc_ds18b20_t *self, uint64_t device_address, int16_t *raw)
Get measured temperature in degrees of Celsius.
Definition: bc_ds18b20.c:108
Hardware revision R1.1.
void bc_ds18b20_set_update_interval(bc_ds18b20_t *self, bc_tick_t interval)
Set measurement interval.
Definition: bc_ds18b20.c:55
Channel has pull-up 56R.
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
bc_gpio_channel_t
GPIO channels.
Definition: bc_gpio.h:12
void bc_onewire_write(bc_gpio_channel_t channel, const void *buffer, size_t length)
Select device.
Definition: bc_onewire.c:132
void bc_onewire_skip_rom(bc_gpio_channel_t channel)
Skip ROM.
Definition: bc_onewire.c:125
bool bc_module_sensor_init(void)
Initialize Sensor Module.
void bc_ds18b20_set_event_handler(bc_ds18b20_t *self, void(*event_handler)(bc_ds18b20_t *, uint64_t _device_address, bc_ds18b20_event_t, void *), void *event_param)
Set callback function.
Definition: bc_ds18b20.c:48
void bc_onewire_read(bc_gpio_channel_t channel, void *buffer, size_t length)
Select device.
Definition: bc_onewire.c:142
void bc_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
Definition: bc_scheduler.c:139