drivers: sensor: Add STM32 VREF+ sensor
Add VREF+ sensor driver and DT node definition. This driver allows determining the actual voltage applied to an SoC's VREF+ pin, by comparing the VREFINT internal bandgap voltage reference with its factory calibration data. In packages where VREF+ is bonded to VDDA, this permits direct measurement of VDDA voltage. Signed-off-by: Kenneth J. Miller <ken@miller.ec>
This commit is contained in:
parent
017ff78466
commit
e2c0e220fd
@ -108,6 +108,7 @@ add_subdirectory_ifdef(CONFIG_SM351LT sm351lt)
|
||||
add_subdirectory_ifdef(CONFIG_HAS_STMEMSC stmemsc)
|
||||
add_subdirectory_ifdef(CONFIG_STM32_TEMP stm32_temp)
|
||||
add_subdirectory_ifdef(CONFIG_STM32_VBAT stm32_vbat)
|
||||
add_subdirectory_ifdef(CONFIG_STM32_VREF stm32_vref)
|
||||
add_subdirectory_ifdef(CONFIG_STTS751 stts751)
|
||||
add_subdirectory_ifdef(CONFIG_SX9500 sx9500)
|
||||
add_subdirectory_ifdef(CONFIG_TH02 th02)
|
||||
|
||||
@ -257,6 +257,8 @@ source "drivers/sensor/stm32_temp/Kconfig"
|
||||
|
||||
source "drivers/sensor/stm32_vbat/Kconfig"
|
||||
|
||||
source "drivers/sensor/stm32_vref/Kconfig"
|
||||
|
||||
source "drivers/sensor/stts751/Kconfig"
|
||||
|
||||
source "drivers/sensor/sx9500/Kconfig"
|
||||
|
||||
5
drivers/sensor/stm32_vref/CMakeLists.txt
Normal file
5
drivers/sensor/stm32_vref/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(stm32_vref.c)
|
||||
12
drivers/sensor/stm32_vref/Kconfig
Normal file
12
drivers/sensor/stm32_vref/Kconfig
Normal file
@ -0,0 +1,12 @@
|
||||
# STM32 vref sensor configuration options
|
||||
|
||||
# Copyright (c) 2023 Kenneth J. Miller <ken@miller.ec>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config STM32_VREF
|
||||
bool "STM32 VREF Sensor"
|
||||
default y
|
||||
depends on DT_HAS_ST_STM32_VREF_ENABLED
|
||||
select ADC
|
||||
help
|
||||
Enable driver for STM32 Vref sensor.
|
||||
142
drivers/sensor/stm32_vref/stm32_vref.c
Normal file
142
drivers/sensor/stm32_vref/stm32_vref.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Kenneth J. Miller <ken@miller.ec>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT st_stm32_vref
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#if defined(CONFIG_SOC_SERIES_STM32H5X)
|
||||
#include <stm32_ll_icache.h>
|
||||
#endif /* CONFIG_SOC_SERIES_STM32H5X */
|
||||
|
||||
LOG_MODULE_REGISTER(stm32_vref, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
struct stm32_vref_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_vref_config {
|
||||
uint16_t *cal_addr;
|
||||
int cal_mv;
|
||||
};
|
||||
|
||||
static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
||||
{
|
||||
struct stm32_vref_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_vref_channel_get(const struct device *dev, enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
struct stm32_vref_data *data = dev->data;
|
||||
const struct stm32_vref_config *cfg = dev->config;
|
||||
float vref;
|
||||
|
||||
if (chan != SENSOR_CHAN_VOLTAGE) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (data->raw == 0) {
|
||||
LOG_ERR("Raw ADC value is zero");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/*
|
||||
* ERRATA: STM32H5X: bus fault errors occur when reading engineering bytes with
|
||||
* icache enabled.
|
||||
* See https://github.com/zephyrproject-rtos/zephyr/commit/065a8f2
|
||||
*/
|
||||
#if defined(CONFIG_SOC_SERIES_STM32H5X)
|
||||
LL_ICACHE_Disable();
|
||||
#endif /* CONFIG_SOC_SERIES_STM32H5X */
|
||||
|
||||
/* Calculate VREF+ using VREFINT bandgap voltage and calibration data */
|
||||
vref = cfg->cal_mv * (*cfg->cal_addr) / data->raw;
|
||||
/* millivolt to volt */
|
||||
vref /= 1000;
|
||||
|
||||
#if defined(CONFIG_SOC_SERIES_STM32H5X)
|
||||
LL_ICACHE_Enable();
|
||||
#endif /* CONFIG_SOC_SERIES_STM32H5X */
|
||||
|
||||
return sensor_value_from_double(val, vref);
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api stm32_vref_driver_api = {
|
||||
.sample_fetch = stm32_vref_sample_fetch,
|
||||
.channel_get = stm32_vref_channel_get,
|
||||
};
|
||||
|
||||
static int stm32_vref_init(const struct device *dev)
|
||||
{
|
||||
struct stm32_vref_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;
|
||||
}
|
||||
|
||||
static struct stm32_vref_data stm32_vref_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},
|
||||
};
|
||||
|
||||
static const struct stm32_vref_config stm32_vref_dev_config = {
|
||||
.cal_addr = (uint16_t *)DT_INST_PROP(0, vrefint_cal_addr),
|
||||
.cal_mv = DT_INST_PROP(0, vrefint_cal_mv),
|
||||
};
|
||||
|
||||
SENSOR_DEVICE_DT_INST_DEFINE(0, stm32_vref_init, NULL, &stm32_vref_dev_data, &stm32_vref_dev_config,
|
||||
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &stm32_vref_driver_api);
|
||||
23
dts/bindings/sensor/st,stm32-vref.yaml
Normal file
23
dts/bindings/sensor/st,stm32-vref.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2023 Kenneth J. Miller <ken@miller.ec>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: STM32 family VREF+ node
|
||||
|
||||
compatible: "st,stm32-vref"
|
||||
|
||||
include: sensor-device.yaml
|
||||
|
||||
properties:
|
||||
vrefint-cal-addr:
|
||||
type: int
|
||||
required: true
|
||||
description: |
|
||||
Device engineering bytes address containing the factory-measured
|
||||
calibration bandgap voltage (VREFINT_CAL).
|
||||
|
||||
vrefint-cal-mv:
|
||||
type: int
|
||||
required: true
|
||||
description: |
|
||||
VDDA/VREF+ voltage in millivolts applied during manufacturing to determine
|
||||
the internal bandgap voltage reference VREFINT.
|
||||
Loading…
Reference in New Issue
Block a user