ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_task_adc.c
Go to the documentation of this file.
1 
13 #if RT_ADC_ENABLED
14 
15 #include "ruuvi_task_adc.h"
16 
17 #include <stdbool.h>
18 #include <string.h>
19 
20 #include "ruuvi_driver_error.h"
21 #include "ruuvi_driver_sensor.h"
23 #include "ruuvi_interface_atomic.h"
24 
25 #define RD_ADC_USE_DIVIDER 1.00f
26 #define RD_ADC_USE_VDD 3.30f
27 
28 #define RD_ADC_DATA_COUNTER 1
29 #define RD_ADC_DATA_START 0
30 #define RD_ADC_DATA_VOLTAGE 1
31 
32 #define RD_ADC_DEFAULT_BITFIELD 0
33 #define RD_ADC_CLEAN_BYTE 0
34 #define RD_ADC_INIT_BYTE 0
35 
36 #define RT_ADC_CH_UNUSED (0xFFU)
37 
38 static ri_atomic_t m_is_init;
39 static bool m_is_configured;
40 static bool m_vdd_prepared;
41 static bool m_vdd_sampled;
42 static bool m_ratio;
43 static float m_vdd;
44 static uint8_t m_handle;
45 static uint8_t m_channel[RI_ADC_CH_NUM];
46 static uint8_t m_next_channel;
47 
55 static rd_status_t channel_assign (const uint8_t handle)
56 {
57  rd_status_t err_code = RD_SUCCESS;
58 
59  if (handle > RI_ADC_CH_NUM)
60  {
61  err_code |= RD_ERROR_INVALID_PARAM;
62  }
63  else if (RT_ADC_CH_UNUSED == m_channel[handle])
64  {
65  if (ri_adc_mcu_is_valid_ch (m_next_channel))
66  {
67  m_channel[handle] = m_next_channel++;
68  }
69  else
70  {
71  err_code |= RD_ERROR_RESOURCES;
72  }
73  }
74  else
75  {
76  // No action needed.
77  }
78 
79  return err_code;
80 }
81 
82 
83 static ri_adc_pins_config_t pins_config =
84 {
86 #ifdef RI_ADC_ADV_CONFIG
87  .p_pin.resistor = RI_ADC_RESISTOR_DISABLED,
88 #endif
89 };
90 
91 static ri_adc_channel_config_t absolute_config =
92 {
94  .vref = RI_ADC_VREF_INTERNAL,
95 #ifdef RI_ADC_ADV_CONFIG
96  .gain = RI_ADC_GAIN1_6,
97  .acqtime = RI_ADC_ACQTIME_10US,
98 #endif
99 };
100 
101 static ri_adc_get_data_t options =
102 {
103  .vdd = RD_ADC_USE_VDD,
104  .divider = RD_ADC_USE_DIVIDER,
105 };
106 
107 static rd_status_t rt_adc_mcu_data_get (rd_sensor_data_t * const
108  p_data)
109 {
111 
112  if (NULL == p_data)
113  {
114  status = RD_ERROR_NULL;
115  }
116  else
117  {
119  rd_sensor_data_t d_adc;
120  rd_sensor_data_fields_t adc_fields = {.bitfield = RD_ADC_DEFAULT_BITFIELD};
121  float adc_values[RD_ADC_DATA_COUNTER] = {0};
122 
123  if (false == m_ratio)
124  {
125  status = ri_adc_get_data_absolute (m_channel[m_handle],
126  &options,
127  &adc_values[RD_ADC_DATA_START]);
128  }
129  else
130  {
131  status = ri_adc_get_data_ratio (m_channel[m_handle],
132  &options,
133  &adc_values[RD_ADC_DATA_START]);
134  }
135 
136  if (RD_SUCCESS == status)
137  {
138  adc_fields.datas.voltage_v = RD_ADC_DATA_COUNTER;
139  d_adc.data = adc_values;
140  d_adc.valid = adc_fields;
141  d_adc.fields = adc_fields;
142  rd_sensor_data_populate (p_data,
143  &d_adc,
144  p_data->fields);
146  }
147  }
148 
149  return RD_SUCCESS;
150 }
151 
153 {
154  rd_status_t err_code = RD_SUCCESS;
155 
156  if (!ri_atomic_flag (&m_is_init, true))
157  {
158  err_code |= RD_ERROR_INVALID_STATE;
159  }
160  else
161  {
162  for (size_t ii = 0; ii < RI_ADC_CH_NUM; ii++)
163  {
164  m_channel[ii] = RT_ADC_CH_UNUSED;
165  }
166 
167  m_next_channel = 0;
168  err_code |= ri_adc_init (NULL);
169  }
170 
171  return err_code;
172 }
173 
175 {
176  rd_status_t err_code = RD_SUCCESS;
177  m_is_configured = false;
178  m_vdd_prepared = false;
179  m_vdd_sampled = false;
180  m_ratio = false;
181  err_code |= ri_adc_stop (m_channel[m_handle]);
182  err_code |= ri_adc_uninit (true);
183 
184  for (size_t ii = 0; ii < RI_ADC_CH_NUM; ii++)
185  {
186  m_channel[ii] = RT_ADC_CH_UNUSED;
187  }
188 
189  m_next_channel = 0;
190 
191  if (!ri_atomic_flag (&m_is_init, false))
192  {
193  err_code |= RD_ERROR_FATAL;
194  }
195 
196  return err_code;
197 }
198 
199 inline bool rt_adc_is_init (void)
200 {
201  return (RD_ADC_INIT_BYTE != m_is_init);
202 }
203 
205  const uint8_t handle, const rt_adc_mode_t mode)
206 {
207  rd_status_t err_code = RD_SUCCESS;
208 
209  if (!rt_adc_is_init() || m_is_configured)
210  {
211  err_code |= RD_ERROR_INVALID_STATE;
212  }
213  else if (RI_ADC_GND == handle)
214  {
215  err_code |= RD_ERROR_INVALID_PARAM;
216  }
217  else
218  {
219  pins_config.p_pin.channel = handle;
220 
221  if (ABSOLUTE == mode)
222  {
223  m_ratio = false;
224  }
225  else
226  {
227  m_ratio = true;
228  }
229 
230  // Handle is used as channel index, however there is NONE at index 0.
231  m_handle = handle;
232  err_code |= channel_assign (m_handle);
233 
234  if (RD_SUCCESS == err_code)
235  {
236  err_code |= ri_adc_configure (m_channel[m_handle],
237  &pins_config,
238  &absolute_config);
239  }
240  }
241 
242  if (RD_SUCCESS == err_code)
243  {
244  m_is_configured = true;
245  }
246 
247  return err_code;
248 }
249 
251 {
252  rd_status_t err_code = RD_SUCCESS;
253 
254  if (!rt_adc_is_init() || !m_is_configured)
255  {
256  err_code |= RD_ERROR_INVALID_STATE;
257  }
258 
259  return err_code;
260 }
261 
263 {
264  rd_status_t err_code = RD_SUCCESS;
265 
266  if (!rt_adc_is_init() || !m_is_configured)
267  {
268  err_code |= RD_ERROR_INVALID_STATE;
269  }
270  else
271  {
272  if (true == m_ratio)
273  {
274  err_code |= RD_ERROR_INVALID_STATE;
275  }
276  else
277  {
278  err_code |= rt_adc_mcu_data_get (data);
279  }
280  }
281 
282  return err_code;
283 }
284 
286 {
287  rd_status_t err_code = RD_SUCCESS;
288 
289  if (!rt_adc_is_init() || !m_is_configured)
290  {
291  err_code |= RD_ERROR_INVALID_STATE;
292  }
293  else
294  {
295  if (false == m_ratio)
296  {
297  err_code |= RD_ERROR_INVALID_STATE;
298  }
299  else
300  {
301  err_code |= rt_adc_mcu_data_get (data);
302  }
303  }
304 
305  return err_code;
306 }
307 
308 rd_status_t rt_adc_vdd_prepare (rd_sensor_configuration_t * const vdd_adc_configuration)
309 {
310  rd_status_t err_code = RD_SUCCESS;
311  err_code |= rt_adc_init();
312 
313  if (err_code == RD_SUCCESS)
314  {
315  err_code |= rt_adc_configure_se (vdd_adc_configuration, RI_ADC_AINVDD,
316  ABSOLUTE);
317 
318  if (err_code == RD_SUCCESS)
319  {
320  m_vdd_prepared = true;
321  }
322  else
323  {
324  err_code |= rt_adc_uninit();
325  }
326  }
327 
328  return err_code;
329 }
330 
332 {
333  rd_status_t err_code = RD_SUCCESS;
334 
335  if (!m_vdd_prepared)
336  {
337  err_code |= RD_ERROR_INVALID_STATE;
338  }
339  else
340  {
341  rd_sensor_data_t battery;
342  memset (&battery, RD_ADC_CLEAN_BYTE, sizeof (rd_sensor_data_t));
343  float battery_values;
344  battery.data = &battery_values;
345  battery.fields.datas.voltage_v = RD_ADC_DATA_VOLTAGE;
346  err_code |= rt_adc_voltage_get (&battery);
347  m_vdd = rd_sensor_data_parse (&battery, battery.fields);
348  err_code |= rt_adc_uninit();
349  m_vdd_prepared = false;
350  m_vdd_sampled = true;
351  }
352 
353  return err_code;
354 }
355 
356 rd_status_t rt_adc_vdd_get (float * const battery)
357 {
358  rd_status_t err_code = RD_SUCCESS;
359 
360  if (true == m_vdd_sampled)
361  {
362  *battery = m_vdd;
363  }
364  else
365  {
366  err_code |= RD_ERROR_INVALID_STATE;
367  }
368 
369  return err_code;
370 }
371 
373  const uint8_t handle, float * const sample)
374 {
375  rd_status_t err_code = RD_SUCCESS;
376 
377  if ( (NULL == configuration) || (NULL == sample)) { return RD_ERROR_NULL; }
378 
379  rd_sensor_data_t d_adc;
380  memset (&d_adc, RD_ADC_CLEAN_BYTE, sizeof (rd_sensor_data_t));
381  float battery_values;
382  d_adc.data = &battery_values;
383  d_adc.fields.datas.voltage_v = RD_ADC_DATA_VOLTAGE;
384  err_code |= rt_adc_init();
385  err_code |= rt_adc_configure_se (configuration, handle, ABSOLUTE);
386  m_vdd_prepared = (RD_SUCCESS == err_code);
387 
388  if (m_vdd_prepared)
389  {
390  err_code |= rt_adc_sample();
391  err_code |= rt_adc_voltage_get (&d_adc);
392  }
393 
394  *sample = rd_sensor_data_parse (&d_adc, d_adc.fields);
395  return err_code;
396 }
397 
399  const uint8_t handle, float * const sample)
400 {
401  rd_status_t err_code = RD_SUCCESS;
402 
403  if ( (NULL == configuration) || (NULL == sample)) { return RD_ERROR_NULL; }
404 
405  rd_sensor_data_t d_adc;
406  memset (&d_adc, RD_ADC_CLEAN_BYTE, sizeof (rd_sensor_data_t));
407  float rate_values;
408  d_adc.data = &rate_values;
409  d_adc.fields.datas.voltage_ratio = RD_ADC_DATA_VOLTAGE;
410  err_code |= rt_adc_init();
411  err_code |= rt_adc_configure_se (configuration, handle, RATIOMETRIC);
412  m_vdd_prepared = (RD_SUCCESS == err_code);
413 
414  if (m_vdd_prepared)
415  {
416  err_code |= rt_adc_sample();
417  err_code |= rt_adc_ratio_get (&d_adc);
418  }
419 
420  *sample = rd_sensor_data_parse (&d_adc, d_adc.fields);
421  return err_code;
422 }
423 #endif
#define RD_ERROR_INVALID_PARAM
Invalid Parameter.
#define RD_ERROR_NULL
Null Pointer.
#define RD_ERROR_FATAL
Program should always reset after this.
uint32_t rd_status_t
bitfield for representing errors
#define RD_ERROR_RESOURCES
Not enough resources for operation.
#define RD_SUCCESS
Internal Error.
#define RD_UINT64_INVALID
Signal that value should not be used.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
void rd_sensor_data_populate(rd_sensor_data_t *const target, const rd_sensor_data_t *const provided, const rd_sensor_data_fields_t requested)
Populate given target data with data provided by sensor as requested.
uint64_t rd_sensor_timestamp_get(void)
Calls the timestamp function and returns its value.
float rd_sensor_data_parse(const rd_sensor_data_t *const provided, const rd_sensor_data_fields_t requested)
Parse data from provided struct.
rd_status_t rt_adc_vdd_get(float *const vdd)
Get VDD.
rd_status_t rt_adc_configure_se(rd_sensor_configuration_t *const config, const uint8_t handle, const rt_adc_mode_t mode)
Configure ADC before sampling.
rd_status_t rt_adc_init(void)
Reserve ADC.
rt_adc_mode_t
rd_status_t rt_adc_absolute_sample(rd_sensor_configuration_t *const configuration, const uint8_t handle, float *const sample)
Get absolute Voltage Sample from selected ADC handle.
rd_status_t rt_adc_vdd_prepare(rd_sensor_configuration_t *const vdd_adc_configuration)
Prepare for sampling VDD.
rd_status_t rt_adc_ratiometric_sample(rd_sensor_configuration_t *const configuration, const uint8_t handle, float *const sample)
Get ratiometric VDD Sample from selected ADC handle.
rd_status_t rt_adc_uninit(void)
Uninitialize ADC to release it for other users.
rd_status_t rt_adc_sample(void)
Take a new sample on ADC configured in single-shot/sleep mode.
rd_status_t rt_adc_ratio_get(rd_sensor_data_t *const data)
Populate data with latest ratiometric value.
bool rt_adc_is_init(void)
Check if ADC is initialized.
rd_status_t rt_adc_voltage_get(rd_sensor_data_t *const data)
Populate data with latest sample.
rd_status_t rt_adc_vdd_sample(void)
Sample VDD.
@ RATIOMETRIC
ADC compares value to VDD.
@ ABSOLUTE
ADC measures absolute voltage in volts.
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
Ruuvi sensor interface Lifecycle: Beta
Interface for controlling ADC onboard MCU.
rd_status_t ri_adc_uninit(bool config_default)
Uninitialize ADC.
@ RI_ADC_MODE_SINGLE
Single ended mode.
@ RI_ADC_VREF_INTERNAL
Internal voltage reference.
rd_status_t ri_adc_get_data_ratio(uint8_t channel_num, ri_adc_get_data_t *p_config, float *p_data)
Get ADC data in volts.
rd_status_t ri_adc_get_data_absolute(uint8_t channel_num, ri_adc_get_data_t *p_config, float *p_data)
Get ADC data in volts.
@ RI_ADC_CH_NUM
Number of ADC inputs.
@ RI_ADC_AINVDD
Analog supply voltage.
@ RI_ADC_GND
GND of device.
bool ri_adc_mcu_is_valid_ch(const uint8_t ch)
Return true if given channel index can be used by underlying implementation.
rd_status_t ri_adc_stop(uint8_t channel_num)
Stop use ADC channel.
rd_status_t ri_adc_configure(uint8_t channel_num, ri_adc_pins_config_t *p_pins, ri_adc_channel_config_t *p_config)
Configure ADC channel.
rd_status_t ri_adc_init(ri_adc_config_t *p_config)
Initialization of ADC.
bool ri_atomic_flag(ri_atomic_t *const flag, const bool set)
Atomic flag check and set/clear function.
volatile uint32_t ri_atomic_t
define atomic type - not portable to 8-bit.
All sensors must implement configuration functions which accept this struct.
unsigned int voltage_v
Voltage, volts.
unsigned int voltage_ratio
Voltage, ratio to maximum.
Generic sensor data struct.
float * data
Data of sensor. Must contain as many elements as fields has bits set.
uint64_t timestamp_ms
Timestamp of the event, rd_sensor_timestamp_get.
rd_sensor_data_fields_t valid
Listing of valid data in this sample.
rd_sensor_data_fields_t fields
Description of datafields which may be contained in this sample.
Union to access sensor data.
uint32_t bitfield
Bitfield used to access sensor data.
rd_sensor_data_bitfield_t datas
Structured data field.