diff --git a/boards/common/nucleo144/include/board.h b/boards/common/nucleo144/include/board.h index 85cac6b173..0623c181e4 100644 --- a/boards/common/nucleo144/include/board.h +++ b/boards/common/nucleo144/include/board.h @@ -37,7 +37,8 @@ extern "C" { * @name LED pin definitions and handlers * @{ */ -#if defined(CPU_MODEL_STM32L496ZG) || defined(CPU_MODEL_STM32L4R5ZI) +#if defined(CPU_MODEL_STM32L496ZG) || defined(CPU_MODEL_STM32L4R5ZI) || \ + defined(CPU_MODEL_STM32L552ZE) #define LED0_PORT GPIOC #define LED0_PIN GPIO_PIN(PORT_C, 7) #define LED0_MASK (1 << 7) @@ -56,11 +57,18 @@ extern "C" { #define LED1_OFF (GPIOB->BSRR = (LED1_MASK << 16)) #define LED1_TOGGLE (GPIOB->ODR ^= LED1_MASK) +#if defined(CPU_MODEL_STM32L552ZE) +#define LED2_PORT GPIOA +#define LED2_PIN GPIO_PIN(PORT_A, 9) +#define LED2_MASK (1 << 9) +#else +#define LED2_PORT GPIOB #define LED2_PIN GPIO_PIN(PORT_B, 14) #define LED2_MASK (1 << 14) -#define LED2_ON (GPIOB->BSRR = LED2_MASK) -#define LED2_OFF (GPIOB->BSRR = (LED2_MASK << 16)) -#define LED2_TOGGLE (GPIOB->ODR ^= LED2_MASK) +#endif +#define LED2_ON (LED2_PORT->BSRR = LED2_MASK) +#define LED2_OFF (LED2_PORT->BSRR = (LED2_MASK << 16)) +#define LED2_TOGGLE (LED2_PORT->ODR ^= LED2_MASK) /* the Nucleo144 boards always use LED0, as there is no dual use of its pin */ #ifndef AUTO_INIT_LED0 diff --git a/boards/common/stm32/dist/stm32l5.cfg b/boards/common/stm32/dist/stm32l5.cfg new file mode 100644 index 0000000000..7e790cc252 --- /dev/null +++ b/boards/common/stm32/dist/stm32l5.cfg @@ -0,0 +1,3 @@ +source [find target/stm32l5x.cfg] +reset_config srst_only +$_TARGETNAME configure -rtos auto diff --git a/boards/common/stm32/include/cfg_i2c1_pb8_pb9.h b/boards/common/stm32/include/cfg_i2c1_pb8_pb9.h index 1dd5bd53c2..985411f1c3 100644 --- a/boards/common/stm32/include/cfg_i2c1_pb8_pb9.h +++ b/boards/common/stm32/include/cfg_i2c1_pb8_pb9.h @@ -50,7 +50,7 @@ static const i2c_conf_t i2c_config[] = { .rcc_mask = RCC_APB1ENR_I2C1EN, .clk = CLOCK_APB1, .irqn = I2C1_EV_IRQn, -#elif CPU_FAM_STM32L4 || CPU_FAM_STM32WB || CPU_FAM_STM32G4 +#elif CPU_FAM_STM32L4 || CPU_FAM_STM32WB || CPU_FAM_STM32G4 || CPU_FAM_STM32L5 .rcc_mask = RCC_APB1ENR1_I2C1EN, .irqn = I2C1_ER_IRQn, #elif CPU_FAM_STM32G0 @@ -71,7 +71,7 @@ static const i2c_conf_t i2c_config[] = { #if CPU_FAM_STM32F4 || CPU_FAM_STM32F2 #define I2C_0_ISR isr_i2c1_ev -#elif CPU_FAM_STM32L4 || CPU_FAM_STM32F7 || CPU_FAM_STM32WB +#elif CPU_FAM_STM32L4 || CPU_FAM_STM32F7 || CPU_FAM_STM32WB || CPU_FAM_STM32L5 #define I2C_0_ISR isr_i2c1_er #elif CPU_FAM_STM32F0 || CPU_FAM_STM32L0 || CPU_FAM_STM32G0 #define I2C_0_ISR isr_i2c1 diff --git a/boards/common/stm32/include/cfg_timer_tim5.h b/boards/common/stm32/include/cfg_timer_tim5.h index 528e6f61a4..5f44ef71d9 100644 --- a/boards/common/stm32/include/cfg_timer_tim5.h +++ b/boards/common/stm32/include/cfg_timer_tim5.h @@ -33,7 +33,7 @@ static const timer_conf_t timer_config[] = { { .dev = TIM5, .max = 0xffffffff, -#if defined(CPU_FAM_STM32G4) +#if defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) .rcc_mask = RCC_APB1ENR1_TIM5EN, #else .rcc_mask = RCC_APB1ENR_TIM5EN, diff --git a/boards/common/stm32/include/l4/cfg_clock_default.h b/boards/common/stm32/include/l4/cfg_clock_default.h index 1ad5a4dc98..f243860895 100644 --- a/boards/common/stm32/include/l4/cfg_clock_default.h +++ b/boards/common/stm32/include/l4/cfg_clock_default.h @@ -177,6 +177,8 @@ extern "C" { #error "SYSCLK cannot exceed 64MHz" #elif CLOCK_CORECLOCK_MAX == MHZ(80) #error "SYSCLK cannot exceed 80MHz" +#elif CLOCK_CORECLOCK_MAX == MHZ(110) +#error "SYSCLK cannot exceed 110MHz" #elif CLOCK_CORECLOCK_MAX == MHZ(120) #error "SYSCLK cannot exceed 120MHz" #else diff --git a/boards/nucleo-l552ze-q/Kconfig b/boards/nucleo-l552ze-q/Kconfig new file mode 100644 index 0000000000..bc415b5b3a --- /dev/null +++ b/boards/nucleo-l552ze-q/Kconfig @@ -0,0 +1,30 @@ +# Copyright (c) 2020 Inria +# +# 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. +# + +config BOARD + default "nucleo-l552ze-q" if BOARD_NUCLEO_L552ZE_Q + +config BOARD_NUCLEO_L552ZE_Q + bool + default y + select BOARD_COMMON_NUCLEO144 + select CPU_MODEL_STM32L552ZE + + # Put defined MCU peripherals here (in alphabetical order) + select HAS_PERIPH_I2C + select HAS_PERIPH_LPUART + select HAS_PERIPH_SPI + select HAS_PERIPH_TIMER + select HAS_PERIPH_UART + + # Put other features for this board (in alphabetical order) + select HAS_RIOTBOOT + + # Clock configuration + select BOARD_HAS_LSE + +source "$(RIOTBOARD)/common/nucleo144/Kconfig" diff --git a/boards/nucleo-l552ze-q/Makefile b/boards/nucleo-l552ze-q/Makefile new file mode 100644 index 0000000000..4dd17b1d0c --- /dev/null +++ b/boards/nucleo-l552ze-q/Makefile @@ -0,0 +1,4 @@ +MODULE = board +DIRS = $(RIOTBOARD)/common/nucleo + +include $(RIOTBASE)/Makefile.base diff --git a/boards/nucleo-l552ze-q/Makefile.dep b/boards/nucleo-l552ze-q/Makefile.dep new file mode 100644 index 0000000000..f41bf0f86b --- /dev/null +++ b/boards/nucleo-l552ze-q/Makefile.dep @@ -0,0 +1,3 @@ +FEATURES_REQUIRED += periph_lpuart + +include $(RIOTBOARD)/common/nucleo/Makefile.dep diff --git a/boards/nucleo-l552ze-q/Makefile.features b/boards/nucleo-l552ze-q/Makefile.features new file mode 100644 index 0000000000..80cb0a23bd --- /dev/null +++ b/boards/nucleo-l552ze-q/Makefile.features @@ -0,0 +1,14 @@ +CPU = stm32 +CPU_MODEL = stm32l552ze + +# Put defined MCU peripherals here (in alphabetical order) +FEATURES_PROVIDED += periph_i2c +FEATURES_PROVIDED += periph_spi +FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_uart periph_lpuart + +# Put other features for this board (in alphabetical order) +FEATURES_PROVIDED += riotboot + +# load the common Makefile.features for Nucleo boards +include $(RIOTBOARD)/common/nucleo144/Makefile.features diff --git a/boards/nucleo-l552ze-q/Makefile.include b/boards/nucleo-l552ze-q/Makefile.include new file mode 100644 index 0000000000..a7e3adb0d8 --- /dev/null +++ b/boards/nucleo-l552ze-q/Makefile.include @@ -0,0 +1,2 @@ +# load the common Makefile.include for Nucleo boards +include $(RIOTBOARD)/common/nucleo144/Makefile.include diff --git a/boards/nucleo-l552ze-q/doc.txt b/boards/nucleo-l552ze-q/doc.txt new file mode 100644 index 0000000000..74394eea4e --- /dev/null +++ b/boards/nucleo-l552ze-q/doc.txt @@ -0,0 +1,26 @@ +/** +@defgroup boards_nucleo-l552ze-q STM32 Nucleo-L552ZE-Q +@ingroup boards_common_nucleo144 +@brief Support for the STM32 Nucleo-L552ZE-Q + +## Flashing the device + +The ST Nucleo-L552ZE-Q board includes an on-board ST-LINK V2.1 programmer. The +easiest way to program the board is to use OpenOCD. Once you have installed +OpenOCD (look [here](https://github.com/RIOT-OS/RIOT/wiki/OpenOCD) for +installation instructions), you can flash the board simply by typing + +``` +make BOARD=nucleo-l552ze-q flash +``` +and debug via GDB by simply typing +``` +make BOARD=nucleo-l552ze-q debug +``` + +## Supported Toolchains + +For using the ST Nucleo-L552ZE-Q board we recommend the usage of the +[GNU Tools for ARM Embedded Processors](https://launchpad.net/gcc-arm-embedded) +toolchain. + */ diff --git a/boards/nucleo-l552ze-q/include/periph_conf.h b/boards/nucleo-l552ze-q/include/periph_conf.h new file mode 100644 index 0000000000..985c14a895 --- /dev/null +++ b/boards/nucleo-l552ze-q/include/periph_conf.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2020 Inria + * + * 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 boards_nucleo-l552ze-q + * @{ + * + * @file + * @brief Peripheral MCU configuration for the nucleo-l552ze-q board + * + * @author Alexandre Abadie + */ + +#ifndef PERIPH_CONF_H +#define PERIPH_CONF_H + +/* Add specific clock configuration (HSE, LSE) for this board here */ +#define CLOCK_CORECLOCK_MAX MHZ(110) + +/* Reach 108MHz by by default setting custom PLL_N factor */ +#ifndef CONFIG_CLOCK_PLL_N +#define CONFIG_CLOCK_PLL_N 27 +#endif + +/* Add specific clock configuration (HSE, LSE) for this board here */ +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif + +#include "periph_cpu.h" +#include "l4/cfg_clock_default.h" +#include "cfg_i2c1_pb8_pb9.h" +#include "cfg_rtt_default.h" +#include "cfg_timer_tim5.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name UART configuration + * @{ + */ +static const uart_conf_t uart_config[] = { + { + .dev = LPUART1, + .rcc_mask = RCC_APB1ENR2_LPUART1EN, + .rx_pin = GPIO_PIN(PORT_G, 8), + .tx_pin = GPIO_PIN(PORT_G, 7), + .rx_af = GPIO_AF8, + .tx_af = GPIO_AF8, + .bus = APB12, + .irqn = LPUART1_IRQn, + .type = STM32_LPUART, + .clk_src = 0, /* Use APB clock */ + }, + { /* Connected to Arduino D0/D1 */ + .dev = USART3, + .rcc_mask = RCC_APB1ENR1_USART3EN, + .rx_pin = GPIO_PIN(PORT_D, 9), + .tx_pin = GPIO_PIN(PORT_D, 8), + .rx_af = GPIO_AF7, + .tx_af = GPIO_AF7, + .bus = APB1, + .irqn = USART3_IRQn, + .type = STM32_USART, + .clk_src = 0, /* Use APB clock */ + }, +}; + +#define UART_0_ISR (isr_lpuart1) +#define UART_1_ISR (isr_usart3) + +#define UART_NUMOF ARRAY_SIZE(uart_config) +/** @} */ + +/** + * @name SPI configuration + * @{ + */ +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), /* Arduino D11 */ + .miso_pin = GPIO_PIN(PORT_A, 6), /* Arduino D12 */ + .sclk_pin = GPIO_PIN(PORT_A, 5), /* Arduino D13 */ + .cs_pin = GPIO_UNDEF, + .mosi_af = GPIO_AF5, + .miso_af = GPIO_AF5, + .sclk_af = GPIO_AF5, + .cs_af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2, + }, +}; + +#define SPI_NUMOF ARRAY_SIZE(spi_config) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CONF_H */ +/** @} */ diff --git a/cpu/stm32/Makefile.features b/cpu/stm32/Makefile.features index 2bed71dcef..4e06213fe5 100644 --- a/cpu/stm32/Makefile.features +++ b/cpu/stm32/Makefile.features @@ -9,7 +9,7 @@ FEATURES_PROVIDED += periph_uart_modecfg FEATURES_PROVIDED += periph_uart_nonblocking FEATURES_PROVIDED += periph_wdt -ifneq (,$(filter $(CPU_FAM),f0 f1 f3 g0 g4 l0 l1 l4 wb)) +ifneq (,$(filter $(CPU_FAM),f0 f1 f3 g0 g4 l0 l1 l4 l5 wb)) FEATURES_PROVIDED += periph_flashpage FEATURES_PROVIDED += periph_flashpage_raw endif @@ -25,7 +25,7 @@ endif # Not all F4 and L0 parts implement a RNG. CPU_MODELS_WITHOUT_HWRNG = stm32f401% stm32f411% stm32f446% stm32l031% stm32l011% -ifneq (,$(filter $(CPU_FAM),f2 f4 f7 g4 l0 l4 wb)) +ifneq (,$(filter $(CPU_FAM),f2 f4 f7 g4 l0 l4 l5 wb)) ifeq (,$(filter $(CPU_MODELS_WITHOUT_HWRNG),$(CPU_MODEL))) FEATURES_PROVIDED += periph_hwrng endif diff --git a/cpu/stm32/cpu_common.c b/cpu/stm32/cpu_common.c index b236812449..8820f2cdf3 100644 --- a/cpu/stm32/cpu_common.c +++ b/cpu/stm32/cpu_common.c @@ -68,7 +68,7 @@ void periph_clk_en(bus_t bus, uint32_t mask) switch (bus) { case APB1: #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) RCC->APB1ENR1 |= mask; #elif defined(CPU_FAM_STM32G0) RCC->APBENR1 |= mask; @@ -82,7 +82,7 @@ void periph_clk_en(bus_t bus, uint32_t mask) break; #endif #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) case APB12: RCC->APB1ENR2 |= mask; break; @@ -105,7 +105,8 @@ void periph_clk_en(bus_t bus, uint32_t mask) break; #elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F7) || \ - defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) case AHB1: RCC->AHB1ENR |= mask; break; @@ -132,7 +133,7 @@ void periph_clk_dis(bus_t bus, uint32_t mask) switch (bus) { case APB1: #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) RCC->APB1ENR1 &= ~(mask); #elif defined(CPU_FAM_STM32G0) RCC->APBENR1 &= ~(mask); @@ -146,7 +147,7 @@ void periph_clk_dis(bus_t bus, uint32_t mask) break; #endif #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) case APB12: RCC->APB1ENR2 &= ~(mask); break; @@ -169,7 +170,8 @@ void periph_clk_dis(bus_t bus, uint32_t mask) break; #elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F7) || \ - defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) case AHB1: RCC->AHB1ENR &= ~(mask); break; @@ -194,7 +196,8 @@ void periph_clk_dis(bus_t bus, uint32_t mask) } } -#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) +#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) void periph_lpclk_en(bus_t bus, uint32_t mask) { switch (bus) { diff --git a/cpu/stm32/cpu_init.c b/cpu/stm32/cpu_init.c index d8f82bcab3..8a70680eff 100644 --- a/cpu/stm32/cpu_init.c +++ b/cpu/stm32/cpu_init.c @@ -39,7 +39,8 @@ #include "periph/init.h" #include "board.h" -#if defined (CPU_FAM_STM32L4) || defined (CPU_FAM_STM32G4) +#if defined (CPU_FAM_STM32L4) || defined (CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) #define BIT_APB_PWREN RCC_APB1ENR1_PWREN #elif defined (CPU_FAM_STM32G0) #define BIT_APB_PWREN RCC_APBENR1_PWREN diff --git a/cpu/stm32/dist/irqs/gen_irqs.py b/cpu/stm32/dist/irqs/gen_irqs.py index 08977565d4..8192ea662b 100755 --- a/cpu/stm32/dist/irqs/gen_irqs.py +++ b/cpu/stm32/dist/irqs/gen_irqs.py @@ -52,6 +52,10 @@ extern "C" {{ def list_cpu_lines(cpu_fam): """Returns the list CPU lines for a given family""" headers = os.listdir(STM32_CMSIS_INCLUDE_DIR.format(cpu_fam)) + if "Templates" in headers: + headers.remove("Templates") + if "partition_stm32l5xx.h" in headers: + headers.remove("partition_stm32l5xx.h") headers.remove("stm32{}xx.h".format(cpu_fam)) headers.remove("system_stm32{}xx.h".format(cpu_fam)) return [header.split(".")[0] for header in headers] diff --git a/cpu/stm32/dist/kconfig/gen_kconfig.py b/cpu/stm32/dist/kconfig/gen_kconfig.py index fe0bacee4a..8780ca5cce 100755 --- a/cpu/stm32/dist/kconfig/gen_kconfig.py +++ b/cpu/stm32/dist/kconfig/gen_kconfig.py @@ -112,9 +112,12 @@ def generate_kconfig(kconfig, context, overwrite, verbose): template = env.get_template(template_file) render = template.render(**context) - kconfig_file = os.path.join( - STM32_KCONFIG_DIR, context["fam"], "Kconfig.{}".format(kconfig) - ) + kconfig_dir = os.path.join(STM32_KCONFIG_DIR, context["fam"]) + kconfig_file = os.path.join(kconfig_dir, "Kconfig.{}".format(kconfig)) + + # Create family Kconfig dir if it doesn't exist yet + if not os.path.exists(kconfig_dir): + os.makedirs(kconfig_dir) if (not os.path.exists(kconfig_file) or (os.path.exists(kconfig_file) and diff --git a/cpu/stm32/include/cpu_conf.h b/cpu/stm32/include/cpu_conf.h index bf5e4f64fc..44e70e607b 100644 --- a/cpu/stm32/include/cpu_conf.h +++ b/cpu/stm32/include/cpu_conf.h @@ -58,6 +58,9 @@ #elif CPU_FAM_STM32L4 #include "stm32l4xx.h" #include "irqs/l4/irqs.h" +#elif CPU_FAM_STM32L5 +#include "stm32l5xx.h" +#include "irqs/l5/irqs.h" #elif CPU_FAM_STM32WB #include "stm32wbxx.h" #include "irqs/wb/irqs.h" @@ -91,7 +94,8 @@ extern "C" { #elif defined(CPU_LINE_STM32F091xC) || defined(CPU_LINE_STM32F072xB) \ || defined(CPU_LINE_STM32F030xC) || defined(CPU_LINE_STM32F103xE) \ || defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) \ - || defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + || defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) \ + || defined(CPU_FAM_STM32L5) #define FLASHPAGE_SIZE (2048U) #elif defined(CPU_LINE_STM32F051x8) || defined(CPU_LINE_STM32F042x6) \ || defined(CPU_LINE_STM32F070xB) || defined(CPU_LINE_STM32F030x8) \ @@ -110,7 +114,8 @@ extern "C" { * However, the erase block is always FLASHPAGE_SIZE. */ #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) #define FLASHPAGE_RAW_BLOCKSIZE (8U) #elif defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) #define FLASHPAGE_RAW_BLOCKSIZE (4U) @@ -119,7 +124,8 @@ extern "C" { #endif #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) #define FLASHPAGE_RAW_ALIGNMENT (8U) #else /* Writing should be always 4 bytes aligned */ diff --git a/cpu/stm32/include/cpu_conf_stm32_common.h b/cpu/stm32/include/cpu_conf_stm32_common.h index 2839660951..37b2917ccf 100644 --- a/cpu/stm32/include/cpu_conf_stm32_common.h +++ b/cpu/stm32/include/cpu_conf_stm32_common.h @@ -31,7 +31,7 @@ extern "C" { defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \ defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32L4) || \ defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ - defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) /** * @brief Timing register settings @@ -41,7 +41,8 @@ extern "C" { static const i2c_timing_param_t timing_params[] = { #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F7) || \ defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) [ I2C_SPEED_NORMAL ] = { .presc = 0xB, .scll = 0x13, /* t_SCLL = 5.0us */ @@ -112,7 +113,7 @@ static const i2c_timing_param_t timing_params[] = { #endif /* CPU_FAM_STM32F0 || CPU_FAM_STM32F3 || CPU_FAM_STM32F7 || CPU_FAM_STM32L0 || CPU_FAM_STM32L4 || CPU_FAM_STM32WB || - CPU_FAM_STM32G4 || CPU_FAM_STM32G0 */ + CPU_FAM_STM32G4 || CPU_FAM_STM32G0 || CPU_FAM_STM32L5 */ #ifdef __cplusplus } diff --git a/cpu/stm32/include/periph/l5/periph_cpu.h b/cpu/stm32/include/periph/l5/periph_cpu.h new file mode 100644 index 0000000000..0c3a214a1a --- /dev/null +++ b/cpu/stm32/include/periph/l5/periph_cpu.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 Inria + * + * 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_stm32 + * @{ + * + * @file + * @brief STM32L5 CPU specific definitions for internal peripheral handling + * + * @author Alexandre Abadie + * + */ + +#ifndef PERIPH_L5_PERIPH_CPU_H +#define PERIPH_L5_PERIPH_CPU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN + +/** + * @brief Starting address of the ROM bootloader + * see application note AN2606 + */ +#define STM32_BOOTLOADER_ADDR (0x0BF90000) + +#endif /* ndef DOXYGEN */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_L5_PERIPH_CPU_H */ +/** @} */ diff --git a/cpu/stm32/include/periph_cpu.h b/cpu/stm32/include/periph_cpu.h index 80b1954848..36ef560477 100644 --- a/cpu/stm32/include/periph_cpu.h +++ b/cpu/stm32/include/periph_cpu.h @@ -46,6 +46,8 @@ #include "periph/l1/periph_cpu.h" #elif defined(CPU_FAM_STM32L4) #include "periph/l4/periph_cpu.h" +#elif defined(CPU_FAM_STM32L5) +#include "periph/l5/periph_cpu.h" #elif defined(CPU_FAM_STM32WB) #include "periph/wb/periph_cpu.h" #endif @@ -65,7 +67,7 @@ extern "C" { #elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L4) || \ defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ - defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) #define CLOCK_LSI (32000U) #else #error "error: LSI clock speed not defined for your target CPU" @@ -171,7 +173,8 @@ typedef enum { APB1, /**< APB1 bus */ APB2, /**< APB2 bus */ #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) APB12, /**< AHB1 bus, second register */ #endif #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32G0) @@ -182,7 +185,8 @@ typedef enum { AHB, /**< AHB bus */ #elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F7) || \ - defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) AHB1, /**< AHB1 bus */ AHB2, /**< AHB2 bus */ AHB3, /**< AHB3 bus */ @@ -669,7 +673,8 @@ typedef struct { #endif #endif #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4) || \ - defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) uart_type_t type; /**< hardware module type (USART or LPUART) */ uint32_t clk_src; /**< clock source used for UART */ #endif @@ -720,7 +725,8 @@ typedef enum { #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \ defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \ defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) I2C_SPEED_FAST_PLUS, /**< fast plus mode: ~1Mbit/s */ #endif } i2c_speed_t; @@ -754,7 +760,8 @@ typedef struct { #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \ defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \ defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) /** * @brief Structure for I2C timing register settings * diff --git a/cpu/stm32/include/vendor/Makefile b/cpu/stm32/include/vendor/Makefile index db0c0c117a..8690f774ef 100644 --- a/cpu/stm32/include/vendor/Makefile +++ b/cpu/stm32/include/vendor/Makefile @@ -14,6 +14,7 @@ PKG_VERSION_g4=7194c403cd5e4bd8bd4621a21d366d525e61b998 # v1.1.1 PKG_VERSION_l0=78696f4f79cf51c8b32d0aa5c199a04f57ee4b27 # v1.9.0 PKG_VERSION_l1=4a2f3cd6ea4bbc8e36daff0c7574b0fc1dfb7df7 # v2.3.0 PKG_VERSION_l4=e442c72651e8d4757f6562acc14da949644944ce # v1.6.1 +PKG_VERSION_l5=d922865fc0326a102c26211c44b8e42f52c1e53d # v1.0.3 PKG_VERSION_wb=44490652c88a513ec9a892c328db0246cf113987 # v1.4.0 PKG_VERSION=$(PKG_VERSION_$(CPU_FAM)) diff --git a/cpu/stm32/kconfigs/l5/Kconfig b/cpu/stm32/kconfigs/l5/Kconfig new file mode 100644 index 0000000000..77dd324983 --- /dev/null +++ b/cpu/stm32/kconfigs/l5/Kconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2020 Inria +# +# 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. +# + +config CPU_FAM_L5 + bool + select CPU_STM32 + select CPU_CORE_CORTEX_M33 + select HAS_CPU_STM32L5 + select HAS_PERIPH_FLASHPAGE + select HAS_PERIPH_FLASHPAGE_RAW + select HAS_PERIPH_HWRNG + +config CPU_FAM + default "l5" if CPU_FAM_L5 + +config HAS_CPU_STM32L5 + bool + help + Indicates that the cpu being used belongs to the 'stm32l5' family. diff --git a/cpu/stm32/kconfigs/l5/Kconfig.lines b/cpu/stm32/kconfigs/l5/Kconfig.lines new file mode 100644 index 0000000000..5653783ad2 --- /dev/null +++ b/cpu/stm32/kconfigs/l5/Kconfig.lines @@ -0,0 +1,15 @@ +# Copyright (c) 2020 Inria +# +# 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. +# + +# CPU lines +config CPU_LINE_STM32L552XX + bool + select CPU_FAM_L5 + +config CPU_LINE_STM32L562XX + bool + select CPU_FAM_L5 diff --git a/cpu/stm32/kconfigs/l5/Kconfig.models b/cpu/stm32/kconfigs/l5/Kconfig.models new file mode 100644 index 0000000000..133f3986f8 --- /dev/null +++ b/cpu/stm32/kconfigs/l5/Kconfig.models @@ -0,0 +1,100 @@ +# Copyright (c) 2020 Inria +# +# 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. +# + +# This file was auto-generated from ST ProductsList.xlsx sheet using the +# script in cpu/stm32/dist/kconfig/gen_kconfig.py +# See cpu/stm32/dist/kconfig/README.md for details + +# CPU models +config CPU_MODEL_STM32L552CC + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552CE + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552ME + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552QC + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552QE + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552RC + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552RE + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552VC + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552VE + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552ZC + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L552ZE + bool + select CPU_LINE_STM32L552XX + +config CPU_MODEL_STM32L562CE + bool + select CPU_LINE_STM32L562XX + +config CPU_MODEL_STM32L562ME + bool + select CPU_LINE_STM32L562XX + +config CPU_MODEL_STM32L562QE + bool + select CPU_LINE_STM32L562XX + +config CPU_MODEL_STM32L562RE + bool + select CPU_LINE_STM32L562XX + +config CPU_MODEL_STM32L562VE + bool + select CPU_LINE_STM32L562XX + +config CPU_MODEL_STM32L562ZE + bool + select CPU_LINE_STM32L562XX + + +# Configure CPU model +config CPU_MODEL + default "stm32l552cc" if CPU_MODEL_STM32L552CC + default "stm32l552ce" if CPU_MODEL_STM32L552CE + default "stm32l552me" if CPU_MODEL_STM32L552ME + default "stm32l552qc" if CPU_MODEL_STM32L552QC + default "stm32l552qe" if CPU_MODEL_STM32L552QE + default "stm32l552rc" if CPU_MODEL_STM32L552RC + default "stm32l552re" if CPU_MODEL_STM32L552RE + default "stm32l552vc" if CPU_MODEL_STM32L552VC + default "stm32l552ve" if CPU_MODEL_STM32L552VE + default "stm32l552zc" if CPU_MODEL_STM32L552ZC + default "stm32l552ze" if CPU_MODEL_STM32L552ZE + default "stm32l562ce" if CPU_MODEL_STM32L562CE + default "stm32l562me" if CPU_MODEL_STM32L562ME + default "stm32l562qe" if CPU_MODEL_STM32L562QE + default "stm32l562re" if CPU_MODEL_STM32L562RE + default "stm32l562ve" if CPU_MODEL_STM32L562VE + default "stm32l562ze" if CPU_MODEL_STM32L562ZE diff --git a/cpu/stm32/periph/Makefile b/cpu/stm32/periph/Makefile index c5b1e81c91..9b171e154c 100644 --- a/cpu/stm32/periph/Makefile +++ b/cpu/stm32/periph/Makefile @@ -2,7 +2,7 @@ MODULE = periph # Select the specific implementation for `periph_i2c` ifneq (,$(filter periph_i2c,$(USEMODULE))) - ifneq (,$(filter $(CPU_FAM),f0 f3 f7 g0 g4 l0 l4 wb)) + ifneq (,$(filter $(CPU_FAM),f0 f3 f7 g0 g4 l0 l4 l5 wb)) SRC += i2c_1.c else # f1/f2/f4/l1 SRC += i2c_2.c diff --git a/cpu/stm32/periph/flash_common.c b/cpu/stm32/periph/flash_common.c index ec3e4ba565..6c8b517bea 100644 --- a/cpu/stm32/periph/flash_common.c +++ b/cpu/stm32/periph/flash_common.c @@ -31,6 +31,13 @@ #define CNTRL_REG (FLASH->PECR) #define CNTRL_REG_LOCK (FLASH_PECR_PELOCK) #define KEY_REG (FLASH->PEKEYR) +#elif defined(CPU_FAM_STM32L5) +#define FLASH_KEY1 ((uint32_t)0x45670123) +#define FLASH_KEY2 ((uint32_t)0xCDEF89AB) +#define CNTRL_REG (FLASH->NSCR) +#define CNTRL_REG_LOCK (FLASH_NSCR_NSLOCK) +#define KEY_REG (FLASH->NSKEYR) +#define FLASH_SR_EOP (FLASH_NSSR_NSEOP) #else #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) @@ -46,6 +53,13 @@ #define FLASH_SR_BSY (FLASH_SR_BSY1) #endif +#if defined(CPU_FAM_STM32L5) +#define FLASH_SR_BSY (FLASH_NSSR_NSBSY) +#define FLASH_SR_REG (FLASH->NSSR) +#else +#define FLASH_SR_REG (FLASH->SR) +#endif + void _unlock(void) { if (CNTRL_REG & CNTRL_REG_LOCK) { @@ -65,9 +79,9 @@ void _lock(void) void _wait_for_pending_operations(void) { - if (FLASH->SR & FLASH_SR_BSY) { + if (FLASH_SR_REG & FLASH_SR_BSY) { DEBUG("[flash-common] waiting for any pending operation to finish\n"); - while (FLASH->SR & FLASH_SR_BSY) {} + while (FLASH_SR_REG & FLASH_SR_BSY) {} } /* Clear 'end of operation' bit in status register, for other STM32 boards @@ -75,6 +89,6 @@ void _wait_for_pending_operations(void) #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \ defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L0) || \ defined(CPU_FAM_STM32L1) - FLASH->SR |= FLASH_SR_EOP; + FLASH_SR_REG |= FLASH_SR_EOP; #endif } diff --git a/cpu/stm32/periph/flashpage.c b/cpu/stm32/periph/flashpage.c index 85d4da1ed4..e7856eb00b 100644 --- a/cpu/stm32/periph/flashpage.c +++ b/cpu/stm32/periph/flashpage.c @@ -39,9 +39,20 @@ #define CNTRL_REG_LOCK (FLASH_PECR_PELOCK) #define FLASH_CR_PER (FLASH_PECR_ERASE | FLASH_PECR_PROG) #define FLASHPAGE_DIV (4U) /* write 4 bytes in one go */ +#elif defined(CPU_FAM_STM32L5) +#define FLASHPAGE_DIV (8U) +#define CNTRL_REG (FLASH->NSCR) +#define CNTRL_REG_LOCK (FLASH_NSCR_NSLOCK) +#define FLASH_CR_PNB (FLASH_NSCR_NSPNB) +#define FLASH_CR_PNB_Pos (FLASH_NSCR_NSPNB_Pos) +#define FLASH_CR_STRT (FLASH_NSCR_NSSTRT) +#define FLASH_CR_PER (FLASH_NSCR_NSPER) +#define FLASH_CR_BKER (FLASH_NSCR_NSBKER) +#define FLASH_CR_PG (FLASH_NSCR_NSPG) #else #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) #define FLASHPAGE_DIV (8U) #else #define FLASHPAGE_DIV (2U) @@ -54,7 +65,7 @@ extern void _lock(void); extern void _unlock(void); extern void _wait_for_pending_operations(void); -#if defined(CPU_FAM_STM32G4) +#if defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) #define MAX_PAGES_PER_BANK (128) #else /* CPU_FAM_STM32L4 */ #define MAX_PAGES_PER_BANK (256) @@ -80,7 +91,8 @@ static void _erase_page(void *page_addr) { #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \ defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) uint32_t *dst = page_addr; #else uint16_t *dst = page_addr; @@ -106,7 +118,8 @@ static void _erase_page(void *page_addr) DEBUG("[flashpage] erase: trigger the page erase\n"); *dst = (uint32_t)0; #elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) DEBUG("[flashpage] erase: setting the page address\n"); uint8_t pn; #if (FLASHPAGE_NUMOF <= MAX_PAGES_PER_BANK) || defined(CPU_FAM_STM32WB) @@ -168,7 +181,8 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) uint32_t *dst = target_addr; const uint32_t *data_addr = data; #elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) uint64_t *dst = target_addr; const uint64_t *data_addr = data; #else @@ -193,7 +207,7 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \ defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \ defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ - defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) /* set PG bit and program page to flash */ CNTRL_REG |= FLASH_CR_PG; #endif @@ -208,7 +222,7 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \ defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \ defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ - defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) CNTRL_REG &= ~(FLASH_CR_PG); #endif DEBUG("[flashpage_raw] write: done writing data\n"); @@ -238,7 +252,7 @@ void flashpage_write(int page, const void *data) /* STM32L0/L1 only supports word sizes */ uint32_t *page_addr = flashpage_addr(page); #elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) || \ - defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) uint64_t *page_addr = flashpage_addr(page); #else /* Default is to support half-word sizes */ diff --git a/cpu/stm32/periph/gpio_all.c b/cpu/stm32/periph/gpio_all.c index ebb58285f5..f95c83799d 100644 --- a/cpu/stm32/periph/gpio_all.c +++ b/cpu/stm32/periph/gpio_all.c @@ -45,7 +45,8 @@ static gpio_isr_ctx_t isr_ctx[EXTI_NUMOF]; #endif /* MODULE_PERIPH_GPIO_IRQ */ #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) #define EXTI_REG_RTSR (EXTI->RTSR1) #define EXTI_REG_FTSR (EXTI->FTSR1) #define EXTI_REG_PR (EXTI->PR1) @@ -92,7 +93,7 @@ static inline void port_init_clock(GPIO_TypeDef *port, gpio_t pin) #elif defined (CPU_FAM_STM32L0) || defined(CPU_FAM_STM32G0) periph_clk_en(IOP, (RCC_IOPENR_GPIOAEN << _port_num(pin))); #elif defined (CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined (CPU_FAM_STM32G4) + defined (CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) periph_clk_en(AHB2, (RCC_AHB2ENR_GPIOAEN << _port_num(pin))); #ifdef PWR_CR2_IOSV if (port == GPIOG) { @@ -158,7 +159,7 @@ void gpio_init_analog(gpio_t pin) #elif defined (CPU_FAM_STM32L0) || defined(CPU_FAM_STM32G0) periph_clk_en(IOP, (RCC_IOPENR_GPIOAEN << _port_num(pin))); #elif defined (CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined (CPU_FAM_STM32G4) + defined (CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) periph_clk_en(AHB2, (RCC_AHB2ENR_GPIOAEN << _port_num(pin))); #else periph_clk_en(AHB1, (RCC_AHB1ENR_GPIOAEN << _port_num(pin))); @@ -236,7 +237,9 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, gpio_init(pin, mode); /* enable global pin interrupt */ -#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \ +#if defined(CPU_FAM_STM32L5) + NVIC_EnableIRQ(EXTI0_IRQn + pin_num); +#elif defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \ defined(CPU_FAM_STM32G0) if (pin_num < 2) { NVIC_EnableIRQ(EXTI0_1_IRQn); @@ -264,7 +267,7 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, EXTI_REG_FTSR &= ~(1 << pin_num); EXTI_REG_FTSR |= ((flank >> 1) << pin_num); -#if defined(CPU_FAM_STM32G0) +#if defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) /* enable specific pin as exti sources */ EXTI->EXTICR[pin_num >> 2] &= ~(0xf << ((pin_num & 0x03) * 8)); EXTI->EXTICR[pin_num >> 2] |= (port_num << ((pin_num & 0x03) * 8)); @@ -286,7 +289,7 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, void isr_exti(void) { -#if defined(CPU_FAM_STM32G0) +#if defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) /* only generate interrupts against lines which have their IMR set */ uint32_t pending_rising_isr = (EXTI->RPR1 & EXTI_REG_IMR); uint32_t pending_falling_isr = (EXTI->FPR1 & EXTI_REG_IMR); diff --git a/cpu/stm32/periph/i2c_1.c b/cpu/stm32/periph/i2c_1.c index 6c88498cf2..80b365fb40 100644 --- a/cpu/stm32/periph/i2c_1.c +++ b/cpu/stm32/periph/i2c_1.c @@ -17,7 +17,7 @@ * @file * @brief Low-level I2C driver implementation * - * This driver supports the STM32 F0, F3, F7, L0, L4 & WB families. + * This driver supports the STM32 F0, F3, F7, L0, L4, L5 & WB families. * @note This implementation only implements the 7-bit addressing polling mode * (for now interrupt mode is not available) * diff --git a/cpu/stm32/periph/pm.c b/cpu/stm32/periph/pm.c index 52288973aa..5425aec391 100644 --- a/cpu/stm32/periph/pm.c +++ b/cpu/stm32/periph/pm.c @@ -46,7 +46,8 @@ #elif defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) /* Enable ultra low-power and clear wakeup flags */ #define PM_STOP_CONFIG (PWR_CR_LPSDSR | PWR_CR_ULP | PWR_CR_CWUF) -#elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) +#elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) #define PM_STOP_CONFIG (PWR_CR1_LPMS_STOP1) #elif defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G0) #define PM_STOP_CONFIG (PWR_CR1_LPMS_0) @@ -66,7 +67,8 @@ */ #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) #define PM_STANDBY_CONFIG (PWR_CR_PDDS | PWR_CR_CWUF | PWR_CR_CSBF | PWR_CR_ULP) -#elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) +#elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) #define PM_STANDBY_CONFIG (PWR_CR1_LPMS_STANDBY) #elif defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G0) #define PM_STANDBY_CONFIG (PWR_CR1_LPMS_0 | PWR_CR1_LPMS_1) @@ -78,7 +80,8 @@ #endif #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) #define PWR_CR_REG PWR->CR1 #define PWR_WUP_REG PWR->CR3 /* Allow overridable SRAM2 retention mode using CFLAGS */ @@ -104,14 +107,15 @@ void pm_set(unsigned mode) PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG); PWR_CR_REG |= PM_STANDBY_CONFIG; #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) #if STM32L4_SRAM2_RETENTION PWR->CR3 |= PWR_CR3_RRS; #else PWR->CR3 &= ~PWR_CR3_RRS; #endif #endif -#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) +#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) /* Clear flags */ PWR->SCR |= PWR_SCR_CSBF; #endif diff --git a/cpu/stm32/periph/uart.c b/cpu/stm32/periph/uart.c index 170dd7c342..2dadad0fb0 100644 --- a/cpu/stm32/periph/uart.c +++ b/cpu/stm32/periph/uart.c @@ -34,7 +34,8 @@ #include "periph/gpio.h" #include "pm_layered.h" -#if defined(CPU_LINE_STM32L4R5xx) || defined(CPU_FAM_STM32G0) +#if defined(CPU_LINE_STM32L4R5xx) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) #define ISR_REG ISR #define ISR_TXE USART_ISR_TXE_TXFNF #define ISR_RXNE USART_ISR_RXNE_RXFNE @@ -60,9 +61,9 @@ #define RDR_REG DR #endif -#if defined(CPU_LINE_STM32L4R5xx) || defined(CPU_FAM_STM32G0) +#if defined(CPU_LINE_STM32L4R5xx) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32L5) #define RXENABLE (USART_CR1_RE | USART_CR1_RXNEIE_RXFNEIE) -#define USART_ISR_RXNE (USART_ISR_RXNE_RXFNE) #else #define RXENABLE (USART_CR1_RE | USART_CR1_RXNEIE) #endif @@ -96,7 +97,8 @@ static inline USART_TypeDef *dev(uart_t uart) static inline void uart_init_usart(uart_t uart, uint32_t baudrate); #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4) || \ - defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) #ifdef MODULE_PERIPH_LPUART static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate); #endif @@ -189,7 +191,8 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) dev(uart)->CR3 = 0; #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4) || \ - defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) switch (uart_config[uart].type) { case STM32_USART: uart_init_usart(uart, baudrate); @@ -301,7 +304,13 @@ static inline void uart_init_usart(uart_t uart, uint32_t baudrate) } #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4) || \ - defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) + defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ + defined(CPU_FAM_STM32L5) +#ifdef CPU_FAM_STM32L5 +#define RCC_CCIPR_LPUART1SEL_0 RCC_CCIPR1_LPUART1SEL_0 +#define RCC_CCIPR_LPUART1SEL_1 RCC_CCIPR1_LPUART1SEL_1 +#define CCIPR CCIPR1 +#endif #ifdef MODULE_PERIPH_LPUART static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate) { diff --git a/cpu/stm32/stm32_info.mk b/cpu/stm32/stm32_info.mk index 80022dbb8d..04175f25e7 100644 --- a/cpu/stm32/stm32_info.mk +++ b/cpu/stm32/stm32_info.mk @@ -32,6 +32,8 @@ else ifeq (f7,$(CPU_FAM)) CPU_CORE = cortex-m7 else ifneq (,$(filter $(CPU_FAM),g0 l0)) CPU_CORE = cortex-m0plus +else ifneq (,$(CPU_FAM),l5) + CPU_CORE = cortex-m33 else $(error Not supported CPU family: 'stm32$(CPU_FAM)') endif diff --git a/cpu/stm32/stm32_mem_lengths.mk b/cpu/stm32/stm32_mem_lengths.mk index 7b4bc9626e..9fcba4afd1 100644 --- a/cpu/stm32/stm32_mem_lengths.mk +++ b/cpu/stm32/stm32_mem_lengths.mk @@ -263,6 +263,10 @@ else ifeq ($(STM32_TYPE), L) else ifeq ($(STM32_MODEL2), R) RAM_LEN = 640K endif + else ifeq ($(STM32_FAMILY), 5) + ifneq (, $(filter $(STM32_MODEL2), 5 6)) + RAM_LEN = 256K + endif endif else ifeq ($(STM32_TYPE), W) ifeq ($(STM32_FAMILY), B) diff --git a/cpu/stm32/stmclk/Makefile b/cpu/stm32/stmclk/Makefile index 6a77ec3984..8203ca23ef 100644 --- a/cpu/stm32/stmclk/Makefile +++ b/cpu/stm32/stmclk/Makefile @@ -10,6 +10,8 @@ else ifneq (,$(filter $(CPU_FAM),l0 l1)) SRC += stmclk_l0l1.c else ifneq (,$(filter $(CPU_FAM),l4 wb)) SRC += stmclk_l4wb.c +else ifneq (,$(filter $(CPU_FAM),l5)) + SRC += stmclk_l5.c else ifneq (,$(filter $(CPU_FAM),g0 g4)) SRC += stmclk_gx.c endif diff --git a/cpu/stm32/stmclk/stmclk_common.c b/cpu/stm32/stmclk/stmclk_common.c index 7862c830f9..70ed5dea1e 100644 --- a/cpu/stm32/stmclk/stmclk_common.c +++ b/cpu/stm32/stmclk/stmclk_common.c @@ -25,7 +25,7 @@ #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F7) || \ defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ - defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) #define REG_PWR_CR CR1 #define BIT_CR_DBP PWR_CR1_DBP #else @@ -49,6 +49,9 @@ #define RCC_CSR_LSIRDY RCC_CSR_LSI1RDY #endif +#if defined(CPU_FAM_STM32L5) +#define RCC_CFGR_SWS_HSI RCC_CFGR_SWS_0 +#endif void stmclk_enable_hsi(void) { diff --git a/cpu/stm32/stmclk/stmclk_l5.c b/cpu/stm32/stmclk/stmclk_l5.c new file mode 100644 index 0000000000..d233e99fd1 --- /dev/null +++ b/cpu/stm32/stmclk/stmclk_l5.c @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * 2017 OTA keys S.A. + * 2017 HAW-Hamburg + * 2020 Inria + * + * 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_stm32 + * @{ + * + * @file + * @brief Implementation of STM32 clock configuration for L5 family + * + * @author Hauke Petersen + * @author Nick van IJzendoorn + * @author Vincent Dupont + * @author Michel Rottleuthner + * @author Francisco Molina + * @author Alexandre Abadie + * @} + */ + +#include "cpu.h" +#include "stmclk.h" +#include "periph_conf.h" + +/* map CMSIS defines not present in wb and l5 families */ +#define RCC_PLLCFGR_PLLSRC_HSE (RCC_PLLCFGR_PLLSRC_1 | RCC_PLLCFGR_PLLSRC_0) +#define RCC_PLLCFGR_PLLSRC_HSI (RCC_PLLCFGR_PLLSRC_1) +#define RCC_PLLCFGR_PLLSRC_MSI (RCC_PLLCFGR_PLLSRC_0) +#define RCC_CFGR_SW_MSI (0x00000000U) +#define RCC_CFGR_SW_HSI (RCC_CFGR_SW_0) +#define RCC_CFGR_SW_HSE (RCC_CFGR_SW_1) +#define RCC_CFGR_SW_PLL (RCC_CFGR_SW_1 | RCC_CFGR_SW_0) +#define RCC_CFGR_SWS_MSI (0x00000000U) +#define RCC_CFGR_SWS_HSI (RCC_CFGR_SWS_0) +#define RCC_CFGR_SWS_HSE (RCC_CFGR_SWS_1) +#define RCC_CFGR_SWS_PLL (RCC_CFGR_SWS_1 | RCC_CFGR_SWS_0) + +/* PLL configuration */ +/* figure out which input to use */ +#if IS_ACTIVE(CONFIG_CLOCK_PLL_SRC_MSI) +#define PLL_SRC RCC_PLLCFGR_PLLSRC_MSI +#elif IS_ACTIVE(CONFIG_CLOCK_PLL_SRC_HSE) && IS_ACTIVE(CONFIG_BOARD_HAS_HSE) +#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSE +#elif IS_ACTIVE(CONFIG_CLOCK_PLL_SRC_HSI) +#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSI +#else +#define PLL_SRC 0 +#endif + +/* check configuration and get the corresponding bitfields */ +#if (CONFIG_CLOCK_PLL_M < 1 || CONFIG_CLOCK_PLL_M > 16) +#error "PLL configuration: PLL M value is out of range" +#endif +#define PLL_M ((CONFIG_CLOCK_PLL_M - 1) << RCC_PLLCFGR_PLLM_Pos) + +#if (CONFIG_CLOCK_PLL_N < 8 || CONFIG_CLOCK_PLL_N > 86) +#error "PLL configuration: PLL N value is out of range" +#endif +#define PLL_N (CONFIG_CLOCK_PLL_N << RCC_PLLCFGR_PLLN_Pos) + +#if (CONFIG_CLOCK_PLL_R == 2) +#define PLL_R (0) +#elif (CONFIG_CLOCK_PLL_R == 4) +#define PLL_R (RCC_PLLCFGR_PLLR_0) +#elif (CONFIG_CLOCK_PLL_R == 6) +#define PLL_R (RCC_PLLCFGR_PLLR_1) +#elif (CONFIG_CLOCK_PLL_R == 8) +#define PLL_R (RCC_PLLCFGR_PLLR_1 | RCC_PLLCFGR_PLLR_0) +#else +#error "PLL configuration: PLL R value is invalid" +#endif + +#if (CONFIG_CLOCK_PLL_Q == 2) +#define PLL_Q (0) +#elif (CONFIG_CLOCK_PLL_Q == 4) +#define PLL_Q (RCC_PLLCFGR_PLLQ_0) +#elif (CONFIG_CLOCK_PLL_Q == 6) +#define PLL_Q (RCC_PLLCFGR_PLLQ_1) +#elif (CONFIG_CLOCK_PLL_Q == 8) +#define PLL_Q (RCC_PLLCFGR_PLLQ_0 | RCC_PLLCFGR_PLLQ_1) +#else +#error "PLL configuration: PLL Q value is invalid" +#endif + +/* Define MSI range bitfields */ +#if CONFIG_CLOCK_MSI == KHZ(100) +#define CLOCK_MSIRANGE (0) +#elif CONFIG_CLOCK_MSI == KHZ(200) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_0) +#elif CONFIG_CLOCK_MSI == KHZ(400) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_1) +#elif CONFIG_CLOCK_MSI == KHZ(800) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_1 | RCC_CR_MSIRANGE_0) +#elif CONFIG_CLOCK_MSI == MHZ(1) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_2) +#elif CONFIG_CLOCK_MSI == MHZ(2) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_2 | RCC_CR_MSIRANGE_0) +#elif CONFIG_CLOCK_MSI == MHZ(4) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_2 | RCC_CR_MSIRANGE_1) +#elif CONFIG_CLOCK_MSI == MHZ(8) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_2 | RCC_CR_MSIRANGE_1 | RCC_CR_MSIRANGE_0) +#elif CONFIG_CLOCK_MSI == MHZ(16) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_3) +#elif CONFIG_CLOCK_MSI == MHZ(24) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_3 | RCC_CR_MSIRANGE_0) +#elif CONFIG_CLOCK_MSI == MHZ(32) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_3 | RCC_CR_MSIRANGE_1) +#elif CONFIG_CLOCK_MSI == MHZ(48) +#define CLOCK_MSIRANGE (RCC_CR_MSIRANGE_3 | RCC_CR_MSIRANGE_1 | RCC_CR_MSIRANGE_0) +#else +#error "Invalid MSI clock" +#endif + +/* Configure 48MHz clock source */ +#define CLOCK_PLLQ ((CLOCK_PLL_SRC / CONFIG_CLOCK_PLL_M) * CONFIG_CLOCK_PLL_N) / CONFIG_CLOCK_PLL_Q + +#if CLOCK_PLLQ == MHZ(48) +#define CLOCK48MHZ_USE_PLLQ 1 +#elif CONFIG_CLOCK_MSI == MHZ(48) +#define CLOCK48MHZ_USE_MSI 1 +#else +#define CLOCK48MHZ_USE_PLLQ 0 +#define CLOCK48MHZ_USE_MSI 0 +#endif + +#if IS_ACTIVE(CLOCK48MHZ_USE_PLLQ) +#define CLOCK48MHZ_SELECT (RCC_CCIPR1_CLK48MSEL_1) +#elif IS_ACTIVE(CLOCK48MHZ_USE_MSI) +#define CLOCK48MHZ_SELECT (RCC_CCIPR1_CLK48MSEL_1 | RCC_CCIPR1_CLK48MSEL_0) +#else +#define CLOCK48MHZ_SELECT (0) +#endif + +/* Configure the AHB and APB buses prescalers */ +#define CLOCK_AHB_DIV (0) + +#if CONFIG_CLOCK_APB1_DIV == 1 +#define CLOCK_APB1_DIV (0) +#elif CONFIG_CLOCK_APB1_DIV == 2 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_2) +#elif CONFIG_CLOCK_APB1_DIV == 4 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_2 | RCC_CFGR_PPRE1_0) +#elif CONFIG_CLOCK_APB1_DIV == 8 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_2 | RCC_CFGR_PPRE1_1) +#elif CONFIG_CLOCK_APB1_DIV == 16 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_2 | RCC_CFGR_PPRE1_1 | RCC_CFGR_PPRE1_0) +#endif + +#if CONFIG_CLOCK_APB2_DIV == 1 +#define CLOCK_APB2_DIV (0) +#elif CONFIG_CLOCK_APB2_DIV == 2 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_2) +#elif CONFIG_CLOCK_APB2_DIV == 4 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_2 | RCC_CFGR_PPRE2_0) +#elif CONFIG_CLOCK_APB2_DIV == 8 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_2 | RCC_CFGR_PPRE2_1) +#elif CONFIG_CLOCK_APB2_DIV == 16 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_2 | RCC_CFGR_PPRE2_1 | RCC_CFGR_PPRE2_0) +#endif + +/* Only periph_hwrng requires 48MHz for the moment */ +#if IS_USED(MODULE_PERIPH_HWRNG) +#if !IS_ACTIVE(CLOCK48MHZ_USE_PLLQ) && !IS_ACTIVE(CLOCK48MHZ_USE_MSI) +#error "No 48MHz clock source available, HWRNG cannot work" +#endif +#define CLOCK_ENABLE_48MHZ 1 +#else +#define CLOCK_ENABLE_48MHZ 0 +#endif + +/* Check if PLL is required + - When used as system clock + - When PLLQ is used as 48MHz clock source +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_PLL) || \ + (IS_ACTIVE(CLOCK_ENABLE_48MHZ) && IS_ACTIVE(CLOCK48MHZ_USE_PLLQ)) +#define CLOCK_ENABLE_PLL 1 +#else +#define CLOCK_ENABLE_PLL 0 +#endif + +/* Check if HSE is required: + - When used as system clock + - When used as PLL input clock +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSE) || \ + (IS_ACTIVE(CLOCK_ENABLE_PLL) && IS_ACTIVE(CONFIG_CLOCK_PLL_SRC_HSE)) +#define CLOCK_ENABLE_HSE 1 +#else +#define CLOCK_ENABLE_HSE 0 +#endif + +/* HSE cannot be enabled if not provided by the board */ +#if IS_ACTIVE(CLOCK_ENABLE_HSE) && !IS_ACTIVE(CONFIG_BOARD_HAS_HSE) +#error "HSE is required by the clock configuration but is not provided by the board." +#endif + +/* Check if HSI is required: + - When used as system clock + - When used as PLL input clock +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSI) || \ + (IS_ACTIVE(CLOCK_ENABLE_PLL) && IS_ACTIVE(CONFIG_CLOCK_PLL_SRC_HSI)) +#define CLOCK_ENABLE_HSI 1 +#else +#define CLOCK_ENABLE_HSI 0 +#endif + +/* Check if MSI is required + - When used as system clock + - When used as PLL input clock +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_MSI) || \ + (IS_ACTIVE(CLOCK_ENABLE_PLL) && IS_ACTIVE(CONFIG_CLOCK_PLL_SRC_MSI)) || \ + (IS_ACTIVE(CLOCK_ENABLE_48MHZ) && IS_ACTIVE(CLOCK48MHZ_USE_MSI)) +#define CLOCK_ENABLE_MSI 1 +#else +#define CLOCK_ENABLE_MSI 0 +#endif + +/* Deduct the needed flash wait states from the core clock frequency */ +#if CLOCK_AHB <= MHZ(20) +#define FLASH_WAITSTATES FLASH_ACR_LATENCY_0WS +#elif CLOCK_AHB <= MHZ(40) +#define FLASH_WAITSTATES FLASH_ACR_LATENCY_1WS +#elif CLOCK_AHB <= MHZ(60) +#define FLASH_WAITSTATES FLASH_ACR_LATENCY_2WS +#elif CLOCK_AHB <= MHZ(80) +#define FLASH_WAITSTATES FLASH_ACR_LATENCY_3WS +#elif CLOCK_AHB <= MHZ(100) +#define FLASH_WAITSTATES FLASH_ACR_LATENCY_4WS +#elif CLOCK_AHB <= MHZ(110) +#define FLASH_WAITSTATES FLASH_ACR_LATENCY_5WS +#endif + +void stmclk_init_sysclk(void) +{ + /* disable any interrupts. Global interrupts could be enabled if this is + * called from some kind of bootloader... */ + unsigned is = irq_disable(); + RCC->CIER = 0; + + /* enable HSI clock for the duration of initialization */ + stmclk_enable_hsi(); + + /* use HSI as system clock while we do any further configuration and + * configure the AHB and APB clock dividers as configured by the board */ + RCC->CFGR = (RCC_CFGR_SW_HSI | CLOCK_AHB_DIV | CLOCK_APB1_DIV | CLOCK_APB2_DIV); + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {} + + /* configure flash wait states */ + FLASH->ACR = FLASH_WAITSTATES; + + /* disable all active clocks except HSI -> resets the clk configuration */ + RCC->CR = RCC_CR_HSION; + + /* Enable the HSE clock only when it's used */ + if (IS_ACTIVE(CLOCK_ENABLE_HSE)) { + RCC->CR |= (RCC_CR_HSEON); + while (!(RCC->CR & RCC_CR_HSERDY)) {} + } + + /* Enable the MSI clock only when it's used */ + if (IS_ACTIVE(CLOCK_ENABLE_MSI)) { + RCC->CR |= (RCC_CR_MSION | CLOCK_MSIRANGE | RCC_CR_MSIRGSEL); + while (!(RCC->CR & RCC_CR_MSIRDY)) {} + } + + /* Enable the PLL clock only when it's used */ + if (IS_ACTIVE(CLOCK_ENABLE_PLL)) { + if (IS_ACTIVE(CONFIG_CLOCK_PLL_SRC_MSI) && IS_ACTIVE(CONFIG_BOARD_HAS_LSE)) { + /* configure the low speed clock domain */ + stmclk_enable_lfclk(); + /* now we can enable the MSI PLL mode to enhance accuracy of the MSI */ + RCC->CR |= RCC_CR_MSIPLLEN; + while (!(RCC->CR & RCC_CR_MSIRDY)) {} + } + + /* configure and start the PLL */ + RCC->PLLCFGR = (PLL_SRC | PLL_M | PLL_N | PLL_R | PLL_Q); + + if (IS_ACTIVE(CONFIG_USE_CLOCK_PLL)) { + /* Enable PLLCLK if PLL is used as system clock */ + RCC->PLLCFGR |= RCC_PLLCFGR_PLLREN; + } + + if (IS_ACTIVE(CLOCK48MHZ_USE_PLLQ)) { + /* Enable PLLQ if PLL is used as 48MHz source clock */ + RCC->PLLCFGR |= RCC_PLLCFGR_PLLQEN; + } + + RCC->CR |= (RCC_CR_PLLON); + while (!(RCC->CR & RCC_CR_PLLRDY)) {} + } + + /* Configure SYSCLK */ + if (!IS_ACTIVE(CONFIG_USE_CLOCK_HSI)) { + RCC->CFGR &= ~RCC_CFGR_SW; + } + + if (IS_ACTIVE(CONFIG_USE_CLOCK_HSE)) { + /* Select HSE as system clock */ + RCC->CFGR |= RCC_CFGR_SW_HSE; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE) {} + } + else if (IS_ACTIVE(CONFIG_USE_CLOCK_MSI)) { + /* Select MSI as system clock */ + RCC->CFGR |= RCC_CFGR_SW_MSI; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_MSI) {} + } + else if (IS_ACTIVE(CONFIG_USE_CLOCK_PLL)) { + if (CLOCK_AHB > MHZ(80)) { + /* Divide HCLK by 2 before enabling the PLL */ + RCC->CFGR |= RCC_CFGR_HPRE_3; + } + + /* Select main PLL as system clock */ + RCC->CFGR |= RCC_CFGR_SW_PLL; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} + + if (CLOCK_AHB > MHZ(80)) { + /* Wait 1us before switching back to full speed */ + /* Use volatile to prevent the compiler from optimizing the loop */ + volatile uint8_t count = CLOCK_CORECLOCK / MHZ(1); + while (count--) {} + RCC->CFGR &= ~RCC_CFGR_HPRE_3; + } + } + + if (!IS_ACTIVE(CLOCK_ENABLE_HSI)) { + /* Disable HSI only if not used */ + stmclk_disable_hsi(); + } + + if (IS_ACTIVE(CLOCK_ENABLE_48MHZ)) { + /* configure the clock used for the 48MHz clock tree (USB, RNG) */ + RCC->CCIPR1 = CLOCK48MHZ_SELECT; + } + + irq_restore(is); +}