From b11f84441538654c4358d5b1403eab1f3c8647be Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Tue, 8 Jul 2025 16:43:27 +0200 Subject: [PATCH] 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. --- software/.vscode/settings.json | 3 + .../boards/weact_stm32g431_core.overlay | 34 ++++ .../bindings/adc/custom,motor-current.yaml | 48 +++++ .../bindings/adc/custom,supply-voltage.yaml | 63 ++++++ software/apps/slave_node/prj.conf | 3 + software/lib/adc_sensor/Kconfig | 2 +- software/lib/adc_sensor/adc_sensor.c | 187 +++++++++++++++++- 7 files changed, 333 insertions(+), 7 deletions(-) create mode 100644 software/apps/slave_node/dts/bindings/adc/custom,motor-current.yaml create mode 100644 software/apps/slave_node/dts/bindings/adc/custom,supply-voltage.yaml diff --git a/software/.vscode/settings.json b/software/.vscode/settings.json index 8d96b49..0e40522 100644 --- a/software/.vscode/settings.json +++ b/software/.vscode/settings.json @@ -9,4 +9,7 @@ "app_version.h": "c" }, "C_Cpp.clang_format_style": "file", + "nrf-connect.applications": [ + "${workspaceFolder}/apps/slave_node" + ], } \ No newline at end of file diff --git a/software/apps/slave_node/boards/weact_stm32g431_core.overlay b/software/apps/slave_node/boards/weact_stm32g431_core.overlay index 2481bba..d3b125e 100644 --- a/software/apps/slave_node/boards/weact_stm32g431_core.overlay +++ b/software/apps/slave_node/boards/weact_stm32g431_core.overlay @@ -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 diff --git a/software/apps/slave_node/dts/bindings/adc/custom,motor-current.yaml b/software/apps/slave_node/dts/bindings/adc/custom,motor-current.yaml new file mode 100644 index 0000000..db9b5c0 --- /dev/null +++ b/software/apps/slave_node/dts/bindings/adc/custom,motor-current.yaml @@ -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 diff --git a/software/apps/slave_node/dts/bindings/adc/custom,supply-voltage.yaml b/software/apps/slave_node/dts/bindings/adc/custom,supply-voltage.yaml new file mode 100644 index 0000000..3bc71ea --- /dev/null +++ b/software/apps/slave_node/dts/bindings/adc/custom,supply-voltage.yaml @@ -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 \ No newline at end of file diff --git a/software/apps/slave_node/prj.conf b/software/apps/slave_node/prj.conf index 24aacee..9d47cf3 100644 --- a/software/apps/slave_node/prj.conf +++ b/software/apps/slave_node/prj.conf @@ -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 + diff --git a/software/lib/adc_sensor/Kconfig b/software/lib/adc_sensor/Kconfig index 13aca87..5767b19 100644 --- a/software/lib/adc_sensor/Kconfig +++ b/software/lib/adc_sensor/Kconfig @@ -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 diff --git a/software/lib/adc_sensor/adc_sensor.c b/software/lib/adc_sensor/adc_sensor.c index 6ec6104..b5be247 100644 --- a/software/lib/adc_sensor/adc_sensor.c +++ b/software/lib/adc_sensor/adc_sensor.c @@ -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 +#include +#include +#include #include #include @@ -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(¤t_sen_gpio)) { + ret = gpio_pin_configure_dt(¤t_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(¤t_s0_gpio)) { + ret = gpio_pin_configure_dt(¤t_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(¤t_s1_gpio)) { + ret = gpio_pin_configure_dt(¤t_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(¤t_sen_gpio)) { + gpio_pin_set_dt(¤t_sen_gpio, enable ? 1 : 0); + } + if (gpio_is_ready_dt(¤t_s0_gpio)) { + gpio_pin_set_dt(¤t_s0_gpio, s0_state ? 1 : 0); + } + if (gpio_is_ready_dt(¤t_s1_gpio)) { + gpio_pin_set_dt(¤t_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 }