feat: Add ADC sensor device tree bindings and configuration

Introduces device tree bindings for custom ADC voltage and current sensors,
allowing for flexible configuration of sensor inputs and associated GPIOs.
This enables proper hardware abstraction for ADC measurements.

The example overlay file
has been removed as its content is now integrated or superseded by the new
binding definitions.
This commit is contained in:
Eduard Iten 2025-07-08 16:43:27 +02:00
parent 2e8a86bc54
commit b11f844415
7 changed files with 333 additions and 7 deletions

View File

@ -9,4 +9,7 @@
"app_version.h": "c"
},
"C_Cpp.clang_format_style": "file",
"nrf-connect.applications": [
"${workspaceFolder}/apps/slave_node"
],
}

View File

@ -11,6 +11,40 @@
s0-gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; // S0 (PB6) - Status/Select 0 output from VND7050AJ
s1-gpios = <&gpiob 5 GPIO_ACTIVE_HIGH>; // S1 (PB5) - Status/Select 1 output from VND7050AJ
};
adc_sensors {
compatible = "adc-sensors";
supply_voltage: supply-voltage {
compatible = "custom,supply-voltage";
io-channels = <&adc1 1>; /* ADC1 channel 1 (PA0) */
io-channel-names = "voltage";
reference-mv = <3300>;
voltage-divider-ratio = <4>; /* Adjust based on your voltage divider */
/* GPIO control pins using VND7050AJ pins */
sen-gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>; /* SEN (PB4) - enable sensor */
s0-gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; /* S0 (PB6) - mux select bit 0 */
s1-gpios = <&gpiob 5 GPIO_ACTIVE_HIGH>; /* S1 (PB5) - mux select bit 1 */
measurement-delay-ms = <5>; /* 5ms delay after GPIO setup */
};
motor_current: motor-current {
compatible = "custom,motor-current";
io-channels = <&adc1 1>; /* Same ADC channel, different mux setting */
io-channel-names = "current";
reference-mv = <3300>;
current-sense-resistor-mohm = <100>; /* 100mΩ sense resistor */
/* GPIO control pins using VND7050AJ pins */
sen-gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>; /* SEN (PB4) - enable sensor */
s0-gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; /* S0 (PB6) - mux select bit 0 */
s1-gpios = <&gpiob 5 GPIO_ACTIVE_HIGH>; /* S1 (PB5) - mux select bit 1 */
measurement-delay-ms = <10>; /* 10ms delay for current settling */
};
};
};
// Clock configuration: Uncomment the following section to use calibrated HSI instead of HSE

View File

@ -0,0 +1,48 @@
description: Custom motor current measurement with GPIO control
compatible: "custom,motor-current"
properties:
io-channels:
type: phandle-array
required: true
description: ADC channel for current measurement
io-channel-names:
type: string-array
description: Names for the ADC channels
current-sense-resistor-mohm:
type: int
required: true
description: Current sense resistor value in milliohms
amplifier-gain:
type: int
default: 1
description: Current sense amplifier gain
reference-mv:
type: int
default: 3300
description: ADC reference voltage in millivolts
sen-gpios:
type: phandle-array
required: true
description: GPIO to enable/disable the current measurement sensor
s0-gpios:
type: phandle-array
required: true
description: GPIO for multiplexer control bit 0
s1-gpios:
type: phandle-array
required: true
description: GPIO for multiplexer control bit 1
measurement-delay-ms:
type: int
default: 10
description: Delay in milliseconds after setting GPIOs before ADC measurement

View File

@ -0,0 +1,63 @@
description: Custom supply voltage measurement with GPIO control
compatible: "custom,supply-voltage"
properties:
io-channels:
type: phandle-array
required: true
description: ADC channel for voltage measurement
io-channel-names:
type: string-array
description: Names for the ADC channels
voltage-divider-ratio:
type: int
required: true
description: Voltage divider ratio for scaling
reference-mv:
type: int
default: 3300
description: ADC reference voltage in millivolts
sen-gpios:
type: phandle-array
required: true
description: GPIO to enable/disable the voltage measurement sensor
s0-gpios:
type: phandle-array
required: true
description: GPIO for multiplexer control bit 0
s1-gpios:
type: phandle-array
required: true
description: GPIO for multiplexer control bit 1
measurement-delay-ms:
type: int
default: 10
description: Delay in milliseconds after setting GPIOs before ADC measurement
sen-gpios:
type: phandle-array
required: true
description: GPIO for SEN (Sense Enable) pin
s0-gpios:
type: phandle-array
required: true
description: GPIO for S0 (Select 0) pin
s1-gpios:
type: phandle-array
required: true
description: GPIO for S1 (Select 1) pin
measurement-delay-ms:
type: int
default: 10
description: Delay in milliseconds after setting control pins before ADC reading

View File

@ -20,3 +20,6 @@ CONFIG_MODBUS=y
CONFIG_MODBUS_ROLE_SERVER=y
CONFIG_MODBUS_BUFFER_SIZE=256
# ADC Sensor Configuration - Use real ADC readings
CONFIG_ADC_SENSOR_SIMULATED=n

View File

@ -8,7 +8,7 @@ if ADC_SENSOR
config ADC_SENSOR_SIMULATED
bool "Use simulated ADC readings"
default y
default n
help
Use simulated values instead of real ADC readings.
Voltage: 12000mV, Current: 45mA

View File

@ -4,10 +4,13 @@
*
* This file contains the implementation for initializing and reading from ADC
* sensors. It currently provides simulated values for voltage and current, with
* placeholders for real hardware ADC implementation.
* placeholders for real hardware ADC implementation including GPIO control.
*/
#include <lib/adc_sensor.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
@ -17,8 +20,150 @@ LOG_MODULE_REGISTER(adc_sensor, LOG_LEVEL_INF);
#define SIMULATED_VOLTAGE_MV 12000
#define SIMULATED_CURRENT_MA 45
static bool initialized =
false; // Flag to indicate if the ADC sensor is initialized
// Devicetree node checks
#define VOLTAGE_SENSOR_NODE DT_NODELABEL(supply_voltage)
#define CURRENT_SENSOR_NODE DT_NODELABEL(motor_current)
static bool initialized = false;
#ifndef CONFIG_ADC_SENSOR_SIMULATED
// GPIO specs for voltage sensor (if devicetree nodes exist)
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
static const struct gpio_dt_spec voltage_sen_gpio =
GPIO_DT_SPEC_GET(VOLTAGE_SENSOR_NODE, sen_gpios);
static const struct gpio_dt_spec voltage_s0_gpio =
GPIO_DT_SPEC_GET(VOLTAGE_SENSOR_NODE, s0_gpios);
static const struct gpio_dt_spec voltage_s1_gpio =
GPIO_DT_SPEC_GET(VOLTAGE_SENSOR_NODE, s1_gpios);
#endif
// GPIO specs for current sensor (if devicetree nodes exist)
#if DT_NODE_EXISTS(CURRENT_SENSOR_NODE)
static const struct gpio_dt_spec current_sen_gpio =
GPIO_DT_SPEC_GET(CURRENT_SENSOR_NODE, sen_gpios);
static const struct gpio_dt_spec current_s0_gpio =
GPIO_DT_SPEC_GET(CURRENT_SENSOR_NODE, s0_gpios);
static const struct gpio_dt_spec current_s1_gpio =
GPIO_DT_SPEC_GET(CURRENT_SENSOR_NODE, s1_gpios);
#endif
/**
* @brief Configure GPIO pins for ADC sensor control
*/
static int configure_sensor_gpios(void) {
int ret = 0;
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
// Configure voltage sensor GPIOs
if (gpio_is_ready_dt(&voltage_sen_gpio)) {
ret = gpio_pin_configure_dt(&voltage_sen_gpio, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to configure voltage sen GPIO: %d", ret);
return ret;
}
}
if (gpio_is_ready_dt(&voltage_s0_gpio)) {
ret = gpio_pin_configure_dt(&voltage_s0_gpio, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to configure voltage s0 GPIO: %d", ret);
return ret;
}
}
if (gpio_is_ready_dt(&voltage_s1_gpio)) {
ret = gpio_pin_configure_dt(&voltage_s1_gpio, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to configure voltage s1 GPIO: %d", ret);
return ret;
}
}
#endif
#if DT_NODE_EXISTS(CURRENT_SENSOR_NODE)
// Configure current sensor GPIOs
if (gpio_is_ready_dt(&current_sen_gpio)) {
ret = gpio_pin_configure_dt(&current_sen_gpio, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to configure current sen GPIO: %d", ret);
return ret;
}
}
if (gpio_is_ready_dt(&current_s0_gpio)) {
ret = gpio_pin_configure_dt(&current_s0_gpio, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to configure current s0 GPIO: %d", ret);
return ret;
}
}
if (gpio_is_ready_dt(&current_s1_gpio)) {
ret = gpio_pin_configure_dt(&current_s1_gpio, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to configure current s1 GPIO: %d", ret);
return ret;
}
}
#endif
return 0;
}
/**
* @brief Set GPIO pins for voltage measurement
* @param s0_state State for S0 pin (multiplexer bit 0)
* @param s1_state State for S1 pin (multiplexer bit 1)
*/
static int set_voltage_sensor_gpios(bool enable, bool s0_state, bool s1_state) {
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
if (gpio_is_ready_dt(&voltage_sen_gpio)) {
gpio_pin_set_dt(&voltage_sen_gpio, enable ? 1 : 0);
}
if (gpio_is_ready_dt(&voltage_s0_gpio)) {
gpio_pin_set_dt(&voltage_s0_gpio, s0_state ? 1 : 0);
}
if (gpio_is_ready_dt(&voltage_s1_gpio)) {
gpio_pin_set_dt(&voltage_s1_gpio, s1_state ? 1 : 0);
}
// Delay for GPIO settling (from devicetree or default)
#if DT_NODE_HAS_PROP(VOLTAGE_SENSOR_NODE, measurement_delay_ms)
k_msleep(DT_PROP(VOLTAGE_SENSOR_NODE, measurement_delay_ms));
#else
k_msleep(5); // Default 5ms delay
#endif
#endif
return 0;
}
/**
* @brief Set GPIO pins for current measurement
* @param s0_state State for S0 pin (multiplexer bit 0)
* @param s1_state State for S1 pin (multiplexer bit 1)
*/
static int set_current_sensor_gpios(bool enable, bool s0_state, bool s1_state) {
#if DT_NODE_EXISTS(CURRENT_SENSOR_NODE)
if (gpio_is_ready_dt(&current_sen_gpio)) {
gpio_pin_set_dt(&current_sen_gpio, enable ? 1 : 0);
}
if (gpio_is_ready_dt(&current_s0_gpio)) {
gpio_pin_set_dt(&current_s0_gpio, s0_state ? 1 : 0);
}
if (gpio_is_ready_dt(&current_s1_gpio)) {
gpio_pin_set_dt(&current_s1_gpio, s1_state ? 1 : 0);
}
// Delay for GPIO settling (from devicetree or default)
#if DT_NODE_HAS_PROP(CURRENT_SENSOR_NODE, measurement_delay_ms)
k_msleep(DT_PROP(CURRENT_SENSOR_NODE, measurement_delay_ms));
#else
k_msleep(10); // Default 10ms delay
#endif
#endif
return 0;
}
#endif /* !CONFIG_ADC_SENSOR_SIMULATED */
int adc_sensor_init(void) {
if (initialized) {
@ -30,8 +175,22 @@ int adc_sensor_init(void) {
LOG_INF("Simulated values: %dmV, %dmA", SIMULATED_VOLTAGE_MV,
SIMULATED_CURRENT_MA);
#else
// Initialize GPIO pins for sensor control
int ret = configure_sensor_gpios();
if (ret < 0) {
LOG_ERR("Failed to configure sensor GPIOs: %d", ret);
return ret;
}
// TODO: Initialize real ADC hardware
LOG_INF("ADC sensor initialized (real ADC mode - not yet implemented)");
LOG_INF("ADC sensor initialized (real ADC mode with GPIO control)");
#if DT_NODE_EXISTS(VOLTAGE_SENSOR_NODE)
LOG_INF("Voltage sensor found in devicetree");
#endif
#if DT_NODE_EXISTS(CURRENT_SENSOR_NODE)
LOG_INF("Current sensor found in devicetree");
#endif
#endif
initialized = true;
@ -47,9 +206,17 @@ uint16_t adc_sensor_get_voltage_mv(void) {
#ifdef CONFIG_ADC_SENSOR_SIMULATED
return SIMULATED_VOLTAGE_MV;
#else
// Set GPIOs for voltage measurement (example: s0=0, s1=0 for channel 0)
set_voltage_sensor_gpios(true, false, false);
// TODO: Read real ADC value for voltage
// For now return simulated value
return SIMULATED_VOLTAGE_MV;
uint16_t voltage = SIMULATED_VOLTAGE_MV;
// Disable sensor after measurement to save power
set_voltage_sensor_gpios(false, false, false);
return voltage;
#endif
}
@ -62,8 +229,16 @@ uint16_t adc_sensor_get_current_ma(void) {
#ifdef CONFIG_ADC_SENSOR_SIMULATED
return SIMULATED_CURRENT_MA;
#else
// Set GPIOs for current measurement (example: s0=1, s1=0 for channel 1)
set_current_sensor_gpios(true, true, false);
// TODO: Read real ADC value for current
// For now return simulated value
return SIMULATED_CURRENT_MA;
uint16_t current = SIMULATED_CURRENT_MA;
// Disable sensor after measurement to save power
set_current_sensor_gpios(false, false, false);
return current;
#endif
}