<alp/adc.h> — Analog-to-Digital Conversion
Single-shot reads, streaming captures, and optional on-chain filtering / spectrum analysis.
Header
#include <alp/adc.h>
#include <alp/e1m_pinout.h>
Single-shot
alp_adc_t *adc = alp_adc_open(&(alp_adc_config_t){
.channel_id = ALP_E1M_ADC0,
.resolution_bits = 12,
.reference = ALP_ADC_REF_INTERNAL,
});
int32_t raw;
alp_adc_read_raw(adc, &raw);
int32_t millivolts = (raw * 3300) / ((1 << 12) - 1);
alp_adc_close(adc);
Config struct
| Field | Type | Notes |
|---|---|---|
channel_id | uint32_t | ALP_E1M_ADC0..ALP_E1M_ADC7. Must be < ALP_E1M_ADC_COUNT. |
resolution_bits | uint8_t | 8 / 10 / 12 / 14 / 16. 0 = devicetree default. Capped by <alp/soc_caps.h>. |
acquisition_us | uint16_t | Sample-and-hold time, microseconds. |
reference | alp_adc_ref_t | Reference source: ALP_ADC_REF_INTERNAL / _EXTERNAL_0 / _EXTERNAL_1 / _VDD. |
gain_num | uint8_t | Gain numerator (e.g. 1 for 1/6 gain). |
gain_den | uint8_t | Gain denominator (e.g. 6 for 1/6 gain). |
oversampling_ratio | uint16_t | HW oversampling ratio (power of two, 1..256). 0 = backend default. |
sample_cycles | uint16_t | Extra sample-and-hold cycles at the ADC clock. 0 = backend default. |
Streaming rate (sample_rate_hz) is not part of this struct — it lives in alp_adc_stream_config_t (see below).
Units
Every read entry point carries its unit as a name suffix, so the split is visible at the call site. The one-shot path favours precision (signed microvolts); the streaming / DSP path favours wire and ring-buffer density (16-bit millivolts — what the 12-bit hardware actually delivers at streaming rates).
| Function | Sample type | Unit |
|---|---|---|
alp_adc_read_raw | int32_t | Native ADC code (no unit). |
alp_adc_read_uv | int32_t | Signed microvolts (µV). |
alp_adc_stream_read_mv | uint16_t | Unsigned millivolts (mV). |
alp_adc_filter_read_mv | int16_t | Signed millivolts (mV) — DSP chains need signed headroom. |
alp_adc_spectrum_read_bins | float | FFT bins (input scale mV). |
Conversion: 1 mV = 1000 µV — a stream sample s sits at s * 1000 on the alp_adc_read_uv scale. The sample widths are wire formats and will not change.
Streaming + filtering (v0.5)
// Plain streaming: unsigned uint16 mV samples straight from the ring.
alp_adc_stream_t *stream = alp_adc_stream_open(&(alp_adc_stream_config_t){
.channel_id = ALP_E1M_ADC0,
.sample_rate_hz = 16000,
});
uint16_t samples[256]; // stream samples are uint16 mV
size_t got;
alp_adc_stream_read_mv(stream, samples, sizeof(samples)/sizeof(samples[0]), &got);
// Filtered streaming: compose the same source with a FIR/IIR chain
// from <alp/dsp.h> under one handle; reads come back as signed int16 mV.
alp_adc_filter_t *filter = alp_adc_filter_open(&(alp_adc_filter_config_t){
.channel_id = ALP_E1M_ADC0,
.sample_rate_hz = 16000,
.stages = my_filter_stages, // FIR / IIR chain (no FFT stage)
.n_stages = n_stages,
});
int16_t filtered[256]; // filter samples are int16 mV (signed DSP headroom)
alp_adc_filter_read_mv(filter, filtered, 256, &got);
alp_adc_spectrum_t composes the same stream with the FFT chain in <alp/dsp.h> for spectrum capture.
V2N: GD32-side ADC bank
On V2N family, eight ADC channels are exposed by the GD32G553 supervisor. Route through <alp/chips/gd32g553.h>:
uint16_t mv;
gd32g553_adc_read_mv(&bridge, /* channel */ 2, &mv);
Pin-as-GPIO fallback
ADC pads that aren't currently sampling can be repurposed as plain GPIOs. Open the pin via <alp/peripheral.h>::alp_gpio_open with the matching ALP_E1M_GPIO_<pad> ID; the SDK detaches the ADC input and switches the pin to GPIO mode automatically. The same applies to DAC pads. Useful when an application uses only a subset of the analog channels and wants the remaining pads as digital I/O without paying for two driver instances.
:::note DAC moved out
Analog output lives in its own header since v0.7 — see <alp/dac.h>. The two share the analog pads (and the pin-as-GPIO fallback above) but are separate registries.
:::
Capability validation
alp_adc_t *adc = alp_adc_open(&(alp_adc_config_t){
.resolution_bits = 16, // ← fails on a 12-bit SoC
});
// adc == NULL; alp_last_error() == ALP_ERR_OUT_OF_RANGE
See also
- Examples: adc-voltmeter
<alp/dsp.h>— FIR/IIR/FFT chains<alp/peripheral.h>