openrcore/core/hardware/adc.c
Aaron Cook 8f0f0a0535 Add basic ADC support
Planning on abstracting this behind hardware setup APIs, but this works
for a simple demo until then
2025-09-08 15:38:08 -05:00

75 lines
1.6 KiB
C

#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/kernel.h>
/** Setup code referenced from Zephyr ADC example **/
#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
#error "No suitable devicetree overlay specified"
#endif
#define DT_SPEC_AND_COMMA(node_id, prop, idx) \
ADC_DT_SPEC_GET_BY_IDX(node_id, idx),
static const struct adc_dt_spec adc_channels[] = {
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA)
};
static int setup = 0;
int
adc_init()
{
for (int i = 0; i < ARRAY_SIZE(adc_channels); i++) {
int err;
const struct adc_dt_spec *chan = &adc_channels[i];
if (!adc_is_ready_dt(chan)) {
return (-1);
}
err = adc_channel_setup_dt(chan);
if (err) {
return (err);
}
}
setup = 1;
return (0);
}
int
adc_get_mv(int channel)
{
uint16_t val_raw;
int32_t val_mv;
struct adc_sequence seq = {
.buffer = &val_raw,
.buffer_size = sizeof(val_raw)
};
const struct adc_dt_spec *chan;
if ((channel >= ARRAY_SIZE(adc_channels)) ||
(!setup)) {
return (INT32_MIN);
}
chan = &adc_channels[channel];
adc_sequence_init_dt(chan, &seq);
if (adc_read_dt(chan, &seq) < 0) {
return (INT32_MIN);
}
val_mv = (int32_t)val_raw;
if (adc_raw_to_millivolts_dt(chan, &val_mv)) {
return (INT32_MIN);
}
return (val_mv);
}