diff --git a/Documentation/platforms/arm/stm32h5/boards/nucleo-h563zi/index.rst b/Documentation/platforms/arm/stm32h5/boards/nucleo-h563zi/index.rst index d4ef0f7b76..c508f6f81d 100644 --- a/Documentation/platforms/arm/stm32h5/boards/nucleo-h563zi/index.rst +++ b/Documentation/platforms/arm/stm32h5/boards/nucleo-h563zi/index.rst @@ -145,6 +145,13 @@ usbnsh: This configuration provides a basic NuttShell through the USB User interface. +dts: +-------- + +This configuration configures the digital temperature sensor (DTS) +at /dev/uorb/sensor_temp0 and provides the test application +sensortest. E.g. sensortest -n 10 temp0 + References =========== diff --git a/Documentation/platforms/arm/stm32h5/index.rst b/Documentation/platforms/arm/stm32h5/index.rst index 9abfebe915..344d51c88a 100644 --- a/Documentation/platforms/arm/stm32h5/index.rst +++ b/Documentation/platforms/arm/stm32h5/index.rst @@ -35,8 +35,10 @@ Peripheral Support Notes ========== ======= ===== ADC Yes ETH Yes +DTS Yes Software trigger only. FLASH Yes Hardware defines only. FDCAN Yes +GPDMA Yes GPIO Yes I2C Yes ICACHE Yes @@ -59,11 +61,9 @@ DBG No DCACHE No DCMI No DLYB No -DTS No EXTI No FMAC No FSMC No -GPDMA No GTZC No HASH No I3C No diff --git a/arch/arm/src/stm32h5/Kconfig b/arch/arm/src/stm32h5/Kconfig index 18ffdcfbb8..5dee7bc065 100644 --- a/arch/arm/src/stm32h5/Kconfig +++ b/arch/arm/src/stm32h5/Kconfig @@ -359,6 +359,14 @@ config STM32H5_DMA2 select STM32H5_DMA select ARCH_DMA +config STM32H5_DTS + bool "DTS" + default n + ---help--- + Enable support for the on‑die digital temperature sensor (DTS) + built into STM32H5 devices. When enabled, the driver will register + a `/dev/sensor_tempX` device using the common NuttX sensor framework. + config STM32H5_ETHMAC bool "Ethernet MAC" default n @@ -625,6 +633,107 @@ config STM32H5_USBFS endmenu # STM32H5 Peripheral Selection +menu "DTS Configuration" + depends on STM32H5_DTS + +config STM32H5_DTS_REFCLK_LSE + bool "Use LSE (32.768 kHz crystal) as DTS reference clock" + default n + ---help--- + Select the low‑speed external (LSE) oscillator as the reference clock + for the DTS. When enabled, DTS_CFGR1.REFCLK_SEL=1 and the driver will + measure FM(T) pulses over N LSE cycles. + + If disabled, the DTS will use the APB‑bus clock (PCLK) as the reference + (REFCLK_SEL=0) and you must supply a valid HSREF_CLK_DIV to keep the + calibration prescaler ≤ 1 MHz. + +config STM32H5_DTS_SMP_TIME + int "DTS sampling time (TS1_SMP_TIME[3:0])" + default 1 + range 1 15 + ---help--- + Number of reference‑clock cycles (PCLK or LSE) counted per + DTS measurement. Valid range 1 (1 cycle) through 15 (15 cycles). + +config STM32H5_DTS_TRIGGER + int "DTS hardware trigger source (TS1_INTRIG_SEL[3:0])" + default 0 + ---help--- + If non‑zero, DTS will start measurements on the rising edge of + the selected hardware line. Values match RM0481 Table 275: + 0=Software Trigger, 1=LPTIM1_CH1,  + 2=LPTIM2_CH1, 3=LPTIM3_CH1, 4=EXTI13, 5-15 are reserved. + +config STM32H5_DTS_LOW_THRESHOLD + int "DTS low‑threshold (°C)" + default 0 + ---help--- + The temperature (in whole °C) below which the DTS window comparator will + assert the low‑threshold flag (TS1_ITLF). To disable, set equal to 0. + +config STM32H5_DTS_HIGH_THRESHOLD + int "DTS high‑threshold (°C)" + default 100 + ---help--- + The temperature (in whole °C) above which the DTS window comparator will + assert the high‑threshold flag (TS1_ITHF). Must be >= LOW_THRESHOLD. + +config STM32H5_DTS_ITEN_ITEF + bool "Enable DTS end‑of‑measurement interrupt (TS1_ITEF)" + default y + ---help--- + Enable the synchronous “end of measurement” interrupt for the + digital temperature sensor. When set, the driver will attach + and unmask TS1_ITEF and will call your ISR on every fresh sample. + +config STM32H5_DTS_ITEN_ITLF + bool "Enable DTS low‑threshold interrupt (TS1_ITLF)" + default n + ---help--- + Enable the synchronous “low threshold crossed” interrupt for the + digital temperature sensor. When set, the driver will unmask + TS1_ITLF so you can get notified whenever the measured value + drops below your programmed low‑threshold. + +config STM32H5_DTS_ITEN_ITHF + bool "Enable DTS high‑threshold interrupt (TS1_ITHF)" + default n + ---help--- + Enable the synchronous “high threshold crossed” interrupt for the + digital temperature sensor. When set, the driver will unmask + TS1_ITHF so you can get notified whenever the measured value + exceeds your programmed high‑threshold. + +config STM32H5_DTS_AITEN_AITEF + bool "Enable DTS asynchronous end‑of‑measurement interrupt (TS1_AITEF)" + depends on STM32H5_DTS_REFCLK_LSE + default n + ---help--- + Enable the asynchronous end‑of‑measurement interrupt. This will + set TS1_AITEEN in DTS_ITENR and cause an _asynchronous_ wakeup + event when a conversion completes (in Stop/Sleep modes). + +config STM32H5_DTS_AITEN_AITLF + bool "Enable DTS asynchronous low‑threshold interrupt (TS1_AITLF)" + depends on STM32H5_DTS_REFCLK_LSE + default n + ---help--- + Enable the asynchronous low‑threshold comparator interrupt. This + will set TS1_AITLEN in DTS_ITENR and generate a wakeup event + when the measurement drops below your low threshold. + +config STM32H5_DTS_AITEN_AITHF + bool "Enable DTS asynchronous high‑threshold interrupt (TS1_AITHF)" + depends on STM32H5_DTS_REFCLK_LSE + default n + ---help--- + Enable the asynchronous high‑threshold comparator interrupt. This + will set TS1_AITHEN in DTS_ITENR and generate a wakeup event + when the measurement exceeds your high threshold. + +endmenu # DTS Configuration + config STM32H5_FLASH_PREFETCH bool "Enable FLASH Pre-fetch" default y diff --git a/arch/arm/src/stm32h5/Make.defs b/arch/arm/src/stm32h5/Make.defs index c2c5430145..44fc7509a9 100644 --- a/arch/arm/src/stm32h5/Make.defs +++ b/arch/arm/src/stm32h5/Make.defs @@ -92,6 +92,10 @@ ifeq ($(CONFIG_STM32H5_DMA),y) CHIP_CSRCS += stm32_dma.c endif +ifeq ($(CONFIG_STM32H5_DTS),y) +CHIP_CSRCS += stm32_dts.c +endif + # Required chip type specific files ifeq ($(CONFIG_STM32H5_STM32H5XXXX),y) diff --git a/arch/arm/src/stm32h5/hardware/stm32_dts.h b/arch/arm/src/stm32h5/hardware/stm32_dts.h index 3e7b570547..4de0575a81 100644 --- a/arch/arm/src/stm32h5/hardware/stm32_dts.h +++ b/arch/arm/src/stm32h5/hardware/stm32_dts.h @@ -71,6 +71,8 @@ # define DTS_CFGR1_TS1_INTRIG_SEL_LPTIM2_CH1 (0x2 << DTS_CFGR1_TS1_INTRIG_SEL_SHIFT) # define DTS_CFGR1_TS1_INTRIG_SEL_LPTIM3_CH1 (0x3 << DTS_CFGR1_TS1_INTRIG_SEL_SHIFT) # define DTS_CFGR1_TS1_INTRIG_SEL_EXTI13 (0x4 << DTS_CFGR1_TS1_INTRIG_SEL_SHIFT) +#define DTS_CFGR1_TS1_INTRIG(n) \ + (((n) << DTS_CFGR1_TS1_INTRIG_SEL_SHIFT) & DTS_CFGR1_TS1_INTRIG_SEL_MASK) #define DTS_CFGR1_TS1_SMP_TIME_SHIFT (16) /* Bits 16-19: Sampling time */ #define DTS_CFGR1_TS1_SMP_TIME_MASK (0xf << DTS_CFGR1_TS1_SMP_TIME_SHIFT) @@ -86,26 +88,26 @@ /* Temperature sensor T0 value register 1 */ #define DTS_T0VALR1_TS1_FMT0_SHIFT (0) /* Engineering value for frequency at T0 */ -#define DTS_T0VALR1_TS1_FMT0_MASK (0xff << DTS_T0VALR1_TS1_FMT0_SHIFT) +#define DTS_T0VALR1_TS1_FMT0_MASK (0xffff << DTS_T0VALR1_TS1_FMT0_SHIFT) #define DTS_T0VALR1_TS1_T0_SHIFT (16) /* Engineering value of T0 */ #define DTS_T0VALR1_TS1_T0_MASK (0b11 << DTS_T0VALR1_TS1_T0_SHIFT) /* Temperature sensor ramp value register */ #define DTS_RAMPVALR_TS1_RAMP_COEFF_SHIFT (0) /* Engineering value of ramp coefficient */ -#define DTS_RAMPVALR_TS1_RAMP_COEFF_MASK (0xff << DTS_RAMPVALR_TS1_RAMP_COEFF_SHIFT) +#define DTS_RAMPVALR_TS1_RAMP_COEFF_MASK (0xffff << DTS_RAMPVALR_TS1_RAMP_COEFF_SHIFT) /* Temperature sensor interrupt threshold register 1 */ #define DTS_ITR1_TS1_LITTHD_SHIFT (0) /* High interrupt threshold */ -#define DTS_ITR1_TS1_LITTHD_MASK (0xff << DTS_ITR1_TS1_LITTHD_SHIFT) +#define DTS_ITR1_TS1_LITTHD_MASK (0xffff << DTS_ITR1_TS1_LITTHD_SHIFT) #define DTS_ITR1_TS1_HITTHD_SHIFT (16) /* Low interrupt threshold */ -#define DTS_ITR1_TS1_HITTHD_MASK (0xff << DTS_ITR1_TS1_HITTHD_SHIFT) +#define DTS_ITR1_TS1_HITTHD_MASK (0xffff << DTS_ITR1_TS1_HITTHD_SHIFT) /* Temperature sensor data register */ #define DTS_DR_TS1_MFREQ_SHIFT (0) -#define DTS_DR_TS1_MFREQ_MASK (0xff << DTS_DR_TS1_MFREQ_SHIFT) +#define DTS_DR_TS1_MFREQ_MASK (0xffff << DTS_DR_TS1_MFREQ_SHIFT) /* Temperature sensor status register */ @@ -134,6 +136,7 @@ #define DTS_ICIFR_CAITEF (1 << 4) /* Asynchronous interrupt clear flag: end of measurement */ #define DTS_ICIFR_CAITLF (1 << 5) /* Asynchronous interrupt clear flag: low threshold */ #define DTS_ICIFR_CAITHF (1 << 6) /* Asynchronous interrupt clear flag: high threshold */ +#define DTS_ICIFR_ALL (0x77) /* All interrupts */ /* Temperature sensor option register */ diff --git a/arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h b/arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h index 4f312333fd..1f5981e628 100644 --- a/arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h +++ b/arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h @@ -264,13 +264,13 @@ # define RCC_CFGR2_HPRE_SYSCLKd256 (14 << RCC_CFGR2_HPRE_SHIFT) /* 1110: SYSCLK divided by 256 */ # define RCC_CFGR2_HPRE_SYSCLKd512 (15 << RCC_CFGR2_HPRE_SHIFT) /* 1111: SYSCLK divided by 512 */ -#define RCC_CFGR2_PPRE1_SHIFT (0) /* Bits 6-4: PPRE1 Prescaler */ +#define RCC_CFGR2_PPRE1_SHIFT (4) /* Bits 6-4: PPRE1 Prescaler */ #define RCC_CFGR2_PPRE1_MASK (0x7 << RCC_CFGR2_PPRE1_SHIFT) # define RCC_CFGR2_PPRE1_HCLK1 (0 << RCC_CFGR2_PPRE1_SHIFT) /* 0xx: HCLK1 not divided */ -# define RCC_CFGR2_PPRE1_HCLK1d2 (4 << RCC_CFGR2_PPRE1_SHIFT) /* 1000: HCLK1 divided by 2 */ -# define RCC_CFGR2_PPRE1_HCLK1d4 (5 << RCC_CFGR2_PPRE1_SHIFT) /* 1001: HCLK1 divided by 4 */ -# define RCC_CFGR2_PPRE1_HCLK1d8 (6 << RCC_CFGR2_PPRE1_SHIFT) /* 1010: HCLK1 divided by 8 */ -# define RCC_CFGR2_PPRE1_HCLK1d16 (7 << RCC_CFGR2_PPRE1_SHIFT) /* 1011: HCLK1 divided by 16 */ +# define RCC_CFGR2_PPRE1_HCLK1d2 (4 << RCC_CFGR2_PPRE1_SHIFT) /* 100: HCLK1 divided by 2 */ +# define RCC_CFGR2_PPRE1_HCLK1d4 (5 << RCC_CFGR2_PPRE1_SHIFT) /* 101: HCLK1 divided by 4 */ +# define RCC_CFGR2_PPRE1_HCLK1d8 (6 << RCC_CFGR2_PPRE1_SHIFT) /* 110: HCLK1 divided by 8 */ +# define RCC_CFGR2_PPRE1_HCLK1d16 (7 << RCC_CFGR2_PPRE1_SHIFT) /* 111: HCLK1 divided by 16 */ #define RCC_CFGR2_PPRE2_SHIFT (8) /* Bits 10-8: PPRE2 Prescaler */ #define RCC_CFGR2_PPRE2_MASK (0x7 << RCC_CFGR2_PPRE2_SHIFT) diff --git a/arch/arm/src/stm32h5/stm32.h b/arch/arm/src/stm32h5/stm32.h index 502f8420c7..7011cf4f5d 100644 --- a/arch/arm/src/stm32h5/stm32.h +++ b/arch/arm/src/stm32h5/stm32.h @@ -39,6 +39,7 @@ #include "chip.h" #include "stm32_adc.h" #include "stm32_dbgmcu.h" +#include "stm32_dts.h" #include "stm32_flash.h" #include "stm32_gpio.h" #include "stm32_i2c.h" diff --git a/arch/arm/src/stm32h5/stm32_dts.c b/arch/arm/src/stm32h5/stm32_dts.c new file mode 100644 index 0000000000..efcf5da479 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_dts.c @@ -0,0 +1,556 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_dts.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include "stm32_rcc.h" +#include "hardware/stm32_dts.h" +#include "stm32_dts.h" + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static float dts_get_fmt_hz (uint16_t mfreq); + +static float dts_get_temp_celsius (float fmt_hz); + +static void dts_handle_result (struct sensor_lowerhalf_s *lower); + +static void dts_configure_cfgr1 (void); + +static void dts_get_cal_data (void); + +static void dts_get_cfg_data (void); + +static int stm32_dts_activate (struct sensor_lowerhalf_s *lower, + struct file *filep, bool enable); + +static int stm32_dts_set_interval (struct sensor_lowerhalf_s *lower, + struct file *filep, + uint32_t *period_us); + +#if CONFIG_STM32H5_DTS_TRIGGER == 0 +static ssize_t stm32_dts_fetch (struct sensor_lowerhalf_s *lower, + struct file *filep, + char *buffer, size_t buflen); +#endif + +static int stm32_dts_get_info (struct sensor_lowerhalf_s *lower, + struct file *filep, + struct sensor_device_info_s *info); + +static int stm32_dts_isr (int irq, void *context, void *arg); + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if CONFIG_STM32H5_DTS_TRIGGER != 0 +# error "Hardware triggers not implemented. Need LP Timers first." +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct stm32_dts_cal_s g_dts_cal = +{ + .fmt0 = 0.0f, + .ramp = 1.0f, + .t0 = 30.0f, +}; + +static struct stm32_dts_cfg_s g_dts_cfg = +{ + .samples = 1, + .lse = false, + .clk_frequency = 0, +}; + +static struct sensor_lowerhalf_s g_dts_lower = +{ + .type = SENSOR_TYPE_TEMPERATURE, + .nbuffer = 1, + .ops = NULL, /* bound in register() */ + .persist = false, +}; + +static const struct sensor_ops_s g_dts_ops = +{ + .open = NULL, /* no per‑open activation */ + .close = NULL, + .activate = stm32_dts_activate, + .set_interval = stm32_dts_set_interval, + .batch = NULL, +#if CONFIG_STM32H5_DTS_TRIGGER == 0 + .fetch = stm32_dts_fetch, +#else + .fetch = NULL, +#endif + .selftest = NULL, + .set_calibvalue = NULL, + .calibrate = NULL, + .get_info = stm32_dts_get_info, + .control = NULL, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dts_get_fmt_hz + * + * Description: + * Compute the value of FM(T) based on the REF_CLK and mfreq. + * See RM0481, Rev 4, section 27.3.7 + * + * Input Parameters: + * mfreq - The value of TS1_MFREQ in DTS_DR. + * + * Returned Value: + * The value of FM(T) in Hz. + * + ****************************************************************************/ + +static float dts_get_fmt_hz(uint16_t mfreq) +{ + /* Convert mfreq -> fmt_hz + * fmt_hz is proportional to clk_ptat based on temperature + */ + + if (g_dts_cfg.lse) + { + /* (LSE) mode: count FM pulses in (samp) LSE cycles */ + + return ((float)mfreq * (float)STM32_LSE_FREQUENCY + / (float)(g_dts_cfg.samples)); + } + else + { + /* (PCLK) mode: count PCLK ticks in (samp) FM(T) cycles */ + + return ((float)STM32_PCLK1_FREQUENCY * (float)(g_dts_cfg.samples) + / (float)mfreq); + } +} + +/**************************************************************************** + * Name: dts_get_temp_celcius + * + * Description: + * Uses calibration data (T0, FM(T0), Ramp Coefficient) and the derived + * FM(T) to compute the temperature measured by the DTS in degrees + * celsius. See RM0481, Rev 4, section 27.3.7 + * + * Input Parameters: + * fmt_hz - The value of FM(T) in Hz. + * + * Returned Value: + * The temperature read by the DTS in degrees celsius + * + ****************************************************************************/ + +static float dts_get_temp_celsius(float fmt_hz) +{ + /* Convert fmt_hz -> temperature in degrees Celsius */ + + return g_dts_cal.t0 + + ((fmt_hz - ((float)g_dts_cal.fmt0 * 100.0f)) / + (float)g_dts_cal.ramp); +} + +/**************************************************************************** + * Name: dts_handle_result + * + * Description: + * Put the computed temperature and timestamp in a sensor_temp structure + * and push the sensor event + * + * Input Parameters: + * *lower - Pointer to sensor lower_half driver + * + ****************************************************************************/ + +static void dts_handle_result(struct sensor_lowerhalf_s *lower) +{ + struct sensor_temp report; + uint16_t mfreq = getreg32(STM32_DTS_DR) & DTS_DR_TS1_MFREQ_MASK; + float fmt_hz = dts_get_fmt_hz(mfreq); + + /* Build the report */ + + report.timestamp = sensor_get_timestamp(); + report.temperature = dts_get_temp_celsius(fmt_hz); + + /* Push into NuttX sensor framework */ + + lower->push_event(lower->priv, &report, sizeof(report)); +} + +/**************************************************************************** + * Name: dts_configure_cfgr1 + * + * Description: + * Write DTS_CFGR1 register based on Kconfig options and the REF_CLK. + * + ****************************************************************************/ + +static void dts_configure_cfgr1(void) +{ + /* Compute PCLK prescaler <= 1MHz */ + +#if !defined(CONFIG_STM32H5_DTS_REFCLK_LSE) + uint32_t div = (STM32_PCLK1_FREQUENCY + 1000000 - 1) / 1000000; + + if (div > 127) + { + div = 127; + } + else if (div == 0) + { + div = 1; + } +#endif + + uint32_t cfgr1 = + DTS_CFGR1_TS1_EN + | DTS_CFGR1_TS1_SMP_TIME(CONFIG_STM32H5_DTS_SMP_TIME) +#if !defined(CONFIG_STM32H5_DTS_REFCLK_LSE) + | DTS_CFGR1_HSREF_CLK_DIV_RATIO(div) +#else + | DTS_CFGR1_REFCLK_SEL +#endif + | DTS_CFGR1_TS1_INTRIG(CONFIG_STM32H5_DTS_TRIGGER); + + putreg32(cfgr1, STM32_DTS_CFGR1); +} + +/**************************************************************************** + * Name: dts_get_cal_data + * + * Description: + * Obtain DTS Calibration data (T0, FM(T0), Ramp Coefficient). + * Store the calibration data in a global data structure. This data is + * constant and needs to be loaded only once. + * + ****************************************************************************/ + +static void dts_get_cal_data(void) +{ + uint32_t t0valr1 = getreg32(STM32_DTS_T0VALR1); + + g_dts_cal.fmt0 = (t0valr1 + & DTS_T0VALR1_TS1_FMT0_MASK) >> DTS_T0VALR1_TS1_FMT0_SHIFT; + + g_dts_cal.ramp = (getreg32(STM32_DTS_RAMPVALR) + & DTS_RAMPVALR_TS1_RAMP_COEFF_MASK) + >> DTS_RAMPVALR_TS1_RAMP_COEFF_SHIFT; + + uint8_t t0valr1_t0 = (t0valr1 + & DTS_T0VALR1_TS1_T0_MASK) >> DTS_T0VALR1_TS1_T0_SHIFT; + + g_dts_cal.t0 = (t0valr1_t0 == 0) ? 30.0f : 130.0f; +} + +/**************************************************************************** + * Name: dts_get_cfg_data + * + * Description: + * Store select configuration data for later use. + * + ****************************************************************************/ + +static void dts_get_cfg_data(void) +{ + uint32_t cfgr1 = getreg32(STM32_DTS_CFGR1); + +#if defined(CONFIG_STM32H5_DTS_REFCLK_LSE) + g_dts_cfg.lse = true; +#else + g_dts_cfg.lse = false; +#endif + + g_dts_cfg.samples = ((cfgr1 & DTS_CFGR1_TS1_SMP_TIME_MASK) >> + DTS_CFGR1_TS1_SMP_TIME_SHIFT); + g_dts_cfg.samples = (g_dts_cfg.samples == 0) ? 1 : g_dts_cfg.samples; + + g_dts_cfg.clk_frequency = (g_dts_cfg.lse) ? STM32_LSE_FREQUENCY : + STM32_PCLK1_FREQUENCY; +} + +/**************************************************************************** + * Name: dts_configure_interrupts + * + * Description: + * Write the DTS_ITENR register based on Kconfig options. + * + * Input Parameters: + * *lower - Pointer to sensor lower_half driver + * + ****************************************************************************/ + +static void dts_configure_interrupts(struct sensor_lowerhalf_s *lower) +{ + uint32_t itenr = 0; + +#ifdef CONFIG_STM32H5_DTS_ITEN_ITEF + itenr |= DTS_ITENR_ITEEN; +#endif +#ifdef CONFIG_STM32H5_DTS_ITEN_ITLF + itenr |= DTS_ITENR_ITLEN; +#endif +#ifdef CONFIG_STM32H5_DTS_ITEN_ITHF + itenr |= DTS_ITENR_ITHEN; +#endif + +#ifdef CONFIG_STM32H5_DTS_AITEN_AITEF + itenr |= DTS_ITENR_AITEEN; +#endif +#ifdef CONFIG_STM32H5_DTS_AITEN_AITLF + itenr |= DTS_ITENR_AITLEN; +#endif +#ifdef CONFIG_STM32H5_DTS_AITEN_AITHF + itenr |= DTS_ITENR_AITHEN; +#endif + + putreg32(itenr, STM32_DTS_ITENR); +} + +/**************************************************************************** + * Name: stm32_dts_activate + * + * Description: + * Enable or disable the DTS block and its clock. Configure CFGR1 for + * sample time, reference clock, and trigger mode. Wait for the initial + * calibration to complete (TS1_RDY = 1). + * + ****************************************************************************/ + +static int stm32_dts_activate(struct sensor_lowerhalf_s *lower, + struct file *filep, bool enable) +{ + if (enable) + { + modifyreg32(STM32_RCC_APB1HENR, 0, RCC_APB1HENR_DTSEN); + + dts_configure_cfgr1(); + + /* Wait for initial calibration (TS1_RDY=1) */ + + while (!(getreg32(STM32_DTS_SR) & DTS_SR_TS1_RDY)); + + dts_get_cal_data(); + + dts_get_cfg_data(); + + dts_configure_interrupts(lower); + + irq_attach(STM32_IRQ_DTS, stm32_dts_isr, lower); + + up_enable_irq(STM32_IRQ_DTS); + } + else + { + /* Disable block‑level IRQ, NVIC, clock */ + + putreg32(0, STM32_DTS_ITENR); + up_disable_irq(STM32_IRQ_DTS); + modifyreg32(STM32_RCC_APB1HENR, RCC_APB1HENR_DTSEN, 0); + } + + return OK; +} + +#if CONFIG_STM32H5_DTS_TRIGGER == 0 +/**************************************************************************** + * Name: stm32_dts_fetch + * + * Description: + * Perform one software‐triggered temperature measurement + * + ****************************************************************************/ + +static ssize_t stm32_dts_fetch(struct sensor_lowerhalf_s *lower, + struct file *filep, + char *buffer, size_t buflen) +{ + struct sensor_temp report; + uint16_t mfreq; + float fmt_hz; + + /* Wait for sensor to be ready before starting */ + + while (!(getreg32(STM32_DTS_SR) & DTS_SR_TS1_RDY)); + + /* Set START = 1 to initiate one measurement */ + + modifyreg32(STM32_DTS_CFGR1, 0, DTS_CFGR1_TS1_START); + + /* Wait for TS1_RDY -> 1: conversion complete */ + + while (!(getreg32(STM32_DTS_SR) & DTS_SR_TS1_RDY)); + + /* Set START = 0 to stop measurements */ + + modifyreg32(STM32_DTS_CFGR1, DTS_CFGR1_TS1_START, 0); + + mfreq = getreg32(STM32_DTS_DR) & DTS_DR_TS1_MFREQ_MASK; + fmt_hz = dts_get_fmt_hz(mfreq); + + report.timestamp = sensor_get_timestamp(); + report.temperature = dts_get_temp_celsius(fmt_hz); + + if (buflen < sizeof(report)) + { + return -EINVAL; + } + + memcpy(buffer, &report, sizeof(report)); + return sizeof(report); +} +#endif + +/**************************************************************************** + * Name: stm32_dts_set_interval + ****************************************************************************/ + +static int stm32_dts_set_interval(struct sensor_lowerhalf_s *lower, + struct file *filep, + uint32_t *period_us) +{ + /* TODO - Requires LP Timer Driver */ + + return OK; +} + +/**************************************************************************** + * Name: stm32_dts_get_info + ****************************************************************************/ + +static int stm32_dts_get_info(struct sensor_lowerhalf_s *lower, + struct file *filep, + struct sensor_device_info_s *info) +{ + /* One factory‐calibrated internal sensor on the STM32H5: + * + * Power: ≈0.5 mW typical when measuring (≈150 uA@3.3 V) + * Max range: –40 C…+125 C + * Resolution: ≈0.15 C => approximation with 15 samples at 125 MHz + * Min delay: ≈200 us per conversion (default sample time) + * Max delay: 0 (one‑shot, not batched) + * FIFO events 1 (no hardware FIFO) + */ + + DEBUGASSERT(info); + info->version = 1; + info->power = 0.5f; + info->max_range = 165.0f; + info->resolution = 0.15f; + info->min_delay = 200; + info->max_delay = 0; + info->fifo_reserved_event_count = 1; + info->fifo_max_event_count = 1; + strlcpy(info->name, "STM32H5 DTS", SENSOR_INFO_NAME_SIZE); + strlcpy(info->vendor, "STMicro", SENSOR_INFO_NAME_SIZE); + return OK; +} + +/**************************************************************************** + * Name: stm32_dts_isr + ****************************************************************************/ + +static int stm32_dts_isr(int irq, void *context, void *arg) +{ + struct sensor_lowerhalf_s *lower = (struct sensor_lowerhalf_s *)arg; + uint32_t sr = getreg32(STM32_DTS_SR); + bool pushed = false; + + /* End‑of‑measurement interrupt? */ + + if (sr & DTS_SR_TS1_ITEF) + { + putreg32(DTS_ICIFR_CITEF, STM32_DTS_ICIFR); + dts_handle_result(lower); + pushed = true; + } + + /* Low‑threshold crossed? */ + + if (sr & DTS_SR_TS1_ITLF) + { + putreg32(DTS_ICIFR_CITLF, STM32_DTS_ICIFR); + if (!pushed) + { + dts_handle_result(lower); + } + + pushed = true; + } + + /* High‑threshold crossed? */ + + if (sr & DTS_SR_TS1_ITHF) + { + putreg32(DTS_ICIFR_CITHF, STM32_DTS_ICIFR); + if (!pushed) + { + dts_handle_result(lower); + } + } + + lower->notify_event(lower->priv); + + return OK; +} + +/**************************************************************************** + * Name: stm32_dts_register + ****************************************************************************/ + +int stm32h5_dts_register(int devno) +{ + int ret; + + g_dts_lower.ops = &g_dts_ops; + + /* Register the driver at /dev/uorb/sensor_tempN */ + + ret = sensor_register(&g_dts_lower, devno); + if (ret < 0) + { + return ret; + } + + return OK; +} diff --git a/arch/arm/src/stm32h5/stm32_dts.h b/arch/arm/src/stm32h5/stm32_dts.h index 8540bce118..67e796699a 100644 --- a/arch/arm/src/stm32h5/stm32_dts.h +++ b/arch/arm/src/stm32h5/stm32_dts.h @@ -28,7 +28,49 @@ ****************************************************************************/ #include -#include "chip.h" -#include "hardware/stm32_dts.h" +#include /* For struct sensor_lowerhalf_s */ +#include /* SNIOC_* if needed */ +#include /* SENSOR_TYPE_AMBIENT_TEMPERATURE */ -#endif /* __ARCH_ARM_SRC_STM32H5_STM32_DTS_H */ \ No newline at end of file +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct stm32_dts_cal_s +{ + uint16_t fmt0; + uint16_t ramp; + float t0; +}; + +struct stm32_dts_cfg_s +{ + uint8_t samples; + bool lse; + uint32_t clk_frequency; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +int stm32h5_dts_register(int devno); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_STM32H5_STM32_DTS_H */ diff --git a/boards/arm/stm32h5/nucleo-h563zi/configs/dts/defconfig b/boards/arm/stm32h5/nucleo-h563zi/configs/dts/defconfig new file mode 100644 index 0000000000..49762f0b5f --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/configs/dts/defconfig @@ -0,0 +1,55 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_ARGCAT is not set +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-h563zi" +CONFIG_ARCH_BOARD_NUCLEO_H563ZI=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32h5" +CONFIG_ARCH_CHIP_STM32H563ZI=y +CONFIG_ARCH_CHIP_STM32H5=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV8M_STACKCHECK=y +CONFIG_BOARD_LOOPSPERMSEC=9251 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_LINE_MAX=64 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=655360 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SENSORS=y +CONFIG_STACK_COLORATION=y +CONFIG_STM32H5_DTS=y +CONFIG_STM32H5_DTS_SMP_TIME=15 +CONFIG_STM32H5_USART3=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_SENSORTEST=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_UORB=y +CONFIG_USART3_SERIAL_CONSOLE=y +CONFIG_USENSOR=y diff --git a/boards/arm/stm32h5/nucleo-h563zi/include/board.h b/boards/arm/stm32h5/nucleo-h563zi/include/board.h index 49ca898078..82aa6b9539 100644 --- a/boards/arm/stm32h5/nucleo-h563zi/include/board.h +++ b/boards/arm/stm32h5/nucleo-h563zi/include/board.h @@ -172,8 +172,8 @@ /* Configure the APB1 prescaler */ -#define STM32_RCC_CFGR2_PPRE1 RCC_CFGR2_PPRE1_HCLK1 /* PCLK1 = HCLK / 1 */ -#define STM32_PCLK1_FREQUENCY (STM32_HCLK_FREQUENCY / 1) +#define STM32_RCC_CFGR2_PPRE1 RCC_CFGR2_PPRE1_HCLK1d2 /* PCLK1 = HCLK / 2 */ +#define STM32_PCLK1_FREQUENCY (STM32_HCLK_FREQUENCY / 2) #define STM32_APB1_TIM2_CLKIN (STM32_PCLK1_FREQUENCY) #define STM32_APB1_TIM3_CLKIN (STM32_PCLK1_FREQUENCY) @@ -199,7 +199,7 @@ /* Configure the APB3 prescaler */ -#define STM32_RCC_CFGR2_PPRE3 RCC_CFGR2_PPRE3_HCLK1 /* PCLK2 = HCLK / 1 */ +#define STM32_RCC_CFGR2_PPRE3 RCC_CFGR2_PPRE3_HCLK1 /* PCLK3 = HCLK / 1 */ #define STM32_PCLK3_FREQUENCY (STM32_HCLK_FREQUENCY / 1) #define STM32_APB3_LPTIM1_CLKIN (STM32_PCLK3_FREQUENCY) diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/Makefile b/boards/arm/stm32h5/nucleo-h563zi/src/Makefile index 36de09b447..50d7d666e6 100644 --- a/boards/arm/stm32h5/nucleo-h563zi/src/Makefile +++ b/boards/arm/stm32h5/nucleo-h563zi/src/Makefile @@ -43,4 +43,8 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif +ifeq ($(CONFIG_STM32H5_DTS),y) +CSRCS += stm32_dts.c +endif + include $(TOPDIR)/boards/Board.mk diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h b/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h index 670551ad73..df052fb85b 100644 --- a/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h +++ b/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h @@ -129,5 +129,9 @@ int stm32_bringup(void); int stm32_adc_setup(void); #endif +#ifdef CONFIG_STM32H5_DTS +int stm32_dts_setup(int devno); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_SRC_NUCLEO_H563ZI_H */ diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c index 48eeeb4b1b..fa715adb27 100644 --- a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c @@ -110,6 +110,16 @@ int stm32_bringup(void) } #endif /* CONFIG_ADC*/ +#ifdef CONFIG_STM32H5_DTS + /* devno == 0 creates /dev/sensor_temp0 */ + + ret = stm32_dts_setup(0); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_adc_setup failed: %d\n", ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_dts.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_dts.c new file mode 100644 index 0000000000..4dc21ff1f7 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_dts.c @@ -0,0 +1,91 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/stm32_dts.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "stm32.h" + +#if defined(CONFIG_STM32H5_DTS) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_dts_setup + * + * Description: + * Initialize DTS and register the DTS driver. + * + ****************************************************************************/ + +int stm32_dts_setup(int devno) +{ + static bool initialized = false; + int ret; + + /* Check if we have already initialized */ + + if (!initialized) + { + /* Register the DTS driver at "/dev/sensor_temp0" */ + + ret = stm32h5_dts_register(0); + if (ret < 0) + { + aerr("ERROR: dts_register /dev/dts0 failed: %d\n", ret); + return ret; + } + + initialized = true; + } + + return OK; +} + +#endif