From 858d364c4ec7377b38cbc219b5c5bea72436b06b Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Wed, 25 Feb 2026 15:41:23 +0100 Subject: [PATCH 01/10] hal/stm32n6: extract common routines Extract common STM32 ARMv8-M console and timer routines. Signed-off-by: Mateusz Karcz --- hal/armv8m/stm32/Makefile | 2 +- hal/armv8m/stm32/{n6 => }/console.c | 5 +++-- hal/armv8m/stm32/hal.c | 7 ++++++- hal/armv8m/stm32/n6/Makefile | 3 ++- hal/armv8m/stm32/stm32.h | 20 ++++++++++++++++++++ hal/armv8m/stm32/{n6 => }/timer.c | 2 +- 6 files changed, 33 insertions(+), 6 deletions(-) rename hal/armv8m/stm32/{n6 => }/console.c (96%) create mode 100644 hal/armv8m/stm32/stm32.h rename hal/armv8m/stm32/{n6 => }/timer.c (97%) diff --git a/hal/armv8m/stm32/Makefile b/hal/armv8m/stm32/Makefile index 6a06cdf3..4b0aef7c 100644 --- a/hal/armv8m/stm32/Makefile +++ b/hal/armv8m/stm32/Makefile @@ -8,4 +8,4 @@ include hal/armv8m/stm32/n6/Makefile CFLAGS += -I../plo/hal/armv8m/stm32/n6 -OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/stm32/, hal.o) +OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/stm32/, hal.o console.o timer.o) diff --git a/hal/armv8m/stm32/n6/console.c b/hal/armv8m/stm32/console.c similarity index 96% rename from hal/armv8m/stm32/n6/console.c rename to hal/armv8m/stm32/console.c index d13afaa3..560c20be 100644 --- a/hal/armv8m/stm32/n6/console.c +++ b/hal/armv8m/stm32/console.c @@ -6,7 +6,8 @@ * Console * * Copyright 2021, 2025 Phoenix Systems - * Authors: Aleksander Kaminski, Jacek Maksymowicz + * Copyright 2026 Apator Metrix + * Authors: Aleksander Kaminski, Jacek Maksymowicz, Mateusz Karcz * * This file is part of Phoenix-RTOS. * @@ -18,7 +19,7 @@ #include -#include "stm32n6.h" +#include "stm32.h" #if !ISEMPTY(UART_CONSOLE_PLO) diff --git a/hal/armv8m/stm32/hal.c b/hal/armv8m/stm32/hal.c index 35cb14b7..dddee7eb 100644 --- a/hal/armv8m/stm32/hal.c +++ b/hal/armv8m/stm32/hal.c @@ -6,7 +6,8 @@ * Hardware Abstraction Layer * * Copyright 2020-2025 Phoenix Systems - * Author: Hubert Buczynski, Marcin Baran, Gerard Swiderski, Aleksander Kaminski + * Copyright 2026 Apator Metrix + * Author: Hubert Buczynski, Marcin Baran, Gerard Swiderski, Aleksander Kaminski, Mateusz Karcz * * This file is part of Phoenix-RTOS. * @@ -98,7 +99,11 @@ void hal_syspageSet(hal_syspage_t *hs) const char *hal_cpuInfo(void) { +#if defined(__CPU_STM32N6) return "Cortex-M55 STM32N6"; +#else +#error "Unsupported platform" +#endif } diff --git a/hal/armv8m/stm32/n6/Makefile b/hal/armv8m/stm32/n6/Makefile index bd223c9a..26f510fb 100644 --- a/hal/armv8m/stm32/n6/Makefile +++ b/hal/armv8m/stm32/n6/Makefile @@ -2,6 +2,7 @@ # Makefile for Phoenix-RTOS loader (ARMv8M HAL stm32n6) # # Copyright 2021, 2025 Phoenix Systems +# Copyright 2026 Apator Metrix # # %LICENSE% # @@ -17,4 +18,4 @@ PLO_COMMANDS ?= alias app blob call console copy devices dump echo erase go help PLO_ALLDEVICES := pipe-rtt ram-storage uart-stm32 flash-stm32xspi -OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/stm32/n6/, _init.o stm32n6.o timer.o console.o otp.o) +OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/stm32/n6/, _init.o stm32n6.o otp.o) diff --git a/hal/armv8m/stm32/stm32.h b/hal/armv8m/stm32/stm32.h new file mode 100644 index 00000000..6df1989d --- /dev/null +++ b/hal/armv8m/stm32/stm32.h @@ -0,0 +1,20 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * STM32 ARMv8-M MCU specific header dispatch + * + * Copyright 2026 Apator Metrix + * Author: Mateusz Karcz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#if defined(__CPU_STM32N6) +#include "n6/stm32n6.h" +#else +#error "Unsupported platform" +#endif diff --git a/hal/armv8m/stm32/n6/timer.c b/hal/armv8m/stm32/timer.c similarity index 97% rename from hal/armv8m/stm32/n6/timer.c rename to hal/armv8m/stm32/timer.c index 960843c9..13d81006 100644 --- a/hal/armv8m/stm32/n6/timer.c +++ b/hal/armv8m/stm32/timer.c @@ -14,7 +14,7 @@ */ #include -#include "stm32n6.h" +#include "stm32.h" #define SYSTICK_IRQ 15 From 122b16f1b6ae0bb2e6ee1b4ef027cd0fd9180034 Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Fri, 27 Feb 2026 18:12:25 +0100 Subject: [PATCH 02/10] hal/stm32u3: add STM32U3 platform bringup Enable basic support for STM32U3 (ARMv8-M) family of microcontrollers: - add STM32U3 vector table - initialize RCC with MSIS as SYSCLK - initialize SRAM - initialize power supplies - initialize GPIO ports - initialize systick and watchdog timer - specify UART console capabilities Signed-off-by: Mateusz Karcz --- hal/armv8m/stm32/Makefile | 10 +- hal/armv8m/stm32/console.c | 11 + hal/armv8m/stm32/hal.c | 2 + hal/armv8m/stm32/stm32.h | 2 + hal/armv8m/stm32/u3/Makefile | 21 ++ hal/armv8m/stm32/u3/_init.S | 97 +++++++ hal/armv8m/stm32/u3/config.h | 41 +++ hal/armv8m/stm32/u3/peripherals.h | 92 ++++++ hal/armv8m/stm32/u3/stm32u3.c | 446 +++++++++++++++++++++++++++++ hal/armv8m/stm32/u3/stm32u3.h | 277 ++++++++++++++++++ hal/armv8m/stm32/u3/stm32u3_regs.h | 178 ++++++++++++ ld/armv8m33-stm32u3.ldt | 65 +++++ 12 files changed, 1240 insertions(+), 2 deletions(-) create mode 100644 hal/armv8m/stm32/u3/Makefile create mode 100644 hal/armv8m/stm32/u3/_init.S create mode 100644 hal/armv8m/stm32/u3/config.h create mode 100644 hal/armv8m/stm32/u3/peripherals.h create mode 100644 hal/armv8m/stm32/u3/stm32u3.c create mode 100644 hal/armv8m/stm32/u3/stm32u3.h create mode 100644 hal/armv8m/stm32/u3/stm32u3_regs.h create mode 100644 ld/armv8m33-stm32u3.ldt diff --git a/hal/armv8m/stm32/Makefile b/hal/armv8m/stm32/Makefile index 4b0aef7c..560125ad 100644 --- a/hal/armv8m/stm32/Makefile +++ b/hal/armv8m/stm32/Makefile @@ -6,6 +6,12 @@ # %LICENSE% # -include hal/armv8m/stm32/n6/Makefile -CFLAGS += -I../plo/hal/armv8m/stm32/n6 +ifneq (, $(findstring stm32n6, $(TARGET_SUBFAMILY))) + include hal/armv8m/stm32/n6/Makefile + CFLAGS += -I../plo/hal/armv8m/stm32/n6 +else ifneq (, $(findstring stm32u3, $(TARGET_SUBFAMILY))) + include hal/armv8m/stm32/u3/Makefile + CFLAGS += -I../plo/hal/armv8m/stm32/u3 +endif + OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/stm32/, hal.o console.o timer.o) diff --git a/hal/armv8m/stm32/console.c b/hal/armv8m/stm32/console.c index 560c20be..6a2c37be 100644 --- a/hal/armv8m/stm32/console.c +++ b/hal/armv8m/stm32/console.c @@ -40,12 +40,16 @@ /* Values for selecting the peripheral clock for an UART */ enum { uart_clk_sel_pclk = 0, /* pclk1 or pclk2 depending on peripheral */ +#if defined(__CPU_STM32N6) uart_clk_sel_per_ck, uart_clk_sel_ic9_ck, uart_clk_sel_ic14_ck, uart_clk_sel_lse_ck, uart_clk_sel_msi_ck, uart_clk_sel_hsi_div_ck, +#elif defined(__CPU_STM32U3) + uart_clk_sel_hsi_ck, +#endif }; @@ -101,11 +105,13 @@ void console_init(void) { UART3_BASE, UART3_CLK, ipclk_usart3sel }, { UART4_BASE, UART4_CLK, ipclk_uart4sel }, { UART5_BASE, UART5_CLK, ipclk_uart5sel }, +#if defined(__CPU_STM32N6) { UART6_BASE, UART6_CLK, ipclk_usart6sel }, { UART7_BASE, UART7_CLK, ipclk_uart7sel }, { UART8_BASE, UART8_CLK, ipclk_uart8sel }, { UART9_BASE, UART9_CLK, ipclk_uart9sel }, { UART10_BASE, UART10_CLK, ipclk_usart10sel }, +#endif }; const int uart = UART_CONSOLE_PLO - 1, port = UART_IO_PORT_DEV, txpin = UART_PIN_TX, rxpin = UART_PIN_RX, af = UART_IO_AF; @@ -120,8 +126,13 @@ void console_init(void) /* Init rxd pin - input, push-pull, low speed, no pull-up */ _stm32_gpioConfig(port, rxpin, gpio_mode_af, af, gpio_otype_pp, gpio_ospeed_low, gpio_pupd_nopull); +#if defined(__CPU_STM32N6) _stm32_rccSetIPClk(uarts[uart].ipclk_sel, uart_clk_sel_hsi_div_ck); halconsole_common.refclkfreq = 64 * 1000 * 1000; +#elif defined(__CPU_STM32U3) + _stm32_rccSetIPClk(uarts[uart].ipclk_sel, uart_clk_sel_pclk); + halconsole_common.refclkfreq = _stm32_rccGetPclkClock(); +#endif /* Enable uart clock */ _stm32_rccSetDevClock(uarts[uart].dev_clk, 1); diff --git a/hal/armv8m/stm32/hal.c b/hal/armv8m/stm32/hal.c index dddee7eb..56e4c44f 100644 --- a/hal/armv8m/stm32/hal.c +++ b/hal/armv8m/stm32/hal.c @@ -101,6 +101,8 @@ const char *hal_cpuInfo(void) { #if defined(__CPU_STM32N6) return "Cortex-M55 STM32N6"; +#elif defined(__CPU_STM32U3) + return "Cortex-M33 STM32U3"; #else #error "Unsupported platform" #endif diff --git a/hal/armv8m/stm32/stm32.h b/hal/armv8m/stm32/stm32.h index 6df1989d..abbbaeb1 100644 --- a/hal/armv8m/stm32/stm32.h +++ b/hal/armv8m/stm32/stm32.h @@ -15,6 +15,8 @@ #if defined(__CPU_STM32N6) #include "n6/stm32n6.h" +#elif defined(__CPU_STM32U3) +#include "u3/stm32u3.h" #else #error "Unsupported platform" #endif diff --git a/hal/armv8m/stm32/u3/Makefile b/hal/armv8m/stm32/u3/Makefile new file mode 100644 index 00000000..18d67e47 --- /dev/null +++ b/hal/armv8m/stm32/u3/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for Phoenix-RTOS loader (ARMv8M HAL stm32u3) +# +# Copyright 2021, 2025 Phoenix Systems +# Copyright 2026 Apator Metrix +# +# %LICENSE% +# + +LDFLAGS := $(filter-out -Tbss% , $(LDFLAGS)) +LDFLAGS := $(filter-out -Tdata% , $(LDFLAGS)) + +CFLAGS := $(filter-out -mfloat-abi% , $(CFLAGS)) +CFLAGS += -mfloat-abi=soft + +PLO_COMMANDS ?= alias app blob call console copy devices dump echo go help kernelimg \ + map mem phfs reboot script stop wait + +PLO_ALLDEVICES := flash-stm32 ram-storage + +OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/stm32/u3/, _init.o stm32u3.o) diff --git a/hal/armv8m/stm32/u3/_init.S b/hal/armv8m/stm32/u3/_init.S new file mode 100644 index 00000000..a38e6fc1 --- /dev/null +++ b/hal/armv8m/stm32/u3/_init.S @@ -0,0 +1,97 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * Low-level initialization for Cortex-M33 (ARMv8) architecture + * + * Copyright 2012, 2016-2017, 2020-2022 Phoenix Systems + * Copyright 2026 Apator Metrix + * Author: Jacek Popko, Pawel Pisarczyk, Jakub Sejdak, Aleksander Kaminski, Damian Loewnau, Mateusz Karcz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#define __ASSEMBLY__ + +#include "config.h" + +.syntax unified + +.section .init, "x" + +.globl _init_vectors +.type _init_vectors, %object +_init_vectors: +.word _stack +.word _start + +.word _exceptions_dispatch /* NMI */ +.word _exceptions_dispatch /* HardFault */ +.word _exceptions_dispatch /* MemMgtFault */ +.word _exceptions_dispatch /* BusFault */ +.word _exceptions_dispatch /* UsageFault */ +.word _exceptions_dispatch /* SecureFault */ +.word 0 +.word 0 +.word 0 +.word 0 /* SVC */ +.word 0 /* Debug */ +.word 0 +.word _interrupts_dispatch /* PendSV */ +.word _interrupts_dispatch /* Systick */ + +.rept 125 /* Max number of ext interrupts - last peripheral id + 1 */ +.word _interrupts_dispatch /* _interrupts_dispatch */ +.endr +.size _init_vectors, .-_init_vectors + +.thumb +.thumb_func + +.globl _start +.type _start, %function +_start: + cpsid if + + /* Init vector table and stack pointer */ + ldr r0, =0xe000ed08 + ldr r1, =_init_vectors + str r1, [r0] + isb + dmb + + ldr r0, [r1] + bic r0, 7 + msr msp, r0 + ldr r8, =_startc + bx r8 +.size _start, .-_start +.ltorg + + +.globl _interrupts_dispatch +.type _interrupts_dispatch, %function +_interrupts_dispatch: + mrs r0, ipsr + stmdb sp!, {r0, r4-r11, lr} + bl hal_interruptDispatch + ldmia sp!, {r0, r4-r11, lr} + dmb + + bx lr +.size _interrupts_dispatch, .-_interrupts_dispatch +.ltorg + + +.globl _exceptions_dispatch +.type _exceptions_dispatch, %function + +_exceptions_dispatch: + cpsid if + /* TODO: implement exception dispatcher */ + 1: b 1b +.size _exceptions_dispatch, .-_exceptions_dispatch +.ltorg diff --git a/hal/armv8m/stm32/u3/config.h b/hal/armv8m/stm32/u3/config.h new file mode 100644 index 00000000..97033145 --- /dev/null +++ b/hal/armv8m/stm32/u3/config.h @@ -0,0 +1,41 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * Platform configuration file + * + * Copyright 2020, 2021 Phoenix Systems + * Copyright 2026 Apator Metrix + * Author: Hubert Buczynski, Aleksander Kaminski, Mateusz Karcz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#ifndef __ASSEMBLY__ + +#include "stm32u3.h" +#include "peripherals.h" +#include "../types.h" + +#include +#include + +#include "../../cpu.h" +#include "../../mpu.h" + +#define PATH_KERNEL "phoenix-armv8m33-stm32u3.elf" + +#endif + + +/* Import platform specific definitions */ +#include "ld/armv8m33-stm32u3.ldt" + +#endif diff --git a/hal/armv8m/stm32/u3/peripherals.h b/hal/armv8m/stm32/u3/peripherals.h new file mode 100644 index 00000000..80a6625a --- /dev/null +++ b/hal/armv8m/stm32/u3/peripherals.h @@ -0,0 +1,92 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * Peripherals definitions for armv8m33-stm32u3 + * + * Copyright 2020, 2021, 2025 Phoenix Systems + * Copyright 2026 Apator Metrix + * Author: Hubert Buczynski, Aleksander Kaminski, Jacek Maksymowicz, Mateusz Karcz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _PERIPHERALS_H_ +#define _PERIPHERALS_H_ + +/* Periperals configuration */ + +/* Interrupts */ +#define SIZE_INTERRUPTS (125 + 16) + + +/* DEBUG - RTT PIPE */ + +#ifndef RTT_ENABLED_PLO +#define RTT_ENABLED_PLO 0 +#endif + +#ifndef RTT_BUFSZ_CONSOLE_TX +#define RTT_BUFSZ_CONSOLE_TX 1024 +#endif + +#ifndef RTT_BUFSZ_CONSOLE_RX +#define RTT_BUFSZ_CONSOLE_RX 1024 +#endif + +#ifndef RTT_BUFSZ_PHOENIXD_TX +#define RTT_BUFSZ_PHOENIXD_TX 1024 +#endif + +#ifndef RTT_BUFSZ_PHOENIXD_RX +#define RTT_BUFSZ_PHOENIXD_RX 1024 +#endif + + +/* UART */ +#define UART_MAX_CNT 5 + +#ifndef UART1 +#define UART1 1 +#endif + +#ifndef UART2 +#define UART2 0 /* STM32U396xx / STM32U3A6xx / STM32U3C5xx */ +#endif + +#ifndef UART3 +#define UART3 0 +#endif + +#ifndef UART4 +#define UART4 0 +#endif + +#ifndef UART5 +#define UART5 0 +#endif + +#define UART_BAUDRATE 115200 + +#define UART1_BASE ((void *)0x40013800) +#define UART2_BASE ((void *)0x40004400) +#define UART3_BASE ((void *)0x40004800) +#define UART4_BASE ((void *)0x40004c00) +#define UART5_BASE ((void *)0x40005000) + +#define UART1_CLK dev_usart1 +#define UART2_CLK dev_usart2 +#define UART3_CLK dev_usart3 +#define UART4_CLK dev_uart4 +#define UART5_CLK dev_uart5 + +#define UART1_IRQ (16 + 61) +#define UART2_IRQ (16 + 62) +#define UART3_IRQ (16 + 63) +#define UART4_IRQ (16 + 64) +#define UART5_IRQ (16 + 65) +#endif diff --git a/hal/armv8m/stm32/u3/stm32u3.c b/hal/armv8m/stm32/u3/stm32u3.c new file mode 100644 index 00000000..6e56b9e9 --- /dev/null +++ b/hal/armv8m/stm32/u3/stm32u3.c @@ -0,0 +1,446 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * STM32U3 basic peripherals control functions + * + * Copyright 2017, 2019, 2020, 2021, 2025 Phoenix Systems + * Copyright 2026 Apator Metrix + * Author: Aleksander Kaminski, Jan Sikorski, Hubert Buczynski, Jacek Maksymowicz, Mateusz Karcz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include "stm32u3.h" + + +#define GPIOA_BASE ((void *)0x42020000) +#define GPIOB_BASE ((void *)0x42020400) +#define GPIOC_BASE ((void *)0x42020800) +#define GPIOD_BASE ((void *)0x42020c00) +#define GPIOE_BASE ((void *)0x42021000) +#define GPIOF_BASE ((void *)0x42021400) +#define GPIOG_BASE ((void *)0x42021800) +#define GPIOH_BASE ((void *)0x42021c00) + +#define IWDG_BASE ((void *)0x40003000) +#define PWR_BASE ((void *)0x40030800) +#define RCC_BASE ((void *)0x40030c00) +#define SYSCFG_BASE ((void *)0x40040400) +#define RAMCFG_BASE ((void *)0x40026000) +#define ICB_BASE ((void *)0xe000e000) + +static struct { + volatile u32 *rcc; + volatile u32 *gpio[8]; + volatile u32 *icb; + volatile u32 *pwr; + volatile u32 *syscfg; + volatile u32 *iwdg; + volatile u32 *ramcfg; + + u32 cpuclk; + + u32 resetFlags; +} stm32_common; + + +/* Systick registers */ +enum { + icb_systick_ctrl = 0x4, + icb_systick_load, + icb_systick_val, + icb_systick_calib, +}; + + +unsigned int hal_getBootReason(void) +{ + return stm32_common.resetFlags; +} + + +/* + * HSE is external crystal oscillator (4 to 50 MHz). + * HSI (16 MHz) and MSIS (3 to 96 MHz, 12 MHz on reset) are internal RC + * oscillators. MSIS selects between MSIRC0 (96 MHz) and MSIRC1 (24 MHz), + * applying prescaler of 1, 2, 4, or 8. + * + * On STM32U3, allowed system clock sources are HSE, HSI16, and MSIS. + * + * Peripheral bus clock is derived as follows: + * + * + * ┌─────┐ HSE ┌────┐ + * │ OSC ├───────┤ │ + * └─────┘ HSI │ │ SYSCLK HCLK + * 16 MHz├──────┤ SW ├───┬───/HPRE───┬────────────────┤AHB1, AHB2 + * ┌─────┐ MSIS │ │ │ │ PCLK1 + * │ RC0 ├───────┤ │ ┴ ├───/PPRE1───────┤APB1 + * │ MSI │ MSIK └────┘ CPU │ PCLK2 + * │ RC1 ├──────┐ ├───/PPRE2───────┤APB2 + * └─────┘ ┴ │ PCLK3 + * (opt) SPI, I2C, CAN... └───/PPRE3───────┤APB3 + */ +static void _stm32_configureClocks(void) +{ + u32 v, clock_source; + + /* Disable HSE */ + *(stm32_common.rcc + rcc_cr) &= ~(1 << 16); /* HSEON off */ + + /* Select the system clock source */ + clock_source = 0; /* MSIS */ + v = *(stm32_common.rcc + rcc_cfgr1); + v |= (clock_source << 0); /* Set SW */ + *(stm32_common.rcc + rcc_cfgr1) = v; + + while (((*(stm32_common.rcc + rcc_cfgr1) >> 2) & 0x3) != clock_source) { + /* Wait for SWS */ + } + stm32_common.cpuclk = 12 * 1000 * 1000; + + /* Set peripheral bus clock prescalers */ + v = *(stm32_common.rcc + rcc_cfgr2); + v &= ~((0x7 << 8) | (0x7 << 4) | (0xF << 0)); /* Clear PPRE2, PPRE1, HPRE */ + v |= (0 << 8) | (0 << 4) | (0x8 << 0); /* Set PPRE1 ~ 2 to 1, HPRE to 2 */ + *(stm32_common.rcc + rcc_cfgr2) = v; + + v = *(stm32_common.rcc + rcc_cfgr3); + v &= ~(0x7 << 4); /* Clear PPRE3 */ + v |= (0 << 4); /* Set PPRE3 to 1 */ + *(stm32_common.rcc + rcc_cfgr3) = v; +} + + +static int _stm32_getDevClockRegShift(unsigned int dev, unsigned int *shift_out) +{ + unsigned int reg = dev / 32; + if (reg > (rcc_apb3enr - rcc_ahb1enr1)) { + return -1; + } + + *shift_out = dev % 32; + return reg; +} + + +int _stm32_rccSetDevClock(unsigned int dev, u32 status) +{ + u32 shift; + int reg; + + reg = _stm32_getDevClockRegShift(dev, &shift); + if (reg < 0) { + return -1; + } + + if (status != 0) { + *(stm32_common.rcc + reg + rcc_ahb1enr1) |= (1 << shift); + *(stm32_common.rcc + reg + rcc_ahb1slpenr1) |= (1 << shift); + } else { + *(stm32_common.rcc + reg + rcc_ahb1enr1) &= ~(1 << shift); + *(stm32_common.rcc + reg + rcc_ahb1slpenr1) &= ~(1 << shift); + } + hal_cpuDataSyncBarrier(); + + return 0; +} + + +u32 _stm32_rccGetCPUClock(void) +{ + return stm32_common.cpuclk; +} + + +u32 _stm32_rccGetPclkClock(void) +{ + return stm32_common.cpuclk / 2; +} + + +void _stm32_rccClearResetFlags(void) +{ + *(stm32_common.rcc + rcc_csr) |= (1 << 23); /* RMVF */ +} + + +int _stm32_rccSetIPClk(unsigned int ipclk, u8 setting) +{ + static const struct { + u16 reg_offs; + u8 mask; + u8 shift; + } ipclk_lookup[ipclks_count] = { + [ipclk_usart1sel] = { rcc_ccipr1, 0x1, 0 }, + [ipclk_usart3sel] = { rcc_ccipr1, 0x1, 2 }, + [ipclk_uart4sel] = { rcc_ccipr1, 0x1, 4 }, + [ipclk_uart5sel] = { rcc_ccipr1, 0x1, 6 }, + [ipclk_i3c1sel] = { rcc_ccipr1, 0x1, 8 }, + [ipclk_i2c1sel] = { rcc_ccipr1, 0x1, 10 }, + [ipclk_i2c2sel] = { rcc_ccipr1, 0x1, 12 }, + [ipclk_i3c2sel] = { rcc_ccipr1, 0x1, 14 }, + [ipclk_spi2sel] = { rcc_ccipr1, 0x1, 16 }, + [ipclk_lptim2sel] = { rcc_ccipr1, 0x3, 18 }, + [ipclk_spi1sel] = { rcc_ccipr1, 0x1, 20 }, + [ipclk_systicksel] = { rcc_ccipr1, 0x3, 22 }, + [ipclk_fdcansel] = { rcc_ccipr1, 0x1, 24 }, + [ipclk_iclksel] = { rcc_ccipr1, 0x3, 26 }, + [ipclk_usb1sel] = { rcc_ccipr1, 0x1, 28 }, + [ipclk_timicsel] = { rcc_ccipr1, 0x7, 29 }, + [ipclk_adf1sel] = { rcc_ccipr2, 0x3, 0 }, + [ipclk_spi3sel] = { rcc_ccipr2, 0x1, 3 }, + [ipclk_sai1sel] = { rcc_ccipr2, 0x3, 5 }, + [ipclk_spi4sel] = { rcc_ccipr2, 0x1, 7 }, + [ipclk_i2c4sel] = { rcc_ccipr2, 0x1, 9 }, + [ipclk_rngsel] = { rcc_ccipr2, 0x1, 11 }, + [ipclk_adcdacsel] = { rcc_ccipr2, 0x3, 16 }, + [ipclk_dac1shsel] = { rcc_ccipr2, 0x1, 19 }, + [ipclk_octospisel] = { rcc_ccipr2, 0x1, 20 }, + [ipclk_usart2sel] = { rcc_ccipr2, 0x1, 22 }, + [ipclk_lpuart1sel] = { rcc_ccipr3, 0x3, 0 }, + [ipclk_i2c3sel] = { rcc_ccipr3, 0x1, 6 }, + [ipclk_lptim34sel] = { rcc_ccipr3, 0x3, 8 }, + [ipclk_lptim1sel] = { rcc_ccipr3, 0x3, 10 }, + }; + + u32 v; + if (ipclk >= ipclks_count) { + return -1; + } + + v = *(stm32_common.rcc + ipclk_lookup[ipclk].reg_offs); + v &= ~((u32)ipclk_lookup[ipclk].mask << ipclk_lookup[ipclk].shift); + setting &= ipclk_lookup[ipclk].mask; + v |= (u32)setting << ipclk_lookup[ipclk].shift; + *(stm32_common.rcc + ipclk_lookup[ipclk].reg_offs) = v; + return 0; +} + + +/* PWR */ + + +static void _stm32_initPowerSupply(unsigned int supply) +{ + u32 enableBit, validBit; + static const u8 supplies[pwr_supplies_count] = { + [pwr_supply_vddio2] = 25, + [pwr_supply_vusb] = 24, + [pwr_supply_vdda] = 26, + }; + + if (supply >= pwr_supplies_count) { + return; + } + + enableBit = 1 << supplies[supply]; /* xVMyEN, xVMyRDY */ + validBit = enableBit << 4; /* xV */ + + *(stm32_common.pwr + pwr_svmcr) |= enableBit; /* Set xVMyEN */ + hal_cpuDataMemoryBarrier(); + while ((*(stm32_common.pwr + pwr_svmsr) & enableBit) == 0) + { + /* Wait for xVMyRDY */ + } + + *(stm32_common.pwr + pwr_svmcr) |= validBit; /* Set xV */ + *(stm32_common.pwr + pwr_svmcr) &= ~enableBit; /* Clear xVMyEN */ +} + + +/* SysTick */ + + +int _stm32_systickInit(u32 interval) +{ + u32 load = (stm32_common.cpuclk / interval) - 1; + if (load > 0x00ffffff) { + return -1; + } + + *(stm32_common.icb + icb_systick_load) = load; + *(stm32_common.icb + icb_systick_val) = 0; + + *(stm32_common.icb + icb_systick_ctrl) |= (1 << 2) | (1 << 1) | (1 << 0); /* CLKSOURCE | TICKINT | ENABLE */ + + return 0; +} + + +void _stm32_systickDone(void) +{ + *(stm32_common.icb + icb_systick_ctrl) = 0; +} + + +/* GPIO */ + + +static volatile u32 *_stm32_gpioGetBase(unsigned int d, u8 pin) +{ + if ((d < dev_gpioa) || (d > dev_gpioh) || (pin > 15)) { + return NULL; + } + + return stm32_common.gpio[d - dev_gpioa]; +} + + +int _stm32_gpioConfig(unsigned int d, u8 pin, u8 mode, u8 af, u8 otype, u8 ospeed, u8 pupd) +{ + volatile u32 *base; + u32 t; + + base = _stm32_gpioGetBase(d, pin); + if (base == NULL) { + return -1; + } + + t = *(base + gpio_moder) & ~(0x3 << (pin << 1)); + *(base + gpio_moder) = t | (mode & 0x3) << (pin << 1); + + t = *(base + gpio_otyper) & ~(1 << pin); + *(base + gpio_otyper) = t | (otype & 1) << pin; + + t = *(base + gpio_ospeedr) & ~(0x3 << (pin << 1)); + *(base + gpio_ospeedr) = t | (ospeed & 0x3) << (pin << 1); + + t = *(base + gpio_pupdr) & ~(0x03 << (pin << 1)); + *(base + gpio_pupdr) = t | (pupd & 0x3) << (pin << 1); + + if (pin < 8) { + t = *(base + gpio_afrl) & ~(0xf << (pin << 2)); + *(base + gpio_afrl) = t | (af & 0xf) << (pin << 2); + } + else { + t = *(base + gpio_afrh) & ~(0xf << ((pin - 8) << 2)); + *(base + gpio_afrh) = t | (af & 0xf) << ((pin - 8) << 2); + } + + return 0; +} + + +/* Watchdog */ + + +static void _stm32_wdgInit(void) +{ +#if defined(WATCHDOG) + /* Enable write access to IWDG */ + *(stm32_common.iwdg + iwdg_kr) = 0x5555; + + /* 32 kHz independent clock */ + *(stm32_common.iwdg + iwdg_pr) = 6; /* prescaler divider / 256 */ + *(stm32_common.iwdg + iwdg_rlr) = 30 /* s */ * 32000 /* Hz */ / 256; + + _stm32_wdgReload(); + + /* Enable watchdog */ + *(stm32_common.iwdg + iwdg_kr) = 0xcccc; +#endif +} + + +void _stm32_wdgReload(void) +{ +#if defined(WATCHDOG) + *(stm32_common.iwdg + iwdg_kr) = 0xaaaa; +#endif +} + + +static void _stm32_initSRAM(void) +{ + /* Enable built-in memories that aren't turned on through reset: + * SRAM3 */ + static const struct { + int dev; + int crOffs; + int erkeyrOffs; + } srams[] = { +#if RAM_BANK_SIZE > 0x00040000 /* SRAM1 + SRAM2 */ + { .dev = dev_sram3, .crOffs = ramcfg_sram3cr, .erkeyrOffs = ramcfg_sram3erkeyr }, +#endif + }; + unsigned int i; + + /* Enable all memories in RCC */ + _stm32_rccSetDevClock(dev_ramcfg, 1); + for (i = 0; i < sizeof(srams) / sizeof(srams[0]); i++) { + _stm32_rccSetDevClock(srams[i].dev, 1); + + *(stm32_common.ramcfg + srams[i].crOffs) &= ~(1 << 20); + if (srams[i].erkeyrOffs >= 0) { + *(stm32_common.ramcfg + srams[i].erkeyrOffs) = 0xca; + *(stm32_common.ramcfg + srams[i].erkeyrOffs) = 0x53; + *(stm32_common.ramcfg + srams[i].crOffs) |= (1 << 8); + while ((*(stm32_common.ramcfg + srams[i].crOffs) & (1 << 8)) != 0) { + /* Wait for end of erase */ + } + } + } +} + + +void _stm32_init(void) +{ + u32 i; + + /* Base addresses init */ + stm32_common.rcc = RCC_BASE; + stm32_common.pwr = PWR_BASE; + stm32_common.icb = ICB_BASE; + stm32_common.iwdg = IWDG_BASE; + stm32_common.syscfg = SYSCFG_BASE; + stm32_common.ramcfg = RAMCFG_BASE; + stm32_common.gpio[0] = GPIOA_BASE; + stm32_common.gpio[1] = GPIOB_BASE; + stm32_common.gpio[2] = GPIOC_BASE; + stm32_common.gpio[3] = GPIOD_BASE; + stm32_common.gpio[4] = GPIOE_BASE; + stm32_common.gpio[5] = GPIOF_BASE; + stm32_common.gpio[6] = GPIOG_BASE; + stm32_common.gpio[7] = GPIOH_BASE; + + /* Store reset flags and then clear them */ + stm32_common.resetFlags = (*(stm32_common.rcc + rcc_csr) >> 25); /* LPWRRSTF ~ OBLRSTF */ + _stm32_rccClearResetFlags(); + + /* Enable System configuration controller */ + _stm32_rccSetDevClock(dev_syscfg, 1); + _stm32_rccSetDevClock(dev_vref, 1); + + /* Enable power module */ + _stm32_rccSetDevClock(dev_pwr, 1); + + _stm32_initSRAM(); + + /* Enable independent power supply for ADCs */ + _stm32_initPowerSupply(pwr_supply_vdda); + /* Enable independent power supply for USB */ + _stm32_initPowerSupply(pwr_supply_vusb); + + /* Disable all RCC interrupts */ + *(stm32_common.rcc + rcc_cier) = 0; + + _stm32_configureClocks(); + + hal_cpuDataMemoryBarrier(); + + /* GPIO init */ + for (i = dev_gpioa; i <= dev_gpioh; i++) { + _stm32_rccSetDevClock(i, 1); + } + + hal_cpuDataMemoryBarrier(); + + _stm32_wdgInit(); +} diff --git a/hal/armv8m/stm32/u3/stm32u3.h b/hal/armv8m/stm32/u3/stm32u3.h new file mode 100644 index 00000000..ea8bb5f4 --- /dev/null +++ b/hal/armv8m/stm32/u3/stm32u3.h @@ -0,0 +1,277 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * STM32U3 basic peripherals control functions + * + * Copyright 2017, 2020, 2021, 2025 Phoenix Systems + * Copyright 2026 Apator Metrix + * Author: Aleksander Kaminski, Pawel Pisarczyk, Hubert Buczynski, Jacek Maksymowicz, Mateusz Karcz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_STM32U3_H_ +#define _HAL_STM32U3_H_ + +#include "../types.h" +#include "stm32u3_regs.h" + +#define _STM32_ID(base, reg, pos) ((((reg) - (base)) << 5) | (pos)) +#define _STM32_DEV_ID(reg, pos) _STM32_ID(rcc_ahb1enr1, reg, pos) +#define _STM32_RST_ID(reg, pos) _STM32_ID(rcc_ahb1rstr1, reg, pos) + +/* Device clocks */ +enum { + dev_gpdma1 = _STM32_DEV_ID(rcc_ahb1enr1, 0), + dev_adf1 = _STM32_DEV_ID(rcc_ahb1enr1, 3), + dev_hsp1 = _STM32_DEV_ID(rcc_ahb1enr1, 4), + dev_flash = _STM32_DEV_ID(rcc_ahb1enr1, 8), + dev_crc = _STM32_DEV_ID(rcc_ahb1enr1, 12), + dev_tsc = _STM32_DEV_ID(rcc_ahb1enr1, 16), + dev_ramcfg = _STM32_DEV_ID(rcc_ahb1enr1, 17), + dev_gtzc1 = _STM32_DEV_ID(rcc_ahb1enr1, 24), + dev_sram4 = _STM32_DEV_ID(rcc_ahb1enr1, 30), + dev_sram1 = _STM32_DEV_ID(rcc_ahb1enr1, 31), + dev_gpioa = _STM32_DEV_ID(rcc_ahb2enr1, 0), + dev_gpiob = _STM32_DEV_ID(rcc_ahb2enr1, 1), + dev_gpioc = _STM32_DEV_ID(rcc_ahb2enr1, 2), + dev_gpiod = _STM32_DEV_ID(rcc_ahb2enr1, 3), + dev_gpioe = _STM32_DEV_ID(rcc_ahb2enr1, 4), + dev_gpiof = _STM32_DEV_ID(rcc_ahb2enr1, 5), + dev_gpiog = _STM32_DEV_ID(rcc_ahb2enr1, 6), + dev_gpioh = _STM32_DEV_ID(rcc_ahb2enr1, 7), + dev_adc12 = _STM32_DEV_ID(rcc_ahb2enr1, 10), + dev_dac1 = _STM32_DEV_ID(rcc_ahb2enr1, 11), + dev_aes = _STM32_DEV_ID(rcc_ahb2enr1, 16), + dev_hash = _STM32_DEV_ID(rcc_ahb2enr1, 17), + dev_rng = _STM32_DEV_ID(rcc_ahb2enr1, 18), + dev_pka = _STM32_DEV_ID(rcc_ahb2enr1, 19), + dev_saes = _STM32_DEV_ID(rcc_ahb2enr1, 20), + dev_ccb = _STM32_DEV_ID(rcc_ahb2enr1, 21), + dev_sdmmc1 = _STM32_DEV_ID(rcc_ahb2enr1, 27), + dev_sram2 = _STM32_DEV_ID(rcc_ahb2enr1, 30), + dev_sram3 = _STM32_DEV_ID(rcc_ahb2enr1, 31), + dev_octospi1 = _STM32_DEV_ID(rcc_ahb2enr2, 4), + dev_pwr = _STM32_DEV_ID(rcc_ahb1enr2, 2), + dev_tim2 = _STM32_DEV_ID(rcc_apb1enr1, 0), + dev_tim3 = _STM32_DEV_ID(rcc_apb1enr1, 1), + dev_tim4 = _STM32_DEV_ID(rcc_apb1enr1, 2), + dev_tim6 = _STM32_DEV_ID(rcc_apb1enr1, 4), + dev_tim7 = _STM32_DEV_ID(rcc_apb1enr1, 5), + dev_spi3 = _STM32_DEV_ID(rcc_apb1enr1, 8), + dev_spi4 = _STM32_DEV_ID(rcc_apb1enr1, 9), + dev_wwdg = _STM32_DEV_ID(rcc_apb1enr1, 11), + dev_spi2 = _STM32_DEV_ID(rcc_apb1enr1, 14), + dev_usart2 = _STM32_DEV_ID(rcc_apb1enr1, 17), + dev_usart3 = _STM32_DEV_ID(rcc_apb1enr1, 18), + dev_uart4 = _STM32_DEV_ID(rcc_apb1enr1, 19), + dev_uart5 = _STM32_DEV_ID(rcc_apb1enr1, 20), + dev_i2c1 = _STM32_DEV_ID(rcc_apb1enr1, 21), + dev_i2c2 = _STM32_DEV_ID(rcc_apb1enr1, 22), + dev_i3c1 = _STM32_DEV_ID(rcc_apb1enr1, 23), + dev_crs = _STM32_DEV_ID(rcc_apb1enr1, 24), + dev_opamp = _STM32_DEV_ID(rcc_apb1enr1, 28), + dev_vref = _STM32_DEV_ID(rcc_apb1enr1, 29), + dev_rtcapb = _STM32_DEV_ID(rcc_apb1enr1, 30), + dev_i2c4 = _STM32_DEV_ID(rcc_apb1enr2, 1), + dev_lptim2 = _STM32_DEV_ID(rcc_apb1enr2, 5), + dev_fdcan = _STM32_DEV_ID(rcc_apb1enr2, 9), + dev_tim1 = _STM32_DEV_ID(rcc_apb2enr, 11), + dev_spi1 = _STM32_DEV_ID(rcc_apb2enr, 12), + dev_tim8 = _STM32_DEV_ID(rcc_apb2enr, 13), + dev_usart1 = _STM32_DEV_ID(rcc_apb2enr, 14), + dev_tim12 = _STM32_DEV_ID(rcc_apb2enr, 15), + dev_tim15 = _STM32_DEV_ID(rcc_apb2enr, 16), + dev_tim16 = _STM32_DEV_ID(rcc_apb2enr, 17), + dev_tim17 = _STM32_DEV_ID(rcc_apb2enr, 18), + dev_sai1 = _STM32_DEV_ID(rcc_apb2enr, 21), + dev_usb1 = _STM32_DEV_ID(rcc_apb2enr, 24), + dev_i3c2 = _STM32_DEV_ID(rcc_apb2enr, 27), + dev_syscfg = _STM32_DEV_ID(rcc_apb3enr, 1), + dev_lpuart1 = _STM32_DEV_ID(rcc_apb3enr, 6), + dev_i2c3 = _STM32_DEV_ID(rcc_apb3enr, 7), + dev_lptim1 = _STM32_DEV_ID(rcc_apb3enr, 11), + dev_lptim3 = _STM32_DEV_ID(rcc_apb3enr, 12), + dev_lptim4 = _STM32_DEV_ID(rcc_apb3enr, 13), + dev_comp = _STM32_DEV_ID(rcc_apb3enr, 15), +}; + + +/* Device resets */ +enum { + dev_rst_gpdma1 = _STM32_RST_ID(rcc_ahb1rstr1, 0), + dev_rst_adf1 = _STM32_RST_ID(rcc_ahb1rstr1, 3), + dev_rst_hsp1 = _STM32_RST_ID(rcc_ahb1rstr1, 4), + dev_rst_crc = _STM32_RST_ID(rcc_ahb1rstr1, 12), + dev_rst_tsc = _STM32_RST_ID(rcc_ahb1rstr1, 16), + dev_rst_ramcfg = _STM32_RST_ID(rcc_ahb1rstr1, 17), + dev_rst_gpioa = _STM32_RST_ID(rcc_ahb2rstr1, 0), + dev_rst_gpiob = _STM32_RST_ID(rcc_ahb2rstr1, 1), + dev_rst_gpioc = _STM32_RST_ID(rcc_ahb2rstr1, 2), + dev_rst_gpiod = _STM32_RST_ID(rcc_ahb2rstr1, 3), + dev_rst_gpioe = _STM32_RST_ID(rcc_ahb2rstr1, 4), + dev_rst_gpiof = _STM32_RST_ID(rcc_ahb2rstr1, 5), + dev_rst_gpiog = _STM32_RST_ID(rcc_ahb2rstr1, 6), + dev_rst_gpioh = _STM32_RST_ID(rcc_ahb2rstr1, 7), + dev_rst_adc12 = _STM32_RST_ID(rcc_ahb2rstr1, 10), + dev_rst_dac1 = _STM32_RST_ID(rcc_ahb2rstr1, 11), + dev_rst_aes = _STM32_RST_ID(rcc_ahb2rstr1, 16), + dev_rst_hash = _STM32_RST_ID(rcc_ahb2rstr1, 17), + dev_rst_rng = _STM32_RST_ID(rcc_ahb2rstr1, 18), + dev_rst_pka = _STM32_RST_ID(rcc_ahb2rstr1, 19), + dev_rst_saes = _STM32_RST_ID(rcc_ahb2rstr1, 20), + dev_rst_ccb = _STM32_RST_ID(rcc_ahb2rstr1, 21), + dev_rst_sdmmc1 = _STM32_RST_ID(rcc_ahb2rstr1, 27), + dev_rst_octospi1 = _STM32_RST_ID(rcc_ahb2rstr2, 4), + dev_rst_tim2 = _STM32_RST_ID(rcc_apb1rstr1, 0), + dev_rst_tim3 = _STM32_RST_ID(rcc_apb1rstr1, 1), + dev_rst_tim4 = _STM32_RST_ID(rcc_apb1rstr1, 2), + dev_rst_tim6 = _STM32_RST_ID(rcc_apb1rstr1, 4), + dev_rst_tim7 = _STM32_RST_ID(rcc_apb1rstr1, 5), + dev_rst_spi3 = _STM32_RST_ID(rcc_apb1rstr1, 8), + dev_rst_spi4 = _STM32_RST_ID(rcc_apb1rstr1, 9), + dev_rst_spi2 = _STM32_RST_ID(rcc_apb1rstr1, 14), + dev_rst_usart2 = _STM32_RST_ID(rcc_apb1rstr1, 17), + dev_rst_usart3 = _STM32_RST_ID(rcc_apb1rstr1, 18), + dev_rst_uart4 = _STM32_RST_ID(rcc_apb1rstr1, 19), + dev_rst_uart5 = _STM32_RST_ID(rcc_apb1rstr1, 20), + dev_rst_i2c1 = _STM32_RST_ID(rcc_apb1rstr1, 21), + dev_rst_i2c2 = _STM32_RST_ID(rcc_apb1rstr1, 22), + dev_rst_i3c1 = _STM32_RST_ID(rcc_apb1rstr1, 23), + dev_rst_crs = _STM32_RST_ID(rcc_apb1rstr1, 24), + dev_rst_opamp = _STM32_RST_ID(rcc_apb1rstr1, 28), + dev_rst_vref = _STM32_RST_ID(rcc_apb1rstr1, 29), + dev_rst_i2c4 = _STM32_RST_ID(rcc_apb1rstr2, 1), + dev_rst_lptim2 = _STM32_RST_ID(rcc_apb1rstr2, 5), + dev_rst_fdcan = _STM32_RST_ID(rcc_apb1rstr2, 9), + dev_rst_tim1 = _STM32_RST_ID(rcc_apb2rstr, 11), + dev_rst_spi1 = _STM32_RST_ID(rcc_apb2rstr, 12), + dev_rst_tim8 = _STM32_RST_ID(rcc_apb2rstr, 13), + dev_rst_usart1 = _STM32_RST_ID(rcc_apb2rstr, 14), + dev_rst_tim12 = _STM32_RST_ID(rcc_apb2rstr, 15), + dev_rst_tim15 = _STM32_RST_ID(rcc_apb2rstr, 16), + dev_rst_tim16 = _STM32_RST_ID(rcc_apb2rstr, 17), + dev_rst_tim17 = _STM32_RST_ID(rcc_apb2rstr, 18), + dev_rst_sai1 = _STM32_RST_ID(rcc_apb2rstr, 21), + dev_rst_usb1 = _STM32_RST_ID(rcc_apb2rstr, 24), + dev_rst_i3c2 = _STM32_RST_ID(rcc_apb2rstr, 27), + dev_rst_syscfg = _STM32_RST_ID(rcc_apb3rstr, 1), + dev_rst_lpuart1 = _STM32_RST_ID(rcc_apb3rstr, 6), + dev_rst_i2c3 = _STM32_RST_ID(rcc_apb3rstr, 7), + dev_rst_lptim1 = _STM32_RST_ID(rcc_apb3rstr, 11), + dev_rst_lptim3 = _STM32_RST_ID(rcc_apb3rstr, 12), + dev_rst_lptim4 = _STM32_RST_ID(rcc_apb3rstr, 13), + dev_rst_comp = _STM32_RST_ID(rcc_apb3rstr, 15), +}; + + +enum ipclks { + ipclk_usart1sel = 0, + ipclk_usart3sel, + ipclk_uart4sel, + ipclk_uart5sel, + ipclk_i3c1sel, + ipclk_i2c1sel, + ipclk_i2c2sel, + ipclk_i3c2sel, + ipclk_spi2sel, + ipclk_lptim2sel, + ipclk_spi1sel, + ipclk_systicksel, + ipclk_fdcansel, + ipclk_iclksel, + ipclk_usb1sel, + ipclk_timicsel, + ipclk_adf1sel, + ipclk_spi3sel, + ipclk_sai1sel, + ipclk_spi4sel, + ipclk_i2c4sel, + ipclk_rngsel, + ipclk_adcdacsel, + ipclk_dac1shsel, + ipclk_octospisel, + ipclk_usart2sel, + ipclk_lpuart1sel, + ipclk_i2c3sel, + ipclk_lptim34sel, + ipclk_lptim1sel, + ipclks_count +}; + + +enum pwr_supplies { + pwr_supply_vddio2 = 0, + pwr_supply_vusb, + pwr_supply_vdda, + pwr_supplies_count, +}; + + +enum gpio_modes { + gpio_mode_gpi = 0, + gpio_mode_gpo = 1, + gpio_mode_af = 2, + gpio_mode_analog = 3, +}; + + +enum gpio_otypes { + gpio_otype_pp = 0, + gpio_otype_od = 1, +}; + + +enum gpio_ospeeds { + gpio_ospeed_low = 0, + gpio_ospeed_med = 1, + gpio_ospeed_hi = 2, + gpio_ospeed_vhi = 3, +}; + + +enum gpio_pupds { + gpio_pupd_nopull = 0, + gpio_pupd_pullup = 1, + gpio_pupd_pulldn = 2, +}; + + +/* Sets peripheral's bus clock */ +extern int _stm32_rccSetDevClock(unsigned int dev, u32 status); + + +/* Sets independent peripheral clock configuration */ +extern int _stm32_rccSetIPClk(unsigned int ipclk, u8 setting); + + +/* Get frequency of CPU clock in Hz */ +extern u32 _stm32_rccGetCPUClock(void); + + +extern void _stm32_rccClearResetFlags(void); + + +/* Get frequency of the PCLKx clock in Hz */ +extern u32 _stm32_rccGetPclkClock(void); + + +extern int _stm32_gpioConfig(unsigned int d, u8 pin, u8 mode, u8 af, u8 otype, u8 ospeed, u8 pupd); + + +extern int _stm32_systickInit(u32 interval); + + +extern void _stm32_systickDone(void); + + +extern void _stm32_wdgReload(void); + + +extern void _stm32_init(void); + +#endif /* _HAL_STM32U3_H_ */ diff --git a/hal/armv8m/stm32/u3/stm32u3_regs.h b/hal/armv8m/stm32/u3/stm32u3_regs.h new file mode 100644 index 00000000..598fcdb0 --- /dev/null +++ b/hal/armv8m/stm32/u3/stm32u3_regs.h @@ -0,0 +1,178 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * Peripheral register definitions for STM32U3 platform + * Based on stm32u3c5xx.h by STMicroelectronics + * + * Copyright 2026 Apator Metrix + * Authors: Mateusz Karcz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _STM32U3_REGS_H_ +#define _STM32U3_REGS_H_ + +enum rcc_regs { + rcc_cr = 0x0, + rcc_icscr1 = 0x2, + rcc_icscr2, + rcc_icscr3, + rcc_crrcr, + rcc_cfgr1 = 0x7, + rcc_cfgr2, + rcc_cfgr3, + rcc_cfgr4, + rcc_cier = 0x14, + rcc_cifr, + rcc_cicr, + rcc_ahb1rstr1 = 0x18, + rcc_ahb2rstr1, + rcc_ahb2rstr2, + rcc_apb1rstr1 = 0x1d, + rcc_apb1rstr2, + rcc_apb2rstr, + rcc_apb3rstr, + rcc_ahb1enr1 = 0x22, + rcc_ahb2enr1, + rcc_ahb2enr2, + rcc_ahb1enr2, + rcc_apb1enr1 = 0x27, + rcc_apb1enr2, + rcc_apb2enr, + rcc_apb3enr, + rcc_ahb1slpenr1 = 0x2c, + rcc_ahb2slpenr1, + rcc_ahb2slpenr2, + rcc_ahb1slpenr2, + rcc_apb1slpenr1 = 0x31, + rcc_apb1slpenr2, + rcc_apb2slpenr, + rcc_apb3slpenr, + rcc_ahb1stpenr1 = 0x36, + rcc_ahb2stpenr1, + rcc_apb1stpenr1 = 0x3b, + rcc_apb1stpenr2, + rcc_apb2stpenr, + rcc_apb3stpenr, + rcc_ccipr1 = 0x40, + rcc_ccipr2, + rcc_ccipr3, + rcc_bdcr = 0x44, + rcc_csr, + rcc_seccfgr = 0x4c, + rcc_privcfgr, +}; + + +enum gpio_regs { + gpio_moder = 0x0, + gpio_otyper, + gpio_ospeedr, + gpio_pupdr, + gpio_idr, + gpio_odr, + gpio_bsrr, + gpio_lckr, + gpio_afrl, + gpio_afrh, + gpio_brr, + gpio_hslvr, + gpio_seccfgr, +}; + + +enum pwr_regs { + pwr_cr1 = 0x0, + pwr_cr2, + pwr_cr3, + pwr_vosr, + pwr_svmcr, + pwr_wucr1, + pwr_wucr2, + pwr_wucr3, + pwr_bdcr = 0x9, + pwr_dbpr, + pwr_seccfgr = 0xc, + pwr_privcfgr, + pwr_sr, + pwr_svmsr, + pwr_wusr = 0x11, + pwr_wuscr, + pwr_apcr, + pwr_pucra, + pwr_pdcra, + pwr_pucrb, + pwr_pdcrb, + pwr_pucrc, + pwr_pdcrc, + pwr_pucrd, + pwr_pdcrd, + pwr_pucre, + pwr_pdcre, + pwr_pucrg = 0x20, + pwr_pdcrg, + pwr_pucrh, + pwr_pdcrh, + pwr_i3cpucr1 = 0x2c, + pwr_i3cpucr2, +}; + + +enum iwdg_regs { + iwdg_kr = 0x0, + iwdg_pr, + iwdg_rlr, + iwdg_sr, + iwdg_winr, + iwdg_ewcr, +}; + +enum syscfg_regs { + syscfg_seccfgr = 0x0, + syscfg_cfgr1, + syscfg_fpuimr, + syscfg_cnslckr, + syscfg_cslckr, + syscfg_cfgr2, + syscfg_cccsr = 0x7, + syscfg_ccvr, + syscfg_cccr, + syscfg_rsscmdr = 0xb, +}; + +enum ramcfg_regs { + ramcfg_sram1cr = 0x0, + ramcfg_sram1ier, + ramcfg_sram1isr, + ramcfg_sram1pear = 0x4, + ramcfg_sram1icr, + ramcfg_sram1wpr1, + ramcfg_sram1wpr2, + ramcfg_sram1parkeyr = 0x9, + ramcfg_sram1erkeyr, + ramcfg_sram2cr = 0x10, + ramcfg_sram2ier, + ramcfg_sram2isr, + ramcfg_sram2pear = 0x14, + ramcfg_sram2icr, + ramcfg_sram2wpr1, + ramcfg_sram2wpr2, + ramcfg_sram2parkeyr = 0x19, + ramcfg_sram2erkeyr, + ramcfg_sram3cr = 0x20, + ramcfg_sram3ier, + ramcfg_sram3isr, + ramcfg_sram3pear = 0x24, + ramcfg_sram3icr, + ramcfg_sram3wpr1, + ramcfg_sram3wpr2, + ramcfg_sram3parkeyr = 0x29, + ramcfg_sram3erkeyr, +}; + +#endif /* _STM32U3_REGS_H_ */ diff --git a/ld/armv8m33-stm32u3.ldt b/ld/armv8m33-stm32u3.ldt new file mode 100644 index 00000000..06fee971 --- /dev/null +++ b/ld/armv8m33-stm32u3.ldt @@ -0,0 +1,65 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * Linker Template and Platform Config for ARMv8-M33 STM32U3 + * + * Copyright 2021-2022 Phoenix Systems + * Copyright 2026 Apator Metrix + * Author: Gerard Swiderski, Damian Loewnau, Mateusz Karcz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef ARMV8M33_STM32U3_LDT +#define ARMV8M33_STM32U3_LDT + + +/* Platform specific definitions */ +#define SIZE_PAGE 0x200 +#define SIZE_STACK (8 * SIZE_PAGE) +#define SIZE_HEAP (8 * SIZE_PAGE) + +#ifndef FLASH_PROGRAM_BANK_SIZE +#define FLASH_PROGRAM_BANK_SIZE (512 * 1024) /* STM32U385xx */ +#endif +#define FLASH_PROGRAM_1_ADDR (0x08000000) +#define FLASH_PROGRAM_2_ADDR (FLASH_PROGRAM_1_ADDR + FLASH_PROGRAM_BANK_SIZE) + +/* Space reserved for kernel data */ +#define AREA_KERNEL 0x10000 + +/* RAM-disk configuration */ +#define RAM_ADDR 0x20000000 +#ifndef RAM_BANK_SIZE +#define RAM_BANK_SIZE (256 * 1024) /* STM32U385xx */ +#endif + + +#if defined(__LINKER__) + +/* Memory map setup */ +MEMORY +{ + m_sram (rwx) : ORIGIN = 0x20000000 + AREA_KERNEL, LENGTH = RAM_BANK_SIZE - AREA_KERNEL + m_flash (rx) : ORIGIN = 0x08000000, LENGTH = FLASH_PROGRAM_BANK_SIZE +} + +/* FLASH image */ +REGION_ALIAS("PLO_IMAGE", m_flash); +REGION_ALIAS("TCM_TEXT", m_flash); +REGION_ALIAS("DATA", m_sram); +REGION_ALIAS("BSS", m_sram); +REGION_ALIAS("HEAP", m_sram); +REGION_ALIAS("STACK", m_sram); + +#include "common/plo-arm.lds" + +#endif /* end of __LINKER__ */ + + +#endif /* end of ARMV8M33_STM32U3_LDT */ From 38830267d28ab583fc44e6688cf4132cab9a8cf1 Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Wed, 4 Mar 2026 13:22:29 +0100 Subject: [PATCH 03/10] hal/stm32u3: allow CPU clock selection Use MSIS as the 24 MHz clock source for SYSCLK. Signed-off-by: Mateusz Karcz --- hal/armv8m/stm32/u3/stm32u3.c | 186 ++++++++++++++++++++++++++++++++-- hal/armv8m/stm32/u3/stm32u3.h | 16 +++ 2 files changed, 191 insertions(+), 11 deletions(-) diff --git a/hal/armv8m/stm32/u3/stm32u3.c b/hal/armv8m/stm32/u3/stm32u3.c index 6e56b9e9..eabbf156 100644 --- a/hal/armv8m/stm32/u3/stm32u3.c +++ b/hal/armv8m/stm32/u3/stm32u3.c @@ -16,6 +16,7 @@ #include #include +#include #include "stm32u3.h" @@ -45,6 +46,7 @@ static struct { volatile u32 *ramcfg; u32 cpuclk; + u32 hsiRefs; u32 resetFlags; } stm32_common; @@ -58,6 +60,32 @@ enum { icb_systick_calib, }; +/* Clock owners */ +typedef enum { + clko_sysclk = 0, + clko_booster, +} clock_owner; + + +/* MSIS clock range mappings */ +typedef struct { + u32 hz; + int range; +} range_mapping; + +#define FREQUENCY_RANGE_COUNT 7 +static const range_mapping frequency_ranges[FREQUENCY_RANGE_COUNT] = { + {3000000, 7}, {6000000, 6}, {12000000, 5}, /* MSIRC1 */ + {16000000, -1}, /* HSI */ + {24000000, 4}, /* MSIRC1 */ + {48000000, 1}, {96000000, 0}, /* MSIRC0 */ +}; + +#define BOOSTEN (1 << 8) +#define VOLTAGE_RANGE_COUNT 3 +static const range_mapping voltage_ranges[VOLTAGE_RANGE_COUNT] = { + {24000000, 2}, {48000000, 2 - BOOSTEN}, {96000000, 1 - BOOSTEN}, +}; unsigned int hal_getBootReason(void) { @@ -89,21 +117,13 @@ unsigned int hal_getBootReason(void) */ static void _stm32_configureClocks(void) { - u32 v, clock_source; + u32 v; /* Disable HSE */ *(stm32_common.rcc + rcc_cr) &= ~(1 << 16); /* HSEON off */ - /* Select the system clock source */ - clock_source = 0; /* MSIS */ - v = *(stm32_common.rcc + rcc_cfgr1); - v |= (clock_source << 0); /* Set SW */ - *(stm32_common.rcc + rcc_cfgr1) = v; - - while (((*(stm32_common.rcc + rcc_cfgr1) >> 2) & 0x3) != clock_source) { - /* Wait for SWS */ - } - stm32_common.cpuclk = 12 * 1000 * 1000; + /* Select the system clock frequency */ + _stm32_rccSetCPUClock(24 * 1000 * 1000); /* Set peripheral bus clock prescalers */ v = *(stm32_common.rcc + rcc_cfgr2); @@ -118,6 +138,113 @@ static void _stm32_configureClocks(void) } +static const range_mapping *_stm32_findRange(u32 hz, const range_mapping *ranges, int length) +{ + int i; + + for (i = 0; i < length; i++) { + if (hz <= ranges[i].hz) + { + return ranges + i; + } + } + + return NULL; +} + + +static void _stm32_acquireHsi(clock_owner owner) +{ + if (stm32_common.hsiRefs == 0) { + *(stm32_common.rcc + rcc_cr) |= (1 << 11); /* Set HSION */ + hal_cpuDataMemoryBarrier(); + + while ((*(stm32_common.rcc + rcc_cr) & (1 << 13)) == 0) { + /* Wait for HSIRDY */ + } + } + + stm32_common.hsiRefs |= 1 << owner; +} + + +static void _stm32_releaseHsi(clock_owner owner) +{ + if (stm32_common.hsiRefs == 0) { + return; + } + + stm32_common.hsiRefs &= ~(1 << owner); + + if (stm32_common.hsiRefs == 0) { + *(stm32_common.rcc + rcc_cr) &= ~(1 << 11); /* Clear HSION */ + hal_cpuDataMemoryBarrier(); + + while ((*(stm32_common.rcc + rcc_cr) & (1 << 13)) != 0) { + /* Wait for HSIRDY */ + } + } +} + + +int _stm32_rccSetCPUClock(u32 hz) +{ + u32 v, clock_source = 0; + const range_mapping *frequency_range, *voltage_range; + + if (!(frequency_range = _stm32_findRange(hz, frequency_ranges, FREQUENCY_RANGE_COUNT))) { + return -ERANGE; + } + + if (!(voltage_range = _stm32_findRange(hz, voltage_ranges, VOLTAGE_RANGE_COUNT))) { + return -ERANGE; + } + + /* Step up */ + if (voltage_range->range < _stm32_pwrGetCPUVolt()) { + _stm32_pwrSetCPUVolt(voltage_range->range); + } + + if (frequency_range->range >= 0) { + /* Configure MSIS */ + v = *(stm32_common.rcc + rcc_icscr1) & ~(0x7 << 29); + v |= ((frequency_range->range & 0x7) << 29) | (1 << 23); /* Set MSISSEL | MSISDIV | MSIRGSEL */ + *(stm32_common.rcc + rcc_icscr1) = v; + hal_cpuDataMemoryBarrier(); + + while ((*(stm32_common.rcc + rcc_cr) & (1 << 2)) == 0) { + /* Wait for MSISRDY */ + } + _stm32_releaseHsi(clko_sysclk); + } else { + /* Configure HSI */ + clock_source = 1; + _stm32_acquireHsi(clko_sysclk); + } + hal_cpuDataMemoryBarrier(); + + /* Configure SYSCLK source */ + v = *(stm32_common.rcc + rcc_cfgr1); + v &= ~(0x3 << 0); + v |= (clock_source << 0); /* Set SW */ + *(stm32_common.rcc + rcc_cfgr1) = v; + hal_cpuDataMemoryBarrier(); + + while (((*(stm32_common.rcc + rcc_cfgr1) >> 2) & 0x3) != clock_source) { + /* Wait for SWS */ + } + + /* Step down */ + if (voltage_range->range > _stm32_pwrGetCPUVolt()) { + _stm32_pwrSetCPUVolt(voltage_range->range); + } + + /* Update the current frequency */ + stm32_common.cpuclk = frequency_range->hz; + return 0; +} + + static int _stm32_getDevClockRegShift(unsigned int dev, unsigned int *shift_out) { unsigned int reg = dev / 32; @@ -255,6 +382,42 @@ static void _stm32_initPowerSupply(unsigned int supply) } +int _stm32_pwrGetCPUVolt(void) +{ + u32 range = *(stm32_common.pwr + pwr_vosr) & (BOOSTEN | 0x3); + return (range & BOOSTEN) ? ((int)range - 2 * BOOSTEN) : range; +} + + +void _stm32_pwrSetCPUVolt(int range) +{ + u32 t, boosten = range < 0; + range += boosten ? BOOSTEN : 0; + + if ((range < 1) || (range > 2)) + return; + + t = *(stm32_common.rcc + rcc_cfgr4) & ~((0xf << 12) | (0x3 << 0)); /* Clear BOOSTDIV (bypass) */ + if (boosten) { + _stm32_acquireHsi(clko_booster); + *(stm32_common.rcc + rcc_cfgr4) = t | 2; /* Set BOOSTSEL to HSI16 */ + range |= BOOSTEN; + } else { + *(stm32_common.rcc + rcc_cfgr4) = t; /* Clear BOOSTSEL */ + _stm32_releaseHsi(clko_booster); + } + hal_cpuDataMemoryBarrier(); + + t = *(stm32_common.pwr + pwr_vosr) & ~(BOOSTEN | 0x3); + *(stm32_common.pwr + pwr_vosr) = t | range; + hal_cpuDataMemoryBarrier(); + + while (((*(stm32_common.pwr + pwr_vosr) >> 16) & (BOOSTEN | 0x3)) != range) { + /* Wait for BOOSTRDY and RxRDY */ + } +} + + /* SysTick */ @@ -409,6 +572,7 @@ void _stm32_init(void) stm32_common.gpio[5] = GPIOF_BASE; stm32_common.gpio[6] = GPIOG_BASE; stm32_common.gpio[7] = GPIOH_BASE; + stm32_common.hsiRefs = 0; /* Store reset flags and then clear them */ stm32_common.resetFlags = (*(stm32_common.rcc + rcc_csr) >> 25); /* LPWRRSTF ~ OBLRSTF */ diff --git a/hal/armv8m/stm32/u3/stm32u3.h b/hal/armv8m/stm32/u3/stm32u3.h index ea8bb5f4..a38058b5 100644 --- a/hal/armv8m/stm32/u3/stm32u3.h +++ b/hal/armv8m/stm32/u3/stm32u3.h @@ -245,6 +245,10 @@ enum gpio_pupds { extern int _stm32_rccSetDevClock(unsigned int dev, u32 status); +/* Set frequency of CPU clock in Hz */ +extern int _stm32_rccSetCPUClock(u32 hz); + + /* Sets independent peripheral clock configuration */ extern int _stm32_rccSetIPClk(unsigned int ipclk, u8 setting); @@ -263,6 +267,18 @@ extern u32 _stm32_rccGetPclkClock(void); extern int _stm32_gpioConfig(unsigned int d, u8 pin, u8 mode, u8 af, u8 otype, u8 ospeed, u8 pupd); +/* Get CPU core voltage range + * 1 - 0.9 V, 2 - 0.75 V, subtracted 256 - EPOD booster is enabled + */ +extern int _stm32_pwrGetCPUVolt(void); + + +/* Set CPU core voltage range + * 1 - 0.9 V, 2 - 0.75 V, subtracted 256 - enable EPOD booster + */ +extern void _stm32_pwrSetCPUVolt(int range); + + extern int _stm32_systickInit(u32 interval); From 9a80268f7949ef2925ef340681ea7a2727233227 Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Thu, 5 Mar 2026 17:43:40 +0100 Subject: [PATCH 04/10] devices/uart-stm32: adjust to work on STM32U3 Add STM32U3 specific UART count and clock source selection. Signed-off-by: Mateusz Karcz --- devices/uart-stm32/uart.c | 26 ++++++++++++++++++++++---- hal/armv8m/stm32/u3/Makefile | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/devices/uart-stm32/uart.c b/devices/uart-stm32/uart.c index d1f5c581..69a62046 100644 --- a/devices/uart-stm32/uart.c +++ b/devices/uart-stm32/uart.c @@ -6,7 +6,8 @@ * STM32L4x6 Serial driver * * Copyright 2021 Phoenix Systems - * Author: Aleksander Kaminski + * Copyright 2026 Apator Metrix + * Author: Aleksander Kaminski, Mateusz Karcz * * This file is part of Phoenix-RTOS. * @@ -37,22 +38,26 @@ enum { cr1 = 0, cr2, cr3, brr, gtpr, rtor, rqr, isr, icr, rdr, tdr, presc }; /* clang-format on */ -#if defined(__CPU_STM32N6) +#if defined(__CPU_STM32N6) || defined(__CPU_STM32U3) /* Values for selecting the peripheral clock for an UART */ enum { uart_clk_sel_pclk = 0, /* pclk1 or pclk2 depending on peripheral */ +#if defined(__CPU_STM32N6) uart_clk_sel_per_ck, uart_clk_sel_ic9_ck, uart_clk_sel_ic14_ck, uart_clk_sel_lse_ck, uart_clk_sel_msi_ck, uart_clk_sel_hsi_div_ck, +#elif defined(__CPU_STM32U3) + uart_clk_sel_hsi_ck, +#endif }; #endif static int uartLut[UART_MAX_CNT] = { -#if defined(__CPU_STM32L4X6) +#if defined(__CPU_STM32L4X6) || defined(__CPU_STM32U3) UART1, UART2, UART3, UART4, UART5 #elif defined(__CPU_STM32N6) UART1, UART2, UART3, UART4, UART5, UART6, UART7, UART8, UART9, UART10 @@ -70,7 +75,7 @@ static const struct { int txport; unsigned char txpin; unsigned char txaf; -#if defined(__CPU_STM32N6) +#if defined(__CPU_STM32N6) || defined(__CPU_STM32U3) u16 ipclk_sel; /* Clock mux (one of ipclk_usart*sel) */ #endif } uartInfo[UART_MAX_CNT] = { @@ -91,6 +96,12 @@ static const struct { { UART8_BASE, UART8_CLK, UART8_IRQ, dev_gpioe, 0, 8, dev_gpioe, 1, 8, ipclk_uart8sel }, { UART9_BASE, UART9_CLK, UART9_IRQ, dev_gpiof, 1, 7, dev_gpiof, 0, 7, ipclk_uart9sel }, { UART10_BASE, UART10_CLK, UART10_IRQ, dev_gpiod, 3, 6, dev_gpiod, 15, 6, ipclk_usart10sel }, +#elif defined(__CPU_STM32U3) + { UART1_BASE, UART1_CLK, UART1_IRQ, dev_gpioa, 10, 7, dev_gpioa, 9, 7, ipclk_usart1sel }, + { UART2_BASE, UART2_CLK, UART2_IRQ, dev_gpiod, 6, 7, dev_gpioa, 5, 7, ipclk_usart2sel }, + { UART3_BASE, UART3_CLK, UART3_IRQ, dev_gpioc, 11, 7, dev_gpiod, 10, 7, ipclk_usart3sel }, + { UART4_BASE, UART4_CLK, UART4_IRQ, dev_gpioa, 1, 8, dev_gpioa, 0, 8, ipclk_uart4sel }, + { UART5_BASE, UART5_CLK, UART5_IRQ, dev_gpiod, 2, 8, dev_gpioc, 12, 8, ipclk_uart5sel }, #else #error "Unknown platform" #endif @@ -254,6 +265,13 @@ static u32 uart_configureRefclk(unsigned int minor) _stm32_rccSetIPClk(uartInfo[minor].ipclk_sel, uart_clk_sel_per_ck); return _stm32_rccGetPerClock(); } +#elif defined(__CPU_STM32U3) +static u32 uart_configureRefclk(unsigned int minor) +{ + /* Switch to PCLK clock */ + _stm32_rccSetIPClk(uartInfo[minor].ipclk_sel, uart_clk_sel_pclk); + return _stm32_rccGetPclkClock(); +} #endif diff --git a/hal/armv8m/stm32/u3/Makefile b/hal/armv8m/stm32/u3/Makefile index 18d67e47..da6a7b13 100644 --- a/hal/armv8m/stm32/u3/Makefile +++ b/hal/armv8m/stm32/u3/Makefile @@ -16,6 +16,6 @@ CFLAGS += -mfloat-abi=soft PLO_COMMANDS ?= alias app blob call console copy devices dump echo go help kernelimg \ map mem phfs reboot script stop wait -PLO_ALLDEVICES := flash-stm32 ram-storage +PLO_ALLDEVICES := flash-stm32 uart-stm32 ram-storage OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/stm32/u3/, _init.o stm32u3.o) From 3d71b798a6950a3fe08fb142490d4f6b92235133 Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Fri, 6 Mar 2026 10:39:55 +0100 Subject: [PATCH 05/10] hal/stm32l4: return error status in bank switch Return zero (success) from _stm32_switchFlashBank, to align with STM32U3 that can fail to switch banks. Signed-off-by: Mateusz Karcz --- hal/armv7m/stm32/l4/stm32l4.c | 4 +++- hal/armv7m/stm32/l4/stm32l4.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hal/armv7m/stm32/l4/stm32l4.c b/hal/armv7m/stm32/l4/stm32l4.c index b11d3049..5b0168d0 100644 --- a/hal/armv7m/stm32/l4/stm32l4.c +++ b/hal/armv7m/stm32/l4/stm32l4.c @@ -425,7 +425,7 @@ int _stm32_getFlashBank(void) } -void _stm32_switchFlashBank(int bank) +int _stm32_switchFlashBank(int bank) { if (bank == 0) { *(stm32_common.syscfg + syscfg_memrmp) &= ~(1 << 8); @@ -433,6 +433,8 @@ void _stm32_switchFlashBank(int bank) else { *(stm32_common.syscfg + syscfg_memrmp) |= 1 << 8; } + + return 0; } diff --git a/hal/armv7m/stm32/l4/stm32l4.h b/hal/armv7m/stm32/l4/stm32l4.h index 9f8cd920..733079f5 100644 --- a/hal/armv7m/stm32/l4/stm32l4.h +++ b/hal/armv7m/stm32/l4/stm32l4.h @@ -99,7 +99,7 @@ extern int _stm32_gpioGetPort(unsigned int d, u16 *val); extern int _stm32_getFlashBank(void); -extern void _stm32_switchFlashBank(int bank); +extern int _stm32_switchFlashBank(int bank); /* Range = 0 - forbidden, 1 - 1.8V, 2 - 1.5V, 3 - 1.2V */ From 56aeaf46ca54c5e8eea7708ec3fa30e7fda61beb Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Fri, 6 Mar 2026 14:17:43 +0100 Subject: [PATCH 06/10] hal/stm32u3: enable bankswitch command support Enable Flash bank switch support for STM32U3 family of microcontrollers: - add Flash controller register definition - enable bankswitch command in Makefile Signed-off-by: Mateusz Karcz --- hal/armv8m/stm32/u3/Makefile | 2 +- hal/armv8m/stm32/u3/stm32u3.c | 99 ++++++++++++++++++++++++++++++ hal/armv8m/stm32/u3/stm32u3.h | 18 ++++++ hal/armv8m/stm32/u3/stm32u3_regs.h | 56 +++++++++++++++++ 4 files changed, 174 insertions(+), 1 deletion(-) diff --git a/hal/armv8m/stm32/u3/Makefile b/hal/armv8m/stm32/u3/Makefile index da6a7b13..ab3bc095 100644 --- a/hal/armv8m/stm32/u3/Makefile +++ b/hal/armv8m/stm32/u3/Makefile @@ -13,7 +13,7 @@ LDFLAGS := $(filter-out -Tdata% , $(LDFLAGS)) CFLAGS := $(filter-out -mfloat-abi% , $(CFLAGS)) CFLAGS += -mfloat-abi=soft -PLO_COMMANDS ?= alias app blob call console copy devices dump echo go help kernelimg \ +PLO_COMMANDS ?= alias app bankswitch blob call console copy devices dump echo go help kernelimg \ map mem phfs reboot script stop wait PLO_ALLDEVICES := flash-stm32 uart-stm32 ram-storage diff --git a/hal/armv8m/stm32/u3/stm32u3.c b/hal/armv8m/stm32/u3/stm32u3.c index eabbf156..87f4e8cf 100644 --- a/hal/armv8m/stm32/u3/stm32u3.c +++ b/hal/armv8m/stm32/u3/stm32u3.c @@ -35,6 +35,14 @@ #define SYSCFG_BASE ((void *)0x40040400) #define RAMCFG_BASE ((void *)0x40026000) #define ICB_BASE ((void *)0xe000e000) +#define FLASH_BASE ((void *)0x40022000) + +/* OPTWERR | PGSERR | SIZERR | PGAERR | WRPERR | PROGERR | OPERR */ +#define FLASH_ERROR_MASK ((1 << 13) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1)) +#define FLASH_KEY1 0x45670123 +#define FLASH_KEY2 0xcdef89ab +#define FLASH_OPTKEY1 0x08192a3b +#define FLASH_OPTKEY2 0x4c5d6e7f static struct { volatile u32 *rcc; @@ -44,6 +52,7 @@ static struct { volatile u32 *syscfg; volatile u32 *iwdg; volatile u32 *ramcfg; + volatile u32 *flash; u32 cpuclk; u32 hsiRefs; @@ -491,6 +500,95 @@ int _stm32_gpioConfig(unsigned int d, u8 pin, u8 mode, u8 af, u8 otype, u8 ospee } +/* Flash banks */ + + +int _stm32_getFlashBank(void) +{ + return (*(stm32_common.flash + flash_optr) >> 20) & 1; +} + + +int _stm32_switchFlashBank(int bank) +{ + int err = -EIO, vrange; + time_t start; + u32 optr; + + if (bank == _stm32_getFlashBank()) { + return 0; + } + + if ((bank < 0) || (bank > 1)) { + return -EINVAL; + } + + if (*(stm32_common.flash + flash_sr) & (1 << 16)) { /* BSY */ + return -EBUSY; + } + + /* Unlock Flash control registers */ + *(stm32_common.flash + flash_keyr) = FLASH_KEY1; + *(stm32_common.flash + flash_keyr) = FLASH_KEY2; + if (*(stm32_common.flash + flash_cr) & (1 << 31)) { /* LOCK */ + return -EPERM; + } + + /* Unlock Flash option-byte */ + *(stm32_common.flash + flash_optkeyr) = FLASH_OPTKEY1; + *(stm32_common.flash + flash_optkeyr) = FLASH_OPTKEY2; + if (*(stm32_common.flash + flash_cr) & (1 << 30)) { /* OPTLOCK */ + return -EPERM; + } + + /* Modify bank selection */ + optr = *(stm32_common.flash + flash_optr) & ~(1 << 20); + if (bank != 0) { + optr |= (1 << 20); /* Set SWAP_BANK */ + } + *(stm32_common.flash + flash_optr) = optr; + + /* Clear previous errors */ + *(stm32_common.flash + flash_sr) |= FLASH_ERROR_MASK; + + /* Ensure proper voltage range for Flash programming */ + vrange = _stm32_pwrGetCPUVolt(); + if ((vrange == 2) || (vrange == 2 - BOOSTEN)) { + _stm32_pwrSetCPUVolt(vrange - 1); + } + + /* Commit option-byte */ + start = hal_timerGet(); + *(stm32_common.flash + flash_cr) |= (1 << 17); /* OPTSTRT */ + while (*(stm32_common.flash + flash_sr) & (1 << 16)) { + /* Wait for BSY to clear */ + if ((hal_timerGet() - start) > 100) { + _stm32_pwrSetCPUVolt(vrange); + return -ETIMEDOUT; + } + } + + if ((*(stm32_common.flash + flash_sr) & FLASH_ERROR_MASK) == 0) { + /* Reload option-byte */ + start = hal_timerGet(); + *(stm32_common.flash + flash_cr) |= (1 << 27); /* OBL_LAUNCH */ + while (*(stm32_common.flash + flash_cr) & (1 << 27)) { + /* Wait for reset to happen (no return on success) */ + if ((hal_timerGet() - start) > 100) { + err = -ETIMEDOUT; + break; + } + } + + /* Option byte loader reset should've happened by this point */ + } + + /* Definitely a failure */ + _stm32_pwrSetCPUVolt(vrange); + return err; +} + + /* Watchdog */ @@ -564,6 +662,7 @@ void _stm32_init(void) stm32_common.iwdg = IWDG_BASE; stm32_common.syscfg = SYSCFG_BASE; stm32_common.ramcfg = RAMCFG_BASE; + stm32_common.flash = FLASH_BASE; stm32_common.gpio[0] = GPIOA_BASE; stm32_common.gpio[1] = GPIOB_BASE; stm32_common.gpio[2] = GPIOC_BASE; diff --git a/hal/armv8m/stm32/u3/stm32u3.h b/hal/armv8m/stm32/u3/stm32u3.h index a38058b5..7055982a 100644 --- a/hal/armv8m/stm32/u3/stm32u3.h +++ b/hal/armv8m/stm32/u3/stm32u3.h @@ -267,6 +267,24 @@ extern u32 _stm32_rccGetPclkClock(void); extern int _stm32_gpioConfig(unsigned int d, u8 pin, u8 mode, u8 af, u8 otype, u8 ospeed, u8 pupd); +/* Get the active Flash bank index */ +extern int _stm32_getFlashBank(void); + + +/* Set the active Flash bank (0 or 1) and trigger option-byte reload. + * + * Returns: + * no return - new bank selected, system reset triggered + * 0 - requested bank already active + * -EBUSY - Flash controller busy + * -EINVAL - invalid bank index + * -EIO - Flash controller error during operation + * -EPERM - Flash option registers could not be unlocked + * -ETIMEDOUT - Flash operation did not complete in time + */ +extern int _stm32_switchFlashBank(int bank); + + /* Get CPU core voltage range * 1 - 0.9 V, 2 - 0.75 V, subtracted 256 - EPOD booster is enabled */ diff --git a/hal/armv8m/stm32/u3/stm32u3_regs.h b/hal/armv8m/stm32/u3/stm32u3_regs.h index 598fcdb0..308e7449 100644 --- a/hal/armv8m/stm32/u3/stm32u3_regs.h +++ b/hal/armv8m/stm32/u3/stm32u3_regs.h @@ -175,4 +175,60 @@ enum ramcfg_regs { ramcfg_sram3erkeyr, }; +enum flash_regs { + flash_acr = 0x0, + flash_keyr = 0x2, + flash_skeyr, + flash_optkeyr, + flash_pdkey1r = 0x6, + flash_pdkey2r, + flash_sr, + flash_ssr, + flash_cr, + flash_scr, + flash_ecccr, + flash_eccdr, + flash_opsr, + flash_optr = 0x10, + flash_boot0r, + flash_boot1r, + flash_sboot0r, + flash_secwm1r1, + flash_secwm1r2, + flash_wrp1ar, + flash_wrp1br, + flash_secwm2r1, + flash_secwm2r2, + flash_wrp2ar, + flash_wrp2br, + flash_secbb1r1 = 0x20, + flash_secbb1r2, + flash_secbb1r3, + flash_secbb1r4, + flash_secbb2r1 = 0x28, + flash_secbb2r2, + flash_secbb2r3, + flash_secbb2r4, + flash_sechdpcr = 0x30, + flash_privcfgr, + flash_sechdpextr, + flash_privbb1r1 = 0x34, + flash_privbb1r2, + flash_privbb1r3, + flash_privbb1r4, + flash_privbb2r1 = 0x3c, + flash_privbb2r2, + flash_privbb2r3, + flash_privbb2r4, + flash_oem1keyr1 = 0x44, + flash_oem1keyr2, + flash_oem1keyr3, + flash_oem1keyr4, + flash_oem2keyr1, + flash_oem2keyr2, + flash_oem2keyr3, + flash_oem2keyr4, + flash_oemkeysr, +}; + #endif /* _STM32U3_REGS_H_ */ From 9a03fedeed9ab1fb06c704319edbbe8386d4ba8a Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Fri, 6 Mar 2026 14:18:53 +0100 Subject: [PATCH 07/10] cmds: report bank switching error status Report the error code if the call to _stm32_switchFlashBank failed. Signed-off-by: Mateusz Karcz --- cmds/bankswitch.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cmds/bankswitch.c b/cmds/bankswitch.c index 89fa49e4..75bb1c1d 100644 --- a/cmds/bankswitch.c +++ b/cmds/bankswitch.c @@ -6,7 +6,8 @@ * Switch Flash Banks * * Copyright 2022 Phoenix Systems - * Author: Aleksander Kaminski + * Copyright 2026 Apator Metrix + * Author: Aleksander Kaminski, Mateusz Karcz * * This file is part of Phoenix-RTOS. * @@ -41,7 +42,14 @@ static int cmd_bankswitch(int argc, char *argv[]) } if (err == CMD_EXIT_SUCCESS) { - _stm32_switchFlashBank(targetBank); + int switchErr = _stm32_switchFlashBank(targetBank); + if (switchErr < 0) { + log_error("\n%s: Bank switch failed (%d)", argv[0], switchErr); + err = CMD_EXIT_FAILURE; + } + } + + if (err == CMD_EXIT_SUCCESS) { log_info("\n%s: Bank switch successful (%d -> %d)", argv[0], (targetBank == 0) ? 1 : 0, targetBank); } From 084472296204415de19331f030be7ab03e9f5730 Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Tue, 10 Mar 2026 12:06:44 +0100 Subject: [PATCH 08/10] hal/stm32u3: parameterize memory size Allow memory size selection for STM32U3 family of microcontrollers: - FLASH_SIZE environment variable for program Flash bank size - RAM_SIZE environment variable for total SRAM capacity Signed-off-by: Mateusz Karcz --- hal/armv8m/stm32/u3/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hal/armv8m/stm32/u3/Makefile b/hal/armv8m/stm32/u3/Makefile index ab3bc095..4bef632b 100644 --- a/hal/armv8m/stm32/u3/Makefile +++ b/hal/armv8m/stm32/u3/Makefile @@ -13,6 +13,13 @@ LDFLAGS := $(filter-out -Tdata% , $(LDFLAGS)) CFLAGS := $(filter-out -mfloat-abi% , $(CFLAGS)) CFLAGS += -mfloat-abi=soft +ifneq (,$(FLASH_SIZE)) + CFLAGS += -DFLASH_PROGRAM_BANK_SIZE=$(FLASH_SIZE) +endif +ifneq (,$(RAM_SIZE)) + CFLAGS += -DRAM_BANK_SIZE=$(RAM_SIZE) +endif + PLO_COMMANDS ?= alias app bankswitch blob call console copy devices dump echo go help kernelimg \ map mem phfs reboot script stop wait From c7820c638a5fd17d1b4807177bd5aa644a6f4183 Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Mon, 23 Mar 2026 15:47:37 +0100 Subject: [PATCH 09/10] devices/uart-stm32: enable board specific UART selection Take UARTx macros from . Signed-off-by: Mateusz Karcz --- devices/uart-stm32/uart.c | 1 + hal/armv8m/stm32/console.c | 3 +-- hal/armv8m/stm32/u3/stm32u3.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/devices/uart-stm32/uart.c b/devices/uart-stm32/uart.c index 69a62046..88cae462 100644 --- a/devices/uart-stm32/uart.c +++ b/devices/uart-stm32/uart.c @@ -14,6 +14,7 @@ * %LICENSE% */ +#include #include #include #include diff --git a/hal/armv8m/stm32/console.c b/hal/armv8m/stm32/console.c index 6a2c37be..f13916ca 100644 --- a/hal/armv8m/stm32/console.c +++ b/hal/armv8m/stm32/console.c @@ -14,11 +14,10 @@ * %LICENSE% */ +#include #include #include -#include - #include "stm32.h" #if !ISEMPTY(UART_CONSOLE_PLO) diff --git a/hal/armv8m/stm32/u3/stm32u3.c b/hal/armv8m/stm32/u3/stm32u3.c index 87f4e8cf..c7c4a35e 100644 --- a/hal/armv8m/stm32/u3/stm32u3.c +++ b/hal/armv8m/stm32/u3/stm32u3.c @@ -14,8 +14,8 @@ * %LICENSE% */ -#include #include +#include #include #include "stm32u3.h" From d9799026d5e1fcc250deb15292b8476dad0ec8c3 Mon Sep 17 00:00:00 2001 From: Mateusz Karcz Date: Mon, 23 Mar 2026 15:51:48 +0100 Subject: [PATCH 10/10] hal/stm32u3: enable UARTs used for TTYs Allow using a single UART for both PLO UART and Phoenix-RTOS TTY. Signed-off-by: Mateusz Karcz --- hal/armv8m/stm32/u3/peripherals.h | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/hal/armv8m/stm32/u3/peripherals.h b/hal/armv8m/stm32/u3/peripherals.h index 80a6625a..d5633a2b 100644 --- a/hal/armv8m/stm32/u3/peripherals.h +++ b/hal/armv8m/stm32/u3/peripherals.h @@ -51,24 +51,44 @@ #define UART_MAX_CNT 5 #ifndef UART1 +#ifdef TTY1 +#define UART1 TTY1 +#else #define UART1 1 #endif +#endif -#ifndef UART2 -#define UART2 0 /* STM32U396xx / STM32U3A6xx / STM32U3C5xx */ +#ifndef UART2 /* STM32U396xx / STM32U3A6xx / STM32U3B5xx / STM32U3C5xx */ +#ifdef TTY2 +#define UART2 TTY2 +#else +#define UART2 0 +#endif #endif #ifndef UART3 +#ifdef TTY3 +#define UART3 TTY3 +#else #define UART3 0 #endif +#endif #ifndef UART4 +#ifdef TTY4 +#define UART4 TTY4 +#else #define UART4 0 #endif +#endif #ifndef UART5 +#ifdef TTY5 +#define UART5 TTY5 +#else #define UART5 0 #endif +#endif #define UART_BAUDRATE 115200