diff --git a/arch/arm/src/stm32h5/Kconfig b/arch/arm/src/stm32h5/Kconfig index f72f3c094ce..c088ad05d85 100644 --- a/arch/arm/src/stm32h5/Kconfig +++ b/arch/arm/src/stm32h5/Kconfig @@ -2,3 +2,897 @@ # For a description of the syntax of this configuration file, # see the file kconfig-language.txt in the NuttX tools repository. # + +if ARCH_CHIP_STM32H5 + +comment "STM32H5 Configuration Options" + +choice + prompt "STM32 H5 Chip Selection" + default ARCH_CHIP_STM32H563ZI + depends on ARCH_CHIP_STM32H5 + +config ARCH_CHIP_STM32H563ZI + bool "STM32H563ZI" + select STM32H5_STM32H5XXXX + select STM32H5_STM32H56XXX + select STM32H5_STM32H563XX + select STM32H5_FLASH_CONFIG_I + select STM32H5_IO_CONFIG_Z + ---help--- + STM32 H5 Cortex M33, 512 Kb FLASH, 256 Kb SRAM + +endchoice # STM32 H5 Chip Selection + +# Chip families: + +config STM32H5_STM32H5XXXX + bool + default n + select ARCH_HAVE_FPU + +config STM32H5_STM32H56XXX + bool + default n + select STM32H5_HAVE_LPUART1 + select STM32H5_HAVE_USART1 + select STM32H5_HAVE_USART2 + select STM32H5_HAVE_USART3 + select STM32H5_HAVE_UART4 + select STM32H5_HAVE_UART5 + select STM32H5_HAVE_USART6 + select STM32H5_HAVE_UART7 + select STM32H5_HAVE_UART8 + select STM32H5_HAVE_UART9 + select STM32H5_HAVE_USART10 + select STM32H5_HAVE_USART11 + select STM32H5_HAVE_UART12 + +config STM32H5_STM32H563XX + # STM32H552 and STM32H562 devices documented in RM0439 + bool + default n + +choice + prompt "Override Flash Size Designator" + depends on ARCH_CHIP_STM32H5 + default STM32H5_FLASH_OVERRIDE_DEFAULT + ---help--- + STM32H5 series parts numbering (sans the package type) ends with a letter + that designates the FLASH size. + + Designator Size in KiB + 8 64 + B 128 + C 256 + E 512 + G 1024 + I 2048 + + This configuration option defaults to using the configuration based on that designator + or the default smaller size if there is no last character designator is present in the + STM32 Chip Selection. + + Examples: + If the STM32H576VE is chosen, the Flash configuration would be 'E', if a variant of + the part with a 1024 KiB Flash is released in the future one could simply select + the 'G' designator here. + + If an STM32H5xxx Series parts is chosen the default Flash configuration will be set + herein and can be changed. + +config STM32H5_FLASH_OVERRIDE_DEFAULT + bool "Default" + +config STM32H5_FLASH_OVERRIDE_8 + bool "8 64 KB" + +config STM32H5_FLASH_OVERRIDE_B + bool "B 128 KB" + +config STM32H5_FLASH_OVERRIDE_C + bool "C 256 KB" + +config STM32H5_FLASH_OVERRIDE_E + bool "E 512 KB" + +config STM32H5_FLASH_OVERRIDE_G + bool "G 1024 KB" + +config STM32H5_FLASH_OVERRIDE_I + bool "I 2048 KB" + +endchoice # "Override Flash Size Designator" + +# Flash configurations + +config STM32H5_FLASH_CONFIG_B + bool + default n + depends on STM32H5_STM32H50XXX + +config STM32H5_FLASH_CONFIG_C + bool + default n + depends on STM32H5_STM32H52XXX + +config STM32H5_FLASH_CONFIG_E + bool + default n + depends on STM32H5_STM32H52XXX || STM32H5_STM32H53XXX + +config STM32H5_FLASH_CONFIG_G + bool + default n + depends on STM32H5_STM32H6XXX + +config STM32H5_FLASH_CONFIG_I + bool + default n + depends on STM32H5_STM32H56XXX || STM32H5_STM32H57XXX + +# Pin/package configurations + +config STM32H5_IO_CONFIG_K + bool + default n + +config STM32H5_IO_CONFIG_T + bool + default n + +config STM32H5_IO_CONFIG_C + bool + default n + +config STM32H5_IO_CONFIG_R + bool + default n + +config STM32H5_IO_CONFIG_J + bool + default n + +config STM32H5_IO_CONFIG_M + bool + default n + +config STM32H5_IO_CONFIG_V + bool + default n + +config STM32H5_IO_CONFIG_Q + bool + default n + +config STM32H5_IO_CONFIG_Z + bool + default n + +config STM32H5_IO_CONFIG_A + bool + default n + +comment "STM32H5 SRAM2 Options" + +config STM32H5_SRAM2_HEAP + bool "SRAM2 is used for heap" + default n + select STM32H5_SRAM2_INIT + +config STM32H5_SRAM2_INIT + bool "SRAM2 is initialized to zero" + default n + ---help--- + If the SRAM2 is being used for it's battery-backed capability, + this may be undesirable (because it will destroy the contents). In that + case, the board should handle the initialization itself at the appropriate + time. + +comment "STM32H5 Peripherals" + +menu "STM32H5 Peripheral Support" + +# These "hidden" settings determine is a peripheral option is available for the +# selection MCU + +config STM32H5_HAVE_LPUART1 + bool + default n + +config STM32H5_HAVE_USART1 + bool + default n + +config STM32H5_HAVE_USART2 + bool + default n + +config STM32H5_HAVE_USART3 + bool + default n + +config STM32H5_HAVE_UART4 + bool + default n + +config STM32H5_HAVE_UART5 + bool + default n + +config STM32H5_HAVE_USART6 + bool + default n + +config STM32H5_HAVE_UART7 + bool + default n + +config STM32H5_HAVE_UART8 + bool + default n + +config STM32H5_HAVE_UART9 + bool + default n + +config STM32H5_HAVE_USART10 + bool + default n + +config STM32H5_HAVE_USART11 + bool + default n + +config STM32H5_HAVE_UART12 + bool + default n + +# These "hidden" settings are the OR of individual peripheral selections +# indicating that the general capability is required. + +config STM32H5_USART + bool + default n + +# These are the peripheral selections proper + +comment "AHB1 Peripherals" + +# TODO +# GPDMA1, GPDMA2 +# FLITF +# CRC +# CORDIC +# FMAC +# RAMCFG +# ETH, ETHTX, ETHRX +# TZSC1 +# BKPRAM +# DCACHE +# SRAM1 + +comment "AHB2 Peripherals" + +# TODO +# GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOH, GPIOI +# ADC +# DAC1 +# DCMI_PSSI +# AES +# HASH +# RNG +# PKA +# SAES +# SRAM2, SRAM3 + +comment "AHB4 Peripherals" + +# TODO +# OTFDEC1 +# SDMMC1, SDMMC2 +# FMC +# OCTOSPI1 + +comment "APB1L Peripherals" + +# TODO +# TIM2, TIM3, TIM4, TIM5, TIM6, TIM7 +# TIM12, TIM13, TIM14 +# WWDGEN +# SPI2, SPI3 +# CEC +# +config STM32H5_USART2 + bool "USART2" + default n + depends on STM32H5_HAVE_USART2 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_USART3 + bool "USART3" + default n + depends on STM32H5_HAVE_USART3 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_UART4 + bool "UART4" + default n + depends on STM32H5_HAVE_UART4 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_UART5 + bool "UART5" + default n + depends on STM32H5_HAVE_UART5 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_USART6 + bool "USART6" + default n + depends on STM32H5_HAVE_USART6 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_UART7 + bool "UART7" + default n + depends on STM32H5_HAVE_UART7 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_UART8 + bool "UART8" + default n + depends on STM32H5_HAVE_UART8 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_USART10 + bool "USART10" + default n + depends on STM32H5_HAVE_USART10 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_USART11 + bool "USART11" + default n + depends on STM32H5_HAVE_USART11 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +comment "APB1H Peripherals" + +# TODO +# DTS +# LPTIM2 +# FDCAN +# UCPD1 + +config STM32H5_UART9 + bool "UART9" + default n + depends on STM32H5_HAVE_UART9 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +config STM32H5_UART12 + bool "UART12" + default n + depends on STM32H5_HAVE_UART12 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +comment "APB2 Peripherals" + +# TODO +# TIM1, TIM8, TIM15, TIM16, TIM17 +# SPI1, SPI4, SPI6 +# SAI1, SAI2 +# USBEN + +config STM32H5_USART1 + bool "USART1" + default n + depends on STM32H5_HAVE_USART1 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +comment "APB3 Peripherals" + +config STM32H5_LPUART1 + bool "LPUART1" + default n + depends on STM32H5_HAVE_LPUART1 + select ARCH_HAVE_SERIAL_TERMIOS + select STM32H5_USART + +# TODO +# SBS +# SPI5 +# I2C3, I2C4, I3C2 +# LPTIM1, LPTIM3, LPTIM4, LPTIM5, LPTIM6 +# VREFBUF +# RTCAPB + +endmenu + + +config STM32H5_FLASH_PREFETCH + bool "Enable FLASH Pre-fetch" + default y + ---help--- + Enable FLASH prefetch + +config STM32H5_DISABLE_IDLE_SLEEP_DURING_DEBUG + bool "Disable IDLE Sleep (WFI) in debug mode" + default n + ---help--- + In debug configuration, disables the WFI instruction in the IDLE loop + to prevent the JTAG from disconnecting. With some JTAG debuggers, such + as the ST-LINK2 with OpenOCD, if the ARM is put to sleep via the WFI + instruction, the debugger will disconnect, terminating the debug session. + +config ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG + bool "Custom clock configuration" + default n + ---help--- + Enables special, board-specific STM32 clock configuration. + +config STM32H5_SERIALDRIVER + bool + +menu "[LP]U[S]ART Configuration" + depends on STM32H5_USART + +choice + prompt "LPUART1 Driver Configuration" + default STM32H5_LPUART1_SERIALDRIVER + depends on STM32H5_LPUART1 + +config STM32H5_LPUART1_SERIALDRIVER + bool "Standard serial driver" + select LPUART1_SERIALDRIVER + select STM32H5_SERIALDRIVER + +endchoice # LPUART1 Driver Configuration + +if LPUART1_SERIALDRIVER + +config LPUART1_RS485 + bool "RS-485 on LPUART1" + default n + depends on STM32H5_LPUART1 + ---help--- + Enable RS-485 interface on LPUART1. Your board config will have to + provide GPIO_LPUART1_RS485_DIR pin definition. Currently it cannot be + used with LPUART1_RXDMA. + +config LPUART1_RS485_DIR_POLARITY + int "LPUART1 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on LPUART1_RS485 + ---help--- + Polarity of DIR pin for RS-485 on LPUART1. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # LPUART1_SERIALDRIVER + +choice + prompt "USART1 Driver Configuration" + default STM32H5_USART1_SERIALDRIVER + depends on STM32H5_USART1 + +config STM32H5_USART1_SERIALDRIVER + bool "Standard serial driver" + select USART1_SERIALDRIVER + select STM32H5_SERIALDRIVER + +endchoice # USART1 Driver Configuration + +if USART1_SERIALDRIVER + +config USART1_RS485 + bool "RS-485 on USART1" + default n + depends on STM32H5_USART1 + ---help--- + Enable RS-485 interface on USART1. Your board config will have to + provide GPIO_USART1_RS485_DIR pin definition. Currently it cannot be + used with USART1_RXDMA. + +config USART1_RS485_DIR_POLARITY + int "USART1 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART1_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART1. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART1_SERIALDRIVER + +choice + prompt "USART2 Driver Configuration" + default STM32H5_USART2_SERIALDRIVER + depends on STM32H5_USART2 + +config STM32H5_USART2_SERIALDRIVER + bool "Standard serial driver" + select USART2_SERIALDRIVER + select STM32H5_SERIALDRIVER + +endchoice # USART2 Driver Configuration + +if USART2_SERIALDRIVER + +config USART2_RS485 + bool "RS-485 on USART2" + default n + depends on STM32H5_USART2 + ---help--- + Enable RS-485 interface on USART2. Your board config will have to + provide GPIO_USART2_RS485_DIR pin definition. Currently it cannot be + used with USART2_RXDMA. + +config USART2_RS485_DIR_POLARITY + int "USART2 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART2_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART2. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART2_SERIALDRIVER + +choice + prompt "USART3 Driver Configuration" + default STM32H5_USART3_SERIALDRIVER + depends on STM32H5_USART3 + +config STM32H5_USART3_SERIALDRIVER + bool "Standard serial driver" + select USART3_SERIALDRIVER + select STM32H5_SERIALDRIVER + +endchoice # USART3 Driver Configuration + +if USART3_SERIALDRIVER + +config USART3_RS485 + bool "RS-485 on USART3" + default n + depends on STM32H5_USART3 + ---help--- + Enable RS-485 interface on USART3. Your board config will have to + provide GPIO_USART3_RS485_DIR pin definition. Currently it cannot be + used with USART3_RXDMA. + +config USART3_RS485_DIR_POLARITY + int "USART3 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART3_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART3. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART3_SERIALDRIVER + +choice + prompt "UART4 Driver Configuration" + default STM32H5_UART4_SERIALDRIVER + depends on STM32H5_UART4 + +config STM32H5_UART4_SERIALDRIVER + bool "Standard serial driver" + select UART4_SERIALDRIVER + select STM32H5_SERIALDRIVER + +endchoice # UART4 Driver Configuration + +if UART4_SERIALDRIVER + +config UART4_RS485 + bool "RS-485 on UART4" + default n + depends on STM32H5_UART4 + ---help--- + Enable RS-485 interface on UART4. Your board config will have to + provide GPIO_UART4_RS485_DIR pin definition. Currently it cannot be + used with UART4_RXDMA. + +config UART4_RS485_DIR_POLARITY + int "UART4 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART4_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART4. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # UART4_SERIALDRIVER + +choice + prompt "UART5 Driver Configuration" + default STM32H5_UART5_SERIALDRIVER + depends on STM32H5_UART5 + +config STM32H5_UART5_SERIALDRIVER + bool "Standard serial driver" + select UART5_SERIALDRIVER + select STM32H5_SERIALDRIVER + +endchoice # UART5 Driver Configuration + +if UART5_SERIALDRIVER + +config UART5_RS485 + bool "RS-485 on UART5" + default n + depends on STM32H5_UART5 + ---help--- + Enable RS-485 interface on UART5. Your board config will have to + provide GPIO_UART5_RS485_DIR pin definition. Currently it cannot be + used with UART5_RXDMA. + +config UART5_RS485_DIR_POLARITY + int "UART5 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART5_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART5. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # UART5_SERIALDRIVER + +if USART6_SERIALDRIVER + +config USART6_RS485 + bool "RS-485 on USART6" + default n + depends on STM32H5_USART6 + ---help--- + Enable RS-485 interface on USART6. Your board config will have to + provide GPIO_USART6_RS485_DIR pin definition. Currently it cannot be + used with USART6_RXDMA. + +config USART6_RS485_DIR_POLARITY + int "USART6 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART6_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART6. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART6_SERIALDRIVER + +if UART7_SERIALDRIVER + +config UART7_RS485 + bool "RS-485 on UART7" + default n + depends on STM32H5_UART7 + ---help--- + Enable RS-485 interface on UART7. Your board config will have to + provide GPIO_UART7_RS485_DIR pin definition. Currently it cannot be + used with UART7_RXDMA. + +config UART7_RS485_DIR_POLARITY + int "UART7 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART7_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART7. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # UART7_SERIALDRIVER + +if UART8_SERIALDRIVER + +config UART8_RS485 + bool "RS-485 on UART8" + default n + depends on STM32H5_UART8 + ---help--- + Enable RS-485 interface on UART8. Your board config will have to + provide GPIO_UART8_RS485_DIR pin definition. Currently it cannot be + used with UART8_RXDMA. + +config UART8_RS485_DIR_POLARITY + int "UART8 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART8_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART8. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # UART8_SERIALDRIVER + +if UART9_SERIALDRIVER + +config UART9_RS485 + bool "RS-485 on UART9" + default n + depends on STM32H5_UART9 + ---help--- + Enable RS-485 interface on UART9. Your board config will have to + provide GPIO_UART9_RS485_DIR pin definition. Currently it cannot be + used with UART9_RXDMA. + +config UART9_RS485_DIR_POLARITY + int "UART9 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART9_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART9. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # UART9_SERIALDRIVER + +if USART10_SERIALDRIVER + +config USART10_RS485 + bool "RS-485 on USART10" + default n + depends on STM32H5_USART10 + ---help--- + Enable RS-485 interface on USART10. Your board config will have to + provide GPIO_USART10_RS485_DIR pin definition. Currently it cannot be + used with USART10_RXDMA. + +config USART10_RS485_DIR_POLARITY + int "USART10 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART10_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART10. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART10_SERIALDRIVER + +if USART11_SERIALDRIVER + +config USART11_RS485 + bool "RS-485 on USART11" + default n + depends on STM32H5_USART11 + ---help--- + Enable RS-485 interface on USART11. Your board config will have to + provide GPIO_USART11_RS485_DIR pin definition. Currently it cannot be + used with USART11_RXDMA. + +config USART11_RS485_DIR_POLARITY + int "USART11 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART11_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART11. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART11_SERIALDRIVER + +if UART12_SERIALDRIVER + +config UART12_RS485 + bool "RS-485 on UART12" + default n + depends on STM32H5_UART12 + ---help--- + Enable RS-485 interface on UART12. Your board config will have to + provide GPIO_UART12_RS485_DIR pin definition. Currently it cannot be + used with UART12_RXDMA. + +config UART12_RS485_DIR_POLARITY + int "UART12 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART12_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART12. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # UART12_SERIALDRIVER + +if STM32H5_SERIALDRIVER + +comment "Serial Driver Configuration" + +config STM32H5_SERIAL_DISABLE_REORDERING + bool "Disable reordering of ttySx devices." + depends on STM32H5_USART1 || STM32H5_USART2 || STM32H5_USART3 || STM32H5_UART4 || STM32H5_UART5 + default n + ---help--- + NuttX per default reorders the serial ports (/dev/ttySx) so that the + console is always on /dev/ttyS0. If more than one UART is in use this + can, however, have the side-effect that all port mappings + (hardware USART1 -> /dev/ttyS0) change if the console is moved to another + UART. This is in particular relevant if a project uses the USB console + in some boards and a serial console in other boards, but does not + want the side effect of having all serial port names change when just + the console is moved from serial to USB. + +config STM32H5_FLOWCONTROL_BROKEN + bool "Use Software UART RTS flow control" + depends on STM32H5_USART + default n + ---help--- + Enable UART RTS flow control using Software. Because STM + Current STM32 have broken HW based RTS behavior (they assert + nRTS after every byte received) Enable this setting workaround + this issue by using software based management of RTS + +config STM32H5_USART_BREAKS + bool "Add TIOxSBRK to support sending Breaks" + depends on STM32H5_USART + default n + ---help--- + Add TIOCxBRK routines to send a line break per the STM32 manual, the + break will be a pulse based on the value M. This is not a BSD compatible + break. + +config STM32H5_SERIALBRK_BSDCOMPAT + bool "Use GPIO To send Break" + depends on STM32H5_USART && STM32H5_USART_BREAKS + default n + ---help--- + Enable using GPIO on the TX pin to send a BSD compatible break: + TIOCSBRK will start the break and TIOCCBRK will end the break. + The current STM32H5 U[S]ARTS have no way to leave the break on + (TX=LOW) because software starts the break and then the hardware + automatically clears the break. This makes it difficult to send + a long break. + +config STM32H5_USART_SINGLEWIRE + bool "Single Wire Support" + default n + depends on STM32H5_USART + ---help--- + Enable single wire UART support. The option enables support for the + TIOCSSINGLEWIRE ioctl in the STM32H5 serial driver. + +config STM32H5_USART_INVERT + bool "Signal Invert Support" + default n + depends on STM32H5_USART + ---help--- + Enable signal inversion UART support. The option enables support for the + TIOCSINVERT ioctl in the STM32H5 serial driver. + +config STM32H5_USART_SWAP + bool "Swap RX/TX pins support" + default n + depends on STM32H5_USART + ---help--- + Enable RX/TX pin swapping support. The option enables support for the + TIOCSSWAP ioctl in the STM32H5 serial driver. + +if PM + +config STM32H5_PM_SERIAL_ACTIVITY + int "PM serial activity" + default 10 + ---help--- + PM activity reported to power management logic on every serial + interrupt. + +endif +endif # STM32H5_SERIALDRIVER + +endmenu # U[S]ART Configuration + +endif # ARCH_CHIP_STM32H5 diff --git a/arch/arm/src/stm32h5/Make.defs b/arch/arm/src/stm32h5/Make.defs index d207672a2ba..56cce6201a3 100644 --- a/arch/arm/src/stm32h5/Make.defs +++ b/arch/arm/src/stm32h5/Make.defs @@ -26,3 +26,26 @@ HEAD_ASRC = # Common ARM and Cortex-M4 files (copied from stm32/Make.defs) include armv8-m/Make.defs + +# Required STM32H5 files + +CHIP_ASRCS = +CHIP_CSRCS = stm32_gpio.c +CHIP_CSRCS += stm32_irq.c stm32_lowputc.c stm32_rcc.c +CHIP_CSRCS += stm32_serial.c stm32_start.c +CHIP_CSRCS += stm32_pwr.c stm32_timerisr.c +CHIP_CSRCS += stm32_lse.c stm32_lsi.c + +ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y) +CHIP_CSRCS += stm32_idle.c +endif + +ifeq ($(CONFIG_TIMER),y) +CHIP_CSRCS += stm32h5_tim_lowerhalf.c +endif + +# Required chip type specific files + +ifeq ($(CONFIG_STM32H5_STM32H5XXXX),y) +CHIP_CSRCS += stm32h5xx_rcc.c +endif diff --git a/arch/arm/src/stm32h5/stm32.h b/arch/arm/src/stm32h5/stm32.h index ff1bf9b3ca2..28d97cac6f8 100644 --- a/arch/arm/src/stm32h5/stm32.h +++ b/arch/arm/src/stm32h5/stm32.h @@ -36,5 +36,10 @@ #include "chip.h" #include "stm32_flash.h" - +#include "stm32_dbgmcu.h" +#include "stm32_gpio.h" +#include "stm32_pwr.h" +#include "stm32_rcc.h" +#include "stm32_uart.h" +#include "stm32_lowputc.h" #endif /* __ARCH_ARM_SRC_STM32H5_STM32_H */ diff --git a/arch/arm/src/stm32h5/stm32_dbgmcu.h b/arch/arm/src/stm32h5/stm32_dbgmcu.h new file mode 100644 index 00000000000..5de96b2ed14 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_dbgmcu.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_dbgmcu.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H5_STM32_DBGMCU_H +#define __ARCH_ARM_SRC_STM32H5_STM32_DBGMCU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +#if defined(CONFIG_STM32H5_STM32H5XXXX) +# include "hardware/stm32_dbgmcu.h" +#else +# error "Unsupported STM32H5 chip" +#endif + +#endif /* __ARCH_ARM_SRC_STM32H5_STM32_DBGMCU_H */ diff --git a/arch/arm/src/stm32h5/stm32_gpio.c b/arch/arm/src/stm32h5/stm32_gpio.c new file mode 100644 index 00000000000..af2165fc176 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_gpio.c @@ -0,0 +1,397 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_gpio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "stm32_gpio.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Base addresses for each GPIO block */ + +const uint32_t g_gpiobase[STM32H5_NPORTS] = +{ +#if STM32H5_NPORTS > 0 + STM32_GPIOA_BASE, +#endif +#if STM32H5_NPORTS > 1 + STM32_GPIOB_BASE, +#endif +#if STM32H5_NPORTS > 2 + STM32_GPIOC_BASE, +#endif +#if STM32H5_NPORTS > 3 + STM32_GPIOD_BASE, +#endif +#if STM32H5_NPORTS > 4 + STM32_GPIOE_BASE, +#endif +#if STM32H5_NPORTS > 5 + STM32_GPIOF_BASE, +#endif +#if STM32H5_NPORTS > 6 + STM32_GPIOG_BASE, +#endif +#if STM32H5_NPORTS > 7 + STM32_GPIOH_BASE, +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: stm32_gpioinit + * + * Description: + * Based on configuration within the .config file, it does: + * - Remaps positions of alternative functions. + * + * Typically called from stm32h5_start(). + * + * Assumptions: + * This function is called early in the initialization sequence so that + * no mutual exclusion is necessary. + * + ****************************************************************************/ + +void stm32_gpioinit(void) +{ +} + +/**************************************************************************** + * Name: stm32_configgpio + * + * Description: + * Configure a GPIO pin based on bit-encoded description of the pin. + * Once it is configured as Alternative (GPIO_ALT|GPIO_CNF_AFPP|...) + * function, it must be unconfigured with stm32_unconfiggpio() with + * the same cfgset first before it can be set to non-alternative function. + * + * Returned Value: + * OK on success + * A negated errno value on invalid port, or when pin is locked as ALT + * function. + * + * To-Do: Auto Power Enable + ****************************************************************************/ + +int stm32_configgpio(uint32_t cfgset) +{ + uintptr_t base; + uint32_t regval; + uint32_t setting; + unsigned int regoffset; + unsigned int port; + unsigned int pin; + unsigned int pos; + unsigned int pinmode; + irqstate_t flags; + + /* Verify that this hardware supports the select GPIO port */ + + port = (cfgset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + if (port >= STM32H5_NPORTS) + { + return -EINVAL; + } + + /* Get the port base address */ + + base = g_gpiobase[port]; + + /* Get the pin number and select the port configuration register for that + * pin + */ + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + /* Set up the mode register (and remember whether the pin mode) */ + + switch (cfgset & GPIO_MODE_MASK) + { + default: + case GPIO_INPUT: /* Input mode */ + pinmode = GPIO_MODER_INPUT; + break; + + case GPIO_OUTPUT: /* General purpose output mode */ + + /* Set the initial output value */ + + stm32_gpiowrite(cfgset, (cfgset & GPIO_OUTPUT_SET) != 0); + pinmode = GPIO_MODER_OUTPUT; + break; + + case GPIO_ALT: /* Alternate function mode */ + pinmode = GPIO_MODER_ALT; + break; + + case GPIO_ANALOG: /* Analog mode */ + pinmode = GPIO_MODER_ANALOG; + break; + } + + /* Interrupts must be disabled from here on out so that we have mutually + * exclusive access to all of the GPIO configuration registers. + */ + + flags = enter_critical_section(); + + /* Now apply the configuration to the mode register */ + + regval = getreg32(base + STM32_GPIO_MODER_OFFSET); + regval &= ~GPIO_MODER_MASK(pin); + regval |= ((uint32_t)pinmode << GPIO_MODER_SHIFT(pin)); + putreg32(regval, base + STM32_GPIO_MODER_OFFSET); + + /* Set up the pull-up/pull-down configuration (all but analog pins) */ + + setting = GPIO_PUPDR_NONE; + if (pinmode != GPIO_MODER_ANALOG) + { + switch (cfgset & GPIO_PUPD_MASK) + { + default: + case GPIO_FLOAT: /* No pull-up, pull-down */ + break; + + case GPIO_PULLUP: /* Pull-up */ + setting = GPIO_PUPDR_PULLUP; + break; + + case GPIO_PULLDOWN: /* Pull-down */ + setting = GPIO_PUPDR_PULLDOWN; + break; + } + } + + regval = getreg32(base + STM32_GPIO_PUPDR_OFFSET); + regval &= ~GPIO_PUPDR_MASK(pin); + regval |= (setting << GPIO_PUPDR_SHIFT(pin)); + putreg32(regval, base + STM32_GPIO_PUPDR_OFFSET); + + /* Set the alternate function (Only alternate function pins) */ + + if (pinmode == GPIO_MODER_ALT) + { + setting = (cfgset & GPIO_AF_MASK) >> GPIO_AF_SHIFT; + } + else + { + setting = 0; + } + + if (pin < 8) + { + regoffset = STM32_GPIO_AFRL_OFFSET; + pos = pin; + } + else + { + regoffset = STM32_GPIO_AFRH_OFFSET; + pos = pin - 8; + } + + regval = getreg32(base + regoffset); + regval &= ~GPIO_AFR_MASK(pos); + regval |= (setting << GPIO_AFR_SHIFT(pos)); + putreg32(regval, base + regoffset); + + /* Set speed (Only outputs and alternate function pins) */ + + if (pinmode == GPIO_MODER_OUTPUT || pinmode == GPIO_MODER_ALT) + { + switch (cfgset & GPIO_SPEED_MASK) + { + default: + case GPIO_SPEED_2MHZ: /* 2 MHz Low speed output */ + setting = GPIO_OSPEED_2MHZ; + break; + + case GPIO_SPEED_25MHZ: /* 25 MHz Medium speed output */ + setting = GPIO_OSPEED_25MHZ; + break; + + case GPIO_SPEED_50MHZ: /* 50 MHz High speed output */ + setting = GPIO_OSPEED_50MHZ; + break; + + case GPIO_SPEED_100MHZ: /* 100 MHz Very High speed output */ + setting = GPIO_OSPEED_100MHZ; + break; + } + } + else + { + setting = 0; + } + + regval = getreg32(base + STM32_GPIO_OSPEED_OFFSET); + regval &= ~GPIO_OSPEED_MASK(pin); + regval |= (setting << GPIO_OSPEED_SHIFT(pin)); + putreg32(regval, base + STM32_GPIO_OSPEED_OFFSET); + + /* Set push-pull/open-drain (Only outputs and alternate function pins) */ + + regval = getreg32(base + STM32_GPIO_OTYPER_OFFSET); + setting = GPIO_OTYPER_OD(pin); + + if ((pinmode == GPIO_MODER_OUTPUT || pinmode == GPIO_MODER_ALT) && + (cfgset & GPIO_OPENDRAIN) != 0) + { + regval |= setting; + } + else + { + regval &= ~setting; + } + + putreg32(regval, base + STM32_GPIO_OTYPER_OFFSET); + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: stm32_unconfiggpio + * + * Description: + * Unconfigure a GPIO pin based on bit-encoded description of the pin, set + * it into default HiZ state (and possibly mark it's unused) and unlock it + * whether it was previously selected as alternative function + * (GPIO_ALT|GPIO_CNF_AFPP|...). + * + * This is a safety function and prevents hardware from shocks, as + * unexpected write to the Timer Channel Output GPIO to fixed '1' or '0' + * while it should operate in PWM mode could produce excessive on-board + * currents and trigger over-current/alarm function. + * + * Returned Value: + * OK on success + * A negated errno value on invalid port + * + * To-Do: Auto Power Disable + ****************************************************************************/ + +int stm32_unconfiggpio(uint32_t cfgset) +{ + /* Reuse port and pin number and set it to default HiZ INPUT */ + + cfgset &= GPIO_PORT_MASK | GPIO_PIN_MASK; + cfgset |= GPIO_INPUT | GPIO_FLOAT; + + /* To-Do: Mark its unuse for automatic power saving options */ + + return stm32_configgpio(cfgset); +} + +/**************************************************************************** + * Name: stm32_gpiowrite + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void stm32_gpiowrite(uint32_t pinset, bool value) +{ + uint32_t base; + uint32_t bit; + unsigned int port; + unsigned int pin; + + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + if (port < STM32H5_NPORTS) + { + /* Get the port base address */ + + base = g_gpiobase[port]; + + /* Get the pin number */ + + pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + /* Set or clear the output on the pin */ + + if (value) + { + bit = GPIO_BSRR_SET(pin); + } + else + { + bit = GPIO_BSRR_RESET(pin); + } + + putreg32(bit, base + STM32_GPIO_BSRR_OFFSET); + } +} + +/**************************************************************************** + * Name: stm32_gpioread + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool stm32_gpioread(uint32_t pinset) +{ + uint32_t base; + unsigned int port; + unsigned int pin; + + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + if (port < STM32H5_NPORTS) + { + /* Get the port base address */ + + base = g_gpiobase[port]; + + /* Get the pin number and return the input state of that pin */ + + pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + return ((getreg32(base + STM32_GPIO_IDR_OFFSET) & (1 << pin)) != 0); + } + + return 0; +} diff --git a/arch/arm/src/stm32h5/stm32_gpio.h b/arch/arm/src/stm32h5/stm32_gpio.h new file mode 100644 index 00000000000..5a7bd9c62dc --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_gpio.h @@ -0,0 +1,326 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_gpio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H5_STM32_GPIO_H +#define __ARCH_ARM_SRC_STM32H5_STM32_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +# include +#endif + +#include +#include + +#include "chip.h" + +#if defined(CONFIG_STM32H5_STM32H5XXXX) +# include "hardware/stm32_gpio.h" +#else +# error "Unsupported STM32H5 chip" +#endif + +/**************************************************************************** + * Pre-Processor Declarations + ****************************************************************************/ + +/* Bit-encoded input to stm32_configgpio() */ + +/* Each port bit of the general-purpose I/O (GPIO) ports can be individually + * configured by software in several modes: + * + * - Input floating + * - Input pull-up + * - Input-pull-down + * - Output open-drain with pull-up or pull-down capability + * - Output push-pull with pull-up or pull-down capability + * - Alternate function push-pull with pull-up or pull-down capability + * - Alternate function open-drain with pull-up or pull-down capability + * - Analog + * + * 20-bit Encoding: 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * Inputs: MMUU .... ...X PPPP BBBB + * Outputs: MMUU .... FFOV PPPP BBBB + * Alternate Functions: MMUU AAAA FFO. PPPP BBBB + * Analog: MM.. .... .... PPPP BBBB + */ + +/* Mode: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * MM.. .... .... .... .... + */ + +#define GPIO_MODE_SHIFT (18) /* Bits 18-19: GPIO port mode */ +#define GPIO_MODE_MASK (3 << GPIO_MODE_SHIFT) +# define GPIO_INPUT (0 << GPIO_MODE_SHIFT) /* Input mode */ +# define GPIO_OUTPUT (1 << GPIO_MODE_SHIFT) /* General purpose output mode */ +# define GPIO_ALT (2 << GPIO_MODE_SHIFT) /* Alternate function mode */ +# define GPIO_ANALOG (3 << GPIO_MODE_SHIFT) /* Analog mode */ + +/* Input/output pull-ups/downs (not used with analog): + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * ..UU .... .... .... .... + */ + +#define GPIO_PUPD_SHIFT (16) /* Bits 16-17: Pull-up/pull down */ +#define GPIO_PUPD_MASK (3 << GPIO_PUPD_SHIFT) +# define GPIO_FLOAT (0 << GPIO_PUPD_SHIFT) /* No pull-up, pull-down */ +# define GPIO_PULLUP (1 << GPIO_PUPD_SHIFT) /* Pull-up */ +# define GPIO_PULLDOWN (2 << GPIO_PUPD_SHIFT) /* Pull-down */ + +/* Alternate Functions: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... AAAA .... .... .... + */ + +#define GPIO_AF_SHIFT (12) /* Bits 12-15: Alternate function */ +#define GPIO_AF_MASK (15 << GPIO_AF_SHIFT) +# define GPIO_AF(n) ((n) << GPIO_AF_SHIFT) +# define GPIO_AF0 (0 << GPIO_AF_SHIFT) +# define GPIO_AF1 (1 << GPIO_AF_SHIFT) +# define GPIO_AF2 (2 << GPIO_AF_SHIFT) +# define GPIO_AF3 (3 << GPIO_AF_SHIFT) +# define GPIO_AF4 (4 << GPIO_AF_SHIFT) +# define GPIO_AF5 (5 << GPIO_AF_SHIFT) +# define GPIO_AF6 (6 << GPIO_AF_SHIFT) +# define GPIO_AF7 (7 << GPIO_AF_SHIFT) +# define GPIO_AF8 (8 << GPIO_AF_SHIFT) +# define GPIO_AF9 (9 << GPIO_AF_SHIFT) +# define GPIO_AF10 (10 << GPIO_AF_SHIFT) +# define GPIO_AF11 (11 << GPIO_AF_SHIFT) +# define GPIO_AF12 (12 << GPIO_AF_SHIFT) +# define GPIO_AF13 (13 << GPIO_AF_SHIFT) +# define GPIO_AF14 (14 << GPIO_AF_SHIFT) +# define GPIO_AF15 (15 << GPIO_AF_SHIFT) + +/* Output/Alt function frequency selection: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... FF.. .... .... + */ + +#define GPIO_SPEED_SHIFT (10) /* Bits 10-11: GPIO frequency selection */ +#define GPIO_SPEED_MASK (3 << GPIO_SPEED_SHIFT) +# define GPIO_SPEED_2MHZ (0 << GPIO_SPEED_SHIFT) /* 2 MHz Low speed output */ +# define GPIO_SPEED_25MHZ (1 << GPIO_SPEED_SHIFT) /* 25 MHz Medium speed output */ +# define GPIO_SPEED_50MHZ (2 << GPIO_SPEED_SHIFT) /* 50 MHz High speed output */ +# define GPIO_SPEED_100MHZ (3 << GPIO_SPEED_SHIFT) /* 100 MHz Very High speed output */ + +/* Output/Alt function type selection: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... ..O. .... .... + */ + +#define GPIO_OPENDRAIN (1 << 9) /* Bit9: 1=Open-drain output */ +#define GPIO_PUSHPULL (0) /* Bit9: 0=Push-pull output */ + +/* If the pin is a GPIO digital output, then this identifies the initial + * output value. If the pin is an input, this bit is overloaded to provide + * the qualifier to distinguish input pull-up and -down: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... ...V .... .... + */ + +#define GPIO_OUTPUT_SET (1 << 8) /* Bit 8: If output, initial value of output */ +#define GPIO_OUTPUT_CLEAR (0) + +/* External interrupt selection (GPIO inputs only): + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... ...X .... .... + */ + +#define GPIO_EXTI (1 << 8) /* Bit 8: Configure as EXTI interrupt */ + +/* This identifies the GPIO port: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... .... PPPP .... + */ + +#define GPIO_PORT_SHIFT (4) /* Bit 4-7: Port number */ +#define GPIO_PORT_MASK (15 << GPIO_PORT_SHIFT) +# define GPIO_PORTA (0 << GPIO_PORT_SHIFT) /* GPIOA */ +# define GPIO_PORTB (1 << GPIO_PORT_SHIFT) /* GPIOB */ +# define GPIO_PORTC (2 << GPIO_PORT_SHIFT) /* GPIOC */ +# define GPIO_PORTD (3 << GPIO_PORT_SHIFT) /* GPIOD */ +# define GPIO_PORTE (4 << GPIO_PORT_SHIFT) /* GPIOE */ +# define GPIO_PORTF (5 << GPIO_PORT_SHIFT) /* GPIOF */ +# define GPIO_PORTG (6 << GPIO_PORT_SHIFT) /* GPIOG */ +# define GPIO_PORTH (7 << GPIO_PORT_SHIFT) /* GPIOH */ + +/* This identifies the bit in the port: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... .... .... BBBB + */ + +#define GPIO_PIN_SHIFT (0) /* Bits 0-3: GPIO number: 0-15 */ +#define GPIO_PIN_MASK (15 << GPIO_PIN_SHIFT) +# define GPIO_PIN0 (0 << GPIO_PIN_SHIFT) +# define GPIO_PIN1 (1 << GPIO_PIN_SHIFT) +# define GPIO_PIN2 (2 << GPIO_PIN_SHIFT) +# define GPIO_PIN3 (3 << GPIO_PIN_SHIFT) +# define GPIO_PIN4 (4 << GPIO_PIN_SHIFT) +# define GPIO_PIN5 (5 << GPIO_PIN_SHIFT) +# define GPIO_PIN6 (6 << GPIO_PIN_SHIFT) +# define GPIO_PIN7 (7 << GPIO_PIN_SHIFT) +# define GPIO_PIN8 (8 << GPIO_PIN_SHIFT) +# define GPIO_PIN9 (9 << GPIO_PIN_SHIFT) +# define GPIO_PIN10 (10 << GPIO_PIN_SHIFT) +# define GPIO_PIN11 (11 << GPIO_PIN_SHIFT) +# define GPIO_PIN12 (12 << GPIO_PIN_SHIFT) +# define GPIO_PIN13 (13 << GPIO_PIN_SHIFT) +# define GPIO_PIN14 (14 << GPIO_PIN_SHIFT) +# define GPIO_PIN15 (15 << GPIO_PIN_SHIFT) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* Base addresses for each GPIO block */ + +EXTERN const uint32_t g_gpiobase[STM32H5_NPORTS]; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_configgpio + * + * Description: + * Configure a GPIO pin based on bit-encoded description of the pin. + * Once it is configured as Alternative (GPIO_ALT|GPIO_CNF_AFPP|...) + * function, it must be unconfigured with stm32_unconfiggpio() with + * the same cfgset first before it can be set to non-alternative function. + * + * Returned Value: + * OK on success + * ERROR on invalid port, or when pin is locked as ALT function. + * + ****************************************************************************/ + +int stm32_configgpio(uint32_t cfgset); + +/**************************************************************************** + * Name: stm32_unconfiggpio + * + * Description: + * Unconfigure a GPIO pin based on bit-encoded description of the pin, set + * it into default HiZ state (and possibly mark it's unused) and unlock it + * whether it was previously selected as alternative function + * (GPIO_ALT|GPIO_CNF_AFPP|...). + * + * This is a safety function and prevents hardware from shocks, as + * unexpected write to the Timer Channel Output GPIO to fixed '1' or '0' + * while it should operate in PWM mode could produce excessive on-board + * currents and trigger over-current/alarm function. + * + * Returned Value: + * OK on success + * ERROR on invalid port + * + ****************************************************************************/ + +int stm32_unconfiggpio(uint32_t cfgset); + +/**************************************************************************** + * Name: stm32_gpiowrite + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void stm32_gpiowrite(uint32_t pinset, bool value); + +/**************************************************************************** + * Name: stm32_gpioread + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool stm32_gpioread(uint32_t pinset); + +/**************************************************************************** + * Function: stm32_gpioinit + * + * Description: + * Based on configuration within the .config file, it does: + * - Remaps positions of alternative functions. + * + * Typically called from stm32h5_start(). + * + ****************************************************************************/ + +void stm32_gpioinit(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_STM32H5_STM32_GPIO_H */ diff --git a/arch/arm/src/stm32h5/stm32_hsi48.c b/arch/arm/src/stm32h5/stm32_hsi48.c new file mode 100644 index 00000000000..6eaed8d3474 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_hsi48.c @@ -0,0 +1,169 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_hsi48.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "stm32_rcc.h" +#include "hardware/stm32_crs.h" + +#include "stm32_hsi48.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_STM32H5_HAVE_HSI48 +/**************************************************************************** + * Name: stm32h5_enable_hsi48 + * + * Description: + * The HSI48 + * clock signal is generated from an internal 48 MHz RC oscillator and can + * be used directly as a system clock or divided and be used as PLL input. + * + * The internal 48MHz RC oscillator is mainly dedicated to provide a high + * precision clock to the USB peripheral by means of a special Clock + * Recovery System (CRS) circuitry, which could use the USB SOF signal or + * the LSE or an external signal to automatically adjust the oscillator + * frequency on-fly, in a very small steps. This oscillator can also be + * used as a system clock source when the system is in run mode; it will + * be disabled as soon as the system enters in Stop or Standby mode. When + * the CRS is not used, the HSI48 RC oscillator runs on its default + * frequency which is subject to manufacturing process variations. + * + * Input Parameters: + * Identifies the syncrhonization source for the HSI48. When used as the + * USB source clock, this must be set to SYNCSRC_USB. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32h5_enable_hsi48(enum syncsrc_e syncsrc) +{ + uint32_t regval; + + /* Enable the HSI48 clock. + * + * The HSI48 RC can be switched on and off using the HSI48ON bit in the + * Clock control register (RCC_CRRCR). + * + * The USB clock may be derived from either the PLL clock or from the + * HSI48 clock. This oscillator will be also automatically enabled (by + * hardware forcing HSI48ON bit to one) as soon as it is chosen as a clock + * source for the USB and the peripheral is + * enabled. + */ + + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_HSI48ON; + putreg32(regval, STM32_RCC_CR); + + /* Wait for the HSI48 clock to stabilize */ + + while ((getreg32(STM32_RCC_CRRCR) & RCC_CRRCR_HSI48RDY) == 0); + + /* Return if no synchronization */ + + if (syncsrc == SYNCSRC_NONE) + { + return; + } + + /* The CRS synchronization (SYNC) source, selectable through the CRS_CFGR + * register, can be the signal from the external CRS_SYNC pin, the LSE + * clock or the USB SOF signal. + */ + + regval = getreg32(STM32_CRS_CFGR); + regval &= ~CRS_CFGR_SYNCSRC_MASK; + + switch (syncsrc) + { + default: + case SYNCSRC_GPIO: /* GPIO selected as SYNC signal source */ + regval |= CRS_CFGR_SYNCSRC_GPIO; + break; + + case SYNCSRC_LSE: /* LSE selected as SYNC signal source */ + regval |= CRS_CFGR_SYNCSRC_LSE; + break; + + case SYNCSRC_USB: /* USB SOF selected as SYNC signal source */ + regval |= CRS_CFGR_SYNCSRC_USBSOF; + break; + } + + putreg32(regval, STM32_CRS_CFGR); + + /* Set the AUTOTRIMEN bit the CRS_CR register to enables the automatic + * hardware adjustment of TRIM bits according to the measured frequency + * error between the selected SYNC event. Also enable CEN bit to enable + * frequency error counter and SYNC events. + */ + + regval = getreg32(STM32_CRS_CR); + regval |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN; + putreg32(regval, STM32_CRS_CR); +} + +/**************************************************************************** + * Name: stm32h5_disable_hsi48 + * + * Description: + * Disable the HSI48 clock. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32h5_disable_hsi48(void) +{ + uint32_t regval; + + /* Disable the HSI48 clock */ + + regval = getreg32(STM32_RCC_CR); + regval &= ~RCC_CR_HSI48ON; + putreg32(regval, STM32_RCC_CR); + + /* Set other registers to the default settings. */ + + regval = getreg32(STM32_CRS_CFGR); + regval &= ~CRS_CFGR_SYNCSRC_MASK; + putreg32(regval, STM32_CRS_CFGR); + + regval = getreg32(STM32_CRS_CR); + regval &= ~CRS_CR_AUTOTRIMEN; + putreg32(regval, STM32_CRS_CR); +} + +#endif /* CONFIG_STM32H5_HAVE_HSI48 */ diff --git a/arch/arm/src/stm32h5/stm32_hsi48.h b/arch/arm/src/stm32h5/stm32_hsi48.h new file mode 100644 index 00000000000..3b934f7736e --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_hsi48.h @@ -0,0 +1,94 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_hsi48.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H5_STM32_HSI48_H +#define __ARCH_ARM_SRC_STM32H5_STM32_HSI48_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_STM32H5_HAVE_HSI48 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum syncsrc_e +{ + SYNCSRC_NONE = 0, /* No SYNC signal */ + SYNCSRC_GPIO, /* GPIO selected as SYNC signal source */ + SYNCSRC_LSE, /* LSE selected as SYNC signal source */ + SYNCSRC_USB, /* USB SOF selected as SYNC signal source */ +}; + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32h5_enable_hsi48 + * + * Description: + * On STM32H5X3, STM32H596xx/4A6xx and STM32H5XR devices only, the HSI48 + * clock signal is generated from an internal 48 MHz RC oscillator and can + * be used directly as a system clock or divided and be used as PLL input. + * + * The internal 48MHz RC oscillator is mainly dedicated to provide a high + * precision clock to the USB peripheral by means of a special Clock + * Recovery System (CRS) circuitry, which could use the USB SOF signal or + * the LSE or an external signal to automatically adjust the oscillator + * frequency on-fly, in a very small steps. This oscillator can also be + * used as a system clock source when the system is in run mode; it will + * be disabled as soon as the system enters in Stop or Standby mode. When + * the CRS is not used, the HSI48 RC oscillator runs on its default + * frequency which is subject to manufacturing process variations. + * + * Input Parameters: + * Identifies the syncrhonization source for the HSI48. When used as the + * USB source clock, this must be set to SYNCSRC_USB. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32h5_enable_hsi48(enum syncsrc_e syncsrc); + +/**************************************************************************** + * Name: stm32h5_disable_hsi48 + * + * Description: + * Disable the HSI48 clock. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32h5_disable_hsi48(void); + +#endif /* CONFIG_STM32H5_HAVE_HSI48 */ +#endif /* __ARCH_ARM_SRC_STM32H5_STM32_HSI48_H */ diff --git a/arch/arm/src/stm32h5/stm32_idle.c b/arch/arm/src/stm32h5/stm32_idle.c new file mode 100644 index 00000000000..a68292725c7 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_idle.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_idle.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include "chip.h" +#include "stm32_rcc.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Does the board support an IDLE LED to indicate that the board is in the + * IDLE state? + */ + +#if defined(CONFIG_ARCH_LEDS) && defined(LED_IDLE) +# define BEGIN_IDLE() board_autoled_on(LED_IDLE) +# define END_IDLE() board_autoled_off(LED_IDLE) +#else +# define BEGIN_IDLE() +# define END_IDLE() +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#define up_idlepm() + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_idle + * + * Description: + * up_idle() is the logic that will be executed when their is no other + * ready-to-run task. This is processor idle time and will continue until + * some interrupt occurs to cause a context switch from the idle task. + * + * Processing in this state may be processor-specific. e.g., this is where + * power management operations might be performed. + * + ****************************************************************************/ + +void up_idle(void) +{ +#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_TIMER_INTS) + /* If the system is idle and there are no timer interrupts, then process + * "fake" timer interrupts. Hopefully, something will wake up. + */ + + nxsched_process_timer(); +#else + + /* Perform IDLE mode power management */ + + up_idlepm(); + + /* Sleep until an interrupt occurs to save power. */ + +#if !(defined(CONFIG_DEBUG_SYMBOLS) && defined(CONFIG_STM32H5_DISABLE_IDLE_SLEEP_DURING_DEBUG)) + BEGIN_IDLE(); + asm("WFI"); + END_IDLE(); +#endif + +#endif +} diff --git a/arch/arm/src/stm32h5/stm32_irq.c b/arch/arm/src/stm32h5/stm32_irq.c new file mode 100644 index 00000000000..4f5c18cb050 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_irq.c @@ -0,0 +1,474 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_irq.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "nvic.h" +#include "ram_vectors.h" +#include "arm_internal.h" +#include "stm32.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Get a 32-bit version of the default priority */ + +#define DEFPRIORITY32 \ + (NVIC_SYSH_PRIORITY_DEFAULT << 24 | \ + NVIC_SYSH_PRIORITY_DEFAULT << 16 | \ + NVIC_SYSH_PRIORITY_DEFAULT << 8 | \ + NVIC_SYSH_PRIORITY_DEFAULT) + +/* Given the address of a NVIC ENABLE register, this is the offset to + * the corresponding CLEAR ENABLE register. + */ + +#define NVIC_ENA_OFFSET (0) +#define NVIC_CLRENA_OFFSET (NVIC_IRQ0_31_CLEAR - NVIC_IRQ0_31_ENABLE) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_dumpnvic + * + * Description: + * Dump some interesting NVIC registers + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_IRQ_INFO) +static void stm32_dumpnvic(const char *msg, int irq) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + irqinfo("NVIC (%s, irq=%d):\n", msg, irq); + irqinfo(" INTCTRL: %08x VECTAB: %08x\n", + getreg32(NVIC_INTCTRL), getreg32(NVIC_VECTAB)); + irqinfo(" IRQ ENABLE: %08x %08x %08x\n", + getreg32(NVIC_IRQ0_31_ENABLE), getreg32(NVIC_IRQ32_63_ENABLE), + getreg32(NVIC_IRQ64_95_ENABLE)); + irqinfo(" SYSH_PRIO: %08x %08x %08x\n", + getreg32(NVIC_SYSH4_7_PRIORITY), getreg32(NVIC_SYSH8_11_PRIORITY), + getreg32(NVIC_SYSH12_15_PRIORITY)); + irqinfo(" IRQ PRIO: %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ0_3_PRIORITY), getreg32(NVIC_IRQ4_7_PRIORITY), + getreg32(NVIC_IRQ8_11_PRIORITY), getreg32(NVIC_IRQ12_15_PRIORITY)); + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ16_19_PRIORITY), getreg32(NVIC_IRQ20_23_PRIORITY), + getreg32(NVIC_IRQ24_27_PRIORITY), + getreg32(NVIC_IRQ28_31_PRIORITY)); + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ32_35_PRIORITY), getreg32(NVIC_IRQ36_39_PRIORITY), + getreg32(NVIC_IRQ40_43_PRIORITY), + getreg32(NVIC_IRQ44_47_PRIORITY)); + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ48_51_PRIORITY), getreg32(NVIC_IRQ52_55_PRIORITY), + getreg32(NVIC_IRQ56_59_PRIORITY), + getreg32(NVIC_IRQ60_63_PRIORITY)); + irqinfo(" %08x\n", + getreg32(NVIC_IRQ64_67_PRIORITY)); + + leave_critical_section(flags); +} +#else +# define stm32_dumpnvic(msg, irq) +#endif + +/**************************************************************************** + * Name: stm32_nmi, stm32_pendsv, stm32_pendsv, stm32_reserved + * + * Description: + * Handlers for various exceptions. None are handled and all are fatal + * error conditions. The only advantage these provide over the default + * unexpected interrupt handler is that they provide a diagnostic output. + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_FEATURES +static int stm32_nmi(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! NMI received\n"); + PANIC(); + return 0; +} + +static int stm32_pendsv(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! PendSV received\n"); + PANIC(); + return 0; +} + +static int stm32_reserved(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! Reserved interrupt\n"); + PANIC(); + return 0; +} +#endif + +/**************************************************************************** + * Name: stm32_prioritize_syscall + * + * Description: + * Set the priority of an exception. This function may be needed + * internally even if support for prioritized interrupts is not enabled. + * + ****************************************************************************/ + +#ifdef CONFIG_ARMV8M_USEBASEPRI +static inline void stm32_prioritize_syscall(int priority) +{ + uint32_t regval; + + /* SVCALL is system handler 11 */ + + regval = getreg32(NVIC_SYSH8_11_PRIORITY); + regval &= ~NVIC_SYSH_PRIORITY_PR11_MASK; + regval |= (priority << NVIC_SYSH_PRIORITY_PR11_SHIFT); + putreg32(regval, NVIC_SYSH8_11_PRIORITY); +} +#endif + +/**************************************************************************** + * Name: stm32_irqinfo + * + * Description: + * Given an IRQ number, provide the register and bit setting to enable or + * disable the irq. + * + ****************************************************************************/ + +static int stm32_irqinfo(int irq, uintptr_t *regaddr, uint32_t *bit, + uintptr_t offset) +{ + int n; + + DEBUGASSERT(irq >= STM32_IRQ_NMI && irq < NR_IRQS); + + /* Check for external interrupt */ + + if (irq >= STM32_IRQ_FIRST) + { + n = irq - STM32_IRQ_FIRST; + *regaddr = NVIC_IRQ_ENABLE(n) + offset; + *bit = (uint32_t)1 << (n & 0x1f); + } + + /* Handle processor exceptions. Only a few can be disabled */ + + else + { + *regaddr = NVIC_SYSHCON; + if (irq == STM32_IRQ_MEMFAULT) + { + *bit = NVIC_SYSHCON_MEMFAULTENA; + } + else if (irq == STM32_IRQ_BUSFAULT) + { + *bit = NVIC_SYSHCON_BUSFAULTENA; + } + else if (irq == STM32_IRQ_USAGEFAULT) + { + *bit = NVIC_SYSHCON_USGFAULTENA; + } + else if (irq == STM32_IRQ_SYSTICK) + { + *regaddr = NVIC_SYSTICK_CTRL; + *bit = NVIC_SYSTICK_CTRL_ENABLE; + } + else + { + return ERROR; /* Invalid or unsupported exception */ + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_irqinitialize + ****************************************************************************/ + +void up_irqinitialize(void) +{ + uint32_t regaddr; + int num_priority_registers; + int i; + + /* Disable all interrupts */ + + for (i = 0; i < NR_IRQS - STM32_IRQ_FIRST; i += 32) + { + putreg32(0xffffffff, NVIC_IRQ_CLEAR(i)); + } + + /* The standard location for the vector table is at the beginning of FLASH + * at address 0x0800:0000. If we are using the STMicro DFU bootloader, + * then the vector table will be offset to a different location in FLASH + * and we will need to set the NVIC vector location to this alternative + * location. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based + * vector table that requires special initialization. + */ + + up_ramvec_initialize(); +#endif + + /* Set all interrupts (and exceptions) to the default priority */ + + putreg32(DEFPRIORITY32, NVIC_SYSH4_7_PRIORITY); + putreg32(DEFPRIORITY32, NVIC_SYSH8_11_PRIORITY); + putreg32(DEFPRIORITY32, NVIC_SYSH12_15_PRIORITY); + + /* The NVIC ICTR register (bits 0-4) holds the number of of interrupt + * lines that the NVIC supports: + * + * 0 -> 32 interrupt lines, 8 priority registers + * 1 -> 64 " " " ", 16 priority registers + * 2 -> 96 " " " ", 32 priority registers + * ... + */ + + num_priority_registers = (getreg32(NVIC_ICTR) + 1) * 8; + + /* Now set all of the interrupt lines to the default priority */ + + regaddr = NVIC_IRQ0_3_PRIORITY; + while (num_priority_registers--) + { + putreg32(DEFPRIORITY32, regaddr); + regaddr += 4; + } + + /* Attach the SVCall and Hard Fault exception handlers. The SVCall + * exception is used for performing context switches; The Hard Fault + * must also be caught because a SVCall may show up as a Hard Fault + * under certain conditions. + */ + + irq_attach(STM32_IRQ_SVCALL, arm_svcall, NULL); + irq_attach(STM32_IRQ_HARDFAULT, arm_hardfault, NULL); + + /* Set the priority of the SVCall interrupt */ + +#ifdef CONFIG_ARCH_IRQPRIO + + /* up_prioritize_irq(STM32_IRQ_PENDSV, NVIC_SYSH_PRIORITY_MIN); */ + +#endif +#ifdef CONFIG_ARMV8M_USEBASEPRI + stm32_prioritize_syscall(NVIC_SYSH_SVCALL_PRIORITY); +#endif + + /* If the MPU is enabled, then attach and enable the Memory Management + * Fault handler. + */ + +#ifdef CONFIG_ARM_MPU + irq_attach(STM32_IRQ_MEMFAULT, arm_memfault, NULL); + up_enable_irq(STM32_IRQ_MEMFAULT); +#endif + + /* Attach all other processor exceptions (except reset and sys tick) */ + +#ifdef CONFIG_DEBUG_FEATURES + irq_attach(STM32_IRQ_NMI, stm32_nmi, NULL); +#ifndef CONFIG_ARM_MPU + irq_attach(STM32_IRQ_MEMFAULT, arm_memfault, NULL); +#endif + irq_attach(STM32_IRQ_BUSFAULT, arm_busfault, NULL); + irq_attach(STM32_IRQ_USAGEFAULT, arm_usagefault, NULL); + irq_attach(STM32_IRQ_PENDSV, stm32_pendsv, NULL); + arm_enable_dbgmonitor(); + irq_attach(STM32_IRQ_DBGMONITOR, arm_dbgmonitor, NULL); + irq_attach(STM32_IRQ_RESERVED, stm32_reserved, NULL); +#endif + + stm32_dumpnvic("initial", NR_IRQS); + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + + /* And finally, enable interrupts */ + + up_irq_enable(); +#endif +} + +/**************************************************************************** + * Name: up_disable_irq + * + * Description: + * Disable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_disable_irq(int irq) +{ + uintptr_t regaddr; + uint32_t regval; + uint32_t bit; + + if (stm32_irqinfo(irq, ®addr, &bit, NVIC_CLRENA_OFFSET) == 0) + { + /* Modify the appropriate bit in the register to disable the interrupt. + * For normal interrupts, we need to set the bit in the associated + * Interrupt Clear Enable register. For other exceptions, we need to + * clear the bit in the System Handler Control and State Register. + */ + + if (irq >= STM32_IRQ_FIRST) + { + putreg32(bit, regaddr); + } + else + { + regval = getreg32(regaddr); + regval &= ~bit; + putreg32(regval, regaddr); + } + } +} + +/**************************************************************************** + * Name: up_enable_irq + * + * Description: + * Enable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_enable_irq(int irq) +{ + uintptr_t regaddr; + uint32_t regval; + uint32_t bit; + + if (stm32_irqinfo(irq, ®addr, &bit, NVIC_ENA_OFFSET) == 0) + { + /* Modify the appropriate bit in the register to enable the interrupt. + * For normal interrupts, we need to set the bit in the associated + * Interrupt Set Enable register. For other exceptions, we need to + * set the bit in the System Handler Control and State Register. + */ + + if (irq >= STM32_IRQ_FIRST) + { + putreg32(bit, regaddr); + } + else + { + regval = getreg32(regaddr); + regval |= bit; + putreg32(regval, regaddr); + } + } +} + +/**************************************************************************** + * Name: arm_ack_irq + * + * Description: + * Acknowledge the IRQ + * + ****************************************************************************/ + +void arm_ack_irq(int irq) +{ +} + +/**************************************************************************** + * Name: up_prioritize_irq + * + * Description: + * Set the priority of an IRQ. + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_IRQPRIO +int up_prioritize_irq(int irq, int priority) +{ + uint32_t regaddr; + uint32_t regval; + int shift; + + DEBUGASSERT(irq >= STM32_IRQ_MEMFAULT && irq < NR_IRQS && + (unsigned)priority <= NVIC_SYSH_PRIORITY_MIN); + + if (irq < STM32_IRQ_FIRST) + { + /* NVIC_SYSH_PRIORITY() maps {0..15} to one of three priority + * registers (0-3 are invalid) + */ + + regaddr = NVIC_SYSH_PRIORITY(irq); + irq -= 4; + } + else + { + /* NVIC_IRQ_PRIORITY() maps {0..} to one of many priority registers */ + + irq -= STM32_IRQ_FIRST; + regaddr = NVIC_IRQ_PRIORITY(irq); + } + + regval = getreg32(regaddr); + shift = ((irq & 3) << 3); + regval &= ~(0xff << shift); + regval |= (priority << shift); + putreg32(regval, regaddr); + + stm32_dumpnvic("prioritize", irq); + return OK; +} +#endif diff --git a/arch/arm/src/stm32h5/stm32_lowputc.c b/arch/arm/src/stm32h5/stm32_lowputc.c new file mode 100644 index 00000000000..63639b44ef4 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_lowputc.c @@ -0,0 +1,550 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_lowputc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +#include "arm_internal.h" +#include "chip.h" + +#include "stm32.h" +#include "stm32_rcc.h" +#include "stm32_gpio.h" +#include "stm32_uart.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Select USART parameters for the selected console */ + +#ifdef HAVE_CONSOLE +# if defined(CONFIG_LPUART1_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_LPUART1_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB3ENR +# define STM32H5_CONSOLE_APBEN RCC_APB3ENR_LPUART1EN +# define STM32H5_CONSOLE_BAUD CONFIG_LPUART1_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_LPUART1_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_LPUART1_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_LPUART1_2STOP +# define STM32H5_CONSOLE_TX GPIO_LPUART1_TX +# define STM32H5_CONSOLE_RX GPIO_LPUART1_RX +# ifdef CONFIG_LPUART1_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_LPUART1_RS485_DIR +# if (CONFIG_LPUART1_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART1_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_USART1_BASE +# define STM32H5_APBCLOCK STM32_PCLK2_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB2ENR +# define STM32H5_CONSOLE_APBEN RCC_APB2ENR_USART1EN +# define STM32H5_CONSOLE_BAUD CONFIG_USART1_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_USART1_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_USART1_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_USART1_2STOP +# define STM32H5_CONSOLE_TX GPIO_USART1_TX +# define STM32H5_CONSOLE_RX GPIO_USART1_RX +# ifdef CONFIG_USART1_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_USART1_RS485_DIR +# if (CONFIG_USART1_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART2_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_USART2_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_USART2EN +# define STM32H5_CONSOLE_BAUD CONFIG_USART2_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_USART2_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_USART2_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_USART2_2STOP +# define STM32H5_CONSOLE_TX GPIO_USART2_TX +# define STM32H5_CONSOLE_RX GPIO_USART2_RX +# ifdef CONFIG_USART2_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_USART2_RS485_DIR +# if (CONFIG_USART2_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART3_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_USART3_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_USART3EN +# define STM32H5_CONSOLE_BAUD CONFIG_USART3_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_USART3_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_USART3_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_USART3_2STOP +# define STM32H5_CONSOLE_TX GPIO_USART3_TX +# define STM32H5_CONSOLE_RX GPIO_USART3_RX +# ifdef CONFIG_USART3_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_USART3_RS485_DIR +# if (CONFIG_USART3_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART4_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_UART4_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_UART4EN +# define STM32H5_CONSOLE_BAUD CONFIG_UART4_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_UART4_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_UART4_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_UART4_2STOP +# define STM32H5_CONSOLE_TX GPIO_UART4_TX +# define STM32H5_CONSOLE_RX GPIO_UART4_RX +# ifdef CONFIG_UART4_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_UART4_RS485_DIR +# if (CONFIG_UART4_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART5_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_UART5_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_UART5EN +# define STM32H5_CONSOLE_BAUD CONFIG_UART5_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_UART5_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_UART5_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_UART5_2STOP +# define STM32H5_CONSOLE_TX GPIO_UART5_TX +# define STM32H5_CONSOLE_RX GPIO_UART5_RX +# ifdef CONFIG_UART5_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_UART5_RS485_DIR +# if (CONFIG_UART5_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART6_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_USART6_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_USART6EN +# define STM32H5_CONSOLE_BAUD CONFIG_USART6_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_USART6_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_USART6_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_USART6_2STOP +# define STM32H5_CONSOLE_TX GPIO_USART6_TX +# define STM32H5_CONSOLE_RX GPIO_USART6_RX +# ifdef CONFIG_USART6_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_USART6_RS485_DIR +# if (CONFIG_USART6_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART7_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_UART7_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_UART7EN +# define STM32H5_CONSOLE_BAUD CONFIG_UART7_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_UART7_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_UART7_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_UART7_2STOP +# define STM32H5_CONSOLE_TX GPIO_UART7_TX +# define STM32H5_CONSOLE_RX GPIO_UART7_RX +# ifdef CONFIG_UART7_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_UART7_RS485_DIR +# if (CONFIG_UART7_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART8_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_UART8_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_UART8EN +# define STM32H5_CONSOLE_BAUD CONFIG_UART8_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_UART8_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_UART8_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_UART8_2STOP +# define STM32H5_CONSOLE_TX GPIO_UART8_TX +# define STM32H5_CONSOLE_RX GPIO_UART8_RX +# ifdef CONFIG_UART8_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_UART8_RS485_DIR +# if (CONFIG_UART8_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART9_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_UART9_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_UART9EN +# define STM32H5_CONSOLE_BAUD CONFIG_UART9_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_UART9_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_UART9_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_UART9_2STOP +# define STM32H5_CONSOLE_TX GPIO_UART9_TX +# define STM32H5_CONSOLE_RX GPIO_UART9_RX +# ifdef CONFIG_UART9_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_UART9_RS485_DIR +# if (CONFIG_UART9_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART10_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_USART10_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_USART10EN +# define STM32H5_CONSOLE_BAUD CONFIG_USART10_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_USART10_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_USART10_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_USART10_2STOP +# define STM32H5_CONSOLE_TX GPIO_USART10_TX +# define STM32H5_CONSOLE_RX GPIO_USART10_RX +# ifdef CONFIG_USART10_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_USART10_RS485_DIR +# if (CONFIG_USART10_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART11_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_USART11_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_USART11EN +# define STM32H5_CONSOLE_BAUD CONFIG_USART11_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_USART11_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_USART11_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_USART11_2STOP +# define STM32H5_CONSOLE_TX GPIO_USART11_TX +# define STM32H5_CONSOLE_RX GPIO_USART11_RX +# ifdef CONFIG_USART11_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_USART11_RS485_DIR +# if (CONFIG_USART11_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART12_SERIAL_CONSOLE) +# define STM32H5_CONSOLE_BASE STM32_UART12_BASE +# define STM32H5_APBCLOCK STM32_PCLK1_FREQUENCY +# define STM32H5_CONSOLE_APBREG STM32_RCC_APB1LENR +# define STM32H5_CONSOLE_APBEN RCC_APB1LENR_UART12EN +# define STM32H5_CONSOLE_BAUD CONFIG_UART12_BAUD +# define STM32H5_CONSOLE_BITS CONFIG_UART12_BITS +# define STM32H5_CONSOLE_PARITY CONFIG_UART12_PARITY +# define STM32H5_CONSOLE_2STOP CONFIG_UART12_2STOP +# define STM32H5_CONSOLE_TX GPIO_UART12_TX +# define STM32H5_CONSOLE_RX GPIO_UART12_RX +# ifdef CONFIG_UART12_RS485 +# define STM32H5_CONSOLE_RS485_DIR GPIO_UART12_RS485_DIR +# if (CONFIG_UART12_RS485_DIR_POLARITY == 0) +# define STM32H5_CONSOLE_RS485_DIR_POLARITY false +# else +# define STM32H5_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# endif + + /* CR1 settings */ + +# if STM32H5_CONSOLE_BITS == 9 +# define USART_CR1_M0_VALUE USART_CR1_M0 +# define USART_CR1_M1_VALUE 0 +# elif STM32H5_CONSOLE_BITS == 7 +# define USART_CR1_M0_VALUE 0 +# define USART_CR1_M1_VALUE USART_CR1_M1 +# else /* 8 bits */ +# define USART_CR1_M0_VALUE 0 +# define USART_CR1_M1_VALUE 0 +# endif + +# if STM32H5_CONSOLE_PARITY == 1 /* odd parity */ +# define USART_CR1_PARITY_VALUE (USART_CR1_PCE|USART_CR1_PS) +# elif STM32H5_CONSOLE_PARITY == 2 /* even parity */ +# define USART_CR1_PARITY_VALUE USART_CR1_PCE +# else /* no parity */ +# define USART_CR1_PARITY_VALUE 0 +# endif + +# if STM32H5_CONSOLE_BASE == STM32_LPUART1_BASE +# define USART_CR1_CLRBITS \ + (USART_CR1_UE | USART_CR1_UESM | USART_CR1_RE | USART_CR1_TE | USART_CR1_PS | \ + USART_CR1_PCE | USART_CR1_WAKE | USART_CR1_M0 | USART_CR1_M1 | \ + USART_CR1_MME | USART_CR1_OVER8 | USART_CR1_DEDT_MASK | \ + USART_CR1_DEAT_MASK | LPUART_CR1_ALLINTS) +# else +# define USART_CR1_CLRBITS \ + (USART_CR1_UE | USART_CR1_UESM | USART_CR1_RE | USART_CR1_TE | USART_CR1_PS | \ + USART_CR1_PCE | USART_CR1_WAKE | USART_CR1_M0 | USART_CR1_M1 | \ + USART_CR1_MME | USART_CR1_OVER8 | USART_CR1_DEDT_MASK | \ + USART_CR1_DEAT_MASK | USART_CR1_ALLINTS) +# endif + +# define USART_CR1_SETBITS (USART_CR1_M0_VALUE|USART_CR1_M1_VALUE|USART_CR1_PARITY_VALUE) + + /* CR2 settings */ + +# if STM32H5_CONSOLE_2STOP != 0 +# define USART_CR2_STOP2_VALUE USART_CR2_STOP2 +# else +# define USART_CR2_STOP2_VALUE 0 +# endif + +# define USART_CR2_CLRBITS \ + (USART_CR2_ADDM7 | USART_CR2_LBDL | USART_CR2_LBDIE | USART_CR2_LBCL | \ + USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | USART_CR2_STOP_MASK | \ + USART_CR2_LINEN | USART_CR2_SWAP | USART_CR2_RXINV | USART_CR2_TXINV | \ + USART_CR2_DATAINV | USART_CR2_MSBFIRST | USART_CR2_ABREN | \ + USART_CR2_ABRMOD_MASK | USART_CR2_RTOEN | USART_CR2_ADD_MASK) + +# define USART_CR2_SETBITS USART_CR2_STOP2_VALUE + + /* CR3 settings */ + +# define USART_CR3_CLRBITS \ + (USART_CR3_EIE | USART_CR3_IREN | USART_CR3_IRLP | USART_CR3_HDSEL | \ + USART_CR3_NACK | USART_CR3_SCEN | USART_CR3_DMAR | USART_CR3_DMAT | \ + USART_CR3_RTSE | USART_CR3_CTSE | USART_CR3_CTSIE | USART_CR3_ONEBIT | \ + USART_CR3_OVRDIS | USART_CR3_DDRE | USART_CR3_DEM | USART_CR3_DEP | \ + USART_CR3_SCARCNT2_MASK | USART_CR3_WUS_MASK | USART_CR3_WUFIE) + +# define USART_CR3_SETBITS 0 + +# undef USE_OVER8 + + /* Calculate USART BAUD rate divider */ +# if STM32H5_CONSOLE_BASE == STM32_LPUART1_BASE + + /* BRR = (256 * (APBCLOCK / Prescaler)) / (Baud rate) + * With Prescaler == 16, BRR = (16 * APBCLOCK / (Baud rate) + * Set Prescaler to 16 to support wide range of standard baud rates + */ + +# define STM32_BRR_VALUE \ + (((STM32_APBCLOCK & 0xf0000000) / STM32_CONSOLE_BAUD) << 4) + \ + (((STM32_APBCLOCK & 0x0fffffff) << 4) / STM32_CONSOLE_BAUD) +# define STM32_PRESC_VALUE 0x7 + +# else + + /* Baud rate for standard USART (SPI mode included): + * + * In case of oversampling by 16, the equation is: + * baud = fCK / UARTDIV + * UARTDIV = fCK / baud + * + * In case of oversampling by 8, the equation is: + * + * baud = 2 * fCK / UARTDIV + * UARTDIV = 2 * fCK / baud + */ + +# define STM32H5_USARTDIV8 \ + (((STM32H5_APBCLOCK << 1) + (STM32H5_CONSOLE_BAUD >> 1)) / STM32H5_CONSOLE_BAUD) +# define STM32H5_USARTDIV16 \ + ((STM32H5_APBCLOCK + (STM32H5_CONSOLE_BAUD >> 1)) / STM32H5_CONSOLE_BAUD) + + /* Use oversamply by 8 only if the divisor is small. But what is small? */ + +# if STM32H5_USARTDIV8 > 2000 +# define STM32H5_BRR_VALUE STM32H5_USARTDIV16 +# else +# define USE_OVER8 1 +# define STM32H5_BRR_VALUE \ + ((STM32H5_USARTDIV8 & 0xfff0) | ((STM32H5_USARTDIV8 & 0x000f) >> 1)) +# endif +# endif +#endif /* HAVE_CONSOLE */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_lowputc + * + * Description: + * Output one byte on the serial console + * + ****************************************************************************/ + +void arm_lowputc(char ch) +{ +#ifdef HAVE_CONSOLE + /* Wait until the TX data register is empty */ + + while ((getreg32(STM32H5_CONSOLE_BASE + STM32_USART_ISR_OFFSET) & + USART_ISR_TXE) == 0); +#ifdef STM32H5_CONSOLE_RS485_DIR + stm32_gpiowrite(STM32H5_CONSOLE_RS485_DIR, + STM32H5_CONSOLE_RS485_DIR_POLARITY); +#endif + + /* Then send the character */ + + putreg32((uint32_t)ch, STM32H5_CONSOLE_BASE + STM32_USART_TDR_OFFSET); + +#ifdef STM32H5_CONSOLE_RS485_DIR + while ((getreg32(STM32H5_CONSOLE_BASE + STM32_USART_ISR_OFFSET) & + USART_ISR_TC) == 0); + stm32_gpiowrite(STM32H5_CONSOLE_RS485_DIR, + !STM32H5_CONSOLE_RS485_DIR_POLARITY); +#endif + +#endif /* HAVE_CONSOLE */ +} + +/**************************************************************************** + * Name: stm32_lowsetup + * + * Description: + * This performs basic initialization of the USART used for the serial + * console. Its purpose is to get the console output available as soon + * as possible. + * + ****************************************************************************/ + +void stm32_lowsetup(void) +{ +#if defined(HAVE_UART) +#if defined(HAVE_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG) + uint32_t cr; +#endif + +#if defined(HAVE_CONSOLE) + /* Enable USART APB clock */ + + modifyreg32(STM32H5_CONSOLE_APBREG, 0, STM32H5_CONSOLE_APBEN); +#endif + + /* Enable the console USART and configure GPIO pins needed for rx/tx. + * + * NOTE: Clocking for selected U[S]ARTs was already provided in + * stm32_rcc.c + */ + +#ifdef STM32H5_CONSOLE_TX + stm32_configgpio(STM32H5_CONSOLE_TX); +#endif +#ifdef STM32H5_CONSOLE_RX + stm32_configgpio(STM32H5_CONSOLE_RX); +#endif + +#ifdef STM32H5_CONSOLE_RS485_DIR + stm32_configgpio(STM32H5_CONSOLE_RS485_DIR); + stm32_gpiowrite(STM32H5_CONSOLE_RS485_DIR, + !STM32H5_CONSOLE_RS485_DIR_POLARITY); +#endif + + /* Enable and configure the selected console device */ + +#if defined(HAVE_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG) + /* Configure CR2 */ + + cr = getreg32(STM32H5_CONSOLE_BASE + STM32_USART_CR2_OFFSET); + cr &= ~USART_CR2_CLRBITS; + cr |= USART_CR2_SETBITS; + putreg32(cr, STM32H5_CONSOLE_BASE + STM32_USART_CR2_OFFSET); + + /* Configure CR1 */ + + cr = getreg32(STM32H5_CONSOLE_BASE + STM32_USART_CR1_OFFSET); + cr &= ~USART_CR1_CLRBITS; + cr |= USART_CR1_SETBITS; + putreg32(cr, STM32H5_CONSOLE_BASE + STM32_USART_CR1_OFFSET); + + /* Configure CR3 */ + + cr = getreg32(STM32H5_CONSOLE_BASE + STM32_USART_CR3_OFFSET); + cr &= ~USART_CR3_CLRBITS; + cr |= USART_CR3_SETBITS; + putreg32(cr, STM32H5_CONSOLE_BASE + STM32_USART_CR3_OFFSET); + + /* Configure the USART Baud Rate */ + + putreg32(STM32H5_BRR_VALUE, + STM32H5_CONSOLE_BASE + STM32_USART_BRR_OFFSET); + + /* Select oversampling by 8 */ + + cr = getreg32(STM32H5_CONSOLE_BASE + STM32_USART_CR1_OFFSET); +#ifdef USE_OVER8 + cr |= USART_CR1_OVER8; + putreg32(cr, STM32H5_CONSOLE_BASE + STM32_USART_CR1_OFFSET); +#endif + + /* Enable Rx, Tx, and the USART */ + + cr |= (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE); + putreg32(cr, STM32H5_CONSOLE_BASE + STM32_USART_CR1_OFFSET); + +#endif /* HAVE_CONSOLE && !CONFIG_SUPPRESS_UART_CONFIG */ +#endif /* HAVE_UART */ +} diff --git a/arch/arm/src/stm32h5/stm32_lowputc.h b/arch/arm/src/stm32h5/stm32_lowputc.h new file mode 100644 index 00000000000..bae3d0017b8 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_lowputc.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_lowputc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H5_STM32_LOWPUTC_H +#define __ARCH_ARM_SRC_STM32H5_STM32_LOWPUTC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: stm32_lowsetup + * + * Description: + * Called at the very beginning of _start. Performs low level + * initialization of serial console. + * + ****************************************************************************/ + +void stm32_lowsetup(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_STM32H5_STM32_LOWPUTC_H */ diff --git a/arch/arm/src/stm32h5/stm32_lse.c b/arch/arm/src/stm32h5/stm32_lse.c new file mode 100644 index 00000000000..e160cc8d1a2 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_lse.c @@ -0,0 +1,163 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_lse.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "arm_internal.h" +#include "stm32_pwr.h" +#include "stm32_rcc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define LSERDY_TIMEOUT (500 * CONFIG_BOARD_LOOPSPERMSEC) + +#ifdef CONFIG_STM32H5_RTC_LSECLOCK_START_DRV_CAPABILITY +# if CONFIG_STM32H5_RTC_LSECLOCK_START_DRV_CAPABILITY < 0 || \ + CONFIG_STM32H5_RTC_LSECLOCK_START_DRV_CAPABILITY > 3 +# error "Invalid LSE drive capability setting" +# endif +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_STM32H5_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY +static const uint32_t drives[4] = +{ + RCC_BDCR_LSEDRV_LOW, + RCC_BDCR_LSEDRV_MEDLO, + RCC_BDCR_LSEDRV_MEDHI, + RCC_BDCR_LSEDRV_HIGH +}; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_rcc_enablelse + * + * Description: + * Enable the External Low-Speed (LSE) oscillator and the LSE system clock. + * + ****************************************************************************/ + +void stm32_rcc_enablelse(void) +{ + bool writable; + uint32_t regval; + volatile int32_t timeout; +#ifdef CONFIG_STM32H5_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + volatile int32_t drive = 0; +#endif + + /* Check if both the External Low-Speed (LSE) oscillator and the LSE system + * clock are already running. + */ + + regval = getreg32(STM32_RCC_BDCR); + + if ((regval & (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) != + (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) + { + /* The LSE is in the RTC domain and write access is denied to this + * domain after reset, you have to enable write access using DBP bit in + * the PWR CR register before to configuring the LSE. + */ + + writable = stm32_pwr_enablebkp(true); + + /* Enable the External Low-Speed (LSE) oscillator by setting the LSEON + * bit the RCC BDCR register. + */ + + regval |= RCC_BDCR_LSEON; + +#ifdef CONFIG_STM32H5_RTC_LSECLOCK_START_DRV_CAPABILITY + /* Set start-up drive capability for LSE oscillator. LSE must be OFF + * to change drive strength. + */ + + regval &= ~(RCC_BDCR_LSEDRV_MASK | RCC_BDCR_LSEON); + regval |= CONFIG_STM32H5_RTC_LSECLOCK_START_DRV_CAPABILITY << + RCC_BDCR_LSEDRV_SHIFT; + putreg32(regval, STM32_RCC_BDCR); + regval |= RCC_BDCR_LSEON; +#endif + +#ifdef CONFIG_STM32H5_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + do + { + regval &= ~(RCC_BDCR_LSEDRV_MASK | RCC_BDCR_LSEON); + regval |= drives[drive++]; + putreg32(regval, STM32_RCC_BDCR); + regval |= RCC_BDCR_LSEON; +#endif + + putreg32(regval, STM32_RCC_BDCR); + + /* Wait for the LSE clock to be ready (or until a timeout elapsed) + */ + + for (timeout = LSERDY_TIMEOUT; timeout > 0; timeout--) + { + /* Check if the LSERDY flag is the set in the BDCR */ + + regval = getreg32(STM32_RCC_BDCR); + + if (regval & RCC_BDCR_LSERDY) + { + /* If so, then break-out with timeout > 0 */ + + break; + } + } + +#ifdef CONFIG_STM32H5_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + if (timeout != 0) + { + break; + } + } + while (drive < sizeof(drives) / sizeof(drives[0])); +#endif + +#ifdef CONFIG_STM32H5_RTC_LSECLOCK_LOWER_RUN_DRV_CAPABILITY + + /* Set running drive capability for LSE oscillator. */ + + regval &= ~RCC_BDCR_LSEDRV_MASK; + regval |= RCC_BDCR_LSEDRV_LOW << RCC_BDCR_LSEDRV_SHIFT; + putreg32(regval, STM32_RCC_BDCR); +#endif + + /* Disable backup domain access if it was disabled on entry */ + + stm32_pwr_enablebkp(writable); + } +} diff --git a/arch/arm/src/stm32h5/stm32_lsi.c b/arch/arm/src/stm32h5/stm32_lsi.c new file mode 100644 index 00000000000..bcc5491a04e --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_lsi.c @@ -0,0 +1,71 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_lsi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "arm_internal.h" +#include "stm32_rcc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_rcc_enablelsi + * + * Description: + * Enable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void stm32_rcc_enablelsi(void) +{ + /* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION + * bit the RCC CSR register. + */ + + modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_LSION); + + /* Wait for the internal LSI oscillator to be stable. */ + + while ((getreg32(STM32_RCC_BDCR) & RCC_BDCR_LSIRDY) == 0); +} + +/**************************************************************************** + * Name: stm32_rcc_disablelsi + * + * Description: + * Disable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void stm32_rcc_disablelsi(void) +{ + /* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION + * bit the RCC CSR register. + */ + + modifyreg32(STM32_RCC_BDCR, RCC_BDCR_LSION, 0); + + /* LSIRDY should go low after 3 LSI clock cycles */ +} diff --git a/arch/arm/src/stm32h5/stm32_pwr.c b/arch/arm/src/stm32h5/stm32_pwr.c new file mode 100644 index 00000000000..ec8526537eb --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_pwr.c @@ -0,0 +1,309 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_pwr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include + +#include "arm_internal.h" +#include "stm32_pwr.h" +#include "stm32_rcc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PWR_TIMEOUT (10 * CONFIG_BOARD_LOOPSPERMSEC) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline uint32_t stm32h5_pwr_getreg(uint16_t offset) +{ + return getreg32(STM32_PWR_BASE + (uint32_t)offset); +} + +static inline void stm32h5_pwr_putreg(uint16_t offset, uint16_t value) +{ + putreg32(value, STM32_PWR_BASE + (uint32_t)offset); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_pwr_enablebkp + * + * Description: + * Enables access to the backup domain (RTC registers, RTC backup data + * registers and backup SRAM). + * + * Input Parameters: + * writable True: enable ability to write to backup domain registers + * + * Returned Value: + * True: The backup domain was previously writable. + * + ****************************************************************************/ + +bool stm32_pwr_enablebkp(bool writable) +{ + uint16_t regval; + bool waswritable; + + /* Get the current state of the PWR disable Backup domain register */ + + regval = stm32h5_pwr_getreg(STM32_PWR_DBPCR_OFFSET); + waswritable = ((regval & PWR_DBPCR_DBP) != 0); + + /* Enable or disable the ability to write */ + + if (waswritable && !writable) + { + /* Disable backup domain access */ + + regval &= ~PWR_DBPCR_DBP; + stm32h5_pwr_putreg(STM32_PWR_DBPCR_OFFSET, regval); + } + else if (!waswritable && writable) + { + /* Enable backup domain access */ + + regval |= PWR_DBPCR_DBP; + stm32h5_pwr_putreg(STM32_PWR_DBPCR_OFFSET, regval); + + /* Enable does not happen right away */ + + up_udelay(4); + } + + return waswritable; +} + +/**************************************************************************** + * Name stm32_pwr_adjustvcore + * + * Description: + * Adjusts the voltage used for digital peripherals (V_CORE) before + * raising or after decreasing the system clock frequency. Compare + * [RM0481], section 10.7 Dynamic voltage scaling management. + * + * Note: Use only for VCore supplied with internal LDO or SMPS. + * For supplying VCore externally, use stm32_pwr_adjustvos_ext. + * + * Input Parameters: + * sysclock - The frequency in Hertz the system clock will or has been set + * to. + * + ****************************************************************************/ + +void stm32_pwr_adjustvcore(unsigned sysclock) +{ + volatile int timeout; + uint32_t vos_range; + uint32_t actvos; + + /* Select the applicable V_CORE voltage range depending on the new system + * clock frequency. + */ + + DEBUGASSERT(sysclock <= 250000000); + + if (sysclock > 200000000) + { + vos_range = PWR_VOSCR_VOS_RANGE0; + } + else if (sysclock > 150000000) + { + vos_range = PWR_VOSCR_VOS_RANGE1; + } + else if (sysclock > 100000000) + { + vos_range = PWR_VOSCR_VOS_RANGE2; + } + else + { + vos_range = PWR_VOSCR_VOS_RANGE3; + } + + actvos = (getreg32(STM32_PWR_VOSSR) & PWR_VOSSR_ACTVOS_MASK); + modreg32(vos_range, PWR_VOSCR_VOS_MASK, STM32_PWR_VOSCR); + + if (vos_range > actvos) + { + /* Wait until the new V_CORE voltage range has been applied. */ + + for (timeout = PWR_TIMEOUT; timeout; timeout--) + { + if (getreg32(STM32_PWR_VOSSR) & PWR_VOSSR_VOSRDY) + { + break; + } + } + + DEBUGASSERT(timeout > 0); + } + else if (vos_range < actvos) + { + /* Wait until the voltage level for the currently used VOS is ready. */ + + for (timeout = PWR_TIMEOUT; timeout; timeout--) + { + if (getreg32(STM32_PWR_VOSSR) & PWR_VOSSR_ACTVOSRDY) + { + break; + } + } + + DEBUGASSERT(timeout > 0); + } + else + { + /* actvos == vos_range. Do nothing. */ + + return; + } +} + +/**************************************************************************** + * Name stm32_pwr_adjustvos_ext + * + * Description: + * When changing VCore with an external supply, VOS must + * incrementally select intermediate levels. + * + * When increasing the performance: + * 1. First, voltage scaling must be incremented (for example when + * changing from VOS3 to VOS0, lower levels must be selected in the + * VOS[1:0] bits: VOS2, VOS1, and then VOS0). + * 2. The external voltage can be increased. + * 3. The system frequency can be increased. + * + * When decreasing the performance: + * 1. The system frequency MUST be decreased. + * 2. The external voltage MUST be decreased. + * 3. The voltage scaling can be decremented (for example when changing + * from VOS1 to VOS3, lower levels must be selected in the VOS[1:0] + * bits: VOS2, and then VOS3) + * + * Input Parameters: + * sysclock - The frequency in Hertz the system clock will or has been set + * to. + * + ****************************************************************************/ + +void stm32_pwr_adjustvos_ext(unsigned sysclock) +{ + uint32_t vos_range; + uint32_t vos_range_val; + uint32_t vos_range_set; + uint32_t actvos_val; + + /* Select the applicable V_CORE voltage range depending on the new system + * clock frequency. + */ + + DEBUGASSERT(sysclock <= 250000000); + + if (sysclock > 200000000) + { + vos_range = PWR_VOSCR_VOS_RANGE0; + } + else if (sysclock > 150000000) + { + vos_range = PWR_VOSCR_VOS_RANGE1; + } + else if (sysclock > 100000000) + { + vos_range = PWR_VOSCR_VOS_RANGE2; + } + else + { + vos_range = PWR_VOSCR_VOS_RANGE3; + } + + vos_range_val = (vos_range & PWR_VOSCR_VOS_MASK) >> PWR_VOSCR_VOS_SHIFT; + + actvos_val = ((getreg32(STM32_PWR_VOSSR) & PWR_VOSSR_ACTVOS_MASK) >> + PWR_VOSSR_ACTVOS_SHIFT); + + if (vos_range_val > actvos_val) + { + /* Gradually Increase VOS Scale */ + + for (int i = actvos_val; i < vos_range_val; ++i) + { + if (i == 0) + { + vos_range_set = PWR_VOSCR_VOS_RANGE2; + } + else if (i == 1) + { + vos_range_set = PWR_VOSCR_VOS_RANGE1; + } + else /* (i == 2) */ + { + vos_range_set = PWR_VOSCR_VOS_RANGE0; + } + + modreg32(vos_range_set, PWR_VOSCR_VOS_MASK, STM32_PWR_VOSCR); + up_udelay(1); + } + } + else if (vos_range_val < actvos_val) + { + /* Gradually Decrease VOS Scale */ + + for (int i = actvos_val; i > vos_range_val; --i) + { + if (i == 1) + { + vos_range_set = PWR_VOSCR_VOS_RANGE3; + } + else if (i == 2) + { + vos_range_set = PWR_VOSCR_VOS_RANGE2; + } + else /* (i == 3) */ + { + vos_range_set = PWR_VOSCR_VOS_RANGE1; + } + + modreg32(vos_range_set, PWR_VOSCR_VOS_MASK, STM32_PWR_VOSCR); + up_udelay(1); + } + } + else + { + /* actvos == new vos. Do nothing. */ + + return; + } +} diff --git a/arch/arm/src/stm32h5/stm32_pwr.h b/arch/arm/src/stm32h5/stm32_pwr.h new file mode 100644 index 00000000000..41c37177a08 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_pwr.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_pwr.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H5_STM32_PWR_H +#define __ARCH_ARM_SRC_STM32H5_STM32_PWR_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" +#include "hardware/stm32_pwr.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_pwr_enablebkp + * + * Description: + * Enables write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). Compare [RM0456], section 10.4.7 + * Battery Backup domain, Backup domain access. + * + * Input Parameters: + * writable - True: enable ability to write to backup domain registers + * + * Returned Value: + * True: The backup domain was previously writable. + * + ****************************************************************************/ + +bool stm32_pwr_enablebkp(bool writable); + +/**************************************************************************** + * Name stm32_pwr_adjustvcore + * + * Description: + * Adjusts the voltage used for digital peripherals (V_CORE) before + * raising or after decreasing the system clock frequency. Compare + * [RM0456], section 10.5.4 Dynamic voltage scaling management. + * + * Input Parameters: + * sysclock - The frequency in Hertz the system clock will be raised to. + * + ****************************************************************************/ + +void stm32_pwr_adjustvcore(unsigned sysclock); + +void stm32_pwr_adjustvos_ext(unsigned sysclock); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_STM32H5_STM32_PWR_H */ diff --git a/arch/arm/src/stm32h5/stm32_rcc.c b/arch/arm/src/stm32h5/stm32_rcc.c new file mode 100644 index 00000000000..20ea4ac08f2 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_rcc.c @@ -0,0 +1,252 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_rcc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "stm32_rcc.h" +#include "hardware/stm32_flash.h" +#include "stm32.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Allow up to 100 milliseconds for the high speed clock to become ready. + * that is a very long delay, but if the clock does not become ready we are + * hosed anyway. + */ + +#define HSERDY_TIMEOUT (100 * CONFIG_BOARD_LOOPSPERMSEC) + +#define LSERDY_TIMEOUT (500 * CONFIG_BOARD_LOOPSPERMSEC) + +#ifdef CONFIG_STM32H5_RTC_LSECLOCK_START_DRV_CAPABILITY +# if CONFIG_STM32H5_RTC_LSECLOCK_START_DRV_CAPABILITY < 0 || \ + CONFIG_STM32H5_RTC_LSECLOCK_START_DRV_CAPABILITY > 3 +# error "Invalid LSE drive capability setting" +# endif +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_STM32H5_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY +static const uint32_t drives[4] = +{ + RCC_BDCR_LSEDRV_LOW, + RCC_BDCR_LSEDRV_MEDLO, + RCC_BDCR_LSEDRV_MEDHI, + RCC_BDCR_LSEDRV_HIGH +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name + * + * Description + * The RTC needs to reset the Backup Domain to change RTCSEL and resetting + * the Backup Domain renders to disabling the LSE as consequence. In + * order to avoid resetting the Backup Domain when we already configured + * LSE we will reset the Backup Domain early (here). + * + * Input Parameters + * None + * + * Returned Value + * None + * + ****************************************************************************/ + +#if defined(CONFIG_STM32H5_PWR) && defined(CONFIG_STM32H5_RTC) +static inline void rcc_resetbkp(void) +{ + bool init_stat; + + /* Check if the RTC is already configured */ + + init_stat = stm32h5_rtc_is_initialized(); + if (!init_stat) + { + uint32_t bkregs[STM32H5_RTC_BKCOUNT]; + int i; + + /* Backup backup-registers before RTC reset. */ + + for (i = 0; i < STM32H5_RTC_BKCOUNT; i++) + { + bkregs[i] = getreg32(STM32H5_RTC_BKR(i)); + } + + /* Enable write access to the backup domain (RTC registers, RTC + * backup data registers and backup SRAM). + */ + + stm32_pwr_enablebkp(true); + + /* We might be changing RTCSEL - to ensure such changes work, we must + * reset the backup domain (having backed up the RTC_MAGIC token) + */ + + modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_BDRST); + modifyreg32(STM32_RCC_BDCR, RCC_BDCR_BDRST, 0); + + /* Restore backup-registers, except RTC related. */ + + for (i = 0; i < STM32H5_RTC_BKCOUNT; i++) + { + if (RTC_MAGIC_REG == STM32H5_RTC_BKR(i)) + { + continue; + } + + putreg32(bkregs[i], STM32H5_RTC_BKR(i)); + } + + stm32_pwr_enablebkp(false); + } +} +#else +# define rcc_resetbkp() +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name + * + * Description + * Called to establish the clock settings based on the values in board.h. + * This function (by default) will reset most everything, enable the PLL, + * and enable peripheral clocking for all peripherals enabled in the NuttX + * configuration file. + * + * If CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG is defined, then + * clocking will be enabled by an externally provided, board-specific + * function called stm32_board_clockconfig(). + * + * Input Parameters + * None + * + * Returned Value + * None + * + ****************************************************************************/ + +void stm32_clockconfig(void) +{ +#if 0 + /* Make sure that we are starting in the reset state */ + + rcc_reset(); + + /* Reset backup domain if appropriate */ + + rcc_resetbkp(); +#endif +#if defined(CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG) + + /* Invoke Board Custom Clock Configuration */ + + stm32_board_clockconfig(); + +#else + + /* Invoke standard, fixed clock configuration based on definitions in + * board.h + */ + + stm32_stdclockconfig(); + +#endif + + /* Enable peripheral clocking */ + + stm32_rcc_enableperipherals(); +} + +/**************************************************************************** + * Name + * + * Description + * Re-enable the clock and restore the clock settings based on settings in + * board.h. This function is only available to support low-power modes of + * operation + * re-enable/re-start the PLL + * + * This function performs a subset of the operations performed by + * stm32_clockconfig() + * reset the currently enabled peripheral clocks. + * + * If CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG is defined, then + * clocking will be enabled by an externally provided, board-specific + * function called stm32_board_clockconfig(). + * + * Input Parameters + * None + * + * Returned Value + * None + * + ****************************************************************************/ + +#ifdef CONFIG_PM +void stm32_clockenable(void) +{ +#if defined(CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG) + + /* Invoke Board Custom Clock Configuration */ + + stm32_board_clockconfig(); + +#else + + /* Invoke standard, fixed clock configuration based on definitions in + * board.h + */ + + stm32_stdclockconfig(); + +#endif +} +#endif diff --git a/arch/arm/src/stm32h5/stm32_rcc.h b/arch/arm/src/stm32h5/stm32_rcc.h new file mode 100644 index 00000000000..be9be1fd37c --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_rcc.h @@ -0,0 +1,251 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_rcc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H5_STM32_RCC_H +#define __ARCH_ARM_SRC_STM32H5_STM32_RCC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "arm_internal.h" +#include "chip.h" + +#if defined(CONFIG_STM32H5_STM32H5XXXX) +# include "hardware/stm32_rcc.h" +#else +# error "Unsupported STM32H5 chip" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_mco1config + * + * Description: + * + * Input Parameters: + * source - One of the definitions for the RCC_CFGR_MCO definitions from + * chip/stm32h5_rcc.h {RCC_CFGR_SYSCLK, RCC_CFGR_INTCLK, + * RCC_CFGR_EXTCLK, RCC_CFGR_PLLCLKd2, RCC_CFGR_PLL2CLK, + * RCC_CFGR_PLL3CLKd2, RCC_CFGR_XT1, RCC_CFGR_PLL3CLK} + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void stm32_mco1config(uint32_t source) +{ + uint32_t regval; + + /* Set MCO source */ + + regval = getreg32(STM32_RCC_CFGR1); + regval &= ~(RCC_CFGR1_MCO1SEL_MASK); + regval |= (source & RCC_CFGR1_MCO1SEL_MASK); + putreg32(regval, STM32_RCC_CFGR1); +} + +/**************************************************************************** + * Name: stm32_mco2config + * + * Description: + * + * Input Parameters: + * source - One of the definitions for the RCC_CFGR_MCO definitions from + * chip/stm32h5_rcc.h {RCC_CFGR_SYSCLK, RCC_CFGR_INTCLK, + * RCC_CFGR_EXTCLK, RCC_CFGR_PLLCLKd2, RCC_CFGR_PLL2CLK, + * RCC_CFGR_PLL3CLKd2, RCC_CFGR_XT1, RCC_CFGR_PLL3CLK} + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void stm32_mco2config(uint32_t source) +{ + uint32_t regval; + + /* Set MCO source */ + + regval = getreg32(STM32_RCC_CFGR1); + regval &= ~(RCC_CFGR1_MCO2SEL_MASK); + regval |= (source & RCC_CFGR1_MCO2SEL_MASK); + putreg32(regval, STM32_RCC_CFGR1); +} + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_clockconfig + * + * Description: + * Called to establish the clock settings based on the values in board.h. + * This function (by default) will reset most everything, enable the PLL, + * and enable peripheral clocking for all periperipherals enabled in the + * NuttX configuration file. + * + * If CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG is defined, then + * clocking will be enabled by an externally provided, board-specific + * function called stm32_board_clockconfig(). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32_clockconfig(void); + +/**************************************************************************** + * Name: stm32_board_clockconfig + * + * Description: + * Any STM32H5 board may replace the "standard" board clock configuration + * logic with its own, custom clock configuration logic. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG +void stm32_board_clockconfig(void); +#endif + +/**************************************************************************** + * Name: stm32_stdclockconfig + * + * Description: + * The standard logic to configure the clocks based on settings in board.h. + * Applicable if no custom clock config is provided. This function is + * chip type specific and implemented in corresponding modules such as e.g. + * stm32h562xx_rcc.c + * + ****************************************************************************/ + +#ifndef CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG +void stm32_stdclockconfig(void); +#endif + +/**************************************************************************** + * Name: stm32_clockenable + * + * Description: + * Re-enable the clock and restore the clock settings based on settings in + * board.h. This function is only available to support low-power modes of + * operation: When re-awakening from deep-sleep modes, it is necessary to + * re-enable/re-start the PLL + * + * This function performs a subset of the operations performed by + * stm32_clockconfig(): It does not reset any devices, and it does not + * reset the currently enabled peripheral clocks. + * + * If CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG is defined, then + * clocking will be enabled by an externally provided, board-specific + * function called stm32_board_clockconfig(). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_PM +void stm32_clockenable(void); +#endif + +/**************************************************************************** + * Name: stm32_rcc_enablelse + * + * Description: + * Enable the External Low-Speed (LSE) Oscillator. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32_rcc_enablelse(void); + +/**************************************************************************** + * Name: stm32_rcc_enablelsi + * + * Description: + * Enable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void stm32_rcc_enablelsi(void); + +/**************************************************************************** + * Name: stm32_rcc_disablelsi + * + * Description: + * Disable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void stm32_rcc_disablelsi(void); + +/**************************************************************************** + * Name: stm32_rcc_enableperipherals + * + * Description: + * Enable all the chip peripherals according to configuration. This is + * chip type specific and thus implemented in corresponding modules such as + * e.g. stm32h562xx_rcc.c + * + ****************************************************************************/ + +void stm32_rcc_enableperipherals(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_STM32H5_STM32_RCC_H */ diff --git a/arch/arm/src/stm32h5/stm32_serial.c b/arch/arm/src/stm32h5/stm32_serial.c new file mode 100644 index 00000000000..5ee638897aa --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_serial.c @@ -0,0 +1,3859 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_serial.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include + +#include "chip.h" +#include "stm32_gpio.h" +#include "stm32_uart.h" + +/* DMA has not been implemented for H5 chip yet, so disable any serial DMA */ + +#ifdef SERIAL_HAVE_DMA +# error Serial DMA not implemented for STM32H5 chips. +#undef SERIAL_HAVE_DMA +#endif + +#include "stm32_rcc.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Some sanity checks *******************************************************/ + +/* DMA configuration */ + +/* If DMA is enabled on any USART, then very that other pre-requisites + * have also been selected. + * UART DMA1 DMA2 + * 1 X X + * 2 X + * 3 X + * 4 X + * 5 X + */ + +#ifdef SERIAL_HAVE_DMA + +/* Verify that DMA has been enabled and the DMA channel has been defined. + */ + +# if defined(CONFIG_USART2_RXDMA) || defined(CONFIG_USART3_RXDMA) +# if !defined(CONFIG_STM32H5_DMA1) && !defined(CONFIG_STM32H5_DMAMUX) +# error STM32H5 USART2/3 receive DMA requires CONFIG_STM32H5_DMA1 +# endif +# endif + +# if defined(CONFIG_UART4_RXDMA) || defined(CONFIG_UART5_RXDMA) +# if !defined(CONFIG_STM32H5_DMA2) && !defined(CONFIG_STM32H5_DMAMUX) +# error STM32H5 UART4/5 receive DMA requires CONFIG_STM32H5_DMA2 +# endif +# endif + +/* Currently RS-485 support cannot be enabled when RXDMA is in use due to + * lack of testing - RS-485 support was developed on STM32F1x + */ + +# if (defined(CONFIG_USART1_RXDMA) && defined(CONFIG_USART1_RS485)) || \ + (defined(CONFIG_USART2_RXDMA) && defined(CONFIG_USART2_RS485)) || \ + (defined(CONFIG_USART3_RXDMA) && defined(CONFIG_USART3_RS485)) || \ + (defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_RS485)) || \ + (defined(CONFIG_UART5_RXDMA) && defined(CONFIG_UART5_RS485)) +# error "RXDMA and RS-485 cannot be enabled at the same time for the same U[S]ART" +# endif + +/* For the L4, there are alternate DMA channels for USART1. + * Logic in the board.h file make the DMA channel selection by defining + * the following in the board.h file. + */ + +# if defined(CONFIG_USART1_RXDMA) && !defined(DMAMAP_USART1_RX) +# error "USART1 DMA channel not defined (DMAMAP_USART1_RX)" +# endif + +/* UART2-5 have no alternate channels without DMAMUX */ + +# ifndef CONFIG_STM32H5_HAVE_DMAMUX +# define DMAMAP_USART2_RX DMACHAN_USART2_RX +# define DMAMAP_USART3_RX DMACHAN_USART3_RX +# define DMAMAP_UART4_RX DMACHAN_UART4_RX +# define DMAMAP_UART5_RX DMACHAN_UART5_RX +# endif + +# if defined(CONFIG_USART2_RXDMA) && !defined(DMAMAP_USART2_RX) +# error "USART2 DMA channel not defined (DMAMAP_USART2_RX)" +# endif + +# if defined(CONFIG_USART3_RXDMA) && !defined(DMAMAP_USART3_RX) +# error "USART3 DMA channel not defined (DMAMAP_USART3_RX)" +# endif + +# if defined(CONFIG_UART4_RXDMA) && !defined(DMAMAP_UART4_RX) +# error "UART4 DMA channel not defined (DMAMAP_UART4_RX)" +# endif + +# if defined(CONFIG_UART5_RXDMA) && !defined(DMAMAP_UART5_RX) +# error "UART5 DMA channel not defined (DMAMAP_UART5_RX)" +# endif + +/* The DMA buffer size when using RX DMA to emulate a FIFO. + * + * When streaming data, the generic serial layer will be called + * every time the FIFO receives half this number of bytes. + * + * If there ever is a STM32H5 with D-cache, the buffer size + * should be an even multiple of ARMV7M_DCACHE_LINESIZE, so that it + * can be individually invalidated. + */ + +# if !defined(CONFIG_STM32H5_SERIAL_RXDMA_BUFFER_SIZE) || \ + CONFIG_STM32H5_SERIAL_RXDMA_BUFFER_SIZE == 0 +# define RXDMA_BUFFER_SIZE 32 +# else +# define RXDMA_BUFFER_SIZE ((CONFIG_STM32H5_SERIAL_RXDMA_BUFFER_SIZE + 31) & ~31) +# endif + +/* DMA priority */ + +# ifndef CONFIG_USART_DMAPRIO +# define CONFIG_USART_DMAPRIO DMA_CCR_PRIMED +# endif +# if (CONFIG_USART_DMAPRIO & ~DMA_CCR_PL_MASK) != 0 +# error "Illegal value for CONFIG_USART_DMAPRIO" +# endif + +/* DMA control words */ + +# define SERIAL_DMA_CONTROL_WORD \ + (DMA_CCR_CIRC | \ + DMA_CCR_MINC | \ + DMA_CCR_PSIZE_8BITS | \ + DMA_CCR_MSIZE_8BITS | \ + CONFIG_USART_DMAPRIO) +# ifdef CONFIG_SERIAL_IFLOWCONTROL +# define SERIAL_DMA_IFLOW_CONTROL_WORD \ + (DMA_CCR_MINC | \ + DMA_CCR_PSIZE_8BITS | \ + DMA_CCR_MSIZE_8BITS | \ + CONFIG_USART_DMAPRIO) +# endif + +#endif + +/* Power management definitions */ + +#if defined(CONFIG_PM) && !defined(CONFIG_STM32H5_PM_SERIAL_ACTIVITY) +# define CONFIG_STM32H5_PM_SERIAL_ACTIVITY 10 +#endif + +/* Keep track if a Break was set + * + * Note: + * + * 1) This value is set in the priv->ie but never written to the control + * register. It must not collide with USART_CR1_USED_INTS or USART_CR3_EIE + * 2) USART_CR3_EIE is also carried in the up_dev_s ie member. + * + * See stm32serial_restoreusartint where the masking is done. + */ + +#ifdef CONFIG_STM32H5_SERIALBRK_BSDCOMPAT +# define USART_CR1_IE_BREAK_INPROGRESS_SHFTS 15 +# define USART_CR1_IE_BREAK_INPROGRESS (1 << USART_CR1_IE_BREAK_INPROGRESS_SHFTS) +#endif + +#ifdef USE_SERIALDRIVER +#ifdef HAVE_UART + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct stm32_serial_s +{ + struct uart_dev_s dev; /* Generic UART device */ + uint16_t ie; /* Saved interrupt mask bits value */ + uint16_t sr; /* Saved status bits */ + + /* Has been initialized and HW is setup. */ + + bool initialized; + +#ifdef CONFIG_PM + bool suspended; /* UART device has been suspended. */ + + /* Interrupt mask value stored before suspending for stop mode. */ + + uint16_t suspended_ie; +#endif + + /* If termios are supported, then the following fields may vary at + * runtime. + */ + +#ifdef CONFIG_SERIAL_TERMIOS + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ + bool stopbits2; /* True: Configure with 2 stop bits instead of 1 */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + bool iflow; /* input flow control (RTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + bool oflow; /* output flow control (CTS) enabled */ +#endif + uint32_t baud; /* Configured baud */ +#else + const uint8_t parity; /* 0=none, 1=odd, 2=even */ + const uint8_t bits; /* Number of bits (7 or 8) */ + const bool stopbits2; /* True: Configure with 2 stop bits instead of 1 */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + const bool iflow; /* input flow control (RTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + const bool oflow; /* output flow control (CTS) enabled */ +#endif + const uint32_t baud; /* Configured baud */ +#endif + + const uint8_t irq; /* IRQ associated with this USART */ + const uint32_t apbclock; /* PCLK 1 or 2 frequency */ + const uint32_t usartbase; /* Base address of USART registers */ + const uint32_t tx_gpio; /* U[S]ART TX GPIO pin configuration */ + const uint32_t rx_gpio; /* U[S]ART RX GPIO pin configuration */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + const uint32_t rts_gpio; /* U[S]ART RTS GPIO pin configuration */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */ +#endif + +#ifdef SERIAL_HAVE_DMA + const unsigned int rxdma_channel; /* DMA channel assigned */ +#endif + + /* RX DMA state */ + +#ifdef SERIAL_HAVE_DMA + DMA_HANDLE rxdma; /* currently-open receive DMA stream */ + bool rxenable; /* DMA-based reception en/disable */ +#ifdef CONFIG_PM + bool rxdmasusp; /* Rx DMA suspended */ +#endif + uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */ + char *const rxfifo; /* Receive DMA buffer */ +#endif + +#ifdef HAVE_RS485 + const uint32_t rs485_dir_gpio; /* U[S]ART RS-485 DIR GPIO pin configuration */ + const bool rs485_dir_polarity; /* U[S]ART RS-485 DIR pin state for TX enabled */ +#endif + const bool islpuart; /* Is this device a Low Power UART? */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifndef CONFIG_SUPPRESS_UART_CONFIG +static void stm32serial_setformat(struct uart_dev_s *dev); +#endif +static int stm32serial_setup(struct uart_dev_s *dev); +static void stm32serial_shutdown(struct uart_dev_s *dev); +static int stm32serial_attach(struct uart_dev_s *dev); +static void stm32serial_detach(struct uart_dev_s *dev); +static int stm32serial_interrupt(int irq, void *context, void *arg); +static int stm32serial_ioctl(struct file *filep, + int cmd, unsigned long arg); +#ifndef SERIAL_HAVE_ONLY_DMA +static int stm32serial_receive(struct uart_dev_s *dev, + unsigned int *status); +static void stm32serial_rxint(struct uart_dev_s *dev, bool enable); +static bool stm32serial_rxavailable(struct uart_dev_s *dev); +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool stm32serial_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper); +#endif +static void stm32serial_send(struct uart_dev_s *dev, int ch); +static void stm32serial_txint(struct uart_dev_s *dev, bool enable); +static bool stm32serial_txready(struct uart_dev_s *dev); + +#ifdef SERIAL_HAVE_DMA +static int stm32serial_dmasetup(struct uart_dev_s *dev); +static void stm32serial_dmashutdown(struct uart_dev_s *dev); +static int stm32serial_dmareceive(struct uart_dev_s *dev, + unsigned int *status); +static void stm32serial_dmareenable(struct stm32_serial_s *priv); +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool stm32serial_dmaiflowrestart(struct stm32_serial_s *priv); +#endif +static void stm32serial_dmarxint(struct uart_dev_s *dev, bool enable); +static bool stm32serial_dmarxavailable(struct uart_dev_s *dev); + +static void stm32serial_dmarxcallback(DMA_HANDLE handle, uint8_t status, + void *arg); +#endif + +#ifdef CONFIG_PM +static void stm32serial_setsuspend(struct uart_dev_s *dev, bool suspend); +static void stm32serial_pm_setsuspend(bool suspend); +static void stm32serial_pmnotify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +static int stm32serial_pmprepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_DMA +static const struct uart_ops_s g_uart_ops = +{ + .setup = stm32serial_setup, + .shutdown = stm32serial_shutdown, + .attach = stm32serial_attach, + .detach = stm32serial_detach, + .ioctl = stm32serial_ioctl, + .receive = stm32serial_receive, + .rxint = stm32serial_rxint, + .rxavailable = stm32serial_rxavailable, +# ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = stm32serial_rxflowcontrol, +# endif + .send = stm32serial_send, + .txint = stm32serial_txint, + .txready = stm32serial_txready, + .txempty = stm32serial_txready, +}; +#endif + +#ifdef SERIAL_HAVE_DMA +static const struct uart_ops_s g_uart_dma_ops = +{ + .setup = stm32serial_dmasetup, + .shutdown = stm32serial_dmashutdown, + .attach = stm32serial_attach, + .detach = stm32serial_detach, + .ioctl = stm32serial_ioctl, + .receive = stm32serial_dmareceive, + .rxint = stm32serial_dmarxint, + .rxavailable = stm32serial_dmarxavailable, +# ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = stm32serial_rxflowcontrol, +# endif + .send = stm32serial_send, + .txint = stm32serial_txint, + .txready = stm32serial_txready, + .txempty = stm32serial_txready, +}; +#endif + +/* I/O buffers */ + +#ifdef CONFIG_STM32H5_LPUART1_SERIALDRIVER +static char g_lpuart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE]; +static char g_lpuart1txbuffer[CONFIG_LPUART1_TXBUFSIZE]; +# ifdef CONFIG_LPUART1_RXDMA +static char g_lpuart1rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_STM32H5_USART1_SERIALDRIVER +static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE]; +static char g_usart1txbuffer[CONFIG_USART1_TXBUFSIZE]; +# ifdef CONFIG_USART1_RXDMA +static char g_usart1rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_STM32H5_USART2_SERIALDRIVER +static char g_usart2rxbuffer[CONFIG_USART2_RXBUFSIZE]; +static char g_usart2txbuffer[CONFIG_USART2_TXBUFSIZE]; +# ifdef CONFIG_USART2_RXDMA +static char g_usart2rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_STM32H5_USART3_SERIALDRIVER +static char g_usart3rxbuffer[CONFIG_USART3_RXBUFSIZE]; +static char g_usart3txbuffer[CONFIG_USART3_TXBUFSIZE]; +# ifdef CONFIG_USART3_RXDMA +static char g_usart3rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_STM32H5_UART4_SERIALDRIVER +static char g_uart4rxbuffer[CONFIG_UART4_RXBUFSIZE]; +static char g_uart4txbuffer[CONFIG_UART4_TXBUFSIZE]; +# ifdef CONFIG_UART4_RXDMA +static char g_uart4rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_STM32H5_UART5_SERIALDRIVER +static char g_uart5rxbuffer[CONFIG_UART5_RXBUFSIZE]; +static char g_uart5txbuffer[CONFIG_UART5_TXBUFSIZE]; +# ifdef CONFIG_UART5_RXDMA +static char g_uart5rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +/* This describes the state of the STM32 USART1 ports. */ + +#ifdef CONFIG_STM32H5_LPUART1_SERIALDRIVER +static struct stm32_serial_s g_lpuart1priv = +{ + .dev = + { +# if CONSOLE_UART == 1 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_LPUART1_RXBUFSIZE, + .buffer = g_lpuart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART1_TXBUFSIZE, + .buffer = g_lpuart1txbuffer, + }, +# ifdef CONFIG_LPUART1_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_lpuart1priv, + }, + + .islpuart = true, + .irq = STM32H5_IRQ_LPUART1, + .parity = CONFIG_LPUART1_PARITY, + .bits = CONFIG_LPUART1_BITS, + .stopbits2 = CONFIG_LPUART1_2STOP, + .baud = CONFIG_LPUART1_BAUD, + .apbclock = STM32_PCLK2_FREQUENCY, + .usartbase = STM32_LPUART1_BASE, + .tx_gpio = GPIO_LPUART1_TX, + .rx_gpio = GPIO_LPUART1_RX, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART1_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_LPUART1_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_LPUART1_RTS, +# endif +# ifdef CONFIG_LPUART1_RXDMA + .rxdma_channel = DMAMAP_LPUSART_RX, + .rxfifo = g_lpuart1rxfifo, +# endif + +# ifdef CONFIG_USART1_RS485 + .rs485_dir_gpio = GPIO_LPUART1_RS485_DIR, +# if (CONFIG_USART1_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +#ifdef CONFIG_STM32H5_USART1_SERIALDRIVER +static struct stm32_serial_s g_usart1priv = +{ + .dev = + { +# if CONSOLE_UART == 2 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_USART1_RXBUFSIZE, + .buffer = g_usart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART1_TXBUFSIZE, + .buffer = g_usart1txbuffer, + }, +# ifdef CONFIG_USART1_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_usart1priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_USART1, + .parity = CONFIG_USART1_PARITY, + .bits = CONFIG_USART1_BITS, + .stopbits2 = CONFIG_USART1_2STOP, + .baud = CONFIG_USART1_BAUD, + .apbclock = STM32_PCLK2_FREQUENCY, + .usartbase = STM32_USART1_BASE, + .tx_gpio = GPIO_USART1_TX, + .rx_gpio = GPIO_USART1_RX, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART1_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART1_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART1_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART1_RTS, +# endif +# ifdef CONFIG_USART1_RXDMA + .rxdma_channel = DMAMAP_USART1_RX, + .rxfifo = g_usart1rxfifo, +# endif + +# ifdef CONFIG_USART1_RS485 + .rs485_dir_gpio = GPIO_USART1_RS485_DIR, +# if (CONFIG_USART1_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 USART2 port. */ + +#ifdef CONFIG_STM32H5_USART2_SERIALDRIVER +static struct stm32_serial_s g_usart2priv = +{ + .dev = + { +# if CONSOLE_UART == 3 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_USART2_RXBUFSIZE, + .buffer = g_usart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART2_TXBUFSIZE, + .buffer = g_usart2txbuffer, + }, +# ifdef CONFIG_USART2_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_usart2priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_USART2, + .parity = CONFIG_USART2_PARITY, + .bits = CONFIG_USART2_BITS, + .stopbits2 = CONFIG_USART2_2STOP, + .baud = CONFIG_USART2_BAUD, + .apbclock = STM32_PCLK1_FREQUENCY, + .usartbase = STM32_USART2_BASE, + .tx_gpio = GPIO_USART2_TX, + .rx_gpio = GPIO_USART2_RX, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART2_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART2_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART2_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART2_RTS, +# endif +# ifdef CONFIG_USART2_RXDMA + .rxdma_channel = DMAMAP_USART2_RX, + .rxfifo = g_usart2rxfifo, +# endif + +# ifdef CONFIG_USART2_RS485 + .rs485_dir_gpio = GPIO_USART2_RS485_DIR, +# if (CONFIG_USART2_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 USART3 port. */ + +#ifdef CONFIG_STM32H5_USART3_SERIALDRIVER +static struct stm32_serial_s g_usart3priv = +{ + .dev = + { +# if CONSOLE_UART == 4 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_USART3_RXBUFSIZE, + .buffer = g_usart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART3_TXBUFSIZE, + .buffer = g_usart3txbuffer, + }, +# ifdef CONFIG_USART3_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_usart3priv, + }, + + .islpuart = false, + .irq = STM32_IRQ_USART3, + .parity = CONFIG_USART3_PARITY, + .bits = CONFIG_USART3_BITS, + .stopbits2 = CONFIG_USART3_2STOP, + .baud = CONFIG_USART3_BAUD, + .apbclock = STM32_PCLK1_FREQUENCY, + .usartbase = STM32_USART3_BASE, + .tx_gpio = GPIO_USART3_TX, + .rx_gpio = GPIO_USART3_RX, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART3_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART3_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART3_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART3_RTS, +# endif +# ifdef CONFIG_USART3_RXDMA + .rxdma_channel = DMAMAP_USART3_RX, + .rxfifo = g_usart3rxfifo, +# endif + +# ifdef CONFIG_USART3_RS485 + .rs485_dir_gpio = GPIO_USART3_RS485_DIR, +# if (CONFIG_USART3_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 UART4 port. */ + +#ifdef CONFIG_STM32H5_UART4_SERIALDRIVER +static struct stm32_serial_s g_uart4priv = +{ + .dev = + { +# if CONSOLE_UART == 5 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_UART4_RXBUFSIZE, + .buffer = g_uart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART4_TXBUFSIZE, + .buffer = g_uart4txbuffer, + }, +# ifdef CONFIG_UART4_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_uart4priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_UART4, + .parity = CONFIG_UART4_PARITY, + .bits = CONFIG_UART4_BITS, + .stopbits2 = CONFIG_UART4_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART4_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART4_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART4_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART4_RTS, +# endif + .baud = CONFIG_UART4_BAUD, + .apbclock = STM32_PCLK1_FREQUENCY, + .usartbase = STM32_UART4_BASE, + .tx_gpio = GPIO_UART4_TX, + .rx_gpio = GPIO_UART4_RX, +# ifdef CONFIG_UART4_RXDMA + .rxdma_channel = DMAMAP_UART4_RX, + .rxfifo = g_uart4rxfifo, +# endif + +# ifdef CONFIG_UART4_RS485 + .rs485_dir_gpio = GPIO_UART4_RS485_DIR, +# if (CONFIG_UART4_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 UART5 port. */ + +#ifdef CONFIG_STM32H5_UART5_SERIALDRIVER +static struct stm32_serial_s g_uart5priv = +{ + .dev = + { +# if CONSOLE_UART == 6 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_UART5_RXBUFSIZE, + .buffer = g_uart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART5_TXBUFSIZE, + .buffer = g_uart5txbuffer, + }, +# ifdef CONFIG_UART5_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_uart5priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_UART5, + .parity = CONFIG_UART5_PARITY, + .bits = CONFIG_UART5_BITS, + .stopbits2 = CONFIG_UART5_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART5_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART5_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART5_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART5_RTS, +# endif + .baud = CONFIG_UART5_BAUD, + .apbclock = STM32_PCLK1_FREQUENCY, + .usartbase = STM32_UART5_BASE, + .tx_gpio = GPIO_UART5_TX, + .rx_gpio = GPIO_UART5_RX, +# ifdef CONFIG_UART5_RXDMA + .rxdma_channel = DMAMAP_UART5_RX, + .rxfifo = g_uart5rxfifo, +# endif + +# ifdef CONFIG_UART5_RS485 + .rs485_dir_gpio = GPIO_UART5_RS485_DIR, +# if (CONFIG_UART5_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 USART6 port. */ + +#ifdef CONFIG_STM32H5_USART6_SERIALDRIVER +static struct stm32_serial_s g_usart6priv = +{ + .dev = + { +# if CONSOLE_UART == 7 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_USART6_RXBUFSIZE, + .buffer = g_usart6rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART6_TXBUFSIZE, + .buffer = g_usart6txbuffer, + }, +# ifdef CONFIG_USART6_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_usart6priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_USART6, + .parity = CONFIG_USART6_PARITY, + .bits = CONFIG_USART6_BITS, + .stopbits2 = CONFIG_USART6_2STOP, + .baud = CONFIG_USART6_BAUD, + .apbclock = STM32_PCLK2_FREQUENCY, + .usartbase = STM32_USART6_BASE, + .tx_gpio = GPIO_USART6_TX, + .rx_gpio = GPIO_USART6_RX, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART6_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART6_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART6_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART6_RTS, +# endif +# ifdef CONFIG_USART6_RXDMA + .rxdma_channel = DMAMAP_USART6_RX, + .rxfifo = g_usart6rxfifo, +# endif + +# ifdef CONFIG_USART6_RS485 + .rs485_dir_gpio = GPIO_USART6_RS485_DIR, +# if (CONFIG_USART6_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 UART7 port. */ + +#ifdef CONFIG_STM32H5_UART7_SERIALDRIVER +static struct stm32_serial_s g_uart7priv = +{ + .dev = + { +# if CONSOLE_UART == 8 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_UART7_RXBUFSIZE, + .buffer = g_uart7rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART7_TXBUFSIZE, + .buffer = g_uart7txbuffer, + }, +# ifdef CONFIG_UART7_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_uart7priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_UART7, + .parity = CONFIG_UART7_PARITY, + .bits = CONFIG_UART7_BITS, + .stopbits2 = CONFIG_UART7_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART7_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART7_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART7_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART7_RTS, +# endif + .baud = CONFIG_UART7_BAUD, + .apbclock = STM32_PCLK1_FREQUENCY, + .usartbase = STM32_UART7_BASE, + .tx_gpio = GPIO_UART7_TX, + .rx_gpio = GPIO_UART7_RX, +# ifdef CONFIG_UART7_RXDMA + .rxdma_channel = DMAMAP_UART7_RX, + .rxfifo = g_uart7rxfifo, +# endif + +# ifdef CONFIG_UART7_RS485 + .rs485_dir_gpio = GPIO_UART7_RS485_DIR, +# if (CONFIG_UART7_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 UART8 port. */ + +#ifdef CONFIG_STM32H5_UART8_SERIALDRIVER +static struct stm32_serial_s g_uart8priv = +{ + .dev = + { +# if CONSOLE_UART == 9 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_UART8_RXBUFSIZE, + .buffer = g_uart8rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART8_TXBUFSIZE, + .buffer = g_uart8txbuffer, + }, +# ifdef CONFIG_UART8_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_uart8priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_UART8, + .parity = CONFIG_UART8_PARITY, + .bits = CONFIG_UART8_BITS, + .stopbits2 = CONFIG_UART8_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART8_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART8_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART8_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART8_RTS, +# endif + .baud = CONFIG_UART8_BAUD, + .apbclock = STM32_PCLK1_FREQUENCY, + .usartbase = STM32_UART8_BASE, + .tx_gpio = GPIO_UART8_TX, + .rx_gpio = GPIO_UART8_RX, +# ifdef CONFIG_UART8_RXDMA + .rxdma_channel = DMAMAP_UART8_RX, + .rxfifo = g_uart8rxfifo, +# endif + +# ifdef CONFIG_UART8_RS485 + .rs485_dir_gpio = GPIO_UART8_RS485_DIR, +# if (CONFIG_UART8_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 UART9 port. */ + +#ifdef CONFIG_STM32H5_UART9_SERIALDRIVER +static struct stm32_serial_s g_uart9priv = +{ + .dev = + { +# if CONSOLE_UART == 10 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_UART9_RXBUFSIZE, + .buffer = g_uart9rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART9_TXBUFSIZE, + .buffer = g_uart9txbuffer, + }, +# ifdef CONFIG_UART9_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_uart9priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_UART9, + .parity = CONFIG_UART9_PARITY, + .bits = CONFIG_UART9_BITS, + .stopbits2 = CONFIG_UART9_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART9_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART9_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART9_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART9_RTS, +# endif + .baud = CONFIG_UART9_BAUD, + .apbclock = STM32_PCLK1_FREQUENCY, + .usartbase = STM32_UART9_BASE, + .tx_gpio = GPIO_UART9_TX, + .rx_gpio = GPIO_UART9_RX, +# ifdef CONFIG_UART9_RXDMA + .rxdma_channel = DMAMAP_UART9_RX, + .rxfifo = g_uart9rxfifo, +# endif + +# ifdef CONFIG_UART9_RS485 + .rs485_dir_gpio = GPIO_UART9_RS485_DIR, +# if (CONFIG_UART9_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 USART10 port. */ + +#ifdef CONFIG_STM32H5_USART10_SERIALDRIVER +static struct stm32_serial_s g_usart10priv = +{ + .dev = + { +# if CONSOLE_UART == 11 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_USART10_RXBUFSIZE, + .buffer = g_usart10rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART10_TXBUFSIZE, + .buffer = g_usart10txbuffer, + }, +# ifdef CONFIG_USART10_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_usart10priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_USART10, + .parity = CONFIG_USART10_PARITY, + .bits = CONFIG_USART10_BITS, + .stopbits2 = CONFIG_USART10_2STOP, + .baud = CONFIG_USART10_BAUD, + .apbclock = STM32_PCLK2_FREQUENCY, + .usartbase = STM32_USART10_BASE, + .tx_gpio = GPIO_USART10_TX, + .rx_gpio = GPIO_USART10_RX, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART10_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART10_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART10_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART10_RTS, +# endif +# ifdef CONFIG_USART10_RXDMA + .rxdma_channel = DMAMAP_USART10_RX, + .rxfifo = g_usart10rxfifo, +# endif + +# ifdef CONFIG_USART10_RS485 + .rs485_dir_gpio = GPIO_USART10_RS485_DIR, +# if (CONFIG_USART10_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 USART11 port. */ + +#ifdef CONFIG_STM32H5_USART11_SERIALDRIVER +static struct stm32_serial_s g_usart11priv = +{ + .dev = + { +# if CONSOLE_UART == 12 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_USART11_RXBUFSIZE, + .buffer = g_usart11rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART11_TXBUFSIZE, + .buffer = g_usart11txbuffer, + }, +# ifdef CONFIG_USART11_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_usart11priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_USART11, + .parity = CONFIG_USART11_PARITY, + .bits = CONFIG_USART11_BITS, + .stopbits2 = CONFIG_USART11_2STOP, + .baud = CONFIG_USART11_BAUD, + .apbclock = STM32_PCLK2_FREQUENCY, + .usartbase = STM32_USART11_BASE, + .tx_gpio = GPIO_USART11_TX, + .rx_gpio = GPIO_USART11_RX, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART11_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART11_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART11_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART11_RTS, +# endif +# ifdef CONFIG_USART11_RXDMA + .rxdma_channel = DMAMAP_USART11_RX, + .rxfifo = g_usart11rxfifo, +# endif + +# ifdef CONFIG_USART11_RS485 + .rs485_dir_gpio = GPIO_USART11_RS485_DIR, +# if (CONFIG_USART11_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This describes the state of the STM32 UART12 port. */ + +#ifdef CONFIG_STM32H5_UART12_SERIALDRIVER +static struct stm32_serial_s g_uart12priv = +{ + .dev = + { +# if CONSOLE_UART == 13 + .isconsole = true, +# endif + .recv = + { + .size = CONFIG_UART12_RXBUFSIZE, + .buffer = g_uart12rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART12_TXBUFSIZE, + .buffer = g_uart12txbuffer, + }, +# ifdef CONFIG_UART12_RXDMA + .ops = &g_uart_dma_ops, +# else + .ops = &g_uart_ops, +# endif + .priv = &g_uart12priv, + }, + + .islpuart = false, + .irq = STM32H5_IRQ_UART12, + .parity = CONFIG_UART12_PARITY, + .bits = CONFIG_UART12_BITS, + .stopbits2 = CONFIG_UART12_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART12_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART12_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART12_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART12_RTS, +# endif + .baud = CONFIG_UART12_BAUD, + .apbclock = STM32_PCLK1_FREQUENCY, + .usartbase = STM32_UART12_BASE, + .tx_gpio = GPIO_UART12_TX, + .rx_gpio = GPIO_UART12_RX, +# ifdef CONFIG_UART12_RXDMA + .rxdma_channel = DMAMAP_UART12_RX, + .rxfifo = g_uart12rxfifo, +# endif + +# ifdef CONFIG_UART12_RS485 + .rs485_dir_gpio = GPIO_UART12_RS485_DIR, +# if (CONFIG_UART12_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +# endif +}; +#endif + +/* This table lets us iterate over the configured USARTs */ + +static struct stm32_serial_s * const + g_uart_devs[STM32H5_NLPUART + STM32H5_NUSART + STM32H5_NUART] = +{ +#ifdef CONFIG_STM32H5_LPUART1_SERIALDRIVER + [0] = &g_lpuart1priv, +#endif +#ifdef CONFIG_STM32H5_USART1_SERIALDRIVER + [1] = &g_usart1priv, +#endif +#ifdef CONFIG_STM32H5_USART2_SERIALDRIVER + [2] = &g_usart2priv, +#endif +#ifdef CONFIG_STM32H5_USART3_SERIALDRIVER + [3] = &g_usart3priv, +#endif +#ifdef CONFIG_STM32H5_UART4_SERIALDRIVER + [4] = &g_uart4priv, +#endif +#ifdef CONFIG_STM32H5_UART5_SERIALDRIVER + [5] = &g_uart5priv, +#endif +#ifdef CONFIG_STM32H5_USART6_SERIALDRIVER + [6] = &g_usart6priv, +#endif +#ifdef CONFIG_STM32H5_UART7_SERIALDRIVER + [7] = &g_uart7priv, +#endif +#ifdef CONFIG_STM32H5_UART8_SERIALDRIVER + [8] = &g_uart8priv, +#endif +#ifdef CONFIG_STM32H5_UART9_SERIALDRIVER + [9] = &g_uart9priv, +#endif +#ifdef CONFIG_STM32H5_USART10_SERIALDRIVER + [10] = &g_usart10priv, +#endif +#ifdef CONFIG_STM32H5_USART11_SERIALDRIVER + [11] = &g_usart11priv, +#endif +#ifdef CONFIG_STM32H5_UART12_SERIALDRIVER + [12] = &g_uart12priv, +#endif +}; + +#ifdef CONFIG_PM +struct serialpm_s +{ + struct pm_callback_s pm_cb; + bool serial_suspended; +}; + +static struct serialpm_s g_serialpm = +{ + .pm_cb.notify = stm32serial_pmnotify, + .pm_cb.prepare = stm32serial_pmprepare, + .serial_suspended = false +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32serial_getreg + ****************************************************************************/ + +static inline +uint32_t stm32serial_getreg(struct stm32_serial_s *priv, int offset) +{ + return getreg32(priv->usartbase + offset); +} + +/**************************************************************************** + * Name: stm32serial_putreg + ****************************************************************************/ + +static inline +void stm32serial_putreg(struct stm32_serial_s *priv, + int offset, uint32_t value) +{ + putreg32(value, priv->usartbase + offset); +} + +/**************************************************************************** + * Name: stm32serial_setusartint + ****************************************************************************/ + +static inline +void stm32serial_setusartint(struct stm32_serial_s *priv, + uint16_t ie) +{ + uint32_t cr; + + /* Save the interrupt mask */ + + priv->ie = ie; + + /* And restore the interrupt state (see the interrupt enable/usage table + * above) + */ + + cr = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + cr &= ~(USART_CR1_USED_INTS); + cr |= (ie & (USART_CR1_USED_INTS)); + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, cr); + + cr = stm32serial_getreg(priv, STM32_USART_CR3_OFFSET); + cr &= ~USART_CR3_EIE; + cr |= (ie & USART_CR3_EIE); + stm32serial_putreg(priv, STM32_USART_CR3_OFFSET, cr); +} + +/**************************************************************************** + * Name: up_restoreusartint + ****************************************************************************/ + +static void stm32serial_restoreusartint(struct stm32_serial_s *priv, + uint16_t ie) +{ + irqstate_t flags; + + flags = spin_lock_irqsave(NULL); + + stm32serial_setusartint(priv, ie); + + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: stm32serial_disableusartint + ****************************************************************************/ + +static void stm32serial_disableusartint(struct stm32_serial_s *priv, + uint16_t *ie) +{ + irqstate_t flags; + + flags = spin_lock_irqsave(NULL); + + if (ie) + { + uint32_t cr1; + uint32_t cr3; + + /* USART interrupts: + * + * Enable Status Meaning Usage + * ---------------- -------------- ---------------------- ------------- + * USART_CR1_IDLEIE USART_ISR_IDLE Idle Line Detected (not used) + * USART_CR1_RXNEIE USART_ISR_RXNE Received Data Ready to + * be Read + * " " USART_ISR_ORE Overrun Error Detected + * USART_CR1_TCIE USART_ISR_TC Transmission Complete (only RS-485) + * USART_CR1_TXEIE USART_ISR_TXE Transmit Data Register + * Empty + * USART_CR1_PEIE USART_ISR_PE Parity Error + * + * USART_CR2_LBDIE USART_ISR_LBD Break Flag (not used) + * USART_CR3_EIE USART_ISR_FE Framing Error + * " " USART_ISR_NF Noise Flag + * " " USART_ISR_ORE Overrun Error Detected + * USART_CR3_CTSIE USART_ISR_CTS CTS flag (not used) + */ + + cr1 = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + cr3 = stm32serial_getreg(priv, STM32_USART_CR3_OFFSET); + + /* Return the current interrupt mask value for the used interrupts. + * Notice that this depends on the fact that none of the used interrupt + * enable bits overlap. This logic would fail if we needed the break + * interrupt! + */ + + *ie = (cr1 & (USART_CR1_USED_INTS)) | (cr3 & USART_CR3_EIE); + } + + /* Disable all interrupts */ + + stm32serial_setusartint(priv, 0); + + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: stm32serial_dmanextrx + * + * Description: + * Returns the index into the RX FIFO where the DMA will place the next + * byte that it receives. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +static int stm32serial_dmanextrx(struct stm32_serial_s *priv) +{ + size_t dmaresidual; + + dmaresidual = stm32_dmaresidual(priv->rxdma); + + return (RXDMA_BUFFER_SIZE - (int)dmaresidual); +} +#endif + +/**************************************************************************** + * Name: stm32serial_setformat + * + * Description: + * Set the serial line format and speed. + * + ****************************************************************************/ + +#ifndef CONFIG_SUPPRESS_UART_CONFIG +static void stm32serial_setformat(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + uint32_t regval; + uint32_t brr; + uint32_t cr1; + + /* This first implementation is for U[S]ARTs that support oversampling + * by 8 in additional to the standard oversampling by 16. + */ +#ifdef CONFIG_STM32H5_LPUART1 + if (priv->islpuart == true) + { + /* LPUART BRR (19:00) = (256*apbclock_hz/baud_rate) */ + + uint32_t apbclock_whole = priv->apbclock; + uint32_t clock_baud_ratio = apbclock_whole / priv->baud; + uint32_t presc_reg = 0x0; + + /* LPUART PRESC (3:0) + * Divide the apbclock if necessary for low baud rates + * 3 * baud_rate <= apbclock_whole <= 4096 * baud_rate + */ + + if (clock_baud_ratio <= 4096) + { + presc_reg = 0x0; + } + else if (clock_baud_ratio > 4096 && clock_baud_ratio <= 8192) + { + presc_reg = 0x1; + apbclock_whole >>= 1; + } + else if (clock_baud_ratio > 8192 && clock_baud_ratio <= 16384) + { + presc_reg = 0x2; + apbclock_whole >>= 2; + } + else if (clock_baud_ratio > 16384 && clock_baud_ratio <= 24576) + { + presc_reg = 0x3; + apbclock_whole /= 6; + } + else if (clock_baud_ratio > 24576 && clock_baud_ratio <= 32768) + { + presc_reg = 0x4; + apbclock_whole >>= 3; + } + else if (clock_baud_ratio > 32768 && clock_baud_ratio <= 40960) + { + presc_reg = 0x5; + apbclock_whole /= 10; + } + else if (clock_baud_ratio > 40960 && clock_baud_ratio <= 49152) + { + presc_reg = 0x6; + apbclock_whole /= 12; + } + else if (clock_baud_ratio > 32768 && clock_baud_ratio <= 65536) + { + presc_reg = 0x7; + apbclock_whole >>= 4; + } + else if (clock_baud_ratio > 65536 && clock_baud_ratio <= 131072) + { + presc_reg = 0x8; + apbclock_whole >>= 5; + } + else if (clock_baud_ratio > 131072 && clock_baud_ratio <= 262144) + { + presc_reg = 0x9; + apbclock_whole >>= 6; + } + else if (clock_baud_ratio > 262144 && clock_baud_ratio <= 524288) + { + presc_reg = 0xa; + apbclock_whole >>= 7; + } + else + { + presc_reg = 0xb; + apbclock_whole >>= 8; + } + + /* Write the PRESC register */ + + up_serialout(priv, STM32_USART_PRESC_OFFSET, presc_reg); + + /* Set the LPUART BRR value after setting Prescaler + * BRR = ( (256 * apbclock_whole) + baud_rate / 2 ) / baud_rate + */ + + brr = (((uint64_t)apbclock_whole << 8) + (priv->baud >> 1)) / \ + priv->baud; + } + else +#endif /* CONFIG_STM32H5_LPUART1 */ + { + uint32_t usartdiv8; + + /* In case of oversampling by 8, the equation is: + * + * baud = 2 * fCK / usartdiv8 + * usartdiv8 = 2 * fCK / baud + */ + + usartdiv8 = ((priv->apbclock << 1) + (priv->baud >> 1)) / priv->baud; + + /* Baud rate for standard USART (SPI mode included): + * + * In case of oversampling by 16, the equation is: + * baud = fCK / usartdiv16 + * usartdiv16 = fCK / baud + * = 2 * usartdiv8 + */ + + /* Use oversamply by 8 only if divisor is small. But what is small? */ + + cr1 = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + if (usartdiv8 > 2000) + { + /* Use usartdiv16 */ + + brr = (usartdiv8 + 1) >> 1; + + /* Clear oversampling by 8 to enable oversampling by 16 */ + + cr1 &= ~USART_CR1_OVER8; + } + else + { + DEBUGASSERT(usartdiv8 >= 8); + + /* Perform mysterious operations on bits 0-3 */ + + brr = ((usartdiv8 & 0xfff0) | ((usartdiv8 & 0x000f) >> 1)); + + /* Set oversampling by 8 */ + + cr1 |= USART_CR1_OVER8; + } + } + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, cr1); + stm32serial_putreg(priv, STM32_USART_BRR_OFFSET, brr); + + /* Configure parity mode */ + + regval = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + regval &= ~(USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0 | USART_CR1_M1); + + if (priv->parity == 1) /* Odd parity */ + { + regval |= (USART_CR1_PCE | USART_CR1_PS); + } + else if (priv->parity == 2) /* Even parity */ + { + regval |= USART_CR1_PCE; + } + + /* Configure word length (parity uses one of configured bits) + * + * Default: 1 start, 8 data (no parity), n stop, OR + * 1 start, 7 data + parity, n stop + */ + + if (priv->bits == 9 || (priv->bits == 8 && priv->parity != 0)) + { + /* Select: 1 start, 8 data + parity, n stop, OR + * 1 start, 9 data (no parity), n stop. + */ + + regval |= USART_CR1_M0; + } + else if (priv->bits == 7 && priv->parity == 0) + { + /* Select: 1 start, 7 data (no parity), n stop, OR + */ + + regval |= USART_CR1_M1; + } + + /* Else Select: 1 start, 7 data + parity, n stop, OR + * 1 start, 8 data (no parity), n stop. + */ + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, regval); + + /* Configure STOP bits */ + + regval = stm32serial_getreg(priv, STM32_USART_CR2_OFFSET); + regval &= ~(USART_CR2_STOP_MASK); + + if (priv->stopbits2) + { + regval |= USART_CR2_STOP2; + } + + stm32serial_putreg(priv, STM32_USART_CR2_OFFSET, regval); + + /* Configure hardware flow control */ + + regval = stm32serial_getreg(priv, STM32_USART_CR3_OFFSET); + regval &= ~(USART_CR3_CTSE | USART_CR3_RTSE); + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && !defined(CONFIG_STM32H5_FLOWCONTROL_BROKEN) + if (priv->iflow && (priv->rts_gpio != 0)) + { + regval |= USART_CR3_RTSE; + } +#endif + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + if (priv->oflow && (priv->cts_gpio != 0)) + { + regval |= USART_CR3_CTSE; + } +#endif + + stm32serial_putreg(priv, STM32_USART_CR3_OFFSET, regval); +} +#endif /* CONFIG_SUPPRESS_UART_CONFIG */ + +/**************************************************************************** + * Name: stm32serial_setsuspend + * + * Description: + * Suspend or resume serial peripheral. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void stm32serial_setsuspend(struct uart_dev_s *dev, bool suspend) +{ + struct stm32_serial_s *priv = (struct stm32_serial_s *)dev->priv; +#ifdef SERIAL_HAVE_DMA + bool dmarestored = false; +#endif + + if (priv->suspended == suspend) + { + return; + } + + priv->suspended = suspend; + + if (suspend) + { +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* Force RTS high to prevent further Rx. */ + + stm32_configgpio((priv->rts_gpio & ~GPIO_MODE_MASK) + | (GPIO_OUTPUT | GPIO_OUTPUT_SET)); + } +#endif + + /* Disable interrupts to prevent Tx. */ + + stm32serial_disableusartint(priv, &priv->suspended_ie); + + /* Wait last Tx to complete. */ + + while ((stm32serial_getreg(priv, STM32_USART_ISR_OFFSET) & + USART_ISR_TC) == 0); + +#ifdef SERIAL_HAVE_DMA + if (priv->dev.ops == &g_uart_dma_ops && !priv->rxdmasusp) + { +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow && priv->rxdmanext == RXDMA_BUFFER_SIZE) + { + /* Rx DMA in non-circular iflow mode and already stopped + * at end of DMA buffer. No need to suspend. + */ + } + else +#endif + { + /* Suspend Rx DMA. */ + + stm32h5_dmastop(priv->rxdma); + priv->rxdmasusp = true; + } + } +#endif + } + else + { +#ifdef SERIAL_HAVE_DMA + if (priv->dev.ops == &g_uart_dma_ops && priv->rxdmasusp) + { +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + stm32serial_dmaiflowrestart(priv); + } + else +#endif + { + /* This USART does not have HW flow-control. Unconditionally + * re-enable DMA (might loss unprocessed bytes received + * to DMA buffer before suspending). + */ + + stm32serial_dmareenable(priv); + priv->rxdmasusp = false; + } + + dmarestored = true; + } +#endif + + /* Re-enable interrupts to resume Tx. */ + + stm32serial_restoreusartint(priv, priv->suspended_ie); + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* Restore peripheral RTS control. */ + + stm32_configgpio(priv->rts_gpio); + } +#endif + } + +#ifdef SERIAL_HAVE_DMA + if (dmarestored) + { + irqstate_t flags; + + flags = enter_critical_section(); + + /* Perform initial Rx DMA buffer fetch to wake-up serial device + * activity. + */ + + if (priv->rxdma != NULL) + { + stm32serial_dmarxcallback(priv->rxdma, 0, priv); + } + + leave_critical_section(flags); + } +#endif +} +#endif + +/**************************************************************************** + * Name: stm32serial_pm_setsuspend + * + * Description: + * Suspend or resume serial peripherals for/from deep-sleep/stop modes. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void stm32serial_pm_setsuspend(bool suspend) +{ + int n; + + /* Already in desired state? */ + + if (suspend == g_serialpm.serial_suspended) + return; + + g_serialpm.serial_suspended = suspend; + + for (n = 0; n < STM32H5_NLPUART + STM32H5_NUSART + STM32H5_NUART; n++) + { + struct stm32_serial_s *priv = g_uart_devs[n]; + + if (!priv || !priv->initialized) + { + continue; + } + + stm32serial_setsuspend(&priv->dev, suspend); + } +} +#endif + +/**************************************************************************** + * Name: stm32serial_setapbclock + * + * Description: + * Enable or disable APB clock for the USART peripheral + * + * Input Parameters: + * dev - A reference to the UART driver state structure + * on - Enable clock if 'on' is 'true' and disable if 'false' + * + ****************************************************************************/ + +static void stm32serial_setapbclock(struct uart_dev_s *dev, bool on) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + uint32_t rcc_en; + uint32_t regaddr; + + /* Determine which USART to configure */ + + switch (priv->usartbase) + { + default: + return; +#ifdef CONFIG_STM32H5_LPUART1_SERIALDRIVER + case STM32_LPUART1_BASE: + rcc_en = RCC_APB3ENR_LPUART1EN ; + regaddr = STM32_RCC_APB3ENR; + break; +#endif +#ifdef CONFIG_STM32H5_USART1_SERIALDRIVER + case STM32_USART1_BASE: + rcc_en = RCC_APB2ENR_USART1EN ; + regaddr = STM32_RCC_APB2ENR; + break; +#endif +#ifdef CONFIG_STM32H5_USART2_SERIALDRIVER + case STM32_USART2_BASE: + rcc_en = RCC_APB1LENR_USART2EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_USART3_SERIALDRIVER + case STM32_USART3_BASE: + rcc_en = RCC_APB1LENR_USART3EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_UART4_SERIALDRIVER + case STM32_UART4_BASE: + rcc_en = RCC_APB1LENR_UART4EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_UART5_SERIALDRIVER + case STM32_UART5_BASE: + rcc_en = RCC_APB1LENR_UART5EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_USART6_SERIALDRIVER + case STM32_USART6_BASE: + rcc_en = RCC_APB1LENR_USART6EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_UART7_SERIALDRIVER + case STM32_UART7_BASE: + rcc_en = RCC_APB1LENR_UART7EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_UART8_SERIALDRIVER + case STM32_UART8_BASE: + rcc_en = RCC_APB1LENR_UART8EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_UART9_SERIALDRIVER + case STM32_UART9_BASE: + rcc_en = RCC_APB1HENR_UART9EN; + regaddr = STM32_RCC_APB1HENR; + break; +#endif + +#ifdef CONFIG_STM32H5_USART10_SERIALDRIVER + case STM32_USART10_BASE: + rcc_en = RCC_APB1LENR_USART10EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_USART11_SERIALDRIVER + case STM32_USART11_BASE: + rcc_en = RCC_APB1LENR_USART11EN; + regaddr = STM32_RCC_APB1LENR; + break; +#endif +#ifdef CONFIG_STM32H5_UART12_SERIALDRIVER + case STM32_UART12_BASE: + rcc_en = RCC_APB1HENR_UART12EN; + regaddr = STM32_RCC_APB1HENR; + break; +#endif + } + + /* Enable/disable APB 1/2 clock for USART */ + + if (on) + { + modifyreg32(regaddr, 0, rcc_en); + } + else + { + modifyreg32(regaddr, rcc_en, 0); + } +} + +/**************************************************************************** + * Name: stm32serial_setup + * + * Description: + * Configure the USART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +static int stm32serial_setup(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + +#ifndef CONFIG_SUPPRESS_UART_CONFIG + uint32_t regval; + + /* Note: The logic here depends on the fact that that the USART module + * was enabled in stm32_lowsetup(). + */ + + /* Enable USART APB1/2 clock */ + + stm32serial_setapbclock(dev, true); + + /* Configure pins for USART use */ + + stm32_configgpio(priv->tx_gpio); + stm32_configgpio(priv->rx_gpio); + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + if (priv->cts_gpio != 0) + { + stm32_configgpio(priv->cts_gpio); + } +#endif + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->rts_gpio != 0) + { + uint32_t config = priv->rts_gpio; + +#ifdef CONFIG_STM32H5_FLOWCONTROL_BROKEN + /* Instead of letting hw manage this pin, we will bitbang */ + + config = (config & ~GPIO_MODE_MASK) | GPIO_OUTPUT; +#endif + stm32_configgpio(config); + } +#endif + +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + stm32_configgpio(priv->rs485_dir_gpio); + stm32_gpiowrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); + } +#endif + + /* Configure CR2 */ + + /* Clear STOP, CLKEN, CPOL, CPHA, LBCL, and interrupt enable bits */ + + regval = stm32serial_getreg(priv, STM32_USART_CR2_OFFSET); + if (priv->islpuart == true) + { + regval &= ~(USART_CR2_STOP_MASK | USART_CR2_CLKEN); + } + else + { + regval &= ~(USART_CR2_STOP_MASK | USART_CR2_CLKEN | USART_CR2_CPOL | + USART_CR2_CPHA | USART_CR2_LBCL | USART_CR2_LBDIE); + } + + /* Configure STOP bits */ + + if (priv->stopbits2) + { + regval |= USART_CR2_STOP2; + } + + stm32serial_putreg(priv, STM32_USART_CR2_OFFSET, regval); + + /* Configure CR1 */ + + /* Clear TE, REm and all interrupt enable bits */ + + regval = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + +#ifdef CONFIG_STM32_LPUART1 + if (priv->islpuart == true) + { + regval &= ~(USART_CR1_TE | USART_CR1_RE | LPUART_CR1_ALLINTS); + } + else +#endif + { + regval &= ~(USART_CR1_TE | USART_CR1_RE | USART_CR1_ALLINTS); + } + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, regval); + + /* Configure CR3 */ + + /* Clear CTSE, RTSE, and all interrupt enable bits */ + + regval = stm32serial_getreg(priv, STM32_USART_CR3_OFFSET); + regval &= ~(USART_CR3_CTSIE | USART_CR3_CTSE | USART_CR3_RTSE | + USART_CR3_EIE); + + stm32serial_putreg(priv, STM32_USART_CR3_OFFSET, regval); + + /* Configure the USART line format and speed. */ + + stm32serial_setformat(dev); + + /* Enable Rx, Tx, and the USART */ + + regval = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + regval |= (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE); + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, regval); + +#endif /* CONFIG_SUPPRESS_UART_CONFIG */ + + /* Set up the cached interrupt enables value */ + + priv->ie = 0; + + /* Mark device as initialized. */ + + priv->initialized = true; + + return OK; +} + +/**************************************************************************** + * Name: stm32serial_dmasetup + * + * Description: + * Configure the USART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +static int stm32serial_dmasetup(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + int result; + uint32_t regval; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = stm32serial_setup(dev); + if (result != OK) + { + return result; + } + } + + /* Acquire the DMA channel. This should always succeed. */ + + priv->rxdma = stm32h5_dmachannel(priv->rxdma_channel); + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* Configure for non-circular DMA reception into the RX FIFO */ + + stm32h5_dmasetup(priv->rxdma, + priv->usartbase + STM32_USART_RDR_OFFSET, + (uint32_t)priv->rxfifo, + RXDMA_BUFFER_SIZE, + SERIAL_DMA_IFLOW_CONTROL_WORD); + } + else +#endif + { + /* Configure for circular DMA reception into the RX FIFO */ + + stm32h5_dmasetup(priv->rxdma, + priv->usartbase + STM32_USART_RDR_OFFSET, + (uint32_t)priv->rxfifo, + RXDMA_BUFFER_SIZE, + SERIAL_DMA_CONTROL_WORD); + } + + /* Reset our DMA shadow pointer to match the address just + * programmed above. + */ + + priv->rxdmanext = 0; + + /* Enable receive DMA for the UART */ + + regval = stm32serial_getreg(priv, STM32_USART_CR3_OFFSET); + regval |= USART_CR3_DMAR; + stm32serial_putreg(priv, STM32_USART_CR3_OFFSET, regval); + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* Start the DMA channel, and arrange for callbacks at the full point + * in the FIFO. After buffer gets full, hardware flow-control kicks + * in and DMA transfer is stopped. + */ + + stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback, + (void *)priv, false); + } + else +#endif + { + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback, + (void *)priv, true); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: stm32serial_shutdown + * + * Description: + * Disable the USART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +static void stm32serial_shutdown(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + uint32_t regval; + + /* Mark device as uninitialized. */ + + priv->initialized = false; + + /* Disable all interrupts */ + + stm32serial_disableusartint(priv, NULL); + + /* Disable USART APB1/2 clock */ + + stm32serial_setapbclock(dev, false); + + /* Disable Rx, Tx, and the UART */ + + regval = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + regval &= ~(USART_CR1_UE | USART_CR1_TE | USART_CR1_RE); + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, regval); + + /* Release pins. "If the serial-attached device is powered down, the TX + * pin causes back-powering, potentially confusing the device to the point + * of complete lock-up." + * + * REVISIT: Is unconfiguring the pins appropriate for all device? If not, + * then this may need to be a configuration option. + */ + + stm32_unconfiggpio(priv->tx_gpio); + stm32_unconfiggpio(priv->rx_gpio); + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + if (priv->cts_gpio != 0) + { + stm32_unconfiggpio(priv->cts_gpio); + } +#endif + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->rts_gpio != 0) + { + stm32_unconfiggpio(priv->rts_gpio); + } +#endif + +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + stm32_unconfiggpio(priv->rs485_dir_gpio); + } +#endif +} + +/**************************************************************************** + * Name: stm32serial_dmashutdown + * + * Description: + * Disable the USART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +static void stm32serial_dmashutdown(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + + /* Perform the normal UART shutdown */ + + stm32serial_shutdown(dev); + + /* Stop the DMA channel */ + + stm32h5_dmastop(priv->rxdma); + + /* Release the DMA channel */ + + stm32h5_dmafree(priv->rxdma); + priv->rxdma = NULL; +} +#endif + +/**************************************************************************** + * Name: stm32serial_attach + * + * Description: + * Configure the USART to operation in interrupt driven mode. This method + * is called when the serial port is opened. Normally, this is just after + * the setup() method is called, however, the serial console may operate in + * a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless + * the hardware supports multiple levels of interrupt enabling). The RX + * and TX interrupts are not enabled until the txint() and rxint() methods + * are called. + * + ****************************************************************************/ + +static int stm32serial_attach(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->irq, stm32serial_interrupt, priv); + + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the USART + */ + + up_enable_irq(priv->irq); + } + + return ret; +} + +/**************************************************************************** + * Name: stm32serial_detach + * + * Description: + * Detach USART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The + * exception is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void stm32serial_detach(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + up_disable_irq(priv->irq); + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: stm32serial_interrupt + * + * Description: + * This is the USART interrupt handler. It will be invoked when an + * interrupt is received on the 'irq'. It should call uart_xmitchars or + * uart_recvchars to perform the appropriate data transfers. The + * interrupt handling logic must be able to map the 'arg' to the + * appropriate uart_dev_s structure in order to call these functions. + * + ****************************************************************************/ + +static int stm32serial_interrupt(int irq, void *context, void *arg) +{ + struct stm32_serial_s *priv = (struct stm32_serial_s *)arg; + int passes; + bool handled; + + DEBUGASSERT(priv != NULL); + + /* Report serial activity to the power management logic */ + +#if defined(CONFIG_PM) && CONFIG_STM32H5_PM_SERIAL_ACTIVITY > 0 + pm_activity(PM_IDLE_DOMAIN, CONFIG_STM32H5_PM_SERIAL_ACTIVITY); +#endif + + /* Loop until there are no characters to be transferred or, + * until we have been looping for a long time. + */ + + handled = true; + for (passes = 0; passes < 256 && handled; passes++) + { + handled = false; + + /* Get the masked USART status word. */ + + priv->sr = stm32serial_getreg(priv, STM32_USART_ISR_OFFSET); + + /* USART interrupts: + * + * Enable Status Meaning Usage + * ---------------- -------------- ---------------------- ------------- + * USART_CR1_IDLEIE USART_ISR_IDLE Idle Line Detected (not used) + * USART_CR1_RXNEIE USART_ISR_RXNE Received Data Ready to + * be Read + * " " USART_ISR_ORE Overrun Error Detected + * USART_CR1_TCIE USART_ISR_TC Transmission Complete (only RS-485) + * USART_CR1_TXEIE USART_ISR_TXE Transmit Data Register + * Empty + * USART_CR1_PEIE USART_ISR_PE Parity Error + * + * USART_CR2_LBDIE USART_ISR_LBD Break Flag (not used) + * USART_CR3_EIE USART_ISR_FE Framing Error + * " " USART_ISR_NE Noise Error + * " " USART_ISR_ORE Overrun Error Detected + * USART_CR3_CTSIE USART_ISR_CTS CTS flag (not used) + * + * NOTE: Some of these status bits must be cleared by explicitly + * writing one to the ICR register: USART_ICR_CTSCF, USART_ICR_LBDCF. + * None of those are currently being used. + */ + +#ifdef HAVE_RS485 + /* Transmission of whole buffer is over - TC is set, TXEIE is cleared. + * Note - this should be first, to have the most recent TC bit value + * from SR register - sending data affects TC, but without refresh we + * will not know that... + */ + + if ((priv->sr & USART_ISR_TC) != 0 && + (priv->ie & USART_CR1_TCIE) != 0 && + (priv->ie & USART_CR1_TXEIE) == 0) + { + stm32_gpiowrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); + stm32serial_restoreusartint(priv, priv->ie & ~USART_CR1_TCIE); + } +#endif + + /* Handle incoming, receive bytes. */ + + if ((priv->sr & USART_ISR_RXNE) != 0 && + (priv->ie & USART_CR1_RXNEIE) != 0) + { + /* Received data ready... process incoming bytes. NOTE the check + * for RXNEIE: We cannot call uart_recvchards of RX interrupts are + * disabled. + */ + + uart_recvchars(&priv->dev); + handled = true; + } + + /* We may still have to read from the DR register to clear any pending + * error conditions. + */ + + else if ((priv->sr & (USART_ISR_ORE | USART_ISR_NF | USART_ISR_FE)) + != 0) + { + /* These errors are cleared by writing the corresponding bit to the + * interrupt clear register (ICR). + */ + + stm32serial_putreg(priv, STM32_USART_ICR_OFFSET, + (USART_ICR_NCF | USART_ICR_ORECF | + USART_ICR_FECF)); + } + + /* Handle outgoing, transmit bytes */ + + if ((priv->sr & USART_ISR_TXE) != 0 && + (priv->ie & USART_CR1_TXEIE) != 0) + { + /* Transmit data register empty ... process outgoing bytes */ + + uart_xmitchars(&priv->dev); + handled = true; + } + } + + return OK; +} + +/**************************************************************************** + * Name: stm32serial_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int stm32serial_ioctl(struct file *filep, int cmd, + unsigned long arg) +{ +#if defined(CONFIG_SERIAL_TERMIOS) || defined(CONFIG_SERIAL_TIOCSERGSTRUCT) + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; +#endif +#if defined(CONFIG_SERIAL_TERMIOS) + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; +#endif + int ret = OK; + + switch (cmd) + { +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + case TIOCSERGSTRUCT: + { + struct stm32_serial_s *user; + + user = (struct stm32_serial_s *)arg; + + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct stm32_serial_s)); + } + } + break; +#endif + +#ifdef CONFIG_STM32H5_USART_SINGLEWIRE + case TIOCSSINGLEWIRE: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, HDSEL can only be written when UE=0 */ + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, cr1); + + /* Change the TX port to be open-drain/push-pull and enable/disable + * half-duplex mode. + */ + + uint32_t cr = stm32serial_getreg(priv, STM32_USART_CR3_OFFSET); + + if ((arg & SER_SINGLEWIRE_ENABLED) != 0) + { + uint32_t gpio_val = GPIO_OPENDRAIN; + + if ((arg & SER_SINGLEWIRE_PULL_MASK) == SER_SINGLEWIRE_PULLUP) + { + gpio_val |= GPIO_PULLUP; + } + else + { + gpio_val |= GPIO_FLOAT; + } + + if ((arg & SER_SINGLEWIRE_PULL_MASK) == SER_SINGLEWIRE_PULLDOWN) + { + gpio_val |= GPIO_PULLDOWN; + } + else + { + gpio_val |= GPIO_FLOAT; + } + + stm32_configgpio((priv->tx_gpio & + ~(GPIO_PUPD_MASK | GPIO_OPENDRAIN)) | + gpio_val); + + cr |= USART_CR3_HDSEL; + } + else + { + stm32_configgpio((priv->tx_gpio & + ~(GPIO_PUPD_MASK | GPIO_OPENDRAIN)) | + GPIO_PUSHPULL); + cr &= ~USART_CR3_HDSEL; + } + + stm32serial_putreg(priv, STM32_USART_CR3_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + +#ifdef CONFIG_STM32H5_USART_INVERT + case TIOCSINVERT: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, {R,T}XINV can only be written when UE=0 */ + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, cr1); + + /* Enable/disable signal inversion. */ + + uint32_t cr = stm32serial_getreg(priv, STM32_USART_CR2_OFFSET); + + if (arg & SER_INVERT_ENABLED_RX) + { + cr |= USART_CR2_RXINV; + } + else + { + cr &= ~USART_CR2_RXINV; + } + + if (arg & SER_INVERT_ENABLED_TX) + { + cr |= USART_CR2_TXINV; + } + else + { + cr &= ~USART_CR2_TXINV; + } + + stm32serial_putreg(priv, STM32_USART_CR2_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + +#ifdef CONFIG_STM32H5_USART_SWAP + case TIOCSSWAP: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, SWAP can only be written when UE=0 */ + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, cr1); + + /* Enable/disable Swap mode. */ + + uint32_t cr = stm32serial_getreg(priv, STM32_USART_CR2_OFFSET); + + if (arg == SER_SWAP_ENABLED) + { + cr |= USART_CR2_SWAP; + } + else + { + cr &= ~USART_CR2_SWAP; + } + + stm32serial_putreg(priv, STM32_USART_CR2_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + cfsetispeed(termiosp, priv->baud); + + /* Note that since we only support 8/9 bit modes and + * there is no way to report 9-bit mode, we always claim 8. + */ + + termiosp->c_cflag = + ((priv->parity != 0) ? PARENB : 0) | + ((priv->parity == 1) ? PARODD : 0) | + ((priv->stopbits2) ? CSTOPB : 0) | +#ifdef CONFIG_SERIAL_OFLOWCONTROL + ((priv->oflow) ? CCTS_OFLOW : 0) | +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + ((priv->iflow) ? CRTS_IFLOW : 0) | +#endif + CS8; + + /* TODO: CRTS_IFLOW, CCTS_OFLOW */ + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios *)arg; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Perform some sanity checks before accepting any changes */ + + if (((termiosp->c_cflag & CSIZE) != CS8) +#ifdef CONFIG_SERIAL_OFLOWCONTROL + || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0)) +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0)) +#endif + ) + { + ret = -EINVAL; + break; + } + + if (termiosp->c_cflag & PARENB) + { + priv->parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + priv->parity = 0; + } + + priv->stopbits2 = (termiosp->c_cflag & CSTOPB) != 0; +#ifdef CONFIG_SERIAL_OFLOWCONTROL + priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; +#endif + + /* Note that since there is no way to request 9-bit mode + * and no way to support 5/6/7-bit modes, we ignore them + * all here. + */ + + /* Note that only cfgetispeed is used because we have knowledge + * that only one speed is supported. + */ + + priv->baud = cfgetispeed(termiosp); + + /* Effect the changes immediately - note that we do not implement + * TCSADRAIN / TCSAFLUSH + */ + + stm32serial_setformat(dev); + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + +#ifdef CONFIG_STM32H5_USART_BREAKS +# ifdef CONFIG_STM32H5_SERIALBRK_BSDCOMPAT + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + { + irqstate_t flags; + uint32_t tx_break; + + flags = enter_critical_section(); + + /* Disable any further tx activity */ + + priv->ie |= USART_CR1_IE_BREAK_INPROGRESS; + + stm32serial_txint(dev, false); + + /* Configure TX as a GPIO output pin and Send a break signal */ + + tx_break = GPIO_OUTPUT | + (~(GPIO_MODE_MASK | GPIO_OUTPUT_SET) & priv->tx_gpio); + stm32_configgpio(tx_break); + + leave_critical_section(flags); + } + break; + + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + { + irqstate_t flags; + + flags = enter_critical_section(); + + /* Configure TX back to U(S)ART */ + + stm32_configgpio(priv->tx_gpio); + + priv->ie &= ~USART_CR1_IE_BREAK_INPROGRESS; + + /* Enable further tx activity */ + + stm32serial_txint(dev, true); + + leave_critical_section(flags); + } + break; +# else + case TIOCSBRK: /* No BSD compatibility: Turn break on for M bit times */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, + cr1 | USART_CR1_SBK); + leave_critical_section(flags); + } + break; + + case TIOCCBRK: /* No BSD compatibility: May turn off break too soon */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = stm32serial_getreg(priv, STM32_USART_CR1_OFFSET); + stm32serial_putreg(priv, STM32_USART_CR1_OFFSET, + cr1 & ~USART_CR1_SBK); + leave_critical_section(flags); + } + break; +# endif +#endif + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: stm32serial_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the USART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_DMA +static int stm32serial_receive(struct uart_dev_s *dev, + unsigned int *status) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + uint32_t rdr; + + /* Get the Rx byte */ + + rdr = stm32serial_getreg(priv, STM32_USART_RDR_OFFSET); + + /* Get the Rx byte plux error information. Return those in status */ + + *status = priv->sr << 16 | rdr; + priv->sr = 0; + + /* Then return the actual received byte */ + + return rdr & 0xff; +} +#endif + +/**************************************************************************** + * Name: stm32serial_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_DMA +static void stm32serial_rxint(struct uart_dev_s *dev, bool enable) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + irqstate_t flags; + uint16_t ie; + + /* USART receive interrupts: + * + * Enable Status Meaning Usage + * ---------------- -------------- ---------------------- ---------- + * USART_CR1_IDLEIE USART_ISR_IDLE Idle Line Detected (not used) + * USART_CR1_RXNEIE USART_ISR_RXNE Received Data Ready + * to be Read + * " " USART_ISR_ORE Overrun Error Detected + * USART_CR1_PEIE USART_ISR_PE Parity Error + * + * USART_CR2_LBDIE USART_ISR_LBD Break Flag (not used) + * USART_CR3_EIE USART_ISR_FE Framing Error + * " " USART_ISR_NF Noise Flag + * " " USART_ISR_ORE Overrun Error Detected + */ + + flags = enter_critical_section(); + ie = priv->ie; + if (enable) + { + /* Receive an interrupt when their is anything in the Rx data + * register (or an Rx timeout occurs). + */ + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS +#ifdef CONFIG_USART_ERRINTS + ie |= (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR3_EIE); +#else + ie |= USART_CR1_RXNEIE; +#endif +#endif + } + else + { + ie &= ~(USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR3_EIE); + } + + /* Then set the new interrupt state */ + + stm32serial_restoreusartint(priv, ie); + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: stm32serial_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_DMA +static bool stm32serial_rxavailable(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + + return ((stm32serial_getreg(priv, STM32_USART_ISR_OFFSET) & + USART_ISR_RXNE) != 0); +} +#endif + +/**************************************************************************** + * Name: stm32serial_rxflowcontrol + * + * Description: + * Called when Rx buffer is full (or exceeds configured watermark levels + * if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined). + * Return true if UART activated RX flow control to block more incoming + * data + * + * Input Parameters: + * dev - UART device instance + * nbuffered - the number of characters currently buffered + * (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is + * not defined the value will be 0 for an empty buffer or the + * defined buffer size for a full buffer) + * upper - true indicates the upper watermark was crossed where + * false indicates the lower watermark has been crossed + * + * Returned Value: + * true if RX flow control activated. + * + ****************************************************************************/ + +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool stm32serial_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + +#if defined(CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS) && \ + defined(CONFIG_STM32H5_FLOWCONTROL_BROKEN) + if (priv->iflow && (priv->rts_gpio != 0)) + { + /* Assert/de-assert nRTS set it high resume/stop sending */ + + stm32_gpiowrite(priv->rts_gpio, upper); + + if (upper) + { + /* With heavy Rx traffic, RXNE might be set and data pending. + * Returning 'true' in such case would cause RXNE left unhandled + * and causing interrupt storm. Sending end might be also be slow + * to react on nRTS, and returning 'true' here would prevent + * processing that data. + * + * Therefore, return 'false' so input data is still being processed + * until sending end reacts on nRTS signal and stops sending more. + */ + + return false; + } + + return upper; + } + +#else + if (priv->iflow) + { + /* Is the RX buffer full? */ + + if (upper) + { + /* Disable Rx interrupt to prevent more data being from + * peripheral. When hardware RTS is enabled, this will + * prevent more data from coming in. + * + * This function is only called when UART recv buffer is full, + * that is: "dev->recv.head + 1 == dev->recv.tail". + * + * Logic in "uart_read" will automatically toggle Rx interrupts + * when buffer is read empty and thus we do not have to re- + * enable Rx interrupts. + */ + + uart_disablerxint(dev); + return true; + } + + /* No.. The RX buffer is empty */ + + else + { + /* We might leave Rx interrupt disabled if full recv buffer was + * read empty. Enable Rx interrupt to make sure that more input is + * received. + */ + + uart_enablerxint(dev); + } + } +#endif + + return false; +} +#endif + +/**************************************************************************** + * Name: stm32serial_dmareceive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the USART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +static int stm32serial_dmareceive(struct uart_dev_s *dev, + unsigned int *status) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + int c = 0; + + if (stm32serial_dmanextrx(priv) != priv->rxdmanext) + { + c = priv->rxfifo[priv->rxdmanext]; + + priv->rxdmanext++; + if (priv->rxdmanext == RXDMA_BUFFER_SIZE) + { +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* RX DMA buffer full. RX paused, RTS line pulled up to prevent + * more input data from other end. + */ + } + else +#endif + { + priv->rxdmanext = 0; + } + } + } + + return c; +} +#endif + +/**************************************************************************** + * Name: stm32serial_dmareenable + * + * Description: + * Call to re-enable RX DMA. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_DMA) +static void stm32serial_dmareenable(struct stm32_serial_s *priv) +{ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* Configure for non-circular DMA reception into the RX FIFO */ + + stm32h5_dmasetup(priv->rxdma, + priv->usartbase + STM32_USART_RDR_OFFSET, + (uint32_t)priv->rxfifo, + RXDMA_BUFFER_SIZE, + SERIAL_DMA_IFLOW_CONTROL_WORD); + } + else +#endif + { + /* Configure for circular DMA reception into the RX FIFO */ + + stm32h5_dmasetup(priv->rxdma, + priv->usartbase + STM32_USART_RDR_OFFSET, + (uint32_t)priv->rxfifo, + RXDMA_BUFFER_SIZE, + SERIAL_DMA_CONTROL_WORD); + } + + /* Reset our DMA shadow pointer to match the address just + * programmed above. + */ + + priv->rxdmanext = 0; + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* Start the DMA channel, and arrange for callbacks at the full point + * in the FIFO. After buffer gets full, hardware flow-control kicks + * in and DMA transfer is stopped. + */ + + stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback, + (void *)priv, false); + } + else +#endif + { + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback, + (void *)priv, true); + } + +#ifdef CONFIG_PM + /* Clear DMA suspended flag. */ + + priv->rxdmasusp = false; +#endif +} +#endif + +/**************************************************************************** + * Name: stm32serial_dmaiflowrestart + * + * Description: + * Call to restart RX DMA for input flow-controlled USART + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_DMA) && defined(CONFIG_SERIAL_IFLOWCONTROL) +static bool stm32serial_dmaiflowrestart(struct stm32_serial_s *priv) +{ + if (!priv->rxenable) + { + /* Rx not enabled by upper layer. */ + + return false; + } + + if (priv->rxdmanext != RXDMA_BUFFER_SIZE) + { +#ifdef CONFIG_PM + if (priv->rxdmasusp) + { + /* Rx DMA in suspended state. */ + + if (stm32serial_dmarxavailable(&priv->dev)) + { + /* DMA buffer has unprocessed data, do not re-enable yet. */ + + return false; + } + } + else +#endif + { + return false; + } + } + + /* DMA is stopped or suspended and DMA buffer does not have pending data, + * re-enabling without data loss is now safe. + */ + + stm32serial_dmareenable(priv); + + return true; +} +#endif + +/**************************************************************************** + * Name: stm32serial_dmarxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +static void stm32serial_dmarxint(struct uart_dev_s *dev, bool enable) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + + /* En/disable DMA reception. + * + * Note that it is not safe to check for available bytes and immediately + * pass them to uart_recvchars as that could potentially recurse back + * to us again. Instead, bytes must wait until the next up_dma_poll or + * DMA event. + */ + + priv->rxenable = enable; + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* Re-enable RX DMA. */ + + stm32serial_dmaiflowrestart(priv); + } +#endif +} +#endif + +/**************************************************************************** + * Name: stm32serial_dmarxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +static bool stm32serial_dmarxavailable(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + + /* Compare our receive pointer to the current DMA pointer, if they + * do not match, then there are bytes to be received. + */ + + return (stm32serial_dmanextrx(priv) != priv->rxdmanext); +} +#endif + +/**************************************************************************** + * Name: stm32serial_send + * + * Description: + * This method will send one byte on the USART + * + ****************************************************************************/ + +static void stm32serial_send(struct uart_dev_s *dev, int ch) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + stm32_gpiowrite(priv->rs485_dir_gpio, priv->rs485_dir_polarity); + } +#endif + + stm32serial_putreg(priv, STM32_USART_TDR_OFFSET, (uint32_t)ch); +} + +/**************************************************************************** + * Name: stm32serial_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void stm32serial_txint(struct uart_dev_s *dev, bool enable) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + irqstate_t flags; + + /* USART transmit interrupts: + * + * Enable Status Meaning Usage + * --------------- ------------- ---------------------------- ------------- + * USART_CR1_TCIE USART_ISR_TC Transmission Complete (only RS-485) + * USART_CR1_TXEIE USART_ISR_TXE Transmit Data Register Empty + * USART_CR3_CTSIE USART_ISR_CTS CTS flag (not used) + */ + + flags = enter_critical_section(); + if (enable) + { + /* Set to receive an interrupt when the TX data register is empty */ + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + uint16_t ie = priv->ie | USART_CR1_TXEIE; + + /* If RS-485 is supported on this U[S]ART, then also enable the + * transmission complete interrupt. + */ + +# ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + ie |= USART_CR1_TCIE; + } +# endif + +# ifdef CONFIG_STM32H5_SERIALBRK_BSDCOMPAT + if (priv->ie & USART_CR1_IE_BREAK_INPROGRESS) + { + leave_critical_section(flags); + return; + } +# endif + + stm32serial_restoreusartint(priv, ie); + + /* Fake a TX interrupt here by just calling uart_xmitchars() with + * interrupts disabled (note this may recurse). + */ + + uart_xmitchars(dev); +#endif + } + else + { + /* Disable the TX interrupt */ + + stm32serial_restoreusartint(priv, priv->ie & ~USART_CR1_TXEIE); + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: stm32serial_txready + * + * Description: + * Return true if the transmit data register is empty + * + ****************************************************************************/ + +static bool stm32serial_txready(struct uart_dev_s *dev) +{ + struct stm32_serial_s *priv = + (struct stm32_serial_s *)dev->priv; + + return ((stm32serial_getreg(priv, STM32_USART_ISR_OFFSET) & + USART_ISR_TXE) != 0); +} + +/**************************************************************************** + * Name: stm32serial_dmarxcallback + * + * Description: + * This function checks the current DMA state and calls the generic + * serial stack when bytes appear to be available. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +static void stm32serial_dmarxcallback(DMA_HANDLE handle, uint8_t status, + void *arg) +{ + struct stm32_serial_s *priv = (struct stm32_serial_s *)arg; + + if (priv->rxenable && stm32serial_dmarxavailable(&priv->dev)) + { + uart_recvchars(&priv->dev); + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->iflow) + { + /* Re-enable RX DMA. */ + + stm32serial_dmaiflowrestart(priv); + } +#endif + } + + /* Get the masked USART status word to check and clear error flags. + * + * When wake-up from low power mode was not fast enough, UART is resumed + * too late and sometimes exactly when character was coming over UART, + * resulting to frame error. + * If error flag is not cleared, Rx DMA will be stuck. Clearing errors + * will release Rx DMA. + */ + + priv->sr = stm32serial_getreg(priv, STM32_USART_ISR_OFFSET); + + if ((priv->sr & (USART_ISR_ORE | USART_ISR_NF | USART_ISR_FE)) != 0) + { + stm32serial_putreg(priv, STM32_USART_ICR_OFFSET, + (USART_ICR_NCF | USART_ICR_ORECF | + USART_ICR_FECF)); + } +} +#endif + +/**************************************************************************** + * Name: stm32serial_pmnotify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opportunity to prepare for the new power state. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * None - The driver already agreed to transition to the low power + * consumption state when when it returned OK to the prepare() call. + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void stm32serial_pmnotify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case PM_NORMAL: + { + stm32serial_pm_setsuspend(false); + } + break; + + case PM_IDLE: + { + stm32serial_pm_setsuspend(false); + } + break; + + case PM_STANDBY: + { + /* TODO: Alternative configuration and logic for enabling serial in + * Stop 1 mode with HSI16 missing. Current logic allows + * suspending serial peripherals for Stop 0/1/2 when serial + * Rx/Tx buffers are empty (checked in pmprepare). + */ + + stm32serial_pm_setsuspend(true); + } + break; + + case PM_SLEEP: + { + stm32serial_pm_setsuspend(true); + } + break; + + default: + + /* Should not get here */ + + break; + } +} +#endif + +/**************************************************************************** + * Name: stm32serial_pmprepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * Zero - (OK) means the event was successfully processed and that the + * driver is prepared for the PM state change. + * + * Non-zero - means that the driver is not prepared to perform the tasks + * needed achieve this power setting and will cause the state + * change to be aborted. NOTE: The prepare() method will also + * be called when reverting from lower back to higher power + * consumption modes (say because another driver refused a + * lower power state change). Drivers are not permitted to + * return non-zero values when reverting back to higher power + * consumption modes! + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int stm32serial_pmprepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + int n; + + /* Logic to prepare for a reduced power state goes here. */ + + switch (pmstate) + { + case PM_NORMAL: + case PM_IDLE: + break; + + case PM_STANDBY: + case PM_SLEEP: + +#ifdef SERIAL_HAVE_DMA + /* Flush Rx DMA buffers before checking state of serial device + * buffers. + */ + + stm32_serial_dma_poll(); +#endif + + /* Check if any of the active ports have data pending on Tx/Rx + * buffers. + */ + + for (n = 0; n < STM32H5_NLPUART + STM32H5_NUSART + STM32H5_NUART; n++) + { + struct stm32_serial_s *priv = g_uart_devs[n]; + + if (!priv || !priv->initialized) + { + /* Not active, skip. */ + + continue; + } + + if (priv->suspended) + { + /* Port already suspended, skip. */ + + continue; + } + + /* Check if port has data pending (Rx & Tx). */ + + if (priv->dev.xmit.head != priv->dev.xmit.tail) + { + return ERROR; + } + + if (priv->dev.recv.head != priv->dev.recv.tail) + { + return ERROR; + } + } + break; + + default: + + /* Should not get here */ + + break; + } + + return OK; +} +#endif + +#endif /* HAVE_UART */ +#endif /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Name: arm_earlyserialinit + * + * Description: + * Performs the low level USART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before arm_serialinit. + * + ****************************************************************************/ + +#ifdef USE_EARLYSERIALINIT +void arm_earlyserialinit(void) +{ +#ifdef HAVE_UART + unsigned i; + + /* Disable all USART interrupts */ + + for (i = 0; i < STM32H5_NLPUART + STM32H5_NUSART + STM32H5_NUART; i++) + { + if (g_uart_devs[i]) + { + stm32serial_disableusartint(g_uart_devs[i], NULL); + } + } + + /* Configure whichever one is the console */ + +#if CONSOLE_UART > 0 + stm32serial_setup(&g_uart_devs[CONSOLE_UART - 1]->dev); +#endif +#endif /* HAVE UART */ +} +#endif /* USE_EARLYSERIALINIT */ + +/**************************************************************************** + * Name: arm_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that arm_earlyserialinit was called previously. + * + ****************************************************************************/ + +void arm_serialinit(void) +{ +#ifdef HAVE_UART + char devname[16]; + unsigned i; + unsigned minor = 0; +#ifdef CONFIG_PM + int ret; +#endif + + /* Register to receive power management callbacks */ + +#ifdef CONFIG_PM + ret = pm_register(&g_serialpm.pm_cb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif + + /* Register the console */ + +#if CONSOLE_UART > 0 + uart_register("/dev/console", &g_uart_devs[CONSOLE_UART - 1]->dev); + +#ifndef CONFIG_STM32H5_SERIAL_DISABLE_REORDERING + /* If not disabled, register the console UART to ttyS0 and exclude + * it from initializing it further down + */ + + uart_register("/dev/ttyS0", &g_uart_devs[CONSOLE_UART - 1]->dev); + minor = 1; +#endif + +#ifdef SERIAL_HAVE_CONSOLE_DMA + /* If we need to re-initialise the console to enable DMA do that here. */ + + stm32serial_dmasetup(&g_uart_devs[CONSOLE_UART - 1]->dev); +#endif +#endif /* CONSOLE_UART > 0 */ + + /* Register all remaining USARTs */ + + strlcpy(devname, "/dev/ttySx", sizeof(devname)); + + for (i = 0; i < STM32H5_NLPUART + STM32H5_NUSART + STM32H5_NUART; i++) + { + /* Don't create a device for non-configured ports. */ + + if (g_uart_devs[i] == 0) + { + continue; + } + +#ifndef CONFIG_STM32H5_SERIAL_DISABLE_REORDERING + /* Don't create a device for the console - we did that above */ + + if (g_uart_devs[i]->dev.isconsole) + { + continue; + } +#endif + + /* Register USARTs as devices in increasing order */ + + devname[9] = '0' + minor++; + uart_register(devname, &g_uart_devs[i]->dev); + } +#endif /* HAVE UART */ +} + +/**************************************************************************** + * Name: stm32_serial_dma_poll + * + * Description: + * Checks receive DMA buffers for received bytes that have not accumulated + * to the point where the DMA half/full interrupt has triggered. + * + * This function should be called from a timer or other periodic context. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +void stm32_serial_dma_poll(void) +{ + irqstate_t flags; + + flags = enter_critical_section(); + +#ifdef CONFIG_LPUART1_RXDMA + if (g_lpuart1priv.rxdma != NULL) + { + stm32serial_dmarxcallback(g_lpuart1priv.rxdma, 0, &g_lpuart1priv); + } +#endif + +#ifdef CONFIG_USART1_RXDMA + if (g_usart1priv.rxdma != NULL) + { + stm32serial_dmarxcallback(g_usart1priv.rxdma, 0, &g_usart1priv); + } +#endif + +#ifdef CONFIG_USART2_RXDMA + if (g_usart2priv.rxdma != NULL) + { + stm32serial_dmarxcallback(g_usart2priv.rxdma, 0, &g_usart2priv); + } +#endif + +#ifdef CONFIG_USART3_RXDMA + if (g_usart3priv.rxdma != NULL) + { + stm32serial_dmarxcallback(g_usart3priv.rxdma, 0, &g_usart3priv); + } +#endif + +#ifdef CONFIG_UART4_RXDMA + if (g_uart4priv.rxdma != NULL) + { + stm32serial_dmarxcallback(g_uart4priv.rxdma, 0, &g_uart4priv); + } +#endif + +#ifdef CONFIG_UART5_RXDMA + if (g_uart5priv.rxdma != NULL) + { + stm32serial_dmarxcallback(g_uart5priv.rxdma, 0, &g_uart5priv); + } +#endif + + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +void up_putc(int ch) +{ +#if CONSOLE_UART > 0 + struct stm32_serial_s *priv = g_uart_devs[CONSOLE_UART - 1]; + uint16_t ie; + + stm32serial_disableusartint(priv, &ie); + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + arm_lowputc('\r'); + } + + arm_lowputc(ch); + stm32serial_restoreusartint(priv, ie); +#endif +} + +#else /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +void up_putc(int ch) +{ +#if CONSOLE_UART > 0 + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + arm_lowputc('\r'); + } + + arm_lowputc(ch); +#endif +} + +#endif /* USE_SERIALDRIVER */ diff --git a/arch/arm/src/stm32h5/stm32_start.c b/arch/arm/src/stm32h5/stm32_start.c new file mode 100644 index 00000000000..03c1241c644 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_start.c @@ -0,0 +1,240 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_start.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "arm_internal.h" +#include "nvic.h" + +#include "stm32.h" +#include "stm32_gpio.h" +#include "stm32_start.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* STM32H523/533 Memory Map *************************************************/ + +/* 0x0800:0000 - Beginning of the internal FLASH. Address of vectors. + * Mapped as boot memory address 0x0000:0000 at reset. + * 0x080f:ffff - End of flash region (assuming the max of 2MiB of FLASH). + * 0x2000:0000 - Start of internal SRAM1 and start of .data (_sdata) + * - End of .data (_edata) and start of .bss (_sbss) + * - End of .bss (_ebss) and bottom of idle stack + * - _ebss + CONFIG_IDLETHREAD_STACKSIZE = end of idle stack, + * start of heap. NOTE that the ARM uses a decrement before + * store stack so that the correct initial value is the end of + * the stack + 4; + * 0x2003:ffff - End of internal SRAM1 + * 0x2004:0000 - Start of internal SRAM2 + * 0x2004:ffff - End of internal SRAM2 + * 0x2005:0000 - Start of internal SRAM3 + * 0x2009:ffff - End of internal SRAM3 + */ + +/* STM32H562/563/573 Memory Map *********************************************/ + +/* 0x0800:0000 - Beginning of the internal FLASH. Address of vectors. + * Mapped as boot memory address 0x0000:0000 at reset. + * 0x080f:ffff - End of flash region (assuming the max of 2MiB of FLASH). + * 0x2000:0000 - Start of internal SRAM1 and start of .data (_sdata) + * - End of .data (_edata) and start of .bss (_sbss) + * - End of .bss (_ebss) and bottom of idle stack + * - _ebss + CONFIG_IDLETHREAD_STACKSIZE = end of idle stack, + * start of heap. NOTE that the ARM uses a decrement before + * store stack so that the correct initial value is the end of + * the stack + 4; + * 0x2001:ffff - End of internal SRAM1 + * 0x2002:0000 - Start of internal SRAM2 + * 0x2002:ffff - End of internal SRAM2 + * 0x2003:0000 - Start of internal SRAM3 + * 0x2003:ffff - End of internal SRAM3 + */ + +#define SRAM2_START STM32_SRAM2_BASE +#define SRAM2_END (SRAM2_START + STM32H5_SRAM2_SIZE) + +#define SRAM3_START STM32_SRAM3_BASE +#define SRAM3_END (SRAM3_START + STM32H5_SRAM3_SIZE) + +#define HEAP_BASE ((uintptr_t)_ebss + CONFIG_IDLETHREAD_STACKSIZE) + +/* g_idle_topstack: _sbss is the start of the BSS region as defined by the + * linker script. _ebss lies at the end of the BSS region. The idle task + * stack starts at the end of BSS and is of size CONFIG_IDLETHREAD_STACKSIZE. + * The IDLE thread is the thread that the system boots on and, eventually, + * becomes the IDLE, do nothing task that runs only when there is nothing + * else to run. The heap continues from there until the end of memory. + * g_idle_topstack is a read-only variable the provides this computed + * address. + */ + +const uintptr_t g_idle_topstack = HEAP_BASE; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: showprogress + * + * Description: + * Print a character on the UART to show boot status. + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_FEATURES +# define showprogress(c) arm_lowputc(c) +#else +# define showprogress(c) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_ARMV8M_STACKCHECK +/* we need to get r10 set before we can allow instrumentation calls */ + +void __start(void) noinstrument_function; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: __start + * + * Description: + * This is the reset entry point. + * + ****************************************************************************/ + +void __start(void) +{ + const uint32_t *src; + uint32_t *dest; + +#ifdef CONFIG_ARMV8M_STACKCHECK + /* Set the stack limit before we attempt to call any functions */ + + __asm__ volatile + ("sub r10, sp, %0" : : "r" (CONFIG_IDLETHREAD_STACKSIZE - 64) :); +#endif + +#ifdef CONFIG_STM32H5_SRAM2_INIT + /* NOTE: this is optional because this may be inappropriate, especially + * if the memory is being used for it's battery backed purpose. In that + * case, the first-time initialization needs to be performed by the board + * under application-specific circumstances. On the other hand, if we're + * using this memory for, say, additional heap space, then this is handy. + */ + + for (dest = (uint32_t *)SRAM2_START; dest < (uint32_t *)SRAM2_END; ) + { + *dest++ = 0; + } +#endif + +#ifdef CONFIG_STM32H5_SRAM3_INIT + for (dest = (uint32_t *)SRAM3_START; dest < (uint32_t *)SRAM3_END; ) + { + *dest++ = 0; + } +#endif + + /* Configure the UART so that we can get debug output as soon as possible */ + + stm32_clockconfig(); + arm_fpuconfig(); + stm32_lowsetup(); + stm32_gpioinit(); + showprogress('A'); + + /* Clear .bss. We'll do this inline (vs. calling memset) just to be + * certain that there are no issues with the state of global variables. + */ + + for (dest = (uint32_t *)_sbss; dest < (uint32_t *)_ebss; ) + { + *dest++ = 0; + } + + showprogress('B'); + + /* Move the initialized data section from his temporary holding spot in + * FLASH into the correct place in SRAM. The correct place in SRAM is + * give by _sdata and _edata. The temporary location is in FLASH at the + * end of all of the other read-only data (.text, .rodata) at _eronly. + */ + + for (src = (const uint32_t *)_eronly, + dest = (uint32_t *)_sdata; dest < (uint32_t *)_edata; + ) + { + *dest++ = *src++; + } + + showprogress('C'); + +#ifdef CONFIG_ARMV8M_STACKCHECK + arm_stack_check_init(); +#endif + +#ifdef CONFIG_ARCH_PERF_EVENTS + up_perf_init((void *)STM32_SYSCLK_FREQUENCY); +#endif + + /* Perform early serial initialization */ + +#ifdef USE_EARLYSERIALINIT + arm_earlyserialinit(); +#endif + showprogress('D'); + + /* Initialize onboard resources */ + + stm32_board_initialize(); + showprogress('F'); + + /* Then start NuttX */ + + showprogress('\r'); + showprogress('\n'); + + nx_start(); + + /* Shoulnd't get here */ + + for (; ; ); +} diff --git a/arch/arm/src/stm32h5/stm32_start.h b/arch/arm/src/stm32h5/stm32_start.h new file mode 100644 index 00000000000..d3d7961bb2b --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_start.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_start.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H5_STM32_START_H +#define __ARCH_ARM_SRC_STM32H5_STM32_START_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_board_initialize + * + * Description: + * All STM32H5 architectures must provide the following entry point. This + * entry point is called early in the initialization -- after all memory + * has been configured and mapped but before any devices have been + * initialized. + * + ****************************************************************************/ + +void stm32_board_initialize(void); + +#endif /* __ARCH_ARM_SRC_STM32H5_STM32_START_H */ diff --git a/arch/arm/src/stm32h5/stm32_timerisr.c b/arch/arm/src/stm32h5/stm32_timerisr.c new file mode 100644 index 00000000000..fd06e32323a --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_timerisr.c @@ -0,0 +1,147 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_timerisr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "nvic.h" +#include "clock/clock.h" +#include "arm_internal.h" +#include "chip.h" +#include "stm32.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The desired timer interrupt frequency is provided by the definition + * CLK_TCK (see include/time.h). CLK_TCK defines the desired number of + * system clock ticks per second. That value is a user configurable setting + * that defaults to 100 (100 ticks per second = 10 MS interval). + * + * The RCC feeds the Cortex System Timer (SysTick) with the AHB clock (HCLK) + * divided by 8. The SysTick can work either with this clock or with the + * Cortex clock (HCLK), configurable in the SysTick Control and Status + * register. + */ + +/* Power up default is HCLK, not HCLK/8. + * And I don't know now to re-configure it yet + */ + +#undef CONFIG_STM32H5_SYSTICK_HCLKd8 + +#ifdef CONFIG_STM32H5_SYSTICK_HCLKd8 +# define SYSTICK_RELOAD ((STM32_HCLK_FREQUENCY / 8 / CLK_TCK) - 1) +#else +# define SYSTICK_RELOAD ((STM32_HCLK_FREQUENCY / CLK_TCK) - 1) +#endif + +/* The size of the reload field is 24 bits. Verify that the reload value + * will fit in the reload register. + */ + +#if SYSTICK_RELOAD > 0x00ffffff +# error SYSTICK_RELOAD exceeds the range of the RELOAD register +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: stm32_timerisr + * + * Description: + * The timer ISR will perform a variety of services for various portions + * of the systems. + * + ****************************************************************************/ + +static int stm32_timerisr(int irq, uint32_t *regs, void *arg) +{ + /* Process timer interrupt */ + + nxsched_process_timer(); + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: up_timer_initialize + * + * Description: + * This function is called during start-up to initialize + * the timer interrupt. + * + ****************************************************************************/ + +void up_timer_initialize(void) +{ + uint32_t regval; + + /* Set the SysTick interrupt to the default priority */ + + regval = getreg32(NVIC_SYSH12_15_PRIORITY); + regval &= ~NVIC_SYSH_PRIORITY_PR15_MASK; + regval |= (NVIC_SYSH_PRIORITY_DEFAULT << NVIC_SYSH_PRIORITY_PR15_SHIFT); + putreg32(regval, NVIC_SYSH12_15_PRIORITY); + + /* Make sure that the SYSTICK clock source is set correctly */ + +#if 0 /* Does not work. Comes up with HCLK source and I can't change it */ + regval = getreg32(NVIC_SYSTICK_CTRL); +#ifdef CONFIG_STM32H5_SYSTICK_HCLKd8 + regval &= ~NVIC_SYSTICK_CTRL_CLKSOURCE; +#else + regval |= NVIC_SYSTICK_CTRL_CLKSOURCE; +#endif + putreg32(regval, NVIC_SYSTICK_CTRL); +#endif + + /* Configure SysTick to interrupt at the requested rate */ + + putreg32(SYSTICK_RELOAD, NVIC_SYSTICK_RELOAD); + + /* Attach the timer interrupt vector */ + + irq_attach(STM32_IRQ_SYSTICK, (xcpt_t)stm32_timerisr, NULL); + + /* Enable SysTick interrupts */ + + putreg32((NVIC_SYSTICK_CTRL_CLKSOURCE | NVIC_SYSTICK_CTRL_TICKINT | + NVIC_SYSTICK_CTRL_ENABLE), NVIC_SYSTICK_CTRL); + + /* And enable the timer interrupt */ + + up_enable_irq(STM32_IRQ_SYSTICK); +} diff --git a/arch/arm/src/stm32h5/stm32_uart.h b/arch/arm/src/stm32h5/stm32_uart.h new file mode 100644 index 00000000000..831d7652552 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32_uart.h @@ -0,0 +1,574 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32_uart.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_STC_STM32H5_STM32_UART_H +#define __ARCH_ARM_STC_STM32H5_STM32_UART_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" + +#if defined(CONFIG_STM32H5_STM32H5XXXX) +# include "hardware/stm32_uart.h" +#else +# error "Unsupported STM32H5 chip" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Make sure that we have not enabled more U[S]ARTs than are supported by the + * device. + */ + +#if !defined(CONFIG_STM32H5_HAVE_UART12) +# undef CONFIG_STM32H5_UART12 +#endif +#if !defined(CONFIG_STM32H5_HAVE_USART11) +# undef CONFIG_STM32H5_USART11 +#endif +#if !defined(CONFIG_STM32H5_HAVE_USART10) +# undef CONFIG_STM32H5_USART10 +#endif +#if !defined(CONFIG_STM32H5_HAVE_UART9) +# undef CONFIG_STM32H5_UART9 +#endif +#if !defined(CONFIG_STM32H5_HAVE_UART8) +# undef CONFIG_STM32H5_UART8 +#endif +#if !defined(CONFIG_STM32H5_HAVE_UART7) +# undef CONFIG_STM32H5_UART7 +#endif +#if !defined(CONFIG_STM32H5_HAVE_USART6) +# undef CONFIG_STM32H5_USART6 +#endif +#if !defined(CONFIG_STM32H5_HAVE_UART5) +# undef CONFIG_STM32H5_UART5 +#endif +#if !defined(CONFIG_STM32H5_HAVE_UART4) +# undef CONFIG_STM32H5_UART4 +#endif +#if !defined(CONFIG_STM32H5_HAVE_USART3) +# undef CONFIG_STM32H5_USART3 +#endif +#if !defined(CONFIG_STM32H5_HAVE_USART2) +# undef CONFIG_STM32H5_USART2 +#endif +#if !defined(CONFIG_STM32H5_HAVE_USART1) +# undef CONFIG_STM32H5_USART1 +#endif +#if !defined(CONFIG_STM32H5_HAVE_LPUART1) +# undef CONFIG_STM32H5_LPUART1 +#endif + +/* Sanity checks */ + +#if !defined(CONFIG_STM32H5_LPUART1) +# undef CONFIG_STM32H5_LPUART1_SERIALDRIVER +# undef CONFIG_STM32H5_LPUART1_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_USART1) +# undef CONFIG_STM32H5_USART1_SERIALDRIVER +# undef CONFIG_STM32H5_USART1_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_USART2) +# undef CONFIG_STM32H5_USART2_SERIALDRIVER +# undef CONFIG_STM32H5_USART2_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_USART3) +# undef CONFIG_STM32H5_USART3_SERIALDRIVER +# undef CONFIG_STM32H5_USART3_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_UART4) +# undef CONFIG_STM32H5_UART4_SERIALDRIVER +# undef CONFIG_STM32H5_UART4_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_UART5) +# undef CONFIG_STM32H5_UART5_SERIALDRIVER +# undef CONFIG_STM32H5_UART5_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_USART6) +# undef CONFIG_STM32H5_USART6_SERIALDRIVER +# undef CONFIG_STM32H5_USART6_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_UART7) +# undef CONFIG_STM32H5_UART7_SERIALDRIVER +# undef CONFIG_STM32H5_UART7_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_UART8) +# undef CONFIG_STM32H5_UART8_SERIALDRIVER +# undef CONFIG_STM32H5_UART8_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_UART9) +# undef CONFIG_STM32H5_UART9_SERIALDRIVER +# undef CONFIG_STM32H5_UART9_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_USART10) +# undef CONFIG_STM32H5_USART10_SERIALDRIVER +# undef CONFIG_STM32H5_USART10_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_USART11) +# undef CONFIG_STM32H5_USART11_SERIALDRIVER +# undef CONFIG_STM32H5_USART11_1WIREDRIVER +#endif +#if !defined(CONFIG_STM32H5_UART12) +# undef CONFIG_STM32H5_UART12_SERIALDRIVER +# undef CONFIG_STM32H5_UART12_1WIREDRIVER +#endif + +/* Is there a USART enabled? */ + +#if defined(CONFIG_STM32H5_LPUART1) || defined(CONFIG_STM32H5_USART1) || \ + defined(CONFIG_STM32H5_USART2) || defined(CONFIG_STM32H5_USART3) || \ + defined(CONFIG_STM32H5_UART4) || defined(CONFIG_STM32H5_UART5) || \ + defined(CONFIG_STM32H5_USART6) || defined(CONFIG_STM32H5_UART7) || \ + defined(CONFIG_STM32H5_UART8) || defined(CONFIG_STM32H5_UART9) || \ + defined(CONFIG_STM32H5_USART10) || defined(CONFIG_STM32H5_USART11) || \ + defined(CONFIG_STM32H5_USART12) +# define HAVE_UART 1 +#endif + +/* Is there a serial console? */ + +#if defined(CONFIG_LPUART1_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_LPUART1_SERIALDRIVER) +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 1 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_USART1_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 2 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_USART2_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 3 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_USART3_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 4 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_UART4_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 5 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_UART5_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 6 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_USART6_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 7 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_UART7_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 8 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART8_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_UART8_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 9 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART9_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_UART9_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 10 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART10_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_USART10_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 11 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART11_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_USART11_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_UART12_SERIAL_CONSOLE +# define CONSOLE_UART 12 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART12_SERIAL_CONSOLE) && defined(CONFIG_STM32H5_UART12_SERIALDRIVER) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# undef CONFIG_UART9_SERIAL_CONSOLE +# undef CONFIG_USART10_SERIAL_CONSOLE +# undef CONFIG_USART11_SERIAL_CONSOLE +# define CONSOLE_UART 13 +# define HAVE_CONSOLE 1 +#else +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# define CONSOLE_UART 0 +# undef HAVE_CONSOLE +#endif + +/* DMA support is only provided if CONFIG_ARCH_DMA is in the NuttX + * configuration + */ + +#if !defined(HAVE_UART) || !defined(CONFIG_ARCH_DMA) +# undef CONFIG_USART1_RXDMA +# undef CONFIG_USART2_RXDMA +# undef CONFIG_USART3_RXDMA +# undef CONFIG_UART4_RXDMA +# undef CONFIG_UART5_RXDMA +# undef CONFIG_USART7_RXDMA +# undef CONFIG_UART7_RXDMA +# undef CONFIG_UART8_RXDMA +# undef CONFIG_UART9_RXDMA +# undef CONFIG_USART10_RXDMA +# undef CONFIG_USART11_RXDMA +# undef CONFIG_UART12_RXDMA +#endif + +/* Disable the DMA configuration on all unused USARTs */ + +#ifndef CONFIG_STM32H5_LPUART1_SERIALDRIVER +# undef CONFIG_LPUART1_RXDMA +#endif + +#ifndef CONFIG_STM32H5_USART1_SERIALDRIVER +# undef CONFIG_USART1_RXDMA +#endif + +#ifndef CONFIG_STM32H5_USART2_SERIALDRIVER +# undef CONFIG_USART2_RXDMA +#endif + +#ifndef CONFIG_STM32H5_USART3_SERIALDRIVER +# undef CONFIG_USART3_RXDMA +#endif + +#ifndef CONFIG_STM32H5_UART4_SERIALDRIVER +# undef CONFIG_UART4_RXDMA +#endif + +#ifndef CONFIG_STM32H5_UART5_SERIALDRIVER +# undef CONFIG_UART5_RXDMA +#endif + +#ifndef CONFIG_STM32H5_USART6_SERIALDRIVER +# undef CONFIG_USART6_RXDMA +#endif + +#ifndef CONFIG_STM32H5_UART7_SERIALDRIVER +# undef CONFIG_UART7_RXDMA +#endif + +#ifndef CONFIG_STM32H5_UART8_SERIALDRIVER +# undef CONFIG_UART8_RXDMA +#endif + +#ifndef CONFIG_STM32H5_UART9_SERIALDRIVER +# undef CONFIG_UART9_RXDMA +#endif + +#ifndef CONFIG_STM32H5_USART10_SERIALDRIVER +# undef CONFIG_USART10_RXDMA +#endif + +#ifndef CONFIG_STM32H5_USART11_SERIALDRIVER +# undef CONFIG_USART11_RXDMA +#endif + +#ifndef CONFIG_STM32H5_UART12_SERIALDRIVER +# undef CONFIG_UART12_RXDMA +#endif + +/* Is DMA available on any (enabled) USART? */ + +#undef SERIAL_HAVE_DMA +#if defined(CONFIG_LPUART1_RXDMA) || defined(CONFIG_USART1_RXDMA) || \ + defined(CONFIG_USART2_RXDMA) || defined(CONFIG_USART3_RXDMA) || \ + defined(CONFIG_UART4_RXDMA) || defined(CONFIG_UART5_RXDMA) || \ + defined(CONFIG_USART6_RXDMA) || defined(CONFIG_UART7_RXDMA) || \ + defined(CONFIG_UART8_RXDMA) || defined(CONFIG_UART9_RXDMA) || \ + defined(CONFIG_USART10_RXDMA) || defined(CONFIG_USART11_RXDMA) || \ + defined(CONFIG_USART12_RXDMA) +# define SERIAL_HAVE_DMA 0 +# warning Serial DMA has not been implemented for STM32H5 chips. +#endif + +/* Is DMA used on the console UART? */ + +#undef SERIAL_HAVE_CONSOLE_DMA +#if defined(CONFIG_LPUART1_SERIAL_CONSOLE) && defined(CONFIG_LPUART1_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_USART1_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_USART2_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_USART3_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_UART4_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_UART5_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_USART6_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_UART7_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_UART8_SERIAL_CONSOLE) && defined(CONFIG_UART8_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_UART9_SERIAL_CONSOLE) && defined(CONFIG_UART9_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_USART10_SERIAL_CONSOLE) && defined(CONFIG_USART10_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_USART11_SERIAL_CONSOLE) && defined(CONFIG_USART11_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#elif defined(CONFIG_UART12_SERIAL_CONSOLE) && defined(CONFIG_UART12_RXDMA) +# define SERIAL_HAVE_CONSOLE_DMA 1 +#endif + +/* Is DMA used on all (enabled) USARTs */ + +#define SERIAL_HAVE_ONLY_DMA 1 +#if defined(CONFIG_STM32H5_LPUART1_SERIALDRIVER) && !defined(CONFIG_LPUART1_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_USART1_SERIALDRIVER) && !defined(CONFIG_USART1_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_USART2_SERIALDRIVER) && !defined(CONFIG_USART2_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_USART3_SERIALDRIVER) && !defined(CONFIG_USART3_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_UART4_SERIALDRIVER) && !defined(CONFIG_UART4_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_UART5_SERIALDRIVER) && !defined(CONFIG_UART5_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_USART6_SERIALDRIVER) && !defined(CONFIG_USART6_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_UART7_SERIALDRIVER) && !defined(CONFIG_UART7_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_UART8_SERIALDRIVER) && !defined(CONFIG_UART8_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_UART9_SERIALDRIVER) && !defined(CONFIG_UART9_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_USART10_SERIALDRIVER) && !defined(CONFIG_USART10_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_USART11_SERIALDRIVER) && !defined(CONFIG_USART11_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#elif defined(CONFIG_STM32H5_UART12_SERIALDRIVER) && !defined(CONFIG_UART12_RXDMA) +# undef SERIAL_HAVE_ONLY_DMA +#endif + +/* Is RS-485 used? */ + +#if defined(CONFIG_LPUART1_RS485) || defined(CONFIG_USART1_RS485) || \ + defined(CONFIG_USART2_RS485) || defined(CONFIG_USART3_RS485) || \ + defined(CONFIG_UART4_RS485) || defined(CONFIG_UART5_RS485) || \ + defined(CONFIG_USART6_RS485) || defined(CONFIG_UART7_RS485) || \ + defined(CONFIG_UART8_RS485) || defined(CONFIG_UART9_RS485) || \ + defined(CONFIG_USART10_RS485) || defined(CONFIG_USART11_RS485) || \ + defined(CONFIG_UART12_RS485) +# define HAVE_RS485 1 +#endif + +#ifdef HAVE_RS485 +# define USART_CR1_USED_INTS (USART_CR1_RXNEIE | USART_CR1_TXEIE | USART_CR1_PEIE | USART_CR1_TCIE) +#else +# define USART_CR1_USED_INTS (USART_CR1_RXNEIE | USART_CR1_TXEIE | USART_CR1_PEIE) +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_serial_dma_poll + * + * Description: + * Must be called periodically if any STM32 UART is configured for DMA. + * The DMA callback is triggered for each fifo size/2 bytes, but this can + * result in some bytes being transferred but not collected if the incoming + * data is not a whole multiple of half the FIFO size. + * + * May be safely called from either interrupt or thread context. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_DMA +void stm32_serial_dma_poll(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_STC_STM32H5_STM32_UART_H */ diff --git a/arch/arm/src/stm32h5/stm32h5xx_rcc.c b/arch/arm/src/stm32h5/stm32h5xx_rcc.c new file mode 100644 index 00000000000..5954b15ed72 --- /dev/null +++ b/arch/arm/src/stm32h5/stm32h5xx_rcc.c @@ -0,0 +1,1344 @@ +/**************************************************************************** + * arch/arm/src/stm32h5/stm32h5xx_rcc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "stm32_pwr.h" +#include "stm32_flash.h" +#include "stm32_rcc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Allow up to 100 milliseconds for the high speed clock to become ready. + * that is a very long delay, but if the clock does not become ready we are + * hosed anyway. Normally this is very fast, but I have seen at least one + * board that required this long, long timeout for the HSE to be ready. + */ + +#define HSERDY_TIMEOUT (100 * CONFIG_BOARD_LOOPSPERMSEC) + +/* Same for HSI and CSI */ + +#define HSIRDY_TIMEOUT HSERDY_TIMEOUT +#define LSIRDY_TIMEOUT HSERDY_TIMEOUT + +/* HSE divisor to yield ~1MHz RTC clock */ + +#define HSE_DIVISOR (STM32H5_HSE_FREQUENCY + 500000) / 1000000 + +/* Determine if board wants to use HSI48 as 48 MHz oscillator. */ + +#if defined(CONFIG_STM32H5_HAVE_HSI48) && defined(STM32H5_USE_CLK48) +# if STM32H5_CLKUSB_SEL == RCC_CCIPR4_USBSEL_HSI48KERCK +# define STM32H5_USE_HSI48 +# endif +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rcc_enableahb1 + * + * Description: + * Enable selected AHB1 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableahb1(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the AHB1ENR register to enabled the + * selected AHB1 peripherals. + */ + + regval = getreg32(STM32_RCC_AHB1ENR); + +#ifdef CONFIG_STM32H5_GPDMA1 + /* DMA 1 clock enable */ + + regval |= RCC_AHB1ENR_GPDMA1EN; +#endif + +#ifdef CONFIG_STM32H5_GPDMA2 + /* DMA 2 clock enable */ + + regval |= RCC_AHB1ENR_GPDMA2EN; +#endif + +#ifdef CONFIG_STM32H5_FLASHEN + /* Flash memory interface clock enable */ + + regval |= RCC_AHB1ENR_FLASHEN; +#endif + +#ifdef CONFIG_STM32H5_CRC + /* CRC clock enable */ + + regval |= RCC_AHB1ENR_CRCEN; +#endif + +#ifdef CONFIG_STM32H5_CORDIC + /* CORDIC clock enable */ + + regval |= RCC_AHB1ENR_CORDICEN; +#endif + +#ifdef CONFIG_STM32H5_FMAC + /* FMAC clock enable */ + + regval |= RCC_AHB1ENR_FMACEN; +#endif + +#ifdef CONFIG_STM32H5_RAMCFG + /* RAMCFG clock enable */ + + regval |= RCC_AHB1ENR_RAMCFGEN; +#endif + +#ifdef CONFIG_STM32H5_ETH + /* ETH clock enable */ + + regval |= RCC_AHB1ENR_ETHEN; +#endif +#ifdef CONFIG_STM32H5_ETHTX + /* ETH TX clock enable */ + + regval |= RCC_AHB1ENR_ETHTXEN; +#endif + +#ifdef CONFIG_STM32H5_ETHRX + /* ETH RX clock enable */ + + regval |= RCC_AHB1ENR_ETHRXEN; +#endif + +#ifdef CONFIG_STM32H5_TZSC1 + + regval |= RCC_AHB1ENR_TZSC1EN; +#endif + +#ifdef CONFIG_STM32H5_BKPRAM + /* BKPRAM clock enable */ + + regval |= RCC_AHB1ENR_BKPRAMEN; +#endif + +#ifdef CONFIG_STM32H5_DCACHE + /* DCACHE clock enable */ + + regval |= RCC_AHB1ENR_DCACHEEN; +#endif + +#ifdef CONFIG_STM32H5_SRAM1 + /* ETH clock enable */ + + regval |= RCC_AHB1ENR_SRAM1EN; +#endif + + putreg32(regval, STM32_RCC_AHB1ENR); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableahb2 + * + * Description: + * Enable selected AHB2 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableahb2(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the AHB2ENR register to enable the + * selected AHB2 peripherals. + */ + + regval = getreg32(STM32_RCC_AHB2ENR); + + /* Enable GPIOA, GPIOB, .... GPIOH */ + +#if STM32H5_NPORTS > 0 + regval |= (RCC_AHB2ENR_GPIOAEN +#if STM32H5_NPORTS > 1 + | RCC_AHB2ENR_GPIOBEN +#endif +#if STM32H5_NPORTS > 2 + | RCC_AHB2ENR_GPIOCEN +#endif +#if STM32H5_NPORTS > 3 + | RCC_AHB2ENR_GPIODEN +#endif +#if STM32H5_NPORTS > 4 + | RCC_AHB2ENR_GPIOEEN +#endif +#if STM32H5_NPORTS > 5 + | RCC_AHB2ENR_GPIOFEN +#endif +#if STM32H5_NPORTS > 6 + | RCC_AHB2ENR_GPIOGEN +#endif +#if STM32H5_NPORTS > 7 + | RCC_AHB2ENR_GPIOHEN +#endif +#if STM32H5_NPORTS > 7 + | RCC_AHB2ENR_GPIOIEN +#endif + + ); +#endif + +#if defined(CONFIG_STM32H5_ADC) + /* ADC clock enable */ + + regval |= RCC_AHB2ENR_ADCEN; +#endif + +#ifdef CONFIG_STM32H5_DAC1 + /* DAC1 clock enable */ + + regval |= RCC_AHB2ENR_DAC1EN; +#endif + +#ifdef CONFIG_STM32H5_DCMI_PSSI + /* Digital Camera Interface clock enable */ + + regval |= RCC_AHB2ENR_DCMI_PSSIEN; +#endif + +#ifdef CONFIG_STM32H5_AES + /* Cryptographic modules clock enable */ + + regval |= RCC_AHB2ENR_AESEN; +#endif + +#ifdef CONFIG_STM32H5_HASH + /* Hash module enable */ + + regval |= RCC_AHB2ENR_HASHEN +#endif + +#ifdef CONFIG_STM32H5_RNG + /* Random number generator clock enable */ + + regval |= RCC_AHB2ENR_RNGEN; +#endif + +#ifdef CONFIG_STM32H5_PKA + /* Public Key Accelerator clock enable */ + + regval |= RCC_AHB2ENR_PKAEN; +#endif + +#ifdef CONFIG_STM32H5_SAES + /* Secure AES coprocessor clock enable */ + + regval |= RCC_AHB2ENR_SAESEN; +#endif + +#ifdef CONFIG_STM32H5_SRAM2 + /* SRAM2 clock enable */ + + regval |= RCC_AHB2ENR_SRAM2EN; +#endif + +#ifdef CONFIG_STM32H5_SRAM3 + /* SRAM2 clock enable */ + + regval |= RCC_AHB2ENR_SRAM3EN; +#endif + + putreg32(regval, STM32_RCC_AHB2ENR); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableahb4 + * + * Description: + * Enable selected AHB4 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableahb4(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the AHB4ENR register to enabled the + * selected AHB4 peripherals. + */ + + regval = getreg32(STM32_RCC_AHB4ENR); + +#ifdef CONFIG_STM32H5_OTFDEC1EN + /* On-the-fly-decryption module clock enable */ + + regval |= RCC_AHB4ENR_OTFDEC1EN; +#endif + +#ifdef CONFIG_STM32H5_SDMMC1 + /* SDMMC1 clock enable */ + + regval |= RCC_AHB4ENR_SDMMC1EN; +#endif + +#ifdef CONFIG_STM32H5_SDMMC2 + /* SDMMC1 clock enable */ + + regval |= RCC_AHB4ENR_SDMMC2EN; +#endif + +#ifdef CONFIG_STM32H5_FMC + /* Flexible memory controller clock enable */ + + regval |= RCC_AHB4ENR_FMCEN; +#endif + +#ifdef CONFIG_STM32H5_OCTOSPI1 + /* OCTOSPI1 module clock enable */ + + regval |= RCC_AHB4ENR_OSPI1EN; +#endif + + putreg32(regval, STM32_RCC_AHB4ENR); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableapb1l + * + * Description: + * Enable selected APB1L peripherals + * + ****************************************************************************/ + +static inline void rcc_enableapb1l(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the APB1LENR register to enabled the + * selected APB1L peripherals. + */ + + regval = getreg32(STM32_RCC_APB1LENR); + +#ifdef CONFIG_STM32H5_TIM2 + /* Bit 0: TIM2 clock enable */ + + regval |= RCC_APB1LENR_TIM2EN; +#endif + +#ifdef CONFIG_STM32H5_TIM3 + /* Bit 1: TIM3 clock enable */ + + regval |= RCC_APB1LENR_TIM3EN; +#endif + +#ifdef CONFIG_STM32H5_TIM4 + /* Bit 2: TIM4 clock enable */ + + regval |= RCC_APB1LENR_TIM4EN; +#endif + +#ifdef CONFIG_STM32H5_TIM5 + /* Bit 3: TIM5 clock enable */ + + regval |= RCC_APB1LENR_TIM5EN; +#endif + +#ifdef CONFIG_STM32H5_TIM6 + /* Bit 4: TIM6 clock enable */ + + regval |= RCC_APB1LENR_TIM6EN; +#endif + +#ifdef CONFIG_STM32H5_TIM7 + /* Bit 5: TIM7 clock enable */ + + regval |= RCC_APB1LENR_TIM7EN; +#endif + +#ifdef CONFIG_STM32H5_TIM12 + /* Bit 5: TIM12 clock enable */ + + regval |= RCC_APB1LENR_TIM12EN; +#endif + +#ifdef CONFIG_STM32H5_TIM13 + /* Bit 5: TIM13 clock enable */ + + regval |= RCC_APB1LENR_TIM13EN; +#endif + +#ifdef CONFIG_STM32H5_TIM14 + /* Bit 5: TIM14 clock enable */ + + regval |= RCC_APB1LENR_TIM14EN; +#endif + +#ifdef CONFIG_STM32H5_SPI2 + /* Bit 14: SPI2 clock enable */ + + regval |= RCC_APB1LENR_SPI2EN; +#endif + +#ifdef CONFIG_STM32H5_SPI3 + /* Bit 15: SPI3 clock enable */ + + regval |= RCC_APB1LENR_SPI3EN; +#endif + +#ifdef CONFIG_STM32H5_USART2 + /* Bit 17: USART2 clock enable */ + + regval |= RCC_APB1LENR_USART2EN; +#endif + +#ifdef CONFIG_STM32H5_USART3 + /* Bit 18: USART3 clock enable */ + + regval |= RCC_APB1LENR_USART3EN; +#endif + +#ifdef CONFIG_STM32H5_UART4 + /* Bit 19: UART4 clock enable */ + + regval |= RCC_APB1LENR_UART4EN; +#endif + +#ifdef CONFIG_STM32H5_UART5 + /* Bit 20: UART5 clock enable */ + + regval |= RCC_APB1LENR_UART5EN; +#endif + +#ifdef CONFIG_STM32H5_I2C1 + /* Bit 21: I2C1 clock enable */ + + regval |= RCC_APB1LENR_I2C1EN; +#endif + +#ifdef CONFIG_STM32H5_I2C2 + /* Bit 22: I2C2 clock enable */ + + regval |= RCC_APB1LENR_I2C2EN; +#endif + +#ifdef CONFIG_STM32H5_I3C1 + /* Bit 23: I3C1 clock enable */ + + regval |= RCC_APB1LENR_I3C1EN; +#endif + +#ifdef STM32H5_USE_HSI48 + if (STM32H5_HSI48_SYNCSRC != SYNCSRC_NONE) + { + /* Bit 24: CRS clock enable */ + + regval |= RCC_APB1LENR_CRSEN; + } +#endif + +#ifdef CONFIG_STM32H5_USART6 + /* Bit 25: USART6 clock enable */ + + regval |= RCC_APB1LENR_USART6EN; +#endif + +#ifdef CONFIG_STM32H5_USART10 + /* Bit 26: USART10 clock enable */ + + regval |= RCC_APB1LENR_USART10EN; +#endif + +#ifdef CONFIG_STM32H5_USART11 + /* Bit 27: USART11 clock enable */ + + regval |= RCC_APB1LENR_USART11EN; +#endif + +#ifdef CONFIG_STM32H5_CEC + /* Bit 28: CEC clock enable */ + + regval |= RCC_APB1LENR_CECEN; +#endif + +#ifdef CONFIG_STM32H5_UART7 + /* Bit 30: UART7 clock enable */ + + regval |= RCC_APB1LENR_UART7EN; +#endif + +#ifdef CONFIG_STM32H5_UART8 + /* Bit 31: UART8 clock enable */ + + regval |= RCC_APB1LENR_UART8EN; +#endif + + putreg32(regval, STM32_RCC_APB1LENR); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableapb1h + * + * Description: + * Enable selected APB1H peripherals + * + ****************************************************************************/ + +static inline void rcc_enableapb1h(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the APB1HENR register to enabled the + * selected APB1H peripherals. + */ + + regval = getreg32(STM32_RCC_APB1HENR); + +#ifdef CONFIG_STM32H5_UART9 + /* Bit 0: UART9 clock enable */ + + regval |= RCC_APB1HENR_UART9EN; +#endif + +#ifdef CONFIG_STM32H5_UART12 + /* Bit 1: UART12 clock enable */ + + regval |= RCC_APB1HENR_UART12EN; +#endif + +#ifdef CONFIG_STM32H5_DTS + /* Bit 3: DTS clock enable */ + + regval |= RCC_APB1HENR_DTSEN; +#endif + +#ifdef CONFIG_STM32H5_LPTIM2 + /* Bit 5: Low-power Timer 2 clock enable */ + + regval |= RCC_APB1HENR_LPTIM2EN; +#endif + +#ifdef CONFIG_STM32H5_FDCAN + /* Bit 9: FDCAN clock enable */ + + regval |= RCC_APB1HENR_FDCANEN; +#endif + +#ifdef CONFIG_STM32H5_UCPD1 + /* Bit 23: UCPD1 clock enable */ + + regval |= RCC_APB1HENR_UCPD1EN; +#endif + + /* Enable APB1H peripherals */ + + putreg32(regval, STM32_RCC_APB1HENR); +} + +/**************************************************************************** + * Name: rcc_enableapb2 + * + * Description: + * Enable selected APB2 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableapb2(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the APB2ENR register to enabled the + * selected APB2 peripherals. + */ + + regval = getreg32(STM32_RCC_APB2ENR); + +#ifdef CONFIG_STM32H5_TIM1 + /* TIM1 clock enable */ + + regval |= RCC_APB2ENR_TIM1EN; +#endif + +#ifdef CONFIG_STM32H5_SPI1 + /* SPI1 clock enable */ + + regval |= RCC_APB2ENR_SPI1EN; +#endif + +#ifdef CONFIG_STM32H5_TIM8 + /* TIM8 clock enable */ + + regval |= RCC_APB2ENR_TIM8EN; +#endif + +#ifdef CONFIG_STM32H5_USART1 + /* USART1 clock enable */ + + regval |= RCC_APB2ENR_USART1EN; +#endif + +#ifdef CONFIG_STM32H5_TIM15 + /* TIM15 clock enable */ + + regval |= RCC_APB2ENR_TIM15EN; +#endif + +#ifdef CONFIG_STM32H5_TIM16 + /* TIM16 clock enable */ + + regval |= RCC_APB2ENR_TIM16EN; +#endif + +#ifdef CONFIG_STM32H5_TIM17 + /* TIM17 clock enable */ + + regval |= RCC_APB2ENR_TIM17EN; +#endif + +#ifdef CONFIG_STM32H5_SPI4 + /* SPI4 clock enable */ + + regval |= RCC_APB2ENR_SPI4EN; +#endif + +#ifdef CONFIG_STM32H5_SPI6 + /* SPI6 clock enable */ + + regval |= RCC_APB2ENR_SPI6EN; +#endif + +#ifdef CONFIG_STM32H5_SAI1 + /* SAI1 clock enable */ + + regval |= RCC_APB2ENR_SAI1EN; +#endif + +#ifdef CONFIG_STM32H5_SAI2 + /* SAI2 clock enable */ + + regval |= RCC_APB2ENR_SAI2EN; +#endif + +#ifdef CONFIG_STM32H5_USB + /* USB clock enable */ + + regval |= RCC_APB2ENR_USBEN; +#endif + + putreg32(regval, STM32_RCC_APB2ENR); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableapb3 + * + * Description: + * Enable selected APB3 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableapb3(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the APB2ENR register to enabled the + * selected APB2 peripherals. + */ + + regval = getreg32(STM32_RCC_APB3ENR); + +#ifdef CONFIG_STM32H5_SBS + /* Bit 1: SBS clock enable */ + + regval |= RCC_APB3ENR_SBSEN; +#endif + +#ifdef CONFIG_STM32H5_SPI5 + /* Bit 5: SPI5 clock enable */ + + regval |= RCC_APB3ENR_SPI5EN; +#endif + +#ifdef CONFIG_STM32H5_LPUART1 + /* Bit 6: LPUART1 clock enable */ + + regval |= RCC_APB3ENR_LPUART1EN; +#endif + +#ifdef CONFIG_STM32H5_I2C3 + /* Bit 7: I2C3 clock enable */ + + regval |= RCC_APB3ENR_I2C3EN; +#endif + +#ifdef CONFIG_STM32H5_I2C4 + /* Bit 8: I2C4 clock enable */ + + regval |= RCC_APB3ENR_I2C4EN; +#endif + +#ifdef CONFIG_STM32H5_I3C2 + /* Bit 9: I3C2 clock enable */ + + regval |= RCC_APB3ENR_I3C2EN; +#endif + +#ifdef CONFIG_STM32H5_LPTIM1 + /* Bit 11: LPTIM1 clock enable */ + + regval |= RCC_APB3ENR_LPTIM1EN; +#endif + +#ifdef CONFIG_STM32H5_LPTIM3 + /* Bit 12: LPTIM3 clock enable */ + + regval |= RCC_APB3ENR_LPTIM3EN; +#endif + +#ifdef CONFIG_STM32H5_LPTIM4 + /* Bit 13: LPTIM4 clock enable */ + + regval |= RCC_APB3ENR_LPTIM4EN; +#endif + +#ifdef CONFIG_STM32H5_LPTIM5 + /* Bit 14: LPTIM5 clock enable */ + + regval |= RCC_APB3ENR_LPTIM5EN; +#endif + +#ifdef CONFIG_STM32H5_LPTIM6 + /* Bit 15: LPTIM6 clock enable */ + + regval |= RCC_APB3ENR_LPTIM6EN; +#endif + +#ifdef CONFIG_STM32H5_VREF + /* Bit 20: VREF clock enable */ + + regval |= RCC_APB3ENR_VREFEN; +#endif + +#ifdef CONFIG_STM32H5_RTCAPB + /* Bit 21: RTCABP clock enable */ + + regval |= RCC_APB3ENR_RTCAPBEN; +#endif + + /* Enable peripherals */ + + putreg32(regval, STM32_RCC_APB3ENR); +} + +/**************************************************************************** + * Name: rcc_enableccip + * + * Description: + * Set peripherals independent clock configuration. + * + ****************************************************************************/ + +static inline void rcc_enableccip(void) +{ +} + +/**************************************************************************** + * Name: rcc_set_flash_latency + * + * Description: + * Set proper flash latency based on VOS Range and SYSCLK_FREQUENCY. + * See table 44 in RM0481. + * TODO - Set prefetch enable based on board.h variable. + * + ****************************************************************************/ + +static inline void rcc_set_flash_latency(void) +{ + uint32_t vos = ((getreg32(STM32_PWR_VOSCR) & PWR_VOSCR_VOS_MASK) >> + PWR_VOSCR_VOS_SHIFT); + + uint32_t regval; + + if (vos == 0) + { + if (STM32_SYSCLK_FREQUENCY <= 20000000) + { + regval = FLASH_ACR_LATENCY(0) | FLASH_ACR_WRHIGHFREQ(0); + } + else if (STM32_SYSCLK_FREQUENCY <= 40000000) + { + regval = FLASH_ACR_LATENCY(1) | FLASH_ACR_WRHIGHFREQ(0); + } + else if (STM32_SYSCLK_FREQUENCY <= 60000000) + { + regval = FLASH_ACR_LATENCY(2) | FLASH_ACR_WRHIGHFREQ(1); + } + else if (STM32_SYSCLK_FREQUENCY <= 80000000) + { + regval = FLASH_ACR_LATENCY(3) | FLASH_ACR_WRHIGHFREQ(1); + } + else + { + regval = FLASH_ACR_LATENCY(4) | FLASH_ACR_WRHIGHFREQ(2); + } + } + else if (vos == 1) + { + if (STM32_SYSCLK_FREQUENCY <= 30000000) + { + regval = FLASH_ACR_LATENCY(0) | FLASH_ACR_WRHIGHFREQ(0); + } + else if (STM32_SYSCLK_FREQUENCY <= 60000000) + { + regval = FLASH_ACR_LATENCY(1) | FLASH_ACR_WRHIGHFREQ(0); + } + else if (STM32_SYSCLK_FREQUENCY <= 90000000) + { + regval = FLASH_ACR_LATENCY(2) | FLASH_ACR_WRHIGHFREQ(1); + } + else if (STM32_SYSCLK_FREQUENCY <= 120000000) + { + regval = FLASH_ACR_LATENCY(3) | FLASH_ACR_WRHIGHFREQ(1); + } + else + { + regval = FLASH_ACR_LATENCY(4) | FLASH_ACR_WRHIGHFREQ(2); + } + } + else if (vos == 2) + { + if (STM32_SYSCLK_FREQUENCY <= 34000000) + { + regval = FLASH_ACR_LATENCY(0) | FLASH_ACR_WRHIGHFREQ(0); + } + else if (STM32_SYSCLK_FREQUENCY <= 68000000) + { + regval = FLASH_ACR_LATENCY(1) | FLASH_ACR_WRHIGHFREQ(0); + } + else if (STM32_SYSCLK_FREQUENCY <= 102000000) + { + regval = FLASH_ACR_LATENCY(2) | FLASH_ACR_WRHIGHFREQ(1); + } + else if (STM32_SYSCLK_FREQUENCY <= 136000000) + { + regval = FLASH_ACR_LATENCY(3) | FLASH_ACR_WRHIGHFREQ(1); + } + else if (STM32_SYSCLK_FREQUENCY <= 170000000) + { + regval = FLASH_ACR_LATENCY(4) | FLASH_ACR_WRHIGHFREQ(2); + } + else + { + regval = FLASH_ACR_LATENCY(5) | FLASH_ACR_WRHIGHFREQ(2); + } + } + else /* vos == 3 */ + { + if (STM32_SYSCLK_FREQUENCY <= 42000000) + { + regval = FLASH_ACR_LATENCY(0) | FLASH_ACR_WRHIGHFREQ(0); + } + else if (STM32_SYSCLK_FREQUENCY <= 84000000) + { + regval = FLASH_ACR_LATENCY(1) | FLASH_ACR_WRHIGHFREQ(0); + } + else if (STM32_SYSCLK_FREQUENCY <= 126000000) + { + regval = FLASH_ACR_LATENCY(2) | FLASH_ACR_WRHIGHFREQ(1); + } + else if (STM32_SYSCLK_FREQUENCY <= 168000000) + { + regval = FLASH_ACR_LATENCY(3) | FLASH_ACR_WRHIGHFREQ(1); + } + else if (STM32_SYSCLK_FREQUENCY <= 210000000) + { + regval = FLASH_ACR_LATENCY(4) | FLASH_ACR_WRHIGHFREQ(2); + } + else + { + regval = FLASH_ACR_LATENCY(5) | FLASH_ACR_WRHIGHFREQ(2); + } + } + + putreg32(regval, STM32_FLASH_ACR); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_rcc_enableperipherals + ****************************************************************************/ + +void stm32_rcc_enableperipherals(void) +{ + rcc_enableccip(); + rcc_enableahb1(); + rcc_enableahb2(); + rcc_enableahb4(); + rcc_enableapb1l(); + rcc_enableapb1h(); + rcc_enableapb2(); + rcc_enableapb3(); + +#ifdef STM32H5_USE_HSI48 + /* Enable HSI48 clocking to support USB transfers or RNG */ + + stm32h5_enable_hsi48(STM32H5_HSI48_SYNCSRC); +#endif +} + +/**************************************************************************** + * Name: stm32_stdclockconfig + * + * Description: + * Called to change to new clock based on settings in board.h + * + * NOTE: This logic would need to be extended if you need to select low- + * power clocking modes! + ****************************************************************************/ + +#ifndef CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG +void stm32_stdclockconfig(void) +{ + uint32_t regval; + volatile int32_t timeout; + +#if defined(STM32_BOARD_USEHSI) + /* Enable Internal High-Speed Clock (HSI) */ + + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_HSION; /* Enable HSI */ + +#if defined(STMT32H5_CR_HSIDIV) + regval |= STM32_CR_HSIDIV; +#else + /* Use default (32 MHz) */ +#endif + + putreg32(regval, STM32_RCC_CR); + + /* Wait until the HSI is ready (or until a timeout elapsed) */ + + for (timeout = HSIRDY_TIMEOUT; timeout > 0; timeout--) + { + /* Check if the HSIRDY flag is the set in the CR */ + + if ((getreg32(STM32_RCC_CR) & RCC_CR_HSIRDY) != 0) + { + /* If so, then break-out with timeout > 0 */ + + break; + } + } + + /* Make sure HSIDIVF is also not 0 */ + + for (timeout = HSIRDY_TIMEOUT; timeout > 0; timeout--) + { + /* Check if the HSIRDY flag is the set in the CR */ + + if ((getreg32(STM32_RCC_CR) & RCC_CR_HSIDIVF) != 0) + { + /* If so, then break-out with timeout > 0 */ + + break; + } + } +#endif + +#if defined(STM32_BOARD_USEHSI) + /* Already set above */ + +#elif defined(STM32H5_BOARD_USECSI) + /* Enable Internal Low Power Internal Clock (CSI) */ + + /* Wait until the CSI is either off or ready (or until a timeout elapsed) */ + + for (timeout = CSIRDY_TIMEOUT; timeout > 0; timeout--) + { + if ((regval = getreg32(STM32_RCC_CR)), + (regval & RCC_CR_CSIRDY) || ~(regval & RCC_CR_CSION)) + { + /* If so, then break-out with timeout > 0 */ + + break; + } + } + + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_CSION; /* Enable CSI */ + putreg32(regval, STM32_RCC_CR); + + /* Wait until the CSI is ready (or until a timeout elapsed) */ + + for (timeout = CSIRDY_TIMEOUT; timeout > 0; timeout--) + { + /* Check if the CSIRDY flag is the set in the CR */ + + if ((getreg32(STM32_RCC_CR) & RCC_CR_CSIRDY) != 0) + { + /* If so, then break-out with timeout > 0 */ + + break; + } + } + +#elif defined(STM32H5_BOARD_USEHSE) + /* Enable External High-Speed Clock (HSE) */ + + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_HSEON; /* Enable HSE */ + putreg32(regval, STM32_RCC_CR); + + /* Wait until the HSE is ready (or until a timeout elapsed) */ + + for (timeout = HSERDY_TIMEOUT; timeout > 0; timeout--) + { + /* Check if the HSERDY flag is the set in the CR */ + + if ((getreg32(STM32_RCC_CR) & RCC_CR_HSERDY) != 0) + { + /* If so, then break-out with timeout > 0 */ + + break; + } + } +#else + +# error stm32h5_stdclockconfig(), must have one of STM32_BOARD_USEHSI, STM32H5_BOARD_USECSI, STM32H5_BOARD_USEHSE defined + +#endif + + /* Check for a timeout. If this timeout occurs, then we are hosed. We + * have no real back-up plan, although the following logic makes it look + * as though we do. + */ + + if (timeout > 0) + { + /* Select main regulator voltage range according to system clock + * frequency. + */ + + stm32_pwr_adjustvcore(STM32_SYSCLK_FREQUENCY); + + regval = getreg32(STM32_RCC_CFGR2); + + /* Set the HCLK source/divider */ + + regval &= ~RCC_CFGR2_HPRE_MASK; + regval |= STM32_RCC_CFGR2_HPRE; + + /* Set the PCLK1 divider */ + + regval &= ~RCC_CFGR2_PPRE1_MASK; + regval |= STM32_RCC_CFGR2_PPRE1; + + /* Set the PCLK2 divider */ + + regval &= ~RCC_CFGR2_PPRE2_MASK; + regval |= STM32_RCC_CFGR2_PPRE2; + + /* Set the PCLK3 divider */ + + regval &= ~RCC_CFGR2_PPRE3_MASK; + regval |= STM32_RCC_CFGR2_PPRE3; + + putreg32(regval, STM32_RCC_CFGR2); + +#ifdef CONFIG_STM32H5_RTC_HSECLOCK + /* Set the RTC clock divisor */ + + regval = getreg32(STM32_RCC_CFGR1); + regval &= ~RCC_CFGR1_RTCPRE_MASK; + regval |= RCC_CFGR1_RTCPRE(HSE_DIVISOR); + putreg32(regval, STM32_RCC_CFGR1); +#endif + + /* Configure PLL1 */ + + /* PLL1CFGR */ + + regval = getreg32(STM32_RCC_PLL1CFGR); + + /* Set the PLL1 source and main divider */ + + /* Use PLL1SRC defnitions to override USE_XXX */ + +#ifdef STM32H5_PLL1SRC_HSI + regval |= RCC_PLL1CFGR_PLL1SRC_HSI; +#elif defined(STM32H5_PLL1SRC_CSI) + regval |= RCC_PLL1CFGR_PLL1SRC_CSI; +#elif defined(STM32H5_PLL1SRC_HSE) + regval |= RCC_PLL1CFGR_PLL1SRC_HSE; +#elif defined(STM32_BOARD_USEHSI) + regval |= RCC_PLL1CFGR_PLL1SRC_HSI; +#elif defined(STM32H5_BOARD_USECSI) + regval |= RCC_PLL1CFGR_PLL1SRC_CSI; +#else /* if STM32H5_BOARD_USEHSE */ + regval |= RCC_PLL1CFGR_PLL1SRC_HSE; +#endif + + /* Set RGE, FRACEN, VCOSEL, and M from board.h */ + + regval |= (STM32_PLL1CFGR_PLL1RGE | STM32_PLL1CFGR_PLL1FRACEN | + STM32_PLL1CFGR_PLL1VCOSEL | STM32_PLL1CFGR_PLL1M); + +#ifdef STM32_PLL1CFGR_PLL1P_ENABLED + regval |= RCC_PLL1CFGR_PLL1PEN; +#endif +#ifdef STM32_PLL1CFGR_PLL1Q_ENABLED + regval |= RCC_PLL1CFGR_PLL1QEN; +#endif +#ifdef STM32_PLL1CFGR_PLL1R_ENABLED + regval |= RCC_PLL1CFGR_PLL1REN; +#endif + + putreg32(regval, STM32_RCC_PLL1CFGR); + + /* PLL1DIVR and PLL1FRACR */ + + /* Get settings from board.h */ + + /* PLL1DIVR */ + + regval = getreg32(STM32_RCC_PLL1DIVR); + regval = (STM32_PLL1DIVR_PLL1N | STM32_PLL1DIVR_PLL1P | + STM32_PLL1DIVR_PLL1Q | STM32_PLL1DIVR_PLL1R); + putreg32(regval, STM32_RCC_PLL1DIVR); + + /* PLL1FRACR */ + + regval = getreg32(STM32_RCC_PLL1FRACR); + regval |= STM32_PLL1FRACR_PLL1FRACN; + putreg32(regval, STM32_RCC_PLL1FRACR); + + /* Enable PLL1 */ + + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_PLL1ON; + putreg32(regval, STM32_RCC_CR); + + /* Wait until PLL1 is ready */ + + while ((getreg32(STM32_RCC_CR) & RCC_CR_PLL1RDY) == 0) + { + } + + /* Configure PLL2 */ + + /* PLL2CFGR */ + + regval = getreg32(STM32_RCC_PLL2CFGR); + + /* Set the PLL2 source and main divider */ + +#ifdef STM32H5_PLL2SRC_HSI + regval |= RCC_PLL2CFGR_PLL2SRC_HSI; +#elif defined(STM32H5_PLL2SRC_CSI) + regval |= RCC_PLL2CFGR_PLL2SRC_CSI; +#elif defined(STM32H5_PLL2SRC_HSE) + regval |= RCC_PLL2CFGR_PLL2SRC_HSE; +#elif defined(STM32_BOARD_USEHSI) + regval |= RCC_PLL2CFGR_PLL2SRC_HSI; +#elif defined(STM32H5_BOARD_USECSI) + regval |= RCC_PLL2CFGR_PLL2SRC_CSI; +#else /* if STM32H5_BOARD_USEHSE */ + regval |= RCC_PLL2CFGR_PLL2SRC_HSE; +#endif + + /* Set RGE, FRACEN, VCOSEL, and M from board.h */ + + regval |= (STM32_PLL2CFGR_PLL2RGE | STM32_PLL2CFGR_PLL2FRACEN | + STM32_PLL2CFGR_PLL2VCOSEL | STM32_PLL2CFGR_PLL2M); + +#ifdef STM32_PLL2CFGR_PLL2P_ENABLED + regval |= RCC_PLL2CFGR_PLL2PEN; +#endif +#ifdef STM32_PLL2CFGR_PLL2Q_ENABLED + regval |= RCC_PLL2CFGR_PLL2QEN; +#endif +#ifdef STM32_PLL2CFGR_PLL2R_ENABLED + regval |= RCC_PLL2CFGR_PLL2REN; +#endif + + putreg32(regval, STM32_RCC_PLL2CFGR); + + /* PLL2DIVR and PLL2FRACR */ + + /* Get settings from board.h */ + + /* PLL2DIVR */ + + regval = getreg32(STM32_RCC_PLL2DIVR); + regval = (STM32_PLL2DIVR_PLL2N | STM32_PLL2DIVR_PLL2P | + STM32_PLL2DIVR_PLL2Q | STM32_PLL2DIVR_PLL2R); + putreg32(regval, STM32_RCC_PLL2DIVR); + + /* PLL2FRACR */ + + regval = getreg32(STM32_RCC_PLL2FRACR); + regval |= STM32_PLL2FRACR_PLL2FRACN; + putreg32(regval, STM32_RCC_PLL2FRACR); + + /* Enable PLL2 */ + + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_PLL2ON; + putreg32(regval, STM32_RCC_CR); + + /* Wait until PLL2 is ready */ + + while ((getreg32(STM32_RCC_CR) & RCC_CR_PLL2RDY) == 0) + { + } + + /* Configure PLL3 */ + + /* PLL3CFGR */ + + regval = getreg32(STM32_RCC_PLL3CFGR); + + /* Set the PLL3 source and main divider */ + +#ifdef STM32H5_PLL3SRC_HSI + regval |= RCC_PLL3CFGR_PLL3SRC_HSI; +#elif defined(STM32H5_PLL3SRC_CSI) + regval |= RCC_PLL3CFGR_PLL3SRC_CSI; +#elif defined(STM32H5_PLL3SRC_HSE) + regval |= RCC_PLL3CFGR_PLL3SRC_HSE; +#elif defined(STM32_BOARD_USEHSI) + regval |= RCC_PLL3CFGR_PLL3SRC_HSI; +#elif defined(STM32H5_BOARD_USECSI) + regval |= RCC_PLL3CFGR_PLL3SRC_CSI; +#else /* if STM32H5_BOARD_USEHSE */ + regval |= RCC_PLL3CFGR_PLL3SRC_HSE; +#endif + + /* Set RGE, FRACEN, VCOSEL, and M from board.h */ + + regval |= (STM32_PLL3CFGR_PLL3RGE | STM32_PLL3CFGR_PLL3FRACEN | + STM32_PLL3CFGR_PLL3VCOSEL | STM32_PLL3CFGR_PLL3M); + +#ifdef STM32_PLL3CFGR_PLL3P_ENABLED + regval |= RCC_PLL3CFGR_PLL3PEN; +#endif +#ifdef STM32_PLL3CFGR_PLL3Q_ENABLED + regval |= RCC_PLL3CFGR_PLL3QEN; +#endif +#ifdef STM32_PLL3CFGR_PLL3R_ENABLED + regval |= RCC_PLL3CFGR_PLL3REN; +#endif + + putreg32(regval, STM32_RCC_PLL3CFGR); + + /* PLL3DIVR and PLL3FRACR */ + + /* Get settings from board.h */ + + /* PLL3DIVR */ + + regval = getreg32(STM32_RCC_PLL3DIVR); + regval = (STM32_PLL3DIVR_PLL3N | STM32_PLL3DIVR_PLL3P | + STM32_PLL3DIVR_PLL3Q | STM32_PLL3DIVR_PLL3R); + putreg32(regval, STM32_RCC_PLL3DIVR); + + /* PLL3FRACR */ + + regval = getreg32(STM32_RCC_PLL3FRACR); + regval |= STM32_PLL3FRACR_PLL3FRACN; + putreg32(regval, STM32_RCC_PLL3FRACR); + + /* Enable PLL3 */ + + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_PLL3ON; + putreg32(regval, STM32_RCC_CR); + + /* Wait until PLL3 is ready */ + + while ((getreg32(STM32_RCC_CR) & RCC_CR_PLL3RDY) == 0) + { + } + + /* Determine wait states based on sysclk frequency and VOS + * Determine WRHIGHFREQ based on wait states + */ + + rcc_set_flash_latency(); + + /* Select the main PLL as system clock source */ + + regval = getreg32(STM32_RCC_CFGR1); + regval &= ~RCC_CFGR1_SW_MASK; + regval |= RCC_CFGR1_SW_PLL; + putreg32(regval, STM32_RCC_CFGR1); + + /* Wait until the PLL source is used as the system clock source */ + + while ((getreg32(STM32_RCC_CFGR1) & RCC_CFGR1_SWS_MASK) != + RCC_CFGR1_SWS_PLL) + { + } + +#if defined(CONFIG_STM32H5_IWDG) || defined(CONFIG_STM32H5_RTC_LSICLOCK) || \ + defined(STM32H5_USE_LSCO_LSI) + + /* Low speed internal clock source LSI */ + + stm32_rcc_enablelsi(); +#endif + +#if defined(STM32_USE_LSE) || defined(STM32H5_USE_LSCO_LSE) + /* Low speed external clock source LSE */ + + stm32_rcc_enablelse(); +#else + /* There is another case where the LSE needs to + * be enabled: if the MCO1 pin selects LSE as source. + * Other cases can be handled by peripheral drivers. + */ + + if ((getreg32(STM32_RCC_CFGR1) & RCC_CFGR1_MCO1SEL_MASK) == + RCC_CFGR1_MCO1SEL_LSE) + { + stm32_rcc_enablelse(); + } + +#endif /* STM32_USE_LSE */ + } +} +#endif diff --git a/boards/Kconfig b/boards/Kconfig index d4a2468bc07..df01b01dad3 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -2795,6 +2795,14 @@ config ARCH_BOARD_STM32L476_MDK The STM32L476ME is a Cortex-M4 optimised for low-power operation at up to 80MHz operation with 1024Kb Flash memory and 96+32Kb SRAM. +config ARCH_BOARD_NUCLEO_H563ZI + bool "NUCLEO_H563ZI" + depends on ARCH_CHIP_STM32H563ZI + select ARCH_HAVE_LEDS + select ARCH_HAVE_BUTTONS + select ARCH_HAVE_IRQBUTTONS + ---help--- + STMicro Nucleo-H563ZI board based on the STMicro STM32H563ZI MCU. config ARCH_BOARD_STM32L562E_DK bool "STM32L562E-DK" @@ -4092,6 +4100,9 @@ endif if ARCH_BOARD_STM32L4R9AI_DISCO source "boards/arm/stm32l4/stm32l4r9ai-disco/Kconfig" endif +if ARCH_BOARD_NUCLEO_H563ZI +source "boards/arm/stm32h5/nucleo-h563zi/Kconfig" +endif if ARCH_BOARD_STM32L562E_DK source "boards/arm/stm32l5/stm32l562e-dk/Kconfig" endif diff --git a/boards/arm/stm32h5/nucleo-h563zi/Kconfig b/boards/arm/stm32h5/nucleo-h563zi/Kconfig new file mode 100644 index 00000000000..e9b20410df9 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/Kconfig @@ -0,0 +1,8 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_BOARD_NUCLEO_H563ZI + +endif diff --git a/boards/arm/stm32h5/nucleo-h563zi/configs/nsh/defconfig b/boards/arm/stm32h5/nucleo-h563zi/configs/nsh/defconfig new file mode 100644 index 00000000000..98332df9c12 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/configs/nsh/defconfig @@ -0,0 +1,49 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_ARGCAT is not set +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-h563zi" +CONFIG_ARCH_BOARD_NUCLEO_H563ZI=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32h5" +CONFIG_ARCH_CHIP_STM32H563ZI=y +CONFIG_ARCH_CHIP_STM32H5=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV8M_STACKCHECK=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=655360 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_STACK_COLORATION=y +CONFIG_STM32H5_USART3=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART3_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32h5/nucleo-h563zi/include/board.h b/boards/arm/stm32h5/nucleo-h563zi/include/board.h new file mode 100644 index 00000000000..ca03ec79660 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/include/board.h @@ -0,0 +1,339 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/include/board.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_INCLUDE_BOARD_H +#define __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_INCLUDE_BOARD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#ifndef __ASSEMBLY__ +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Clocking *****************************************************************/ + +/* The NUCLEO-H563ZI-Q supports both HSE and LSE crystals (X2 and X3). + * However, as shipped, the X3 crystal is not populated. Therefore the + * Nucleo-H563ZI-Q will need to run off the 16MHz HSI clock, or the + * 32kHz-synced CSI. This configuration uses the CSI. + * + * System Clock source : PLL (CSI) + * SYSCLK(Hz) : 250000000 Determined by PLL1 configuration + * HCLK(Hz) : 250000000 (STM32_RCC_CFGR_HPRE) (Max 250MHz) + * AHB Prescaler : 1 (STM32_RCC_CFGR_HPRE) (Max 250MHz) + * APB1 Prescaler : 1 (STM32_RCC_CFGR_PPRE1) (Max 250MHz) + * APB2 Prescaler : 1 (STM32_RCC_CFGR_PPRE2) (Max 250MHz) + * CSI Frequency(Hz) : 4000000 (nominal) + * PLL1M : 2 (STM32_PLL1CFGR_PLLM) + * PLL1N : 125 (STM32_PLL1CFGR_PLLN) + * PLL1P : 0 (STM32_PLL1CFGR_PLLP) + * PLL1Q : 0 (STM32_PLL1CFGR_PLLQ) + * PLL1R : 1 (STM32_PLL1CFGR_PLLR) + * PLL2M : 2 (STM32_PLL2CFGR_PLLM) + * PLL2N : 125 (STM32_PLL2CFGR_PLLN) + * PLL2P : 0 (STM32_PLL2CFGR_PLLP) + * PLL2Q : 0 (STM32_PLL2CFGR_PLLQ) + * PLL2R : 1 (STM32_PLL2CFGR_PLLR) + * PLL3M : 2 (STM32_PLL3CFGR_PLLM) + * PLL3N : 125 (STM32_PLL3CFGR_PLLN) + * PLL3P : 0 (STM32_PLL3CFGR_PLLP) + * PLL3Q : 0 (STM32_PLL3CFGR_PLLQ) + * PLL3R : 1 (STM32_PLL3CFGR_PLLR) + * Flash Latency(WS) : 5 + */ + +/* HSI - 32 MHz RC factory-trimmed + * LSI - 32 KHz RC + * CSI - 4 MHz, autotrimmed via LSE + * HSE - not installed + * LSE - 32.768 kHz installed + * SYSCLK = 250 MHz + */ + +#define STM32_SYSCLK_FREQUENCY 250000000ul +#define STM32_HSI_FREQUENCY 32000000ul +#define STM32_LSI_FREQUENCY 32000 +#define STM32_LSE_FREQUENCY 32768 + +#define STM32_BOARD_USEHSI 1 +#define STM32_CR_HSIDIV RCC_CR_HSIDIV(1) + +/* prescaler common to all PLL inputs */ + +/* 'main' PLL1 config; we use this to generate our system clock */ + +/* Use 32 MHz HSI, set M to 2, N to 15, FRAC to 0x1400 (5120) + * SYSCLK = (32000000 / 2) * (15 + (5120/8192)) = 250000000 + */ + +#define STM32_PLL1CFGR_PLL1FRACEN RCC_PLL1CFGR_PLL1FRACEN +#define STM32_PLL1CFGR_PLL1VCOSEL 0 +#define STM32_PLL1CFGR_PLL1RGE RCC_PLL1CFGR_PLL1RGE_8_16M + +#define STM32_PLL1CFGR_PLL1M RCC_PLL1CFGR_PLL1M(2) +#define STM32_PLL1DIVR_PLL1N RCC_PLL1DIVR_PLL1N(15) + +#define STM32_PLL1DIVR_PLL1P RCC_PLL1DIVR_PLL1P(1) +#define STM32_PLL1CFGR_PLL1P_ENABLED 1 +#define STM32_PLL1DIVR_PLL1Q 0 +#undef STM32_PLL1CFGR_PLL1Q_ENABLED +#define STM32_PLL1DIVR_PLL1R 0 +#undef STM32_PLL1CFGR_PLL1R_ENABLED + +#define STM32_PLL1FRACR_PLL1FRACN 5120ul + +/* PLL2 config */ + +#define STM32_PLL2CFGR_PLL2M RCC_PLL2CFGR_PLL2M(4) +#define STM32_PLL2CFGR_PLL2FRACEN RCC_PLL2CFGR_PLL2FRACEN +#define STM32_PLL2CFGR_PLL2VCOSEL RCC_PLL2CFGR_PLL2VCOSEL +#define STM32_PLL2CFGR_PLL2RGE RCC_PLL2CFGR_PLL2RGE_8_16M + +#define STM32_PLL2DIVR_PLL2N RCC_PLL2DIVR_PLL2N(15) + +#define STM32_PLL2DIVR_PLL2P RCC_PLL2DIVR_PLL2P(1) +#define STM32_PLL2CFGR_PLL2P_ENABLED +#define STM32_PLL2DIVR_PLL2Q 0 +#undef STM32_PLL2CFGR_PLL2Q_ENABLED +#define STM32_PLL2DIVR_PLL2R 0 +#undef STM32_PLL2CFGR_PLL2R_ENABLED + +#define STM32_PLL2FRACR_PLL2FRACN 5120ul + +/* PLL3 config */ + +#define STM32_PLL3CFGR_PLL3M RCC_PLL3CFGR_PLL3M(4) +#define STM32_PLL3CFGR_PLL3FRACEN RCC_PLL3CFGR_PLL3FRACEN +#define STM32_PLL3CFGR_PLL3VCOSEL RCC_PLL3CFGR_PLL3VCOSEL +#define STM32_PLL3CFGR_PLL3RGE RCC_PLL3CFGR_PLL3RGE_8_16M + +#define STM32_PLL3DIVR_PLL3N RCC_PLL3DIVR_PLL3N(15) + +#define STM32_PLL3DIVR_PLL3P RCC_PLL3DIVR_PLL3P(1) +#define STM32_PLL3CFGR_PLL3P_ENABLED +#define STM32_PLL3DIVR_PLL3Q 0 +#undef STM32_PLL3CFGR_PLL3Q_ENABLED +#define STM32_PLL3DIVR_PLL3R 0 +#undef STM32_PLL3CFGR_PLL3R_ENABLED + +#define STM32_PLL3FRACR_PLL3FRACN 5120ul + +/* Enable CLK48; get it from HSI48 */ + +#if defined(CONFIG_STM32H5_USBFS) || defined(CONFIG_STM32H5_RNG) +# define STM32H5_USE_CLK48 1 +# define STM32H5_CLKUSB_SEL RCC_CCIPR4_USBSEL_HSI48KERCK +# define STM32H5_HSI48_SYNCSRC SYNCSRC_NONE +#endif + +/* Enable LSE (for the RTC) */ + +#define STM32_USE_LSE 1 + +/* Configure the HCLK divisor (for the AHB bus, core, memory, and DMA */ + +#define STM32_RCC_CFGR2_HPRE RCC_CFGR2_HPRE_SYSCLK /* HCLK = SYSCLK / 1 */ +#define STM32_HCLK_FREQUENCY STM32_SYSCLK_FREQUENCY + +/* Configure the APB1 prescaler */ + +#define STM32_RCC_CFGR2_PPRE1 RCC_CFGR2_PPRE1_HCLK1 /* PCLK1 = HCLK / 1 */ +#define STM32_PCLK1_FREQUENCY (STM32_HCLK_FREQUENCY / 1) + +#define STM32_APB1_TIM2_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM3_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM4_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM5_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM6_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM7_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM12_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM13_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM14_CLKIN (STM32_PCLK1_FREQUENCY) +#define STM32_APB1_LPTIM2_CLKIN (STM32_PCLK1_FREQUENCY) + +/* Configure the APB2 prescaler */ + +#define STM32_RCC_CFGR2_PPRE2 RCC_CFGR2_PPRE2_HCLK1 /* PCLK2 = HCLK / 1 */ +#define STM32_PCLK2_FREQUENCY (STM32_HCLK_FREQUENCY / 1) + +#define STM32_APB2_TIM1_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM8_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM15_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM16_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM17_CLKIN (STM32_PCLK2_FREQUENCY) + +/* Configure the APB3 prescaler */ + +#define STM32_RCC_CFGR2_PPRE3 RCC_CFGR2_PPRE3_HCLK1 /* PCLK2 = HCLK / 1 */ +#define STM32_PCLK3_FREQUENCY (STM32_HCLK_FREQUENCY / 1) + +#define STM32_APB3_LPTIM1_CLKIN (STM32_PCLK3_FREQUENCY) +#define STM32_APB3_LPTIM3_CLKIN (STM32_PCLK3_FREQUENCY) +#define STM32_APB3_LPTIM4_CLKIN (STM32_PCLK3_FREQUENCY) +#define STM32_APB3_LPTIM5_CLKIN (STM32_PCLK3_FREQUENCY) +#define STM32_APB3_LPTIM6_CLKIN (STM32_PCLK3_FREQUENCY) +/* The timer clock frequencies are automatically defined by hardware. If the + * APB prescaler equals 1, the timer clock frequencies are set to the same + * frequency as that of the APB domain. Otherwise they are set to twice. + */ + +#define BOARD_TIM1_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM2_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM3_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM4_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM5_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM6_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM7_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM8_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM12_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM13_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM14_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM15_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_TIM16_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_LPTIM1_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_LPTIM2_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_LPTIM3_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_LPTIM4_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_LPTIM5_FREQUENCY STM32_HCLK_FREQUENCY +#define BOARD_LPTIM6_FREQUENCY STM32_HCLK_FREQUENCY + +/* Configure the Kernel clocks */ + +/* DMA Channel/Stream Selections ********************************************/ + +/* Alternate function pin selections ****************************************/ + +/* USART3: Connected to Arduino connector D0/D1 (or to STLink VCP if solder + * bridges SB123 to SB130 are re-worked accordingly). + */ + +#define GPIO_USART3_RX GPIO_USART3_RX_4 /* PD9 */ +#define GPIO_USART3_TX GPIO_USART3_TX_4 /* PD8 */ + +/* LED definitions **********************************************************/ + +/* The Nucleo board has numerous LEDs but only three, LD1 a Green LED, + * LD2 a Yellow LED, and LD3 a Red LED, that can be controlled by software. + * The following definitions assume the default Solder Bridges are installed. + * + * If CONFIG_ARCH_LEDS is not defined, then the user can control the LEDs + * in any way. + * The following definitions are used to access individual LEDs. + */ + +/* LED index values for use with board_userled() */ + +#define BOARD_LED1 0 +#define BOARD_LED2 1 +#define BOARD_LED3 2 +#define BOARD_NLEDS 3 + +#define BOARD_LED_GREEN BOARD_LED1 +#define BOARD_LED_YELLOW BOARD_LED2 +#define BOARD_LED_RED BOARD_LED3 + +/* LED bits for use with board_userled_all() */ + +#define BOARD_LED1_BIT (1 << BOARD_LED1) +#define BOARD_LED2_BIT (1 << BOARD_LED2) +#define BOARD_LED3_BIT (1 << BOARD_LED3) + +/* If CONFIG_ARCH_LEDS is defined, the usage by the board port is defined in + * include/board.h and src/stm32_autoleds.c. The LEDs are used to encode OS- + * related events as follows: + * + * + * SYMBOL Meaning LED state + * Red Green Blue + * ---------------------- -------------------------- ------ ------ ---- + */ +#define LED_STARTED 0 /* NuttX has been started OFF OFF OFF */ +#define LED_HEAPALLOCATE 1 /* Heap has been allocated OFF OFF ON */ +#define LED_IRQSENABLED 2 /* Interrupts enabled OFF ON OFF */ +#define LED_STACKCREATED 3 /* Idle stack created OFF ON ON */ +#define LED_INIRQ 4 /* In an interrupt N/C N/C GLOW */ +#define LED_SIGNAL 5 /* In a signal handler N/C GLOW N/C */ +#define LED_ASSERTION 6 /* An assertion failed GLOW N/C GLOW */ +#define LED_PANIC 7 /* The system has crashed Blink OFF N/C */ +#define LED_IDLE 8 /* MCU is is sleep mode ON OFF OFF */ + +/* Thus if the Green LED is statically on, NuttX has successfully booted and + * is, apparently, running normally. If the Red LED is flashing at + * approximately 2Hz, then a fatal error has been detected and the system + * has halted. + */ + +/* Button definitions *******************************************************/ + +/* The Nucleo-H563ZI supports one button: Pushbutton B1, labeled "User", is + * connected to GPIO PC13. + * A high value will be sensed when the button is pressed. + */ + +#define BUTTON_USER 0 +#define NUM_BUTTONS 1 +#define BUTTON_USER_BIT (1 << BUTTON_USER) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_board_initialize + * + * Description: + * All STM32H5 architectures must provide the following entry point. + * This entry point is called early in the initialization -- after all + * memory has been configured and mapped but before any devices + * have been initialized. + * + ****************************************************************************/ + +void stm32_board_initialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_INCLUDE_BOARD_H */ diff --git a/boards/arm/stm32h5/nucleo-h563zi/scripts/Make.defs b/boards/arm/stm32h5/nucleo-h563zi/scripts/Make.defs new file mode 100644 index 00000000000..e4bb4ef55fc --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/scripts/Make.defs @@ -0,0 +1,38 @@ +############################################################################## +# boards/arm/stm32h5/nucleo-h563zi/scripts/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################## + +include ${TOPDIR}/.config +include ${TOPDIR}/tools/Config.mk +include ${TOPDIR}/arch/arm/src/armv8-m/Toolchain.defs + +ARCHSCRIPT = $(BOARD_DIR)$(DELIM)scripts$(DELIM)flash.ld + +ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10 + +CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) +CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) +CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ + +NXFLATLDFLAGS1 = -r -d -warn-common +NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)$(DELIM)binfmt$(DELIM)libnxflat$(DELIM)gnu-nxflat-pcrel.ld -no-check-sections +LDNXFLATFLAGS = -e main -s 2048 diff --git a/boards/arm/stm32h5/nucleo-h563zi/scripts/flash.ld b/boards/arm/stm32h5/nucleo-h563zi/scripts/flash.ld new file mode 100644 index 00000000000..f5e49a0de3a --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/scripts/flash.ld @@ -0,0 +1,104 @@ +/**************************************************************************** + * boards/arm/stm32u5/nucleo-u5a5zj-q/scripts/flash.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* The STM32H562/563/573 has 1 MiB of FLASH beginning at address 0x0800:0000 and + * 256 KiB of SRAM beginning at address 0x2000:0000. When booting from + * FLASH, FLASH memory is aliased to address 0x0000:0000 where the code + * expects to begin execution by jumping to the entry point in the + * 0x0800:0000 address range. + */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + sram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K +} + +OUTPUT_ARCH(arm) +ENTRY(_stext) +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/stm32h5/nucleo-h563zi/scripts/tfm-ns.ld b/boards/arm/stm32h5/nucleo-h563zi/scripts/tfm-ns.ld new file mode 100644 index 00000000000..ae910e64805 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/scripts/tfm-ns.ld @@ -0,0 +1,115 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/scripts/tfm-ns.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This linker script supports running NuttX in the 'Non-Secure' (ns) domain + * in conjunction with TrustedFirmware-M (tfm). + * + * NuttX will run as the 'Non secure application' in the 'Non-Secure Image + * primary primary slot Area 1' in external flash. Compare [UM2671], + * Figure 8. Furthermore, see Figure 15 for the SRAM area used for 'Non- + * Secure application volatile data' + * + * While the 'Non-Secure Image primary slot Area 1' is actually one MiB large + * in the referenced setup, the image will be enriched with a header of 0x400 + * bytes and a trailer of 0x2000 bytes. Thus the 'flash' statement in the + * MEMORY definition below. + * + * References + * [UM2671] STMicroelectronics. UM2671: Getting started with STM32CubeL5 TFM + * application, 2nd edition, July 2020 + */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x90000400, LENGTH = 0xFDC00 + sram (rwx) : ORIGIN = 0x20000000, LENGTH = 192K +} + +OUTPUT_ARCH(arm) +ENTRY(_stext) +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/.gitignore b/boards/arm/stm32h5/nucleo-h563zi/src/.gitignore new file mode 100644 index 00000000000..726d936e1e3 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/.gitignore @@ -0,0 +1,2 @@ +/.depend +/Make.dep diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/Makefile b/boards/arm/stm32h5/nucleo-h563zi/src/Makefile new file mode 100644 index 00000000000..27f58d4ceed --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/Makefile @@ -0,0 +1,40 @@ +############################################################################## +# boards/arm/stm32h5/nucleo-h563zi/src/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################## + +-include $(TOPDIR)/Make.defs + +ASRCS = +CSRCS = stm32_boot.c stm32_bringup.c stm32_clockconfig.c + +ifeq ($(CONFIG_ARCH_LEDS),y) +CSRCS += stm32_autoleds.c +else +CSRCS += stm32_userleds.c +endif + +ifeq ($(CONFIG_ARCH_BUTTONS),y) +CSRCS += stm32_buttons.c +endif + +ifeq ($(CONFIG_BOARDCTL),y) +CSRCS += stm32_appinit.c +endif + +include $(TOPDIR)/boards/Board.mk diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h b/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h new file mode 100644 index 00000000000..d83420d19a4 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h @@ -0,0 +1,120 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_SRC_NUCLEO_H563ZI_H +#define __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_SRC_NUCLEO_H563ZI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "stm32_gpio.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#define HAVE_PROC 1 +#define HAVE_RTC_DRIVER 1 + +#if !defined(CONFIG_FS_PROCFS) +# undef HAVE_PROC +#endif + +#if defined(HAVE_PROC) && defined(CONFIG_DISABLE_MOUNTPOINT) +# warning Mountpoints disabled. No procfs support +# undef HAVE_PROC +#endif + +/* Check if we can support the RTC driver */ + +#if !defined(CONFIG_RTC) || !defined(CONFIG_RTC_DRIVER) +# undef HAVE_RTC_DRIVER +#endif + +/* NUCLEO-H563ZI GPIOs ******************************************************/ + +/* LED I/O Color + * LD1 PB0 Green + * LD2 PF4 Yellow + * LD3 PG4 Red + * + * - When the I/O is LOW, the LED is on. + * - When the I/O is HIGH value, the LED is off + */ + +#define GPIO_LD1 (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_2MHZ | \ + GPIO_OUTPUT_SET | GPIO_PORTB | GPIO_PIN0) +#define GPIO_LD2 (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_2MHZ | \ + GPIO_OUTPUT_SET | GPIO_PORTF | GPIO_PIN4) +#define GPIO_LD3 (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_2MHZ | \ + GPIO_OUTPUT_SET | GPIO_PORTG | GPIO_PIN4) + +/* Button definitions *******************************************************/ + +/* B1 USER: the user button is connected to the I/O PC13 (pin 2) of the STM32 + * microcontroller. + */ + +#define MIN_IRQBUTTON BUTTON_USER +#define MAX_IRQBUTTON BUTTON_USER +#define NUM_IRQBUTTONS 1 + +#define GPIO_BTN_USER (GPIO_INPUT | GPIO_FLOAT | GPIO_EXTI | \ + GPIO_PORTC | GPIO_PIN13) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_bringup + * + * Description: + * Perform architecture-specific initialization + * + * CONFIG_BOARD_LATE_INITIALIZE=y : + * Called from board_late_initialize(). + * + * CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y : + * Called from the NSH library + * + ****************************************************************************/ + +int stm32_bringup(void); + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_SRC_NUCLEO_H563ZI_H */ diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_appinit.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_appinit.c new file mode 100644 index 00000000000..af1977d1252 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_appinit.c @@ -0,0 +1,71 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/stm32_appinit.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "nucleo-h563zi.h" + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; the meaning of the argument is a contract + * between the board-specific initialization logic and the + * matching application logic. The value cold be such things as a + * mode enumeration value, a set of DIP switch switch settings, a + * pointer to configuration data read from a file or serial FLASH, + * or whatever you would like to do with it. Every implementation + * should accept zero/NULL as a default configuration. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ + +int board_app_initialize(uintptr_t arg) +{ + /* Did we already initialize via board_late_initialize()? */ + +#ifndef CONFIG_BOARD_LATE_INITIALIZE + return stm32_bringup(); +#else + return OK; +#endif +} diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_autoleds.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_autoleds.c new file mode 100644 index 00000000000..111cebe98ae --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_autoleds.c @@ -0,0 +1,186 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/stm32_autoleds.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include + +#include "chip.h" +#include "arm_internal.h" +#include "stm32_gpio.h" +#include "nucleo-h563zi.h" + +#include + +#ifdef CONFIG_ARCH_LEDS + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Indexed by BOARD_LED_ */ + +static const uint32_t g_ledmap[BOARD_NLEDS] = +{ + GPIO_LD1, + GPIO_LD2, + GPIO_LD3, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void phy_set_led(int led, bool state) +{ + /* Active High */ + + stm32_gpiowrite(g_ledmap[led], state); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_autoled_initialize + ****************************************************************************/ + +void board_autoled_initialize(void) +{ + int i; + + /* Configure the LD1, LD2, and LD3 GPIOs for output. Initial state is OFF */ + + for (i = 0; i < nitems(g_ledmap); i++) + { + stm32_configgpio(g_ledmap[i]); + stm32_gpiowrite(g_ledmap[i], false); + } +} + +/**************************************************************************** + * Name: board_autoled_on + ****************************************************************************/ + +void board_autoled_on(int led) +{ + switch (led) + { + case LED_HEAPALLOCATE: + phy_set_led(BOARD_LED_GREEN, false); + phy_set_led(BOARD_LED_YELLOW, false); + phy_set_led(BOARD_LED_RED, false); + break; + + case LED_IDLE: + phy_set_led(BOARD_LED_GREEN, true); + phy_set_led(BOARD_LED_YELLOW, false); + phy_set_led(BOARD_LED_RED, false); + break; + + case LED_IRQSENABLED: + phy_set_led(BOARD_LED_GREEN, false); + phy_set_led(BOARD_LED_YELLOW, true); + phy_set_led(BOARD_LED_RED, false); + break; + + case LED_STACKCREATED: + phy_set_led(BOARD_LED_GREEN, true); + phy_set_led(BOARD_LED_YELLOW, true); + phy_set_led(BOARD_LED_RED, false); + break; + + case LED_INIRQ: + phy_set_led(BOARD_LED_GREEN, false); + phy_set_led(BOARD_LED_YELLOW, false); + phy_set_led(BOARD_LED_RED, true); + break; + + case LED_SIGNAL: + phy_set_led(BOARD_LED_GREEN, true); + phy_set_led(BOARD_LED_YELLOW, false); + phy_set_led(BOARD_LED_RED, true); + break; + + case LED_ASSERTION: + phy_set_led(BOARD_LED_GREEN, false); + phy_set_led(BOARD_LED_YELLOW, true); + phy_set_led(BOARD_LED_RED, true); + break; + + case LED_PANIC: + phy_set_led(BOARD_LED_GREEN, true); + phy_set_led(BOARD_LED_YELLOW, true); + phy_set_led(BOARD_LED_RED, true); + break; + + default: + break; + } +} + +/**************************************************************************** + * Name: board_autoled_off + ****************************************************************************/ + +void board_autoled_off(int led) +{ + switch (led) + { + case LED_SIGNAL: + phy_set_led(BOARD_LED_RED, false); + phy_set_led(BOARD_LED_GREEN, false); + break; + + case LED_INIRQ: + phy_set_led(BOARD_LED_RED, false); + break; + + case LED_ASSERTION: + phy_set_led(BOARD_LED_YELLOW, false); + break; + + case LED_PANIC: + phy_set_led(BOARD_LED_GREEN, false); + phy_set_led(BOARD_LED_RED, false); + phy_set_led(BOARD_LED_YELLOW, false); + break; + + case LED_IDLE: + phy_set_led(BOARD_LED_GREEN, false); + break; + + default: + break; + } +} + +#endif /* CONFIG_ARCH_LEDS */ diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_boot.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_boot.c new file mode 100644 index 00000000000..0421083e61b --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_boot.c @@ -0,0 +1,82 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/stm32_boot.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +#include "arm_internal.h" +#include "nucleo-h563zi.h" +#include "stm32_pwr.h" + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_board_initialize + * + * Description: + * All STM32 architectures must provide the following entry point. This + * entry point is called early in the initialization -- after all memory + * has been configured and mapped but before any devices have been + * initialized. + * + ****************************************************************************/ + +void stm32_board_initialize(void) +{ +#ifdef CONFIG_ARCH_LEDS + /* Configure on-board LEDs if LED support has been selected. */ + + board_autoled_initialize(); +#endif +} + +/**************************************************************************** + * Name: board_late_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_late_initialize(). board_late_initialize() will + * be called immediately after up_initialize() is called and just before + * the initial application is started. This additional initialization + * phase may be used, for example, to initialize board-specific device + * drivers. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARD_LATE_INITIALIZE +void board_late_initialize(void) +{ + /* Perform board-specific initialization here if so configured */ + + stm32_bringup(); +} +#endif diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c new file mode 100644 index 00000000000..37fbc400cb1 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c @@ -0,0 +1,105 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "nucleo-h563zi.h" + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_bringup + * + * Description: + * Perform architecture-specific initialization + * + * CONFIG_BOARD_LATE_INITIALIZE=y : + * Called from board_late_initialize(). + * + * CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y : + * Called from the NSH library + * + ****************************************************************************/ + +int stm32_bringup(void) +{ + int ret; + +#ifdef CONFIG_FS_PROCFS + /* Mount the procfs file system */ + + ret = mount(NULL, "/proc", "procfs", 0, NULL); + if (ret < 0) + { + ferr("ERROR: Failed to mount procfs at /proc: %d\n", ret); + } +#endif + +#if !defined(CONFIG_ARCH_LEDS) && defined(CONFIG_USERLED_LOWER) + /* Register the LED driver */ + + ret = userled_lower_initialize("/dev/userleds"); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: userled_lower_initialize() failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_INPUT_BUTTONS +#ifdef CONFIG_INPUT_BUTTONS_LOWER + iinfo("Initializing button driver\n"); + + /* Register the BUTTON driver */ + + ret = btn_lower_initialize("/dev/buttons"); + if (ret < 0) + { + ierr("ERROR: btn_lower_initialize() failed: %d\n", ret); + } +#else + /* Enable BUTTON support for some other purpose */ + + board_button_initialize(); +#endif +#endif /* CONFIG_INPUT_BUTTONS */ + + UNUSED(ret); + return OK; +} diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_buttons.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_buttons.c new file mode 100644 index 00000000000..776b8eb8aca --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_buttons.c @@ -0,0 +1,77 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/stm32_buttons.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "stm32_gpio.h" +#include "nucleo-h563zi.h" + +#include + +#ifdef CONFIG_ARCH_BUTTONS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_button_initialize + * + * Description: + * board_button_initialize() must be called to initialize button resources. + * After that, board_buttons() may be called to collect the current state + * of all buttons or board_button_irq() may be called to register button + * interrupt handlers. + * + ****************************************************************************/ + +uint32_t board_button_initialize(void) +{ + /* Configure the single button as an input. NOTE that EXTI interrupts are + * also configured for the pin. + */ + + stm32_configgpio(GPIO_BTN_USER); + return NUM_BUTTONS; +} + +/**************************************************************************** + * Name: board_buttons + ****************************************************************************/ + +uint32_t board_buttons(void) +{ + /* Check the state of the USER button. */ + + return stm32_gpioread(GPIO_BTN_USER) ? BUTTON_USER_BIT : 0; +} + +#endif /* CONFIG_ARCH_BUTTONS */ diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_clockconfig.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_clockconfig.c new file mode 100644 index 00000000000..d5eea201d12 --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_clockconfig.c @@ -0,0 +1,48 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/stm32_clockconfig.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_board_clockconfig + * + * Description: + * Currently the NUCLEO-H563ZI board support is restricted to running NuttX + * in the Non-Secure domain together with TrustedFirmware-M (TFM). In this + * setup the clock configuration is done by TFM, not by NuttX. Thus, the + * board's configuration sets CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG + * to avoid the standard clock config logic to run and instead do just + * nothing in this function. + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG) +void stm32_board_clockconfig(void) +{ +} +#endif diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_userleds.c b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_userleds.c new file mode 100644 index 00000000000..4cb87018dfa --- /dev/null +++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_userleds.c @@ -0,0 +1,124 @@ +/**************************************************************************** + * boards/arm/stm32h5/nucleo-h563zi/src/stm32_userleds.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include +#include + +#include "stm32_gpio.h" +#include "nucleo-h563zi.h" + +#ifndef CONFIG_ARCH_LEDS + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This array maps an LED number to GPIO pin configuration and is indexed by + * BOARD_LED_ + */ + +static const uint32_t g_ledcfg[BOARD_NLEDS] = +{ + GPIO_LD1, + GPIO_LD2, + GPIO_LD3, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_userled_initialize + * + * Description: + * If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board + * LEDs. If CONFIG_ARCH_LEDS is not defined, then the + * board_userled_initialize() is available to initialize the LEDs from user + * application logic. + * + ****************************************************************************/ + +uint32_t board_userled_initialize(void) +{ + int i; + + /* Configure LED1-2 GPIOs for output */ + + for (i = 0; i < nitems(g_ledcfg); i++) + { + stm32_configgpio(g_ledcfg[i]); + } + + return BOARD_NLEDS; +} + +/**************************************************************************** + * Name: board_userled + * + * Description: + * If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board + * LEDs. If CONFIG_ARCH_LEDS is not defined, then the board_userled() is + * available to control the LEDs from user application logic. + * + ****************************************************************************/ + +void board_userled(int led, bool ledon) +{ + if ((unsigned)led < nitems(g_ledcfg)) + { + stm32_gpiowrite(g_ledcfg[led], ledon); + } +} + +/**************************************************************************** + * Name: board_userled_all + * + * Description: + * If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board + * LEDs. If CONFIG_ARCH_LEDS is not defined, then the board_userled_all() + * is available to control the LED from user application logic. + * + ****************************************************************************/ + +void board_userled_all(uint32_t ledset) +{ + int i; + + /* Configure LED1-2 GPIOs for output */ + + for (i = 0; i < nitems(g_ledcfg); i++) + { + stm32_gpiowrite(g_ledcfg[i], (ledset & (1 << i))); + } +} + +#endif /* !CONFIG_ARCH_LEDS */