drivers: sensor: add a stm32 sensor driver for the internal VBat

Similar to the internal temperature sensor of the stm32
this driver controls the Vbat monitoring in Volts,
using an ADC internal input and the stm32-vbat node of the DTS.
The ref voltage is given by the ADC.
Note that stm32F1x does not propose the feature.

Signed-off-by: Francois Ramu <francois.ramu@st.com>
This commit is contained in:
Francois Ramu 2022-03-16 12:55:35 +01:00 committed by Carles Cufí
commit 32222e07a4
5 changed files with 146 additions and 0 deletions

View file

@ -89,6 +89,7 @@ add_subdirectory_ifdef(CONFIG_SI7210 si7210)
add_subdirectory_ifdef(CONFIG_SM351LT sm351lt) add_subdirectory_ifdef(CONFIG_SM351LT sm351lt)
add_subdirectory_ifdef(CONFIG_HAS_STMEMSC stmemsc) add_subdirectory_ifdef(CONFIG_HAS_STMEMSC stmemsc)
add_subdirectory_ifdef(CONFIG_STM32_TEMP stm32_temp) add_subdirectory_ifdef(CONFIG_STM32_TEMP stm32_temp)
add_subdirectory_ifdef(CONFIG_STM32_VBAT stm32_vbat)
add_subdirectory_ifdef(CONFIG_STTS751 stts751) add_subdirectory_ifdef(CONFIG_STTS751 stts751)
add_subdirectory_ifdef(CONFIG_SX9500 sx9500) add_subdirectory_ifdef(CONFIG_SX9500 sx9500)
add_subdirectory_ifdef(CONFIG_TH02 th02) add_subdirectory_ifdef(CONFIG_TH02 th02)

View file

@ -216,6 +216,8 @@ source "drivers/sensor/sm351lt/Kconfig"
source "drivers/sensor/stm32_temp/Kconfig" source "drivers/sensor/stm32_temp/Kconfig"
source "drivers/sensor/stm32_vbat/Kconfig"
source "drivers/sensor/stts751/Kconfig" source "drivers/sensor/stts751/Kconfig"
source "drivers/sensor/sx9500/Kconfig" source "drivers/sensor/sx9500/Kconfig"

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources(stm32_vbat.c)

View file

@ -0,0 +1,10 @@
# STM32 battery sensor configuration options
# Copyright (c) 2022 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
config STM32_VBAT
bool "STM32 Vbat Sensor"
depends on ADC && (SOC_FAMILY_STM32 && !SOC_SERIES_STM32F1X)
help
Enable driver for STM32 Vbat sensor and then also ADC

View file

@ -0,0 +1,128 @@
/*
* Copyright (c) 2022 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <device.h>
#include <drivers/sensor.h>
#include <drivers/adc.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(stm32_vbat, CONFIG_SENSOR_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_vbat)
#define DT_DRV_COMPAT st_stm32_vbat
#else
#error "No compatible devicetree node found"
#endif
struct stm32_vbat_data {
const struct device *adc;
const struct adc_channel_cfg adc_cfg;
struct adc_sequence adc_seq;
struct k_mutex mutex;
int16_t sample_buffer;
int16_t raw; /* raw adc Sensor value */
};
struct stm32_vbat_config {
uint16_t vref_mv;
int ratio;
};
static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel chan)
{
struct stm32_vbat_data *data = dev->data;
struct adc_sequence *sp = &data->adc_seq;
int rc;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) {
return -ENOTSUP;
}
k_mutex_lock(&data->mutex, K_FOREVER);
rc = adc_channel_setup(data->adc, &data->adc_cfg);
if (rc) {
LOG_DBG("Setup AIN%u got %d", data->adc_cfg.channel_id, rc);
goto unlock;
}
rc = adc_read(data->adc, sp);
if (rc == 0) {
data->raw = data->sample_buffer;
}
unlock:
k_mutex_unlock(&data->mutex);
return rc;
}
static int stm32_vbat_channel_get(const struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
struct stm32_vbat_data *data = dev->data;
const struct stm32_vbat_config *cfg = dev->config;
float voltage;
if (chan != SENSOR_CHAN_VOLTAGE) {
return -ENOTSUP;
}
voltage = data->raw * cfg->vref_mv / 0x0FFF; /* Sensor value in millivolts */
/* considering the vbat input through a resistor bridge */
voltage = voltage * cfg->ratio / 1000; /* value of SENSOR_CHAN_VOLTAGE in Volt */
return sensor_value_from_double(val, voltage);
}
static const struct sensor_driver_api stm32_vbat_driver_api = {
.sample_fetch = stm32_vbat_sample_fetch,
.channel_get = stm32_vbat_channel_get,
};
static int stm32_vbat_init(const struct device *dev)
{
struct stm32_vbat_data *data = dev->data;
struct adc_sequence *asp = &data->adc_seq;
k_mutex_init(&data->mutex);
if (!device_is_ready(data->adc)) {
LOG_ERR("Device %s is not ready", data->adc->name);
return -ENODEV;
}
*asp = (struct adc_sequence){
.channels = BIT(data->adc_cfg.channel_id),
.buffer = &data->sample_buffer,
.buffer_size = sizeof(data->sample_buffer),
.resolution = 12U,
};
return 0;
}
#define STM32_VBAT DT_PROP(DT_INST_IO_CHANNELS_CTLR(0), vref_mv)
static struct stm32_vbat_config stm32_vbat_dev_config = {
.vref_mv = DT_PROP(DT_INST_IO_CHANNELS_CTLR(0), vref_mv),
.ratio = DT_INST_PROP(0, ratio),
};
static struct stm32_vbat_data stm32_vbat_dev_data = {
.adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(0)),
.adc_cfg = {
.gain = ADC_GAIN_1,
.reference = ADC_REF_INTERNAL,
.acquisition_time = ADC_ACQ_TIME_MAX,
.channel_id = DT_INST_IO_CHANNELS_INPUT(0),
.differential = 0,
},
};
DEVICE_DT_INST_DEFINE(0, stm32_vbat_init, NULL, &stm32_vbat_dev_data, &stm32_vbat_dev_config,
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &stm32_vbat_driver_api);