From 431e6efdf63f1586d307341a538d2f15a2b106eb Mon Sep 17 00:00:00 2001 From: Bas Stottelaar Date: Wed, 8 Jan 2020 00:44:48 +0100 Subject: [PATCH] cpu/efm32: add coretemp driver --- cpu/efm32/Makefile | 5 ++ cpu/efm32/Makefile.dep | 4 ++ cpu/efm32/Makefile.include | 3 + cpu/efm32/drivers/coretemp/Makefile | 3 + cpu/efm32/drivers/coretemp/coretemp.c | 79 ++++++++++++++++++++++ cpu/efm32/drivers/coretemp/coretemp_saul.c | 44 ++++++++++++ cpu/efm32/drivers/doc.txt | 5 ++ cpu/efm32/include/drivers/coretemp.h | 68 +++++++++++++++++++ 8 files changed, 211 insertions(+) create mode 100644 cpu/efm32/drivers/coretemp/Makefile create mode 100644 cpu/efm32/drivers/coretemp/coretemp.c create mode 100644 cpu/efm32/drivers/coretemp/coretemp_saul.c create mode 100644 cpu/efm32/drivers/doc.txt create mode 100644 cpu/efm32/include/drivers/coretemp.h diff --git a/cpu/efm32/Makefile b/cpu/efm32/Makefile index f922b518c3..fd6fe9d806 100644 --- a/cpu/efm32/Makefile +++ b/cpu/efm32/Makefile @@ -29,4 +29,9 @@ ifneq (,$(filter cpu_ezr32wg,$(USEMODULE))) DIRS += families/ezr32wg endif +# add EFM32 specific drivers, if enabled +ifneq (,$(filter efm32_coretemp,$(USEMODULE))) + DIRS += drivers/coretemp +endif + include $(RIOTBASE)/Makefile.base diff --git a/cpu/efm32/Makefile.dep b/cpu/efm32/Makefile.dep index fc8804802e..2d83ee7ed5 100644 --- a/cpu/efm32/Makefile.dep +++ b/cpu/efm32/Makefile.dep @@ -16,6 +16,10 @@ USEPKG += gecko_sdk # include layered power management USEMODULE += pm_layered +ifneq (,$(filter efm32_coretemp,$(USEMODULE))) + FEATURES_REQUIRED += periph_adc +endif + # CMSIS-DSP is needed for arm_math.h on Cortex-M0+ architectures ifeq ($(CPU_CORE),cortex-m0plus) USEPKG += cmsis-dsp diff --git a/cpu/efm32/Makefile.include b/cpu/efm32/Makefile.include index 1dc766b3d2..f6cb1d3d3b 100644 --- a/cpu/efm32/Makefile.include +++ b/cpu/efm32/Makefile.include @@ -16,6 +16,9 @@ RIOTBOOT_LEN ?= 0x2000 # the em_device.h header requires a global define with the cpu model CFLAGS += -D$(call uppercase_and_underscore,$(CPU_MODEL)) +# include EFM32 specific driver headers +INCLUDES += -I$(RIOTCPU)/efm32/include/drivers + # include cortexm_common LINKER_SCRIPT = cortexm.ld diff --git a/cpu/efm32/drivers/coretemp/Makefile b/cpu/efm32/drivers/coretemp/Makefile new file mode 100644 index 0000000000..f75581314f --- /dev/null +++ b/cpu/efm32/drivers/coretemp/Makefile @@ -0,0 +1,3 @@ +MODULE = efm32_coretemp + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/efm32/drivers/coretemp/coretemp.c b/cpu/efm32/drivers/coretemp/coretemp.c new file mode 100644 index 0000000000..b3d9832857 --- /dev/null +++ b/cpu/efm32/drivers/coretemp/coretemp.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018-2020 Bas Stottelaar + * + * 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 cpu_efm32_drivers_coretemp + * @{ + * + * @file + * @brief Implementation of EFM32 internal temperature sensor + * + * @author Bas Stottelaar + * + * @} + */ + +#include + +#include "board.h" +#include "coretemp.h" + +#include "periph/adc.h" + +#include "em_device.h" + +int16_t coretemp_read(void) +{ + /* initialize factory calibration values */ + int32_t cal_temp = ((DEVINFO->CAL & _DEVINFO_CAL_TEMP_MASK) >> + _DEVINFO_CAL_TEMP_SHIFT); +#if defined(_SILICON_LABS_32B_SERIES_0) + int32_t cal_value = ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_TEMP1V25_MASK) >> + _DEVINFO_ADC0CAL2_TEMP1V25_SHIFT); +#else + int32_t cal_value = ((DEVINFO->ADC0CAL3 & _DEVINFO_ADC0CAL3_TEMPREAD1V25_MASK) >> + _DEVINFO_ADC0CAL3_TEMPREAD1V25_SHIFT); +#endif + + /* no factory calibration values */ + if ((cal_temp == 0xFF) || (cal_value == 0x0FFF)) { + return -10000; + } + + /* convert temperature channel */ + int32_t value = adc_sample(CORETEMP_ADC, ADC_RES_12BIT); + + /* t_grad is the inverse of 1.25 Vref / (4096 * mV/C) times 1000, so that + we can divide by an integer below with sufficient resolution (values + are from the datasheets) */ +#if defined(_SILICON_LABS_32B_SERIES_0) + int32_t t_grad = -6291; /* -1.92 mV/C */ +#else + int32_t t_grad = -6029; /* -1.84 mv/C */ +#endif + + /* convert to degrees centi-degrees Celsius (times 100) */ + return (int16_t) ((cal_temp * 100) - ((cal_value - value) * 100000 / t_grad)); +} + +int coretemp_init(void) +{ + /* sanity check to ensure the internal temperature sensor is selected */ +#if defined(_SILICON_LABS_32B_SERIES_0) + assert(adc_channel_config[CORETEMP_ADC].input == adcSingleInputTemp); +#else + assert(adc_channel_config[CORETEMP_ADC].input == adcPosSelTEMP); +#endif + + /* initialize ADC */ + if (adc_init(CORETEMP_ADC) != 0) { + return -EIO; + } + + return 0; +} diff --git a/cpu/efm32/drivers/coretemp/coretemp_saul.c b/cpu/efm32/drivers/coretemp/coretemp_saul.c new file mode 100644 index 0000000000..04ccbb5fbc --- /dev/null +++ b/cpu/efm32/drivers/coretemp/coretemp_saul.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 Bas Stottelaar + * + * 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 cpu_efm32_drivers_coretemp + * @{ + * + * @file + * @brief SAUL adoption for EFM32 internal temperature sensor + * + * @author Bas Stottelaar + * + * @} + */ + +#include "coretemp.h" + +#include "saul_reg.h" + +static int _read(const void *dev, phydat_t *res) +{ + (void)dev; + + res->val[0] = coretemp_read(); + res->unit = UNIT_TEMP_C; + res->scale = -2; + + return 1; +} + +const saul_driver_t efm32_coretemp_saul_driver = { + .read = _read, + .write = saul_notsup, + .type = SAUL_SENSE_TEMP +}; + +const saul_reg_info_t efm32_coretemp_saul_info = { + .name = "coretemp" +}; diff --git a/cpu/efm32/drivers/doc.txt b/cpu/efm32/drivers/doc.txt new file mode 100644 index 0000000000..d61411f7ea --- /dev/null +++ b/cpu/efm32/drivers/doc.txt @@ -0,0 +1,5 @@ +/** + * @defgroup cpu_efm32_drivers EFM32 specific drivers + * @ingroup cpu_efm32 + * @brief Specific drivers for the EFM32 family of CPUs. + */ \ No newline at end of file diff --git a/cpu/efm32/include/drivers/coretemp.h b/cpu/efm32/include/drivers/coretemp.h new file mode 100644 index 0000000000..cdf69ce519 --- /dev/null +++ b/cpu/efm32/include/drivers/coretemp.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 Bas Stottelaar + * + * 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. + */ + +/** + * @defgroup cpu_efm32_drivers_coretemp EFM32 internal temperature sensor + * @ingroup cpu_efm32_drivers + * @ingroup drivers_saul + * @brief Driver for the EFM32 internal temperature sensor + * + * All EFM32 chips have an internal ADC input channel that reads the internal + * temperature sensor. This EFM32-specific driver provides an interface for + * reading this value, compensated using factory-calibrated values. + * + * The board must define `CORETEMP_ADC` to point to the ADC line that connects + * to the right ADC input channel. + * + * This driver provides @ref drivers_saul capabilities. + * + * @{ + * + * @file + * @brief Interface definition of the EFM32 internal temperature sensor + * driver. + * + * @author Bas Stottelaar + */ + +#ifndef DRIVERS_CORETEMP_H +#define DRIVERS_CORETEMP_H + +#include "kernel_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the sensor. + * + * @return 0 on successful initialization + * @return -EIO on ADC initialization error + * + * This driver assumes that the `CORETEMP_ADC` is defined and points to the ADC + * input channel that is connected to the internal temperature sensor. + */ +int coretemp_init(void); + +/** + * @brief Read the current temperature from the sensor. + * + * @return current temperature in centi-degrees Celsius + * (times 100) + * + * Temperature readings are compensated using the factory-calibration values. + */ +int16_t coretemp_read(void); + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_CORETEMP_H */ +/** @} */