diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 35afb62c1f..97362cb6fe 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -264,6 +264,11 @@ ifneq (,$(filter ws281x_%,$(USEMODULE))) USEMODULE += ws281x endif +ifneq (,$(filter saul_bat_voltage,$(USEMODULE))) + FEATURES_REQUIRED += periph_adc + FEATURES_REQUIRED += board_bat_voltage +endif + ifneq (,$(filter saul_adc,$(USEMODULE))) FEATURES_REQUIRED += periph_adc endif diff --git a/drivers/include/saul/bat_voltage.h b/drivers/include/saul/bat_voltage.h new file mode 100644 index 0000000000..ff92638ea1 --- /dev/null +++ b/drivers/include/saul/bat_voltage.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_saul + * @{ + * + * @file + * @brief Parameter definitions for mapping battery voltage to SAUL + * + * @author Martine S. Lenders + */ + +#ifndef SAUL_BAT_VOLTAGE_H +#define SAUL_BAT_VOLTAGE_H + +#include + +#include "periph/adc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief SAUL battery voltage configuration values + */ +typedef struct { + const char *name; /**< name of the device connected to this pin */ + int8_t phydat_scale; /**< Phydat scale of the resulting voltage */ + adc_t line; /**< ADC line to initialize and expose */ + adc_res_t res; /**< ADC resolution */ + /** + * @brief Conversion function to convert raw ADC data to voltage + * + * @param[in] adc_sample The raw ADC sample. + * + * @return Voltage value for phydat. + */ + int16_t (*convert)(int32_t adc_sample); +} saul_bat_voltage_params_t; + +#ifdef __cplusplus +} +#endif + +#endif /* SAUL_BAT_VOLTAGE_H */ +/** @} */ diff --git a/drivers/saul/Makefile b/drivers/saul/Makefile index 0e9946400c..e5d9b717dc 100644 --- a/drivers/saul/Makefile +++ b/drivers/saul/Makefile @@ -3,6 +3,9 @@ SRC = saul.c saul_str.c ifneq (,$(filter saul_gpio,$(USEMODULE))) SRC += gpio_saul.c endif +ifneq (,$(filter saul_bat_voltage,$(USEMODULE))) + SRC += bat_voltage_saul.c +endif ifneq (,$(filter saul_adc,$(USEMODULE))) SRC += adc_saul.c endif diff --git a/drivers/saul/bat_voltage_saul.c b/drivers/saul/bat_voltage_saul.c new file mode 100644 index 0000000000..f283839251 --- /dev/null +++ b/drivers/saul/bat_voltage_saul.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_saul + * @{ + * + * @file + * @brief SAUL wrapper to gauge battery voltage. + * + * Adafruit Feather-type boards typically have an ADC pin exposed to read + * the battery voltage. + * + * @author Martine S. Lenders + * + * @} + */ + +#include + +#include "saul.h" +#include "saul/bat_voltage.h" +#include "phydat.h" +#include "periph/adc.h" + +static int read_adc(const void *dev, phydat_t *res) +{ + const saul_bat_voltage_params_t *params = *((const saul_bat_voltage_params_t **)dev); + int32_t sample = adc_sample(params->line, params->res); + res->val[0] = params->convert(sample); + res->unit = UNIT_V; + res->scale = params->phydat_scale; + return 1; +} + +const saul_driver_t bat_voltage_saul_driver = { + .read = read_adc, + .write = saul_write_notsup, + .type = SAUL_SENSE_VOLTAGE, +}; diff --git a/drivers/saul/init_devs/auto_init_saul_bat_voltage.c b/drivers/saul/init_devs/auto_init_saul_bat_voltage.c new file mode 100644 index 0000000000..091bef3dfc --- /dev/null +++ b/drivers/saul/init_devs/auto_init_saul_bat_voltage.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + */ + +/** + * @ingroup sys_auto_init_saul + * @{ + * + * @file + * @brief Auto initialization of mapping battery voltage to SAUL + * + * @author Martine S. Lenders + * + * @} + */ + +#include "log.h" +#include "saul_reg.h" +#include "saul/bat_voltage.h" +#include "bat_voltage_params.h" + +/** + * @brief Define the number of configured sensors + */ +#define SAUL_BAT_VOLTAGE_NUMOF ARRAY_SIZE(saul_bat_voltage_params) + +/** + * @brief Allocate memory for pointers to the BAT voltage parameter structs + * + * We use this extra level of indirection to be able to keep the saul_bat_voltage_params + * array const and residing in ROM. + */ +static const saul_bat_voltage_params_t *saul_bat_voltages[SAUL_BAT_VOLTAGE_NUMOF]; + +/** + * @brief Memory for the registry entries + */ +static saul_reg_t saul_reg_entries[SAUL_BAT_VOLTAGE_NUMOF]; + +/** + * @brief Reference the driver struct + */ +extern saul_driver_t bat_voltage_saul_driver; + +void auto_init_saul_bat_voltage(void) +{ + for (unsigned i = 0; i < SAUL_BAT_VOLTAGE_NUMOF; i++) { + const saul_bat_voltage_params_t *p = &saul_bat_voltage_params[i]; + saul_bat_voltages[i] = p; + + printf("[auto_init_saul] initializing BAT voltage #%u\n", i); + + saul_reg_entries[i].dev = &saul_bat_voltages[i]; + saul_reg_entries[i].name = p->name; + saul_reg_entries[i].driver = &bat_voltage_saul_driver; + /* initialize the ADC line */ + adc_init(p->line); + /* add to registry */ + saul_reg_add(&(saul_reg_entries[i])); + } +} diff --git a/drivers/saul/init_devs/init.c b/drivers/saul/init_devs/init.c index bfb4d10ead..53e39e9698 100644 --- a/drivers/saul/init_devs/init.c +++ b/drivers/saul/init_devs/init.c @@ -31,6 +31,10 @@ void saul_init_devs(void) extern void auto_init_saul_adc(void); auto_init_saul_adc(); } + if (IS_USED(MODULE_SAUL_BAT_VOLTAGE)) { + extern void auto_init_saul_bat_voltage(void); + auto_init_saul_bat_voltage(); + } if (IS_USED(MODULE_SAUL_GPIO)) { extern void auto_init_gpio(void); auto_init_gpio(); diff --git a/features.yaml b/features.yaml index f40c454a95..ca514dbb3f 100644 --- a/features.yaml +++ b/features.yaml @@ -796,6 +796,8 @@ groups: - title: Platform Specific help: Things specific to a single MCU family / MCU vendor features: + - name: board_bat_voltage + help: Measures battery voltage based on ADC sampling. - name: periph_ics help: An NXP Kinetis Internal Clock Source Controller (ICS peripheral) is present. diff --git a/makefiles/features_existing.inc.mk b/makefiles/features_existing.inc.mk index fc1c34926b..4aecbb5984 100644 --- a/makefiles/features_existing.inc.mk +++ b/makefiles/features_existing.inc.mk @@ -42,6 +42,7 @@ FEATURES_EXISTING := \ ble_nimble_netif \ ble_phy_2mbit \ ble_phy_coded \ + board_bat_voltage \ bootloader_stm32 \ can_rx_mailbox \ cortexm_fpu \ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index c6cb490c27..253086ed4d 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -374,6 +374,7 @@ PSEUDOMODULES += fortuna_reseed PSEUDOMODULES += riotboot_% PSEUDOMODULES += rtt_cmd PSEUDOMODULES += saul_adc +PSEUDOMODULES += saul_bat_voltage PSEUDOMODULES += saul_default PSEUDOMODULES += saul_gpio PSEUDOMODULES += saul_nrf_temperature