ruuvi.drivers.c ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules
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"
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
38static ri_atomic_t m_is_init;
39static bool m_is_configured;
40static bool m_vdd_prepared;
41static bool m_vdd_sampled;
42static bool m_ratio;
43static float m_vdd;
44static uint8_t m_handle;
45static uint8_t m_channel[RI_ADC_CH_NUM];
46static uint8_t m_next_channel;
47
55static 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
83static 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
91static ri_adc_channel_config_t absolute_config =
92{
95#ifdef RI_ADC_ADV_CONFIG
96 .gain = RI_ADC_GAIN1_6,
97 .acqtime = RI_ADC_ACQTIME_10US,
98#endif
99};
100
101static ri_adc_get_data_t options =
102{
103 .vdd = RD_ADC_USE_VDD,
104 .divider = RD_ADC_USE_DIVIDER,
105};
106
107static 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;
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
199inline 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
308rd_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
356rd_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.