Fix ADC devicetree compilation error for voltage divider

- Fix voltage divider devicetree configuration to reference ADC controller directly instead of channel node
- Switch from ADC API to sensor API for voltage divider usage
- Add required sensor and voltage divider configuration options
- Remove unnecessary zephyr,user node that was causing compilation issues
- The voltage divider now properly uses sensor framework and builds successfully

Hardware setup:
- Uses ADC1 channel 1 on pin PA0
- Voltage divider with 2.2kΩ output and 3.2kΩ total resistance
- Provides voltage readings through sensor API accounting for divider ratio
This commit is contained in:
2025-07-07 13:36:44 +02:00
parent dcb73c0a25
commit d48281436e
13 changed files with 348 additions and 179 deletions

View File

@@ -1,28 +1,38 @@
/ {
zephyr,user {
io-channels = <&adc1 1>;
io-channel-names = "multi_sense";
};
vdd_sense: voltage-divider {
compatible = "voltage-divider";
/*
* This reference must provide one argument (the channel number)
* because of the "#io-channel-cells = <1>" in the &adc1 node.
*/
io-channels = <&adc1 1>;
output-ohms = <2200>;
full-ohms = <3200>;
};
};
&adc1 {
status = "okay";
status = "okay";
pinctrl-0 = <&adc1_in1_pa0>;
pinctrl-names = "default";
pinctrl-0 = <&adc1_in1_pa0>;
pinctrl-names = "default";
st,adc-clock-source = "SYNC";
st,adc-prescaler = <4>;
st,adc-clock-source = "SYNC";
st,adc-prescaler = <4>;
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
/*
* This line is required by the st,stm32-adc driver binding.
* It declares that references to its channels need one extra argument.
*/
#io-channel-cells = <1>;
/* This defines channel 1 on adc1. The "1" in io-channels refers to this reg value. */
adc_channel_1: channel@1 {
reg = <1>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,resolution = <12>;
};
adc_channel_1: channel@1 {
reg = <1>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,resolution = <12>;
};
};

View File

@@ -1,2 +1,4 @@
CONFIG_ADC=y
CONFIG_SENSOR=y
CONFIG_VOLTAGE_DIVIDER=y
CONFIG_LOG=y

View File

@@ -1,57 +1,43 @@
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(adc_dt_example, LOG_LEVEL_DBG);
/* Get the ADC channel specification from the devicetree */
#define SENSE_NODE DT_PATH(zephyr_user)
static const struct adc_dt_spec sense_channel = ADC_DT_SPEC_GET_BY_NAME(SENSE_NODE, multi_sense);
/* Get the voltage divider device */
#define VOLTAGE_DIVIDER_NODE DT_NODELABEL(vdd_sense)
int main(void)
{
const struct device *vdd_dev = DEVICE_DT_GET(VOLTAGE_DIVIDER_NODE);
struct sensor_value val;
int err;
uint16_t buf;
struct adc_sequence sequence = {
.buffer = &buf,
.buffer_size = sizeof(buf),
};
if (!device_is_ready(sense_channel.dev)) {
LOG_ERR("ADC controller device not ready");
if (!device_is_ready(vdd_dev)) {
LOG_ERR("Voltage divider device not ready");
return 0;
}
err = adc_channel_setup_dt(&sense_channel);
if (err < 0) {
LOG_ERR("Could not setup channel #%u (%d)", sense_channel.channel_id, err);
return 0;
}
LOG_INF("ADC channel setup successful!");
LOG_INF("Voltage divider device ready!");
while (1) {
// 1. Explicitly initialize the sequence structure from the devicetree spec.
// This sets sequence.channels correctly.
(void)adc_sequence_init_dt(&sense_channel, &sequence);
// 2. Perform the read on the ADC device with the now-configured sequence.
err = adc_read(sense_channel.dev, &sequence);
err = sensor_sample_fetch(vdd_dev);
if (err < 0) {
LOG_ERR("Could not read (%d)", err);
LOG_ERR("Could not fetch sample (%d)", err);
k_sleep(K_MSEC(1000));
continue;
}
int32_t val_mv = buf;
err = adc_raw_to_millivolts_dt(&sense_channel, &val_mv);
err = sensor_channel_get(vdd_dev, SENSOR_CHAN_VOLTAGE, &val);
if (err < 0) {
LOG_WRN("Could not convert to millivolts (%d)", err);
LOG_ERR("Could not get channel (%d)", err);
k_sleep(K_MSEC(1000));
continue;
}
LOG_INF("ADC reading raw: %d -> %d mV", buf, val_mv);
LOG_INF("Voltage reading: %d.%06d V", val.val1, val.val2);
k_sleep(K_MSEC(1000));
}