File syn_adc.c¶
File List > drivers > syn_adc.c
Go to the documentation of this file
#if __has_include("syn_config.h")
#include "syn_config.h"
#endif
#if !defined(SYN_USE_ADC) || SYN_USE_ADC
#include "../util/syn_assert.h"
#include "syn_adc.h"
#include <string.h>
SYN_Status syn_adc_init(SYN_ADC *adc, const SYN_ADC_Config *cfg)
{
SYN_ASSERT(adc != NULL);
SYN_ASSERT(cfg != NULL);
memset(adc, 0, sizeof(*adc));
adc->cfg = *cfg;
if (adc->cfg.oversample == 0)
adc->cfg.oversample = 1;
if (adc->cfg.cal_scale == 0)
adc->cfg.cal_scale = 1;
return syn_port_adc_init(cfg->channel);
}
static int16_t apply_filter(SYN_ADC *adc, int16_t value)
{
if (adc->cfg.filter == NULL)
return value;
switch (adc->cfg.filter_type) {
case SYN_ADC_FILTER_MA:
return syn_filter_ma_update((SYN_FilterMA *)adc->cfg.filter, value);
case SYN_ADC_FILTER_EMA:
return syn_filter_ema_update((SYN_FilterEMA *)adc->cfg.filter, value);
case SYN_ADC_FILTER_MEDIAN:
return syn_filter_median_update((SYN_FilterMedian *)adc->cfg.filter, value);
default:
return value;
}
}
int32_t syn_adc_read(SYN_ADC *adc)
{
SYN_ASSERT(adc != NULL);
if (adc == NULL)
return 0;
/* Oversampling */
uint8_t oversample = adc->cfg.oversample > 0 ? adc->cfg.oversample : 1;
int32_t sum = 0;
for (uint8_t i = 0; i < oversample; i++) {
sum += (int32_t)syn_port_adc_read(adc->cfg.channel);
}
adc->raw = sum / oversample;
/* Filter */
adc->filtered = apply_filter(adc, (int16_t)adc->raw);
/* Calibration: (filtered + offset) * scale >> shift */
int32_t cal = ((int32_t)adc->filtered + adc->cfg.cal_offset);
if (adc->cfg.cal_scale != 1 || adc->cfg.cal_scale_shift != 0) {
cal = (int32_t)(((int64_t)cal * (int32_t)adc->cfg.cal_scale) >> adc->cfg.cal_scale_shift);
}
adc->calibrated = cal;
/* Push to stats window (if attached) */
if (adc->stats != NULL) {
syn_signal_push(adc->stats, adc->calibrated);
}
return adc->calibrated;
}
int32_t syn_adc_read_mv(SYN_ADC *adc)
{
SYN_ASSERT(adc != NULL);
syn_adc_read(adc);
/* Convert raw (after oversample) to millivolts */
uint16_t ref_mv = syn_port_adc_reference_mv();
uint8_t bits = syn_port_adc_resolution();
int32_t max_raw = (int32_t)((1L << bits) - 1);
if (max_raw == 0)
return 0;
return (int32_t)(((int64_t)adc->raw * (int32_t)ref_mv) / max_raw);
}
void syn_adc_set_calibration(SYN_ADC *adc, int16_t offset, uint16_t scale, uint8_t shift)
{
SYN_ASSERT(adc != NULL);
adc->cfg.cal_offset = offset;
adc->cfg.cal_scale = scale;
adc->cfg.cal_scale_shift = shift;
}
void syn_adc_set_stats(SYN_ADC *adc, SYN_Signal *stats)
{
SYN_ASSERT(adc != NULL);
adc->stats = stats;
}
#endif /* SYN_USE_ADC */