arch/arm/stm32h5: Add LPTIM support.

Add LPTIM 1, 3, 4, 5 support. Based on STM32H7. setperiod and
setcompare have been made to wait for the auto-reload value to
be applied before returning.

6 is absent since generic stm32 configs for a 6th LPTIM are not
present yet. 2 is absent for no good reason besides maybe
that it's in a different RCC APB register. I am not adding
support last-minute without more testing. The build fails
noisily when LPTIM2 is enabled so the shortcoming is clear.

Corrected some RCC definitions. They are needed for selecting the LPTIMx
clock source. This is not done in the LPTIM driver. It is done
outside and the definitions should ideally be correct for that.

Signed-off-by: Liam Howatt <liamhowatt@geotab.com>
Co-authored-by: Farzan Farhangian <farzanfarhangian@geotab.com>
This commit is contained in:
Liam Howatt 2026-08-21 17:58:28 -04:00 committed by Xiang Xiao
parent c92b1ed9ac
commit 10d0fa4485
8 changed files with 830 additions and 24 deletions

View file

@ -752,7 +752,7 @@ config STM32_UART8
config STM32_LPTIM1
bool "LPTIM1"
depends on STM32_HAVE_LPTIM1
select STM32_LPTIM if ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32L4 || ARCH_CHIP_STM32WB
select STM32_LPTIM if ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32L4 || ARCH_CHIP_STM32WB || ARCH_CHIP_STM32H5
config STM32_TIM1
bool "TIM1"
@ -841,22 +841,22 @@ config STM32_TIM17
config STM32_LPTIM2
bool "LPTIM2"
depends on ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32U5 || ARCH_CHIP_STM32WB || ARCH_CHIP_STM32L4 && STM32_HAVE_LPTIM2
select STM32_LPTIM if ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32L4 || ARCH_CHIP_STM32WB
depends on ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32U5 || ARCH_CHIP_STM32WB || ARCH_CHIP_STM32H5 || ARCH_CHIP_STM32L4 && STM32_HAVE_LPTIM2
select STM32_LPTIM if ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32L4 || ARCH_CHIP_STM32WB || ARCH_CHIP_STM32H5
config STM32_LPTIM3
bool "LPTIM3"
depends on STM32_HAVE_LPTIM3
select STM32_LPTIM if ARCH_CHIP_STM32H7
select STM32_LPTIM if ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32H5
config STM32_LPTIM4
bool "LPTIM4"
depends on STM32_HAVE_LPTIM4
select STM32_LPTIM if ARCH_CHIP_STM32H7
select STM32_LPTIM if ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32H5
config STM32_LPTIM5
bool "LPTIM5"
depends on ARCH_CHIP_STM32H7
depends on ARCH_CHIP_STM32H7 || ARCH_CHIP_STM32H5
select STM32_LPTIM
config STM32_HRTIM1

View file

@ -88,6 +88,10 @@ if(CONFIG_STM32_TIM)
list(APPEND SRCS stm32_tim.c)
endif()
if(CONFIG_STM32_LPTIM)
list(APPEND SRCS stm32_lptim.c)
endif()
if(CONFIG_STM32_HAVE_HSI48)
list(APPEND SRCS stm32_hsi48.c)
endif()

View file

@ -14,6 +14,11 @@ config STM32_H5_PERIPHERALS
select STM32_HAVE_DMA2
select STM32_HAVE_I2C1
select STM32_HAVE_I2C2
select STM32_HAVE_LPTIM1
select STM32_HAVE_LPTIM2
select STM32_HAVE_LPTIM3
select STM32_HAVE_LPTIM4
select STM32_HAVE_LPTIM5
select STM32_HAVE_RNG
select STM32_HAVE_SPI1
select STM32_HAVE_SPI2

View file

@ -84,6 +84,10 @@ ifeq ($(CONFIG_STM32_TIM),y)
CHIP_CSRCS += stm32_tim.c
endif
ifeq ($(CONFIG_STM32_LPTIM),y)
CHIP_CSRCS += stm32_lptim.c
endif
ifeq ($(CONFIG_STM32_HAVE_HSI48),y)
CHIP_CSRCS += stm32_hsi48.c
endif

View file

@ -0,0 +1,168 @@
/****************************************************************************
* arch/arm/src/stm32h5/hardware/stm32_lptim.h
*
* 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.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32_LPTIM_H
#define __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32_LPTIM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "chip.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Register Offsets *********************************************************/
#define STM32_LPTIM_ISR_OFFSET 0x0000 /* Interrupt and status register */
#define STM32_LPTIM_ICR_OFFSET 0x0004 /* Interrupt clear register */
#define STM32_LPTIM_IER_OFFSET 0x0008 /* Interrupt enable register */
#define STM32_LPTIM_CFGR_OFFSET 0x000C /* Configuration register */
#define STM32_LPTIM_CR_OFFSET 0x0010 /* Control register */
#define STM32_LPTIM_CMP_OFFSET 0x0014 /* Compare register */
#define STM32_LPTIM_ARR_OFFSET 0x0018 /* Autoreloar register */
#define STM32_LPTIM_CNT_OFFSET 0x001C /* Counter register */
#define STM32_LPTIM_CFGR2_OFFSET 0x0024 /* Configuration register 2 */
/* Register Addresses *******************************************************/
# define STM32_LPTIM1_ISR (STM32_LPTIM1_BASE+STM32_LPTIM_ISR_OFFSET)
# define STM32_LPTIM1_ICR (STM32_LPTIM1_BASE+STM32_LPTIM_ICR_OFFSET)
# define STM32_LPTIM1_IER (STM32_LPTIM1_BASE+STM32_LPTIM_IER_OFFSET)
# define STM32_LPTIM1_CFGR (STM32_LPTIM1_BASE+STM32_LPTIM_CFGR_OFFSET)
# define STM32_LPTIM1_CR (STM32_LPTIM1_BASE+STM32_LPTIM_CR_OFFSET)
# define STM32_LPTIM1_CMP (STM32_LPTIM1_BASE+STM32_LPTIM_CMP_OFFSET)
# define STM32_LPTIM1_ARR (STM32_LPTIM1_BASE+STM32_LPTIM_ARR_OFFSET)
# define STM32_LPTIM1_CNT (STM32_LPTIM1_BASE+STM32_LPTIM_CNT_OFFSET)
# define STM32_LPTIM1_CFGR2 (STM32_LPTIM1_BASE+STM32_LPTIM_CFGR2_OFFSET)
# define STM32_LPTIM3_ISR (STM32_LPTIM3_BASE+STM32_LPTIM_ISR_OFFSET)
# define STM32_LPTIM3_ICR (STM32_LPTIM3_BASE+STM32_LPTIM_ICR_OFFSET)
# define STM32_LPTIM3_IER (STM32_LPTIM3_BASE+STM32_LPTIM_IER_OFFSET)
# define STM32_LPTIM3_CFGR (STM32_LPTIM3_BASE+STM32_LPTIM_CFGR_OFFSET)
# define STM32_LPTIM3_CR (STM32_LPTIM3_BASE+STM32_LPTIM_CR_OFFSET)
# define STM32_LPTIM3_CMP (STM32_LPTIM3_BASE+STM32_LPTIM_CMP_OFFSET)
# define STM32_LPTIM3_ARR (STM32_LPTIM3_BASE+STM32_LPTIM_ARR_OFFSET)
# define STM32_LPTIM3_CNT (STM32_LPTIM3_BASE+STM32_LPTIM_CNT_OFFSET)
# define STM32_LPTIM3_CFGR2 (STM32_LPTIM3_BASE+STM32_LPTIM_CFGR2_OFFSET)
# define STM32_LPTIM4_ISR (STM32_LPTIM4_BASE+STM32_LPTIM_ISR_OFFSET)
# define STM32_LPTIM4_ICR (STM32_LPTIM4_BASE+STM32_LPTIM_ICR_OFFSET)
# define STM32_LPTIM4_IER (STM32_LPTIM4_BASE+STM32_LPTIM_IER_OFFSET)
# define STM32_LPTIM4_CFGR (STM32_LPTIM4_BASE+STM32_LPTIM_CFGR_OFFSET)
# define STM32_LPTIM4_CR (STM32_LPTIM4_BASE+STM32_LPTIM_CR_OFFSET)
# define STM32_LPTIM4_CMP (STM32_LPTIM4_BASE+STM32_LPTIM_CMP_OFFSET)
# define STM32_LPTIM4_ARR (STM32_LPTIM4_BASE+STM32_LPTIM_ARR_OFFSET)
# define STM32_LPTIM4_CNT (STM32_LPTIM4_BASE+STM32_LPTIM_CNT_OFFSET)
# define STM32_LPTIM4_CFGR2 (STM32_LPTIM4_BASE+STM32_LPTIM_CFGR2_OFFSET)
# define STM32_LPTIM5_ISR (STM32_LPTIM5_BASE+STM32_LPTIM_ISR_OFFSET)
# define STM32_LPTIM5_ICR (STM32_LPTIM5_BASE+STM32_LPTIM_ICR_OFFSET)
# define STM32_LPTIM5_IER (STM32_LPTIM5_BASE+STM32_LPTIM_IER_OFFSET)
# define STM32_LPTIM5_CFGR (STM32_LPTIM5_BASE+STM32_LPTIM_CFGR_OFFSET)
# define STM32_LPTIM5_CR (STM32_LPTIM5_BASE+STM32_LPTIM_CR_OFFSET)
# define STM32_LPTIM5_CMP (STM32_LPTIM5_BASE+STM32_LPTIM_CMP_OFFSET)
# define STM32_LPTIM5_ARR (STM32_LPTIM5_BASE+STM32_LPTIM_ARR_OFFSET)
# define STM32_LPTIM5_CNT (STM32_LPTIM5_BASE+STM32_LPTIM_CNT_OFFSET)
# define STM32_LPTIM5_CFGR2 (STM32_LPTIM5_BASE+STM32_LPTIM_CFGR2_OFFSET)
/* Register Bitfield Definitions ********************************************/
/* Interrupt flags for ISR, ICR and IER */
#define LPTIM_ISR_CMPM (1 << 0) /* Bit 0: Compare match */
#define LPTIM_ISR_ARRM (1 << 1) /* Bit 1: Autoreload match */
#define LPTIM_ISR_EXTTRIG (1 << 2) /* Bit 2: External trigger edge event */
#define LPTIM_ISR_CMPOK (1 << 3) /* Bit 3: Compare register update OK */
#define LPTIM_ISR_ARROK (1 << 4) /* Bit 4: Autoreload register update OK */
#define LPTIM_ISR_UP (1 << 5) /* Bit 5: Counter direction change down to up */
#define LPTIM_ISR_DOWN (1 << 6) /* Bit 6: Counter direction change up to down */
/* Configuration register */
#define LPTIM_CFGR_CKSEL (1 << 0) /* Bit 0: Clock selector */
#define LPTIM_CFGR_CKPOL_SHIFT (1) /* Bits 1-2: Clock polarity */
#define LPTIM_CFGR_CKPOL_MASK (3 << LPTIM_CFGR_CKPOL_SHIFT)
# define LPTIM_CFGR_CKPOL_RISE (0 << LPTIM_CFGR_CKPOL_SHIFT) /* 00: Rising edge */
# define LPTIM_CFGR_CKPOL_FALL (1 << LPTIM_CFGR_CKPOL_SHIFT) /* 01: Falling edge */
# define LPTIM_CFGR_CKPOL_BOTH (2 << LPTIM_CFGR_CKPOL_SHIFT) /* 10: Both edges */
#define LPTIM_CFGR_CKFLT_SHIFT (3) /* Bits 3-4: Digital filter for clock*/
#define LPTIM_CFGR_CKFLT_MASK (3 << LPTIM_CFGR_CKFLT_SHIFT)
# define LPTIM_CFGR_CKFLT_ANY (0 << LPTIM_CFGR_CKFLT_SHIFT) /* 00: Any */
# define LPTIM_CFGR_CKFLT_2 (1 << LPTIM_CFGR_CKFLT_SHIFT) /* 01: 2 clocks */
# define LPTIM_CFGR_CKFLT_4 (2 << LPTIM_CFGR_CKFLT_SHIFT) /* 10: 4 clocks */
# define LPTIM_CFGR_CKFLT_8 (3 << LPTIM_CFGR_CKFLT_SHIFT) /* 11: 8 clocks */
#define LPTIM_CFGR_TRGFLT_SHIFT (6) /* Bits 6-7: digital filter for trigger */
#define LPTIM_CFGR_TRGFLT_MASK (3 << LPTIM_CFGR_TRGFLT_SHIFT)
# define LPTIM_CFGR_TRGFLT_ANY (0 << LPTIM_CFGR_TRGFLT_SHIFT) /* 00: Any */
# define LPTIM_CFGR_TRGFLT_2 (1 << LPTIM_CFGR_TRGFLT_SHIFT) /* 01: 2 clocks */
# define LPTIM_CFGR_TRGFLT_4 (2 << LPTIM_CFGR_TRGFLT_SHIFT) /* 10: 4 clocks */
# define LPTIM_CFGR_TRGFLT_8 (3 << LPTIM_CFGR_TRGFLT_SHIFT) /* 11: 8 clocks */
#define LPTIM_CFGR_PRESC_SHIFT (9) /* Bits 9-11: Clock prescaler */
#define LPTIM_CFGR_PRESC_MASK (7 << LPTIM_CFGR_PRESC_SHIFT)
# define LPTIM_CFGR_PRESC_1 (0 << LPTIM_CFGR_PRESC_SHIFT)
# define LPTIM_CFGR_PRESC_2 (1 << LPTIM_CFGR_PRESC_SHIFT)
# define LPTIM_CFGR_PRESC_4 (2 << LPTIM_CFGR_PRESC_SHIFT)
# define LPTIM_CFGR_PRESC_8 (3 << LPTIM_CFGR_PRESC_SHIFT)
# define LPTIM_CFGR_PRESC_16 (4 << LPTIM_CFGR_PRESC_SHIFT)
# define LPTIM_CFGR_PRESC_32 (5 << LPTIM_CFGR_PRESC_SHIFT)
# define LPTIM_CFGR_PRESC_64 (6 << LPTIM_CFGR_PRESC_SHIFT)
# define LPTIM_CFGR_PRESC_128 (7 << LPTIM_CFGR_PRESC_SHIFT)
#define LPTIM_CFGR_TRIGSEL_SHIFT (13) /* Bits 13-15: Trigger selector */
#define LPTIM_CFGR_TRIGSEL_MASK (7 << LPTIM_CFGR_TRIGSEL_SHIFT)
#define LPTIM_CFGR_TRIGEN_SHIFT (17) /* Bits 17-18: Trigger enable and polarity */
#define LPTIM_CFGR_TRIGEN_MASK (3 << LPTIM_CFGR_TRIGEN_SHIFT)
# define LPTIM_CFGR_TRIGEN_SW (0 << LPTIM_CFGR_TRIGEN_SHIFT) /* 00: software */
# define LPTIM_CFGR_TRIGEN_RISE (1 << LPTIM_CFGR_TRIGEN_SHIFT) /* 01: rising edge */
# define LPTIM_CFGR_TRIGEN_FALL (2 << LPTIM_CFGR_TRIGEN_SHIFT) /* 10: falling edge */
# define LPTIM_CFGR_TRIGEN_BOTH (3 << LPTIM_CFGR_TRIGEN_SHIFT) /* 11: both edges */
#define LPTIM_CFGR_TIMEOUT (1 << 19) /* Bit 19: Timeout enable */
#define LPTIM_CFGR_WAVE (1 << 20) /* Bit 20: Waveform shape */
#define LPTIM_CFGR_WAVPOL (1 << 21) /* Bit 21: Waveform shape polarity */
#define LPTIM_CFGR_PRELOAD (1 << 22) /* Bit 22: Registers update mode */
#define LPTIM_CFGR_COUNTMODE (1 << 23) /* Bit 23: Counter mode enable */
#define LPTIM_CFGR_ENC (1 << 24) /* Bit 24: Encoder mode enable */
/* Control register */
#define LPTIM_CR_ENABLE (1 << 0) /* Bit 0: Enable */
#define LPTIM_CR_SNGSTRT (1 << 1) /* Bit 1: Start in single mode */
#define LPTIM_CR_CNTSTRT (1 << 2) /* Bit 2: Start in continuous mode */
#define LPTIM_CR_COUNTRST (1 << 3) /* Bit 3: Counter reset */
#define LPTIM_CR_RSTARE (1 << 4) /* Reset after read enable */
/* Configuration register 2 */
#define LPTIM_CFGR2_IN1SEL_SHIFT (0) /* Input 1 selection */
#define LPTIM_CFGR2_IN1SEL_MASK (3 << LPTIM_CFGR2_IN1SEL_SHIFT)
#define LPTIM_CFGR2_IN2SEL_SHIFT (4) /* Input 2 selection */
#define LPTIM_CFGR2_IN2SEL_MASK (3 << LPTIM_CFGR2_IN2SEL_SHIFT)
#endif /* __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32_LPTIM_H */

View file

@ -937,54 +937,54 @@
# define RCC_CCIPR2_LPTIM1SEL_RCCPCLK3 (0 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
# define RCC_CCIPR2_LPTIM1SEL_PLL2PCK (1 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
# define RCC_CCIPR2_LPTIM1SEL_PLL3RCK (2 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
# define RCC_CCIPR2_LPTIM1SEL_HSIKERCK (3 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
# define RCC_CCIPR2_LPTIM1SEL_CSIKERCK (4 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
# define RCC_CCIPR2_LPTIM1SEL_LSECK (5 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
# define RCC_CCIPR2_LPTIM1SEL_LSEKERCK (3 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
# define RCC_CCIPR2_LPTIM1SEL_LSIKERCK (4 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
# define RCC_CCIPR2_LPTIM1SEL_PERCK (5 << RCC_CCIPR2_LPTIM1SEL_SHIFT)
#define RCC_CCIPR2_LPTIM2SEL_SHIFT (12)
#define RCC_CCIPR2_LPTIM2SEL_MASK (7 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_RCCPCLK1 (0 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_PLL2PCK (1 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_PLL3RCK (2 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_HSIKERCK (3 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_CSIKERCK (4 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_LSECK (5 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_LSEKERCK (3 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_LSIKERCK (4 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
# define RCC_CCIPR2_LPTIM2SEL_PERCK (5 << RCC_CCIPR2_LPTIM2SEL_SHIFT)
#define RCC_CCIPR2_LPTIM3SEL_SHIFT (16)
#define RCC_CCIPR2_LPTIM3SEL_MASK (7 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_RCCPCLK3 (0 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_PLL2PCK (1 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_PLL3RCK (2 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_HSIKERCK (3 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_CSIKERCK (4 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_LSECK (5 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_LSEKERCK (3 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_LSIKERCK (4 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
# define RCC_CCIPR2_LPTIM3SEL_PERCK (5 << RCC_CCIPR2_LPTIM3SEL_SHIFT)
#define RCC_CCIPR2_LPTIM4SEL_SHIFT (20)
#define RCC_CCIPR2_LPTIM4SEL_MASK (7 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_RCCPCLK3 (0 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_PLL2PCK (1 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_PLL3RCK (2 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_HSIKERCK (3 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_CSIKERCK (4 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_LSECK (5 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_LSEKERCK (3 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_LSIKERCK (4 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
# define RCC_CCIPR2_LPTIM4SEL_PERCK (5 << RCC_CCIPR2_LPTIM4SEL_SHIFT)
#define RCC_CCIPR2_LPTIM5SEL_SHIFT (24)
#define RCC_CCIPR2_LPTIM5SEL_MASK (7 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_RCCPCLK3 (0 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_PLL2PCK (1 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_PLL3RCK (2 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_HSIKERCK (3 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_CSIKERCK (4 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_LSECK (5 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_LSEKERCK (3 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_LSIKERCK (4 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
# define RCC_CCIPR2_LPTIM5SEL_PERCK (5 << RCC_CCIPR2_LPTIM5SEL_SHIFT)
#define RCC_CCIPR2_LPTIM6SEL_SHIFT (28)
#define RCC_CCIPR2_LPTIM6SEL_MASK (7 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_RCCPCLK3 (0 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_PLL2PCK (1 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_PLL3RCK (2 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_HSIKERCK (3 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_CSIKERCK (4 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_LSECK (5 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_LSEKERCK (3 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_LSIKERCK (4 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
# define RCC_CCIPR2_LPTIM6SEL_PERCK (5 << RCC_CCIPR2_LPTIM6SEL_SHIFT)
/* Kernel Clock Configuration register 3 */

View file

@ -0,0 +1,514 @@
/****************************************************************************
* arch/arm/src/stm32h5/stm32_lptim.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 <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/debug.h>
#include <arch/board/board.h>
#include "chip.h"
#include "arm_internal.h"
#include "stm32_rcc.h"
#include "stm32_gpio.h"
#include "stm32_lptim.h"
#if defined(CONFIG_STM32_LPTIM1) || defined(CONFIG_STM32_LPTIM2) || \
defined(CONFIG_STM32_LPTIM3) || defined(CONFIG_STM32_LPTIM4) || \
defined(CONFIG_STM32_LPTIM5)
/****************************************************************************
* Private Function prototypes
****************************************************************************/
/* Low-power timer methods */
static void stm32_lptim_setcfgr(struct stm32_lptim_dev_s *dev,
uint32_t regval);
static void stm32_lptim_setperiod(struct stm32_lptim_dev_s *dev,
uint32_t period);
static void stm32_lptim_setcompare(struct stm32_lptim_dev_s *dev,
uint32_t cmp);
static uint32_t stm32_lptim_getcounter(struct stm32_lptim_dev_s *dev);
static int stm32_lptim_setinput(struct stm32_lptim_dev_s *dev,
uint32_t input, uint32_t mux);
static void stm32_lptim_enable(struct stm32_lptim_dev_s *dev, bool on);
static void stm32_lptim_start(struct stm32_lptim_dev_s *dev,
stm32_lptim_start_mode_t mode);
static void stm32_lptim_resetcounter(struct stm32_lptim_dev_s *dev);
static void stm32_lptim_enablerar(struct stm32_lptim_dev_s *dev,
bool on);
static int stm32_lptim_setisr(struct stm32_lptim_dev_s *dev,
xcpt_t handler, void *arg, int source);
static void stm32_lptim_enableint(struct stm32_lptim_dev_s *dev,
int source);
static void stm32_lptim_disableint(struct stm32_lptim_dev_s *dev,
int source);
static void stm32_lptim_ackint(struct stm32_lptim_dev_s *dev,
int source);
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static const struct stm32_lptim_ops_s stm32_lptim_ops =
{
.setcfgr = &stm32_lptim_setcfgr,
.setperiod = &stm32_lptim_setperiod,
.setcompare = &stm32_lptim_setcompare,
.getcounter = &stm32_lptim_getcounter,
.setinput = &stm32_lptim_setinput,
.enable = &stm32_lptim_enable,
.start = &stm32_lptim_start,
.resetcounter = &stm32_lptim_resetcounter,
.enablerar = &stm32_lptim_enablerar,
.setisr = &stm32_lptim_setisr,
.enableint = &stm32_lptim_enableint,
.disableint = &stm32_lptim_disableint,
.ackint = &stm32_lptim_ackint
};
#ifdef CONFIG_STM32_LPTIM1
struct stm32_lptim_dev_s stm32_lptim1_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM1_BASE,
};
#endif
#ifdef CONFIG_STM32_LPTIM2
struct stm32_lptim_dev_s stm32_lptim2_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM2_BASE,
};
#endif
#ifdef CONFIG_STM32_LPTIM3
struct stm32_lptim_dev_s stm32_lptim3_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM3_BASE,
};
#endif
#ifdef CONFIG_STM32_LPTIM4
struct stm32_lptim_dev_s stm32_lptim4_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM4_BASE,
};
#endif
#ifdef CONFIG_STM32_LPTIM5
struct stm32_lptim_dev_s stm32_lptim5_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM5_BASE,
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/* Get a 32-bit register value by offset.
*/
static inline uint32_t stm32_getreg32(struct stm32_lptim_dev_s *dev,
uint8_t offset)
{
return getreg32(dev->base + offset);
}
/* Put a 32-bit register value by offset.
*/
static inline void stm32_putreg32(struct stm32_lptim_dev_s *dev,
uint8_t offset, uint32_t value)
{
putreg32(value, dev->base + offset);
}
static void stm32_lptim_setcfgr(struct stm32_lptim_dev_s *dev,
uint32_t regval)
{
stm32_putreg32(dev, STM32_LPTIM_CFGR_OFFSET, regval);
}
static void stm32_lptim_setperiod(struct stm32_lptim_dev_s *dev,
uint32_t period)
{
uint32_t timeout;
/* For STM32H5: Clear ARROK flag BEFORE writing ARR when timer is enabled
* This ensures we wait for the new value to be loaded
*/
if (stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET) & LPTIM_CR_ENABLE)
{
stm32_putreg32(dev, STM32_LPTIM_ICR_OFFSET, LPTIM_ISR_ARROK);
}
stm32_putreg32(dev, STM32_LPTIM_ARR_OFFSET, period);
/* Wait for ARROK flag when timer is enabled */
if (stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET) & LPTIM_CR_ENABLE)
{
timeout = 10000;
while (!(stm32_getreg32(dev, STM32_LPTIM_ISR_OFFSET) & LPTIM_ISR_ARROK)
&& timeout > 0)
{
timeout--;
}
}
}
static void stm32_lptim_setcompare(struct stm32_lptim_dev_s *dev,
uint32_t cmp)
{
uint32_t timeout;
/* For STM32H5: Clear CMPOK flag BEFORE writing CMP when timer is enabled */
if (stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET) & LPTIM_CR_ENABLE)
{
stm32_putreg32(dev, STM32_LPTIM_ICR_OFFSET, LPTIM_ISR_CMPOK);
}
stm32_putreg32(dev, STM32_LPTIM_CMP_OFFSET, cmp);
/* Wait for CMPOK flag when timer is enabled */
if (stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET) & LPTIM_CR_ENABLE)
{
timeout = 10000;
while (!(stm32_getreg32(dev, STM32_LPTIM_ISR_OFFSET) & LPTIM_ISR_CMPOK)
&& timeout > 0)
{
timeout--;
}
}
}
static uint32_t stm32_lptim_getcounter(struct stm32_lptim_dev_s *dev)
{
/* For a reliable LPTIM_CNT register read access, two consecutive
* read accesses must be performed and compared
*/
uint32_t cnt1;
uint32_t cnt2;
cnt2 = stm32_getreg32(dev, STM32_LPTIM_CNT_OFFSET);
do
{
cnt1 = cnt2;
cnt2 = stm32_getreg32(dev, STM32_LPTIM_CNT_OFFSET);
}
while (cnt1 != cnt2);
return cnt1;
}
static int stm32_lptim_setinput(struct stm32_lptim_dev_s *dev,
uint32_t input, uint32_t mux)
{
switch (dev->base)
{
#ifdef CONFIG_STM32_LPTIM1
case STM32_LPTIM1_BASE:
if (input == 0)
{
modifyreg32(dev->base + STM32_LPTIM_CFGR2_OFFSET,
LPTIM_CFGR2_IN1SEL_MASK, mux);
}
else
{
modifyreg32(dev->base + STM32_LPTIM_CFGR2_OFFSET,
LPTIM_CFGR2_IN2SEL_MASK,
mux << LPTIM_CFGR2_IN2SEL_SHIFT);
}
break;
#endif
#ifdef CONFIG_STM32_LPTIM3
case STM32_LPTIM3_BASE:
modifyreg32(dev->base + STM32_LPTIM_CFGR2_OFFSET,
LPTIM_CFGR2_IN1SEL_MASK, mux);
break;
#endif
default:
return -EINVAL;
}
return OK;
}
static void stm32_lptim_enable(struct stm32_lptim_dev_s *dev, bool on)
{
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET);
if (on)
{
val |= LPTIM_CR_ENABLE;
}
else
{
val &= ~LPTIM_CR_ENABLE;
}
stm32_putreg32(dev, STM32_LPTIM_CR_OFFSET, val);
}
static void stm32_lptim_start(struct stm32_lptim_dev_s *dev,
stm32_lptim_start_mode_t mode)
{
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET);
switch (mode)
{
case STM32_LPTIM_MODE_CONTINUOUS:
val |= LPTIM_CR_CNTSTRT;
break;
case STM32_LPTIM_MODE_SINGLE:
val |= LPTIM_CR_SNGSTRT;
break;
}
stm32_putreg32(dev, STM32_LPTIM_CR_OFFSET, val);
}
static void stm32_lptim_resetcounter(struct stm32_lptim_dev_s *dev)
{
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET);
val |= LPTIM_CR_COUNTRST;
stm32_putreg32(dev, STM32_LPTIM_CR_OFFSET, val);
}
static void stm32_lptim_enablerar(struct stm32_lptim_dev_s *dev, bool on)
{
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET);
if (on)
{
val |= LPTIM_CR_RSTARE;
}
else
{
val &= ~LPTIM_CR_RSTARE;
}
stm32_putreg32(dev, STM32_LPTIM_CR_OFFSET, val);
}
static int stm32_lptim_setisr(struct stm32_lptim_dev_s *dev,
xcpt_t handler, void *arg, int source)
{
int vectorno;
DEBUGASSERT(dev != NULL);
DEBUGASSERT(source == 0);
switch (dev->base)
{
#ifdef CONFIG_STM32_LPTIM1
case STM32_LPTIM1_BASE:
vectorno = STM32_IRQ_LPTIM1;
break;
#endif
#ifdef CONFIG_STM32_LPTIM2
case STM32_LPTIM2_BASE:
vectorno = STM32_IRQ_LPTIM2;
break;
#endif
#ifdef CONFIG_STM32_LPTIM3
case STM32_LPTIM3_BASE:
vectorno = STM32_IRQ_LPTIM3;
break;
#endif
#ifdef CONFIG_STM32_LPTIM4
case STM32_LPTIM4_BASE:
vectorno = STM32_IRQ_LPTIM4;
break;
#endif
#ifdef CONFIG_STM32_LPTIM5
case STM32_LPTIM5_BASE:
vectorno = STM32_IRQ_LPTIM5;
break;
#endif
default:
return -EINVAL;
}
/* Disable interrupt when callback is removed */
if (!handler)
{
up_disable_irq(vectorno);
irq_detach(vectorno);
return OK;
}
/* Otherwise set callback and enable interrupt */
irq_attach(vectorno, handler, arg);
up_enable_irq(vectorno);
#ifdef CONFIG_ARCH_IRQPRIO
/* Set the interrupt priority */
up_prioritize_irq(vectorno, NVIC_SYSH_PRIORITY_DEFAULT);
#endif
return OK;
}
static void stm32_lptim_enableint(struct stm32_lptim_dev_s *dev,
int source)
{
DEBUGASSERT(dev != NULL);
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_IER_OFFSET);
val |= source;
stm32_putreg32(dev, STM32_LPTIM_IER_OFFSET, val);
}
static void stm32_lptim_disableint(struct stm32_lptim_dev_s *dev,
int source)
{
DEBUGASSERT(dev != NULL);
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_IER_OFFSET);
val &= ~source;
stm32_putreg32(dev, STM32_LPTIM_IER_OFFSET, val);
}
static void stm32_lptim_ackint(struct stm32_lptim_dev_s *dev, int source)
{
stm32_putreg32(dev, STM32_LPTIM_ICR_OFFSET, source);
}
/****************************************************************************
* Public Functions
****************************************************************************/
struct stm32_lptim_dev_s *stm32_lptim_init(int lptimer)
{
struct stm32_lptim_dev_s *dev = NULL;
/* Get structure and enable power */
switch (lptimer)
{
#ifdef CONFIG_STM32_LPTIM1
case 1:
dev = &stm32_lptim1_priv;
modifyreg32(STM32_RCC_APB3ENR, 0, RCC_APB3ENR_LPTIM1EN);
break;
#endif
#ifdef CONFIG_STM32_LPTIM3
case 3:
dev = &stm32_lptim3_priv;
modifyreg32(STM32_RCC_APB3ENR, 0, RCC_APB3ENR_LPTIM3EN);
break;
#endif
#ifdef CONFIG_STM32_LPTIM4
case 4:
dev = &stm32_lptim4_priv;
modifyreg32(STM32_RCC_APB3ENR, 0, RCC_APB3ENR_LPTIM4EN);
break;
#endif
#ifdef CONFIG_STM32_LPTIM5
case 5:
dev = &stm32_lptim5_priv;
modifyreg32(STM32_RCC_APB3ENR, 0, RCC_APB3ENR_LPTIM5EN);
break;
#endif
#ifdef CONFIG_STM32_LPTIM6
case 6:
dev = &stm32_lptim6_priv;
modifyreg32(STM32_RCC_APB3ENR, 0, RCC_APB3ENR_LPTIM6EN);
break;
#endif
default:
return NULL;
}
return dev;
}
int stm32_lptim_deinit(struct stm32_lptim_dev_s * dev)
{
DEBUGASSERT(dev != NULL);
/* Disable power */
switch (dev->base)
{
#ifdef CONFIG_STM32_LPTIM1
case STM32_LPTIM1_BASE:
modifyreg32(STM32_RCC_APB3ENR, RCC_APB3ENR_LPTIM1EN, 0);
break;
#endif
#ifdef CONFIG_STM32_LPTIM3
case STM32_LPTIM3_BASE:
modifyreg32(STM32_RCC_APB3ENR, RCC_APB3ENR_LPTIM3EN, 0);
break;
#endif
#ifdef CONFIG_STM32_LPTIM4
case STM32_LPTIM4_BASE:
modifyreg32(STM32_RCC_APB3ENR, RCC_APB3ENR_LPTIM4EN, 0);
break;
#endif
#ifdef CONFIG_STM32_LPTIM5
case STM32_LPTIM5_BASE:
modifyreg32(STM32_RCC_APB3ENR, RCC_APB3ENR_LPTIM5EN, 0);
break;
#endif
#ifdef CONFIG_STM32_LPTIM6
case STM32_LPTIM6_BASE:
modifyreg32(STM32_RCC_APB3ENR, RCC_APB3ENR_LPTIM6EN, 0);
break;
#endif
default:
return -EINVAL;
}
return OK;
}
#endif /* defined(CONFIG_STM32_LPTIM1 || ... || CONFIG_STM32_LPTIM5) */

View file

@ -0,0 +1,111 @@
/****************************************************************************
* arch/arm/src/stm32h5/stm32_lptim.h
*
* 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.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_STM32H5_STM32_LPTIM_H
#define __ARCH_ARM_SRC_STM32H5_STM32_LPTIM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "chip.h"
#include "hardware/stm32_lptim.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
typedef enum
{
STM32_LPTIM_MODE_CONTINUOUS = 0x00,
STM32_LPTIM_MODE_SINGLE = 0x01
} stm32_lptim_start_mode_t;
/* LPTIM Device Structure */
struct stm32_lptim_dev_s
{
const struct stm32_lptim_ops_s *ops;
uint32_t base;
};
/* LPTIM Operations */
struct stm32_lptim_ops_s
{
void (*setcfgr)(struct stm32_lptim_dev_s *dev, uint32_t regval);
void (*setperiod)(struct stm32_lptim_dev_s *dev, uint32_t period);
void (*setcompare)(struct stm32_lptim_dev_s *dev, uint32_t cmp);
uint32_t (*getcounter)(struct stm32_lptim_dev_s *dev);
int (*setinput)(struct stm32_lptim_dev_s *dev, uint32_t input,
uint32_t mux);
void (*enable)(struct stm32_lptim_dev_s *dev, bool on);
void (*start)(struct stm32_lptim_dev_s *dev,
stm32_lptim_start_mode_t mode);
void (*resetcounter)(struct stm32_lptim_dev_s *dev);
void (*enablerar)(struct stm32_lptim_dev_s *dev, bool on);
/* Low-power timer interrupts */
int (*setisr)(struct stm32_lptim_dev_s *dev, xcpt_t handler,
void *arg, int source);
void (*enableint)(struct stm32_lptim_dev_s *dev, int source);
void (*disableint)(struct stm32_lptim_dev_s *dev, int source);
void (*ackint)(struct stm32_lptim_dev_s *dev, int source);
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Power-up low power timer and get its structure */
struct stm32_lptim_dev_s *stm32_lptim_init(int lptimer);
/* Power-down low power timer, mark it as unused */
int stm32_lptim_deinit(struct stm32_lptim_dev_s *dev);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_STM32H5_STM32_LPTIM_H */