diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c5619ceffb9..025b23fd414 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -523,6 +523,7 @@ config ARCH_CHIP_STM32U5 select ARM_HAVE_DSP select ARCH_HAVE_FETCHADD select ARCH_HAVE_HEAPCHECK + select ARCH_HAVE_HEAP2 select ARCH_HAVE_PROGMEM select ARCH_HAVE_SPI_BITORDER select ARCH_HAVE_TICKLESS diff --git a/arch/arm/include/stm32u5/chip.h b/arch/arm/include/stm32u5/chip.h index 9b2708cf476..c4e491ddb35 100644 --- a/arch/arm/include/stm32u5/chip.h +++ b/arch/arm/include/stm32u5/chip.h @@ -31,15 +31,23 @@ * Pre-processor Prototypes ****************************************************************************/ -#if defined(CONFIG_STM32U5_STM32U585XX) -# define STM32_SRAM1_SIZE (192*1024) /* 192Kb SRAM1 on AHB bus Matrix */ -# define STM32_SRAM2_SIZE (64*1024) /* 64kB SRAM2 on AHB bus Matrix */ -# define STM32_SRAM3_SIZE (512*1024) /* 512kB SRAM3 on AHB bus Matrix */ +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) +# define STM32_SRAM1_SIZE (0x00030000) /* 192Kb SRAM1 */ +# define STM32_SRAM2_SIZE (0x00010000) /* 64kB SRAM2 */ +#elif defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) +# define STM32_SRAM1_SIZE (0x00030000) /* 192Kb SRAM1 */ +# define STM32_SRAM2_SIZE (0x00010000) /* 64kB SRAM2 */ +# define STM32_SRAM3_SIZE (0x00080000) /* 512kB SRAM3 */ +#elif defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) +# define STM32_SRAM1_SIZE (0x000C0000) /* 768Kb SRAM1 */ +# define STM32_SRAM2_SIZE (0x00010000) /* 64kB SRAM2 */ +# define STM32_SRAM3_SIZE (0x000d0000) /* 832kB SRAM3 */ +# define STM32_SRAM5_SIZE (0x000d0000) /* 832kB SRAM5 */ #else # error "Unsupported STM32U5 chip" #endif -#if defined(CONFIG_STM32U5_STM32U585XX) +#if defined(CONFIG_STM32U5_STM32U585XX) || defined(CONFIG_STM32U5_STM32U5A5XX) # define STM32_NFSMC 1 /* Have FSMC memory controller */ # define STM32_NATIM 2 /* Two advanced timers TIM1 and 8 */ # define STM32_NGTIM32 2 /* 32-bit general timers TIM2 and 5 with DMA */ @@ -70,6 +78,10 @@ # define STM32_NOPAMP 2 /* Operational Amplifiers */ #endif /* CONFIG_STM32U5_STM32U585XX */ +#if defined(CONFIG_STM32U5_STM32U5A5ZJT) +# define STM32_NUSBOTGHS 1 /* USB OTG HS */ +#endif + /* NVIC priority levels *****************************************************/ /* 16 Programmable interrupt levels */ diff --git a/arch/arm/include/stm32u5/irq.h b/arch/arm/include/stm32u5/irq.h index 6bd2ef79b04..c40997d715c 100644 --- a/arch/arm/include/stm32u5/irq.h +++ b/arch/arm/include/stm32u5/irq.h @@ -31,8 +31,11 @@ #include -#if defined(CONFIG_STM32U5_STM32U585XX) -# include +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) || \ + defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) || \ + defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || \ + defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) +# include #else # error "Unsupported STM32U5 chip" #endif diff --git a/arch/arm/include/stm32u5/stm32u585xx_irq.h b/arch/arm/include/stm32u5/stm32u5xx_irq.h similarity index 93% rename from arch/arm/include/stm32u5/stm32u585xx_irq.h rename to arch/arm/include/stm32u5/stm32u5xx_irq.h index 48c74ac0858..a352e2c2d3a 100644 --- a/arch/arm/include/stm32u5/stm32u585xx_irq.h +++ b/arch/arm/include/stm32u5/stm32u5xx_irq.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/include/stm32u5/stm32u585xx_irq.h + * arch/arm/include/stm32u5/stm32u5xx_irq.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_INCLUDE_STM32U5_STM32U585XX_IRQ_H -#define __ARCH_ARM_INCLUDE_STM32U5_STM32U585XX_IRQ_H +#ifndef __ARCH_ARM_INCLUDE_STM32U5_STM32U5XX_IRQ_H +#define __ARCH_ARM_INCLUDE_STM32U5_STM32U5XX_IRQ_H /**************************************************************************** * Included Files @@ -128,7 +128,15 @@ #define STM32_IRQ_TIM16 (STM32_IRQ_FIRST + 70) /* 70: TIM16 global interrupt */ #define STM32_IRQ_TIM17 (STM32_IRQ_FIRST + 71) /* 71: TIM17 global interrupt */ #define STM32_IRQ_COMP (STM32_IRQ_FIRST + 72) /* 72: COMP1/COMP2 interrupts */ -#define STM32_IRQ_OTG_FS (STM32_IRQ_FIRST + 73) /* 73: USB OTG FS global interrupt */ +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) || \ + defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) +# define STM32_IRQ_OTG_FS (STM32_IRQ_FIRST + 73) /* 73: USB OTG FS global interrupt */ +#elif defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || \ + defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) +# define STM32_IRQ_OTG_HS (STM32_IRQ_FIRST + 73) /* 73: USB OTG HS global interrupt */ +#else +# error "Unsupported STM32U5 chip" +#endif #define STM32_IRQ_CRS (STM32_IRQ_FIRST + 74) /* 74: CRS global interrupt */ #define STM32_IRQ_FMC (STM32_IRQ_FIRST + 75) /* 75: FMC global interrupt */ #define STM32_IRQ_OCTOSPI1 (STM32_IRQ_FIRST + 76) /* 76: OCTOSPI1 global interrupt */ @@ -181,7 +189,10 @@ #define STM32_IRQ_CORDIC (STM32_IRQ_FIRST + 123) /* 123: CORDIC interrupt */ #define STM32_IRQ_FMAC (STM32_IRQ_FIRST + 124) /* 124: FMAC interrupt */ -#if defined(CONFIG_STM32U5_STM32U585XX) +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) || \ + defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) || \ + defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || \ + defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) # define STM32_IRQ_NEXTINTS 125 #else # error "Unsupported STM32U5 chip" @@ -191,4 +202,4 @@ #define NR_IRQS (STM32_IRQ_FIRST + STM32_IRQ_NEXTINTS) -#endif /* __ARCH_ARM_INCLUDE_STM32U5_STM32U585XX_IRQ_H */ +#endif /* __ARCH_ARM_INCLUDE_STM32U5_STM32U5XX_IRQ_H */ diff --git a/arch/arm/src/stm32u5/Kconfig b/arch/arm/src/stm32u5/Kconfig index 55d8f5084aa..5cf57354f87 100644 --- a/arch/arm/src/stm32u5/Kconfig +++ b/arch/arm/src/stm32u5/Kconfig @@ -20,10 +20,29 @@ config ARCH_CHIP_STM32U585AI ---help--- STM32 U5 Cortex M33, 2048 Kb FLASH, 768 Kb SRAM -endchoice # STM32 L5 Chip Selection +config ARCH_CHIP_STM32U5A5ZJT + bool "STM32U5A5ZJT" + select STM32U5_STM32U5A5XX + select STM32U5_IO_CONFIG_A + ---help--- + STM32 U5 Cortex M33, 4096 Kb FLASH, 2500 Kb SRAM, tqfp144 + +endchoice # STM32 U5 Chip Selection # Chip families: +config STM32U5_STM32U5A5XX + # STM32U575 and STM32U585 devices documented in RM0456 + bool + default n + select ARCH_HAVE_FPU + select STM32U5_HAVE_LPUART1 + select STM32U5_HAVE_USART1 + select STM32U5_HAVE_USART2 + select STM32U5_HAVE_USART3 + select STM32U5_HAVE_UART4 + select STM32U5_HAVE_UART5 + config STM32U5_STM32U585XX # STM32U575 and STM32U585 devices documented in RM0456 bool @@ -155,34 +174,6 @@ config STM32U5_IO_CONFIG_A bool default n -comment "STM32U5 SRAM2 Options" - -config STM32U5_SRAM2_HEAP - bool "SRAM2 is used for heap" - default n - select STM32U5_SRAM2_INIT - ---help--- - The STM32U5 SRAM2 region has special properties (power, protection, parity) - which may be used by the application for special purposes. But if these - special properties are not needed, it may be instead added to the heap for - use by malloc(). - NOTE: you must also select an appropriate number of memory regions in the - 'Memory Management' section. - -config STM32U5_SRAM2_INIT - bool "SRAM2 is initialized to zero" - default n - ---help--- - The STM32U5 SRAM2 region has parity checking. However, when the system - powers on, the memory is in an unknown state, and reads from uninitialized - memory can trigger parity faults from the random data. This can be - avoided by first writing to all locations to force the parity into a valid - state. - However, 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 "STM32U5 Peripherals" menu "STM32U5 Peripheral Support" @@ -284,6 +275,62 @@ config STM32U5_DCACHE1 config STM32U5_SRAM1 bool "SRAM1" + default y + +config STM32U5_SRAM2 + bool "SRAM2" + default n + +config STM32U5_SRAM3 + bool "SRAM3" + default n + depends on STM32U5_STM32U575XX || STM32U5_STM32U585XX || STM32U5_STM32U59XX || STM32U5_STM32U59AXX || \ + STM32U5_STM32U5A5XX || STM32U5_STM32U5A9XX + +config STM32U5_SRAM5 + bool "SRAM5" + default n + depends on STM32U5_STM32U575XX || STM32U5_STM32U585XX || STM32U5_STM32U59XX || STM32U5_STM32U59AXX || \ + STM32U5_STM32U5A5XX || STM32U5_STM32U5A9XX + +comment "SRAM Options" + +config STM32U5_SRAM2_HEAP + bool "SRAM2 is used for heap" + default n + depends on STM32U5_SRAM2 + select STM32U5_SRAM2_INIT + ---help--- + The STM32U5 SRAM2 region has special properties (power, protection, parity) + which may be used by the application for special purposes. But if these + special properties are not needed, it may be instead added to the heap for + use by malloc(). + NOTE: you must also select an appropriate number of memory regions in the + 'Memory Management' section. + +config STM32U5_SRAM2_INIT + bool "SRAM2 is initialized to zero" + default n + depends on STM32U5_SRAM2 + ---help--- + The STM32U5 SRAM2 region has parity checking. However, when the system + powers on, the memory is in an unknown state, and reads from uninitialized + memory can trigger parity faults from the random data. This can be + avoided by first writing to all locations to force the parity into a valid + state. + However, 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. + +config STM32U5_SRAM3_HEAP + bool "SRAM3 is used for heap" + depends on STM32U5_SRAM3 + default n + +config STM32U5_SRAM5_HEAP + bool "SRAM5 is used for heap" + depends on STM32U5_SRAM5 default n comment "AHB2 Peripherals" @@ -296,8 +343,14 @@ config STM32U5_DCMI_PSSI bool "DCMI_PSSI" default n -config STM32U5_OTG - bool "OTG" +config STM32U5_OTGFS + bool "OTG FS" + depends on STM32U5_STM32U535XX || CONFIG_STM32U5_STM32U545XX || STM32U5_STM32U575XX || STM32U5_STM32U585XX + default n + +config STM32U5_OTGHS + bool "OTG HS" + depends on STM32U5_STM32U59XX || STM32U5_STM32U59AXX || STM32U5_STM32U5A5XX || STM32U5_STM32U5A9XX default n config STM32U5_AES @@ -340,14 +393,6 @@ config STM32U5_SDMMC2 bool "SDMMC2" default n -config STM32U5_SRAM2 - bool "SRAM2" - default n - -config STM32U5_SRAM3 - bool "SRAM3" - default n - config STM32U5_FSMC bool "FSMC" default n @@ -390,10 +435,6 @@ config STM32U5_GTZC2 bool "GTZC2" default n -config STM32U5_SRAM4 - bool "SRAM4" - default n - comment "APB1 Peripherals" config STM32U5_TIM2 @@ -457,18 +498,38 @@ config STM32U5_UART5 config STM32U5_I2C1 bool "I2C1" default n + select STM32U5_I2C config STM32U5_I2C2 bool "I2C2" default n + select STM32U5_I2C -config STM32U5_CRS - bool "CRS" +config STM32U5_I2C3 + bool "I2C3" default n + select STM32U5_I2C config STM32U5_I2C4 bool "I2C4" default n + select STM32U5_I2C + +config STM32U5_I2C5 + bool "I2C5" + depends on STM32U5_STM32U59XX || STM32U5_STM32U59AXX || STM32U5_STM32U5A5XX || STM32U5_STM32U5A9XX + default n + select STM32U5_I2C + +config STM32U5_I2C6 + bool "I2C6" + depends on STM32U5_STM32U59XX || STM32U5_STM32U59AXX || STM32U5_STM32U5A5XX || STM32U5_STM32U5A9XX + default n + select STM32U5_I2C + +config STM32U5_CRS + bool "CRS" + default n config STM32U5_LPTIM2 bool "LPTIM2" @@ -542,10 +603,6 @@ config STM32U5_LPUART1 select ARCH_HAVE_SERIAL_TERMIOS select STM32U5_USART -config STM32U5_I2C3 - bool "I2C3" - default n - config STM32U5_LPTIM1 bool "LPTIM1" default n @@ -614,11 +671,6 @@ config ARCH_BOARD_STM32U5_CUSTOM_CLOCKCONFIG ---help--- Enables special, board-specific STM32 clock configuration. -config STM32U5_HAVE_RTC_SUBSECONDS - bool - select ARCH_HAVE_RTC_SUBSECONDS - default y - menu "RTC Configuration" depends on STM32U5_RTC @@ -3171,6 +3223,10 @@ config STM32U5_SPI_DMA endmenu +config STM32U5_I2C + bool + default n + menu "I2C Configuration" depends on STM32U5_I2C diff --git a/arch/arm/src/stm32u5/Make.defs b/arch/arm/src/stm32u5/Make.defs index c72ebb14232..e69eec8b2de 100644 --- a/arch/arm/src/stm32u5/Make.defs +++ b/arch/arm/src/stm32u5/Make.defs @@ -31,9 +31,9 @@ include armv8-m/Make.defs CHIP_ASRCS = CHIP_CSRCS = stm32_allocateheap.c stm32_exti_gpio.c stm32_gpio.c -CHIP_CSRCS += stm32_irq.c stm32_lowputc.c stm32_rcc.c +CHIP_CSRCS += stm32_irq.c stm32_lowputc.c stm32_rcc.c stm32_i2c.c CHIP_CSRCS += stm32_serial.c stm32_start.c stm32_waste.c stm32_uid.c -CHIP_CSRCS += stm32_spi.c stm32_lse.c stm32_lsi.c +CHIP_CSRCS += stm32_spi.c stm32_lse.c stm32_lsi.c stm32u5xx_rcc.c CHIP_CSRCS += stm32_pwr.c stm32_tim.c stm32_flash.c stm32_timerisr.c ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y) @@ -54,6 +54,6 @@ endif # Required chip type specific files -ifeq ($(CONFIG_STM32U5_STM32U585XX),y) -CHIP_CSRCS += stm32u585xx_rcc.c +ifeq ($(CONFIG_USBDEV),y) +CHIP_CSRCS += stm32_otgdev.c endif diff --git a/arch/arm/src/stm32u5/hardware/stm32_flash.h b/arch/arm/src/stm32u5/hardware/stm32_flash.h index 14531b84487..74a43dd3487 100644 --- a/arch/arm/src/stm32u5/hardware/stm32_flash.h +++ b/arch/arm/src/stm32u5/hardware/stm32_flash.h @@ -41,38 +41,46 @@ * Parts STM32U585 and STM32U575 have 2048Kb of FLASH */ -#if !defined(CONFIG_STM32U5_FLASH_OVERRIDE_DEFAULT) && \ +#if defined(CONFIG_ARCH_CHIP_STM32U585AI) +# if !defined(CONFIG_STM32U5_FLASH_OVERRIDE_DEFAULT) && \ !defined(CONFIG_STM32U5_FLASH_OVERRIDE_C) && \ !defined(CONFIG_STM32U5_FLASH_OVERRIDE_E) && \ !defined(CONFIG_STM32U5_FLASH_CONFIG_C) && \ !defined(CONFIG_STM32U5_FLASH_CONFIG_E) -# define CONFIG_STM32U5_FLASH_OVERRIDE_E -# warning "Flash size not defined defaulting to 512KiB (E)" -#endif +# define CONFIG_STM32U5_FLASH_OVERRIDE_E +# warning "Flash size not defined defaulting to 512KiB (E)" +# endif /* Override of the Flash has been chosen */ -#if !defined(CONFIG_STM32U5_FLASH_OVERRIDE_DEFAULT) -# undef CONFIG_STM32U5_FLASH_CONFIG_C -# undef CONFIG_STM32U5_FLASH_CONFIG_E -# if defined(CONFIG_STM32U5_FLASH_OVERRIDE_C) -# define CONFIG_STM32U5_FLASH_CONFIG_C -# elif defined(CONFIG_STM32U5_FLASH_OVERRIDE_E) -# define CONFIG_STM32U5_FLASH_CONFIG_E +# if !defined(CONFIG_STM32U5_FLASH_OVERRIDE_DEFAULT) +# undef CONFIG_STM32U5_FLASH_CONFIG_C +# undef CONFIG_STM32U5_FLASH_CONFIG_E +# if defined(CONFIG_STM32U5_FLASH_OVERRIDE_C) +# define CONFIG_STM32U5_FLASH_CONFIG_C +# elif defined(CONFIG_STM32U5_FLASH_OVERRIDE_E) +# define CONFIG_STM32U5_FLASH_CONFIG_E +# endif # endif -#endif /* Define the valid configuration */ -#if defined(CONFIG_STM32U5_FLASH_CONFIG_I) /* 2048 kB */ -# define STM32_FLASH_NPAGES 256 -# define STM32_FLASH_PAGESIZE 8192 -#else -# error "unknown flash configuration!" +# if defined(CONFIG_STM32U5_FLASH_CONFIG_I) /* 2048 kB */ +# define STM32_FLASH_NPAGES 256 +# define STM32_FLASH_PAGESIZE 8192 +# else +# error "unknown flash configuration!" +# endif #endif #ifdef STM32_FLASH_PAGESIZE -# define STM32_FLASH_SIZE (STM32_FLASH_NPAGES * STM32_FLASH_PAGESIZE) +# define STM32_FLASH_SIZE (STM32_FLASH_NPAGES * STM32_FLASH_PAGESIZE) +#endif + +#if defined(CONFIG_STM32U5_STM32U5A5XX) +# define STM32_FLASH_NPAGES 512 +# define STM32_FLASH_PAGESIZE 8192 +# define STM32_FLASH_SIZE (STM32_FLASH_NPAGES * STM32_FLASH_PAGESIZE) #endif /* Register Offsets *********************************************************/ diff --git a/arch/arm/src/stm32u5/hardware/stm32_i2c.h b/arch/arm/src/stm32u5/hardware/stm32_i2c.h new file mode 100644 index 00000000000..c9dfc7d7fb3 --- /dev/null +++ b/arch/arm/src/stm32u5/hardware/stm32_i2c.h @@ -0,0 +1,250 @@ +/**************************************************************************** + * arch/arm/src/stm32u5/hardware/stm32_i2c.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_STM32U5_HARDWARE_STM32_I2C_H +#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32_I2C_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define STM32_I2C_CR1_OFFSET 0x0000 /* Control register 1 (32-bit) */ +#define STM32_I2C_CR2_OFFSET 0x0004 /* Control register 2 (32-bit) */ +#define STM32_I2C_OAR1_OFFSET 0x0008 /* Own address register 1 (16-bit) */ +#define STM32_I2C_OAR2_OFFSET 0x000c /* Own address register 2 (16-bit) */ +#define STM32_I2C_TIMINGR_OFFSET 0x0010 /* Timing register */ +#define STM32_I2C_TIMEOUTR_OFFSET 0x0014 /* Timeout register */ +#define STM32_I2C_ISR_OFFSET 0x0018 /* Interrupt and Status register */ +#define STM32_I2C_ICR_OFFSET 0x001c /* Interrupt clear register */ +#define STM32_I2C_PECR_OFFSET 0x0020 /* Packet error checking register */ +#define STM32_I2C_RXDR_OFFSET 0x0024 /* Receive data register */ +#define STM32_I2C_TXDR_OFFSET 0x0028 /* Transmit data register */ + +/* Register Addresses *******************************************************/ + +#if STM32_NI2C > 0 +# define STM32_I2C1_CR1 (STM32_I2C1_BASE+STM32_I2C_CR1_OFFSET) +# define STM32_I2C1_CR2 (STM32_I2C1_BASE+STM32_I2C_CR2_OFFSET) +# define STM32_I2C1_OAR1 (STM32_I2C1_BASE+STM32_I2C_OAR1_OFFSET) +# define STM32_I2C1_OAR2 (STM32_I2C1_BASE+STM32_I2C_OAR2_OFFSET) +# define STM32_I2C1_TIMINGR (STM32_I2C1_BASE+STM32_I2C_TIMINGR_OFFSET) +# define STM32_I2C1_TIMEOUTR (STM32_I2C1_BASE+STM32_I2C_TIMEOUTR_OFFSET) +# define STM32_I2C1_ISR (STM32_I2C1_BASE+STM32_I2C_ISR_OFFSET) +# define STM32_I2C1_ICR (STM32_I2C1_BASE+STM32_I2C_ICR_OFFSET) +# define STM32_I2C1_PECR (STM32_I2C1_BASE+STM32_I2C_PECR_OFFSET) +# define STM32_I2C1_RXDR (STM32_I2C1_BASE+STM32_I2C_RXDR_OFFSET) +# define STM32_I2C1_TXDR (STM32_I2C1_BASE+STM32_I2C_TXDR_OFFSET) +#endif + +#if STM32_NI2C > 1 +# define STM32_I2C2_CR1 (STM32_I2C2_BASE+STM32_I2C_CR1_OFFSET) +# define STM32_I2C2_CR2 (STM32_I2C2_BASE+STM32_I2C_CR2_OFFSET) +# define STM32_I2C2_OAR1 (STM32_I2C2_BASE+STM32_I2C_OAR1_OFFSET) +# define STM32_I2C2_OAR2 (STM32_I2C2_BASE+STM32_I2C_OAR2_OFFSET) +# define STM32_I2C2_TIMINGR (STM32_I2C2_BASE+STM32_I2C_TIMINGR_OFFSET) +# define STM32_I2C2_TIMEOUTR (STM32_I2C2_BASE+STM32_I2C_TIMEOUTR_OFFSET) +# define STM32_I2C2_ISR (STM32_I2C2_BASE+STM32_I2C_ISR_OFFSET) +# define STM32_I2C2_ICR (STM32_I2C2_BASE+STM32_I2C_ICR_OFFSET) +# define STM32_I2C2_PECR (STM32_I2C2_BASE+STM32_I2C_PECR_OFFSET) +# define STM32_I2C2_RXDR (STM32_I2C2_BASE+STM32_I2C_RXDR_OFFSET) +# define STM32_I2C2_TXDR (STM32_I2C2_BASE+STM32_I2C_TXDR_OFFSET) +#endif + +#if STM32_NI2C > 2 +# define STM32_I2C3_CR1 (STM32_I2C3_BASE+STM32_I2C_CR1_OFFSET) +# define STM32_I2C3_CR2 (STM32_I2C3_BASE+STM32_I2C_CR2_OFFSET) +# define STM32_I2C3_OAR1 (STM32_I2C3_BASE+STM32_I2C_OAR1_OFFSET) +# define STM32_I2C3_OAR2 (STM32_I2C3_BASE+STM32_I2C_OAR2_OFFSET) +# define STM32_I2C3_TIMINGR (STM32_I2C3_BASE+STM32_I2C_TIMINGR_OFFSET) +# define STM32_I2C3_TIMEOUTR (STM32_I2C3_BASE+STM32_I2C_TIMEOUTR_OFFSET) +# define STM32_I2C3_ISR (STM32_I2C3_BASE+STM32_I2C_ISR_OFFSET) +# define STM32_I2C3_ICR (STM32_I2C3_BASE+STM32_I2C_ICR_OFFSET) +# define STM32_I2C3_PECR (STM32_I2C3_BASE+STM32_I2C_PECR_OFFSET) +# define STM32_I2C3_RXDR (STM32_I2C3_BASE+STM32_I2C_RXDR_OFFSET) +# define STM32_I2C3_TXDR (STM32_I2C3_BASE+STM32_I2C_TXDR_OFFSET) +#endif + +#if STM32_NI2C > 3 +# define STM32_I2C4_CR1 (STM32_I2C4_BASE+STM32_I2C_CR1_OFFSET) +# define STM32_I2C4_CR2 (STM32_I2C4_BASE+STM32_I2C_CR2_OFFSET) +# define STM32_I2C4_OAR1 (STM32_I2C4_BASE+STM32_I2C_OAR1_OFFSET) +# define STM32_I2C4_OAR2 (STM32_I2C4_BASE+STM32_I2C_OAR2_OFFSET) +# define STM32_I2C4_TIMINGR (STM32_I2C4_BASE+STM32_I2C_TIMINGR_OFFSET) +# define STM32_I2C4_TIMEOUTR (STM32_I2C4_BASE+STM32_I2C_TIMEOUTR_OFFSET) +# define STM32_I2C4_ISR (STM32_I2C4_BASE+STM32_I2C_ISR_OFFSET) +# define STM32_I2C4_ICR (STM32_I2C4_BASE+STM32_I2C_ICR_OFFSET) +# define STM32_I2C4_PECR (STM32_I2C4_BASE+STM32_I2C_PECR_OFFSET) +# define STM32_I2C4_RXDR (STM32_I2C4_BASE+STM32_I2C_RXDR_OFFSET) +# define STM32_I2C4_TXDR (STM32_I2C4_BASE+STM32_I2C_TXDR_OFFSET) +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* Control register 1 */ + +#define I2C_CR1_PE (1 << 0) /* Bit 0: Peripheral Enable */ +#define I2C_CR1_TXIE (1 << 1) /* Bit 1: TX Interrupt enable */ +#define I2C_CR1_RXIE (1 << 2) /* Bit 2: RX Interrupt enable */ +#define I2C_CR1_ADDRIE (1 << 3) /* Bit 3: Address match interrupt enable (slave) */ +#define I2C_CR1_NACKIE (1 << 4) /* Bit 4: Not acknowledge received interrupt enable */ +#define I2C_CR1_STOPIE (1 << 5) /* Bit 5: STOP detection interrupt enable */ +#define I2C_CR1_TCIE (1 << 6) /* Bit 6: Transfer Complete interrupt enable */ +#define I2C_CR1_ERRIE (1 << 7) /* Bit 7: Error interrupts enable */ +#define I2C_CR1_DNF_SHIFT (8) /* Bits 8-11: Digital noise filter */ +#define I2C_CR1_DNF_MASK (15 << I2C_CR1_DNF_SHIFT) +# define I2C_CR1_DNF_DISABLE (0 << I2C_CR1_DNF_SHIFT) +# define I2C_CR1_DNF(n) ((n) << I2C_CR1_DNF_SHIFT) /* Up to n * Ti2cclk, n=1..15 */ + +#define I2C_CR1_ANFOFF (1 << 12) /* Bit 12: Analog noise filter OFF */ +#define I2C_CR1_TXDMAEN (1 << 14) /* Bit 14: DMA transmission requests enable */ +#define I2C_CR1_RXDMAEN (1 << 15) /* Bit 15: DMA reception requests enable */ +#define I2C_CR1_SBC (1 << 16) /* Bit 16: Slave byte control */ +#define I2C_CR1_NOSTRETCH (1 << 17) /* Bit 17: Clock stretching disable */ +#define I2C_CR1_WUPEN (1 << 18) /* Bit 18: Wakeup from STOP enable */ +#define I2C_CR1_GCEN (1 << 19) /* Bit 19: General call enable */ +#define I2C_CR1_SMBHEN (1 << 20) /* Bit 20: SMBus Host address enable */ +#define I2C_CR1_SMBDEN (1 << 21) /* Bit 21: SMBus Device Default address enable */ +#define I2C_CR1_ALERTEN (1 << 22) /* Bit 22: SMBus alert enable */ +#define I2C_CR1_PECEN (1 << 23) /* Bit 23: PEC enable */ + +/* Control register 2 */ + +#define I2C_CR2_SADD10_SHIFT (0) /* Bits 0-9: Slave 10-bit address (master) */ +#define I2C_CR2_SADD10_MASK (0x3ff << I2C_CR2_SADD10_SHIFT) +#define I2C_CR2_SADD7_SHIFT (1) /* Bits 1-7: Slave 7-bit address (master) */ +#define I2C_CR2_SADD7_MASK (0x7f << I2C_CR2_SADD7_SHIFT) +#define I2C_CR2_RD_WRN (1 << 10) /* Bit 10: Transfer direction (master) */ +#define I2C_CR2_ADD10 (1 << 11) /* Bit 11: 10-bit addressing mode (master) */ +#define I2C_CR2_HEAD10R (1 << 12) /* Bit 12: 10-bit address header only read direction (master) */ +#define I2C_CR2_START (1 << 13) /* Bit 13: Start generation */ +#define I2C_CR2_STOP (1 << 14) /* Bit 14: Stop generation (master) */ +#define I2C_CR2_NACK (1 << 15) /* Bit 15: NACK generation (slave) */ +#define I2C_CR2_NBYTES_SHIFT (16) /* Bits 16-23: Number of bytes */ +#define I2C_CR2_NBYTES_MASK (0xff << I2C_CR2_NBYTES_SHIFT) +#define I2C_CR2_RELOAD (1 << 24) /* Bit 24: NBYTES reload mode */ +#define I2C_CR2_AUTOEND (1 << 25) /* Bit 25: Automatic end mode (master) */ +#define I2C_CR2_PECBYTE (1 << 26) /* Bit 26: Packet error checking byte */ + +/* Own address register 1 */ + +#define I2C_OAR1_OA1_10_SHIFT (0) /* Bits 0-9: 10-bit interface address */ +#define I2C_OAR1_OA1_10_MASK (0x3ff << I2C_OAR1_OA1_10_SHIFT) +#define I2C_OAR1_OA1_7_SHIFT (1) /* Bits 1-7: 7-bit interface address */ +#define I2C_OAR1_OA1_7_MASK (0x7f << I2C_OAR1_OA1_7_SHIFT) +#define I2C_OAR1_OA1MODE (1 << 10) /* Bit 10: Own Address 1 10-bit mode */ +#define I2C_OAR1_OA1EN (1 << 15) /* Bit 15: Own Address 1 enable */ + +/* Own address register 2 */ + +#define I2C_OAR2_OA2_SHIFT (1) /* Bits 1-7: 7-bit interface address */ +#define I2C_OAR2_OA2_MASK (0x7f << I2C_OAR2_OA2_SHIFT) +#define I2C_OAR2_OA2MSK_SHIFT (8) /* Bits 8-10: Own Address 2 masks */ +#define I2C_OAR2_OA2MSK_MASK (7 << I2C_OAR2_OA2MSK_SHIFT) +# define I2C_OAR2_OA2MSK_NONE (0 << I2C_OAR2_OA2MSK_SHIFT) /* No mask */ +# define I2C_OAR2_OA2MSK_2_7 (1 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:2] are compared */ +# define I2C_OAR2_OA2MSK_3_7 (2 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:3] are compared */ +# define I2C_OAR2_OA2MSK_4_7 (3 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:4] are compared */ +# define I2C_OAR2_OA2MSK_5_7 (4 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:5] are compared */ +# define I2C_OAR2_OA2MSK_6_7 (5 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:6] are compared */ +# define I2C_OAR2_OA2MSK_7 (6 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7] is compared */ +# define I2C_OAR2_OA2MSK_ALL (7 << I2C_OAR2_OA2MSK_SHIFT) /* All 7-bit addresses acknowledged */ + +#define I2C_OAR2_OA2EN (1 << 15) /* Bit 15: Own Address 2 enable */ + +/* Timing register */ + +#define I2C_TIMINGR_SCLL_SHIFT (0) /* Bits 0-7: SCL low period (master) */ +#define I2C_TIMINGR_SCLL_MASK (0xff << I2C_TIMINGR_SCLL_SHIFT) +# define I2C_TIMINGR_SCLL(n) (((n)-1) << I2C_TIMINGR_SCLL_SHIFT) /* tSCLL = n x tPRESC */ + +#define I2C_TIMINGR_SCLH_SHIFT (8) /* Bits 8-15: SCL high period (master) */ +#define I2C_TIMINGR_SCLH_MASK (0xff << I2C_TIMINGR_SCLH_SHIFT) +# define I2C_TIMINGR_SCLH(n) (((n)-1) << I2C_TIMINGR_SCLH_SHIFT) /* tSCLH = n x tPRESC */ + +#define I2C_TIMINGR_SDADEL_SHIFT (16) /* Bits 16-19: Data hold time */ +#define I2C_TIMINGR_SDADEL_MASK (15 << I2C_TIMINGR_SDADEL_SHIFT) +# define I2C_TIMINGR_SDADEL(n) ((n) << I2C_TIMINGR_SDADEL_SHIFT) /* tSDADEL= n x tPRESC */ + +#define I2C_TIMINGR_SCLDEL_SHIFT (20) /* Bits 20-23: Data setup time */ +#define I2C_TIMINGR_SCLDEL_MASK (15 << I2C_TIMINGR_SCLDEL_SHIFT) +# define I2C_TIMINGR_SCLDEL(n) (((n)-1) << I2C_TIMINGR_SCLDEL_SHIFT) /* tSCLDEL = n x tPRESC */ + +#define I2C_TIMINGR_PRESC_SHIFT (28) /* Bits 28-31: Timing prescaler */ +#define I2C_TIMINGR_PRESC_MASK (15 << I2C_TIMINGR_PRESC_SHIFT) +# define I2C_TIMINGR_PRESC(n) (((n)-1) << I2C_TIMINGR_PRESC_SHIFT) /* tPRESC = n x tI2CCLK */ + +/* Timeout register */ + +#define I2C_TIMEOUTR_A_SHIFT (0) /* Bits 0-11: Bus Timeout A */ +#define I2C_TIMEOUTR_A_MASK (0x0fff << I2C_TIMEOUTR_A_SHIFT) +# define I2C_TIMEOUTR_A(n) ((n) << I2C_TIMEOUTR_A_SHIFT) +#define I2C_TIMEOUTR_TIDLE (1 << 12) /* Bit 12: Idle clock timeout detection */ +#define I2C_TIMEOUTR_TIMOUTEN (1 << 15) /* Bit 15: Clock timeout enable */ +#define I2C_TIMEOUTR_B_SHIFT (16) /* Bits 16-27: Bus Timeout B */ +#define I2C_TIMEOUTR_B_MASK (0x0fff << I2C_TIMEOUTR_B_SHIFT) +# define I2C_TIMEOUTR_B(n) ((n) << I2C_TIMEOUTR_B_SHIFT) +#define I2C_TIMEOUTR_TEXTEN (1 << 31) /* Bits 31: Extended clock timeout enable */ + +/* Interrupt and Status register and interrupt clear register */ + +/* Common interrupt bits */ + +#define I2C_INT_ADDR (1 << 3) /* Bit 3: Address matched (slave) */ +#define I2C_INT_NACK (1 << 4) /* Bit 4: Not Acknowledge received flag */ +#define I2C_INT_STOP (1 << 5) /* Bit 5: Stop detection flag */ +#define I2C_INT_BERR (1 << 8) /* Bit 8: Bus error */ +#define I2C_INT_ARLO (1 << 9) /* Bit 9: Arbitration lost */ +#define I2C_INT_OVR (1 << 10) /* Bit 10: Overrun/Underrun (slave) */ +#define I2C_INT_PECERR (1 << 11) /* Bit 11: PEC Error in reception */ +#define I2C_INT_TIMEOUT (1 << 12) /* Bit 12: Timeout or tLOW detection flag */ +#define I2C_INT_ALERT (1 << 13) /* Bit 13: SMBus alert */ + +/* Fields unique to the Interrupt and Status register */ + +#define I2C_ISR_TXE (1 << 0) /* Bit 0: Transmit data register empty (transmitters) */ +#define I2C_ISR_TXIS (1 << 1) /* Bit 1: Transmit interrupt status (transmitters) */ +#define I2C_ISR_RXNE (1 << 2) /* Bit 2: Receive data register not empty (receivers) */ +#define I2C_ISR_TC (1 << 6) /* Bit 6: Transfer Complete (master) */ +#define I2C_ISR_TCR (1 << 7) /* Bit 7: Transfer Complete Reload */ +#define I2C_ISR_BUSY (1 << 15) /* Bit 15: Bus busy */ +#define I2C_ISR_DIR (1 << 16) /* Bit 16: Transfer direction (slave) */ +#define I2C_ISR_ADDCODE_SHIFT (17) /* Bits 17-23: Address match code (slave) */ +#define I2C_ISR_ADDCODE_MASK (0x7f << I2C_ISR_ADDCODE_SHIFT) + +#define I2C_ISR_ERRORMASK (I2C_INT_BERR | I2C_INT_ARLO | I2C_INT_OVR | I2C_INT_PECERR | I2C_INT_TIMEOUT) + +#define I2C_ICR_CLEARMASK (I2C_INT_ADDR | I2C_INT_NACK | I2C_INT_STOP | I2C_INT_BERR | I2C_INT_ARLO \ + | I2C_INT_OVR | I2C_INT_PECERR | I2C_INT_TIMEOUT | I2C_INT_ALERT) + +/* Packet error checking register */ + +#define I2C_PECR_MASK (0xff) + +/* Receive data register */ + +#define I2C_RXDR_MASK (0xff) + +/* Transmit data register */ + +#define I2C_TXDR_MASK (0xff) + +#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32_I2C_H */ diff --git a/arch/arm/src/stm32u5/hardware/stm32_memorymap.h b/arch/arm/src/stm32u5/hardware/stm32_memorymap.h index 40666086586..6815978b39f 100644 --- a/arch/arm/src/stm32u5/hardware/stm32_memorymap.h +++ b/arch/arm/src/stm32u5/hardware/stm32_memorymap.h @@ -43,11 +43,34 @@ /* Code Base Addresses ******************************************************/ -#define STM32_BOOT_BASE 0x00000000 /* 0x00000000-0x000fffff: Aliased boot memory */ -#define STM32_FLASH_BASE 0x08000000 /* 0x08000000-0x081fffff: FLASH memory */ -#define STM32_SRAM1_BASE 0x20000000 /* 0x20000000-0x2002ffff: 192k SRAM1 */ -#define STM32_SRAM2_BASE 0x20030000 /* 0x20030000-0x2003ffff: 64k SRAM2 */ -#define STM32_SRAM3_BASE 0x20040000 /* 0x20040000-0x200bffff: 512k SRAM3 */ +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) +# define STM32_BOOT_BASE 0x00000000 /* 0x00000000-0x000fffff: Aliased boot memory */ +# define STM32_FLASH_BASE 0x08000000 /* 0x08000000-0x081fffff: FLASH memory */ +# define STM32_SRAM1_BASE 0x20000000 /* 0x20000000-0x2002ffff: 192k SRAM1 */ +# define STM32_SRAM2_BASE 0x20030000 /* 0x20030000-0x2003ffff: 64k SRAM2 */ + +#elif defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) + +# define STM32_BOOT_BASE 0x00000000 /* 0x00000000-0x000fffff: Aliased boot memory */ +# define STM32_FLASH_BASE 0x08000000 /* 0x08000000-0x081fffff: FLASH memory */ +# define STM32_SRAM1_BASE 0x20000000 /* 0x20000000-0x2002ffff: 192k SRAM1 */ +# define STM32_SRAM2_BASE 0x20030000 /* 0x20030000-0x2003ffff: 64k SRAM2 */ +# define STM32_SRAM3_BASE 0x20040000 /* 0x20040000-0x200bffff: 512k SRAM3 */ + +#elif defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || \ + defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) + +# define STM32_BOOT_BASE 0x00000000 /* 0x00000000-0x000fffff: Aliased boot memory */ +# define STM32_FLASH_BASE 0x08000000 /* 0x08000000-0x081fffff: FLASH memory */ +# define STM32_SRAM1_BASE 0x20000000 /* 0x20000000-0x200bffff: 768k SRAM1 */ +# define STM32_SRAM2_BASE 0x200c0000 /* 0x200c0000-0x200cffff: 64k SRAM2 */ +# define STM32_SRAM3_BASE 0x200d0000 /* 0x200d0000-0x2019ffff: 832k SRAM3 */ +# define STM32_SRAM4_BASE 0x28000000 /* 0x28000000-0x20003fff: 16k SRAM4 */ +# define STM32_SRAM5_BASE 0x201a0000 /* 0x201a0000-0x2027ffff: 832k SRAM5 */ + +#else +# error "stm32_memorymap: unsupported STM32U5 memory map" +#endif /* System Memory Addresses **************************************************/ @@ -135,6 +158,7 @@ #define STM32_DCMI_BASE 0x4202c000 #define STM32_PSSI_BASE 0x4202c400 #define STM32_OTG_FS_BASE 0x42040000 +#define STM32_USBOTGHS_BASE 0x42040000 /* HS */ #define STM32_AES_BASE 0x420c0000 #define STM32_HASH_BASE 0x420c0400 #define STM32_RNG_BASE 0x420c0800 diff --git a/arch/arm/src/stm32u5/hardware/stm32_pinmap.h b/arch/arm/src/stm32u5/hardware/stm32_pinmap.h index 858ab601f71..3b15599b343 100644 --- a/arch/arm/src/stm32u5/hardware/stm32_pinmap.h +++ b/arch/arm/src/stm32u5/hardware/stm32_pinmap.h @@ -28,8 +28,8 @@ #include #include "chip.h" -#if defined(CONFIG_STM32U5_STM32U585XX) -# include "hardware/stm32u585xx_pinmap.h" +#if defined(CONFIG_STM32U5_STM32U585XX) || defined(CONFIG_STM32U5_STM32U5A5XX) +# include "hardware/stm32u5xx_pinmap.h" #else # error "Unsupported STM32U5 pin map" #endif diff --git a/arch/arm/src/stm32u5/hardware/stm32_spi.h b/arch/arm/src/stm32u5/hardware/stm32_spi.h index 6a98c3e13ae..540fb892730 100644 --- a/arch/arm/src/stm32u5/hardware/stm32_spi.h +++ b/arch/arm/src/stm32u5/hardware/stm32_spi.h @@ -28,10 +28,13 @@ #include #include "chip.h" -#if defined(CONFIG_STM32U5_STM32U585XX) -# include "hardware/stm32u585xx_spi.h" +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) || \ + defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) || \ + defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || \ + defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) +# include "hardware/stm32u5xx_spi.h" #else -# error "Unsupported STM32 U5 sub family" +# error "Unsupported STM32U5 chip" #endif #endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32_SPI_H */ diff --git a/arch/arm/src/stm32u5/hardware/stm32_syscfg.h b/arch/arm/src/stm32u5/hardware/stm32_syscfg.h index 342cdc513f4..9825980f826 100644 --- a/arch/arm/src/stm32u5/hardware/stm32_syscfg.h +++ b/arch/arm/src/stm32u5/hardware/stm32_syscfg.h @@ -28,8 +28,8 @@ #include #include "chip.h" -#if defined(CONFIG_STM32U5_STM32U585XX) -# include "hardware/stm32u585xx_syscfg.h" +#if defined(CONFIG_STM32U5_STM32U585XX) || defined(CONFIG_STM32U5_STM32U5A5XX) +# include "hardware/stm32u5xx_syscfg.h" #else # error "Unsupported STM32U5 chip" #endif diff --git a/arch/arm/src/stm32u5/hardware/stm32u585xx_dbgmcu.h b/arch/arm/src/stm32u5/hardware/stm32u5xx_dbgmcu.h similarity index 95% rename from arch/arm/src/stm32u5/hardware/stm32u585xx_dbgmcu.h rename to arch/arm/src/stm32u5/hardware/stm32u5xx_dbgmcu.h index 8528eb4be1d..765d0f89942 100644 --- a/arch/arm/src/stm32u5/hardware/stm32u585xx_dbgmcu.h +++ b/arch/arm/src/stm32u5/hardware/stm32u5xx_dbgmcu.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32u5/hardware/stm32u585xx_dbgmcu.h + * arch/arm/src/stm32u5/hardware/stm32u5xx_dbgmcu.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_DBGMCU_H -#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_DBGMCU_H +#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_DBGMCU_H +#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_DBGMCU_H /**************************************************************************** * Included Files @@ -93,4 +93,4 @@ #define DBGMCU_APB2_TIM16STOP (1 << 17) /* Bit 17: TIM16 stopped when core is halted */ #define DBGMCU_APB2_TIM17STOP (1 << 18) /* Bit 18: TIM17 stopped when core is halted */ -#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XXDBGMCU_H */ +#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XXD_BGMCU_H */ diff --git a/arch/arm/src/stm32u5/hardware/stm32u585xx_pinmap.h b/arch/arm/src/stm32u5/hardware/stm32u5xx_pinmap.h similarity index 99% rename from arch/arm/src/stm32u5/hardware/stm32u585xx_pinmap.h rename to arch/arm/src/stm32u5/hardware/stm32u5xx_pinmap.h index 9939e82c7d1..10921cf3de9 100644 --- a/arch/arm/src/stm32u5/hardware/stm32u585xx_pinmap.h +++ b/arch/arm/src/stm32u5/hardware/stm32u5xx_pinmap.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32u5/hardware/stm32u585xx_pinmap.h + * arch/arm/src/stm32u5/hardware/stm32u5xx_pinmap.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_PINMAP_H -#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_PINMAP_H +#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_PINMAP_H +#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_PINMAP_H /**************************************************************************** * Included Files @@ -409,8 +409,8 @@ #define GPIO_I2C1_SCL_2 (GPIO_ALT|GPIO_AF4|GPIO_PORTB|GPIO_PIN8) #define GPIO_I2C1_SCL_3 (GPIO_ALT|GPIO_AF4|GPIO_PORTG|GPIO_PIN14) #define GPIO_I2C1_SDA_1 (GPIO_ALT|GPIO_AF4|GPIO_PORTB|GPIO_PIN3) -#define GPIO_I2C1_SDA_2 (GPIO_ALT|GPIO_AF4|GPIO_PORTB|GPIO_PIN7) -#define GPIO_I2C1_SDA_3 (GPIO_ALT|GPIO_AF4|GPIO_PORTB|GPIO_PIN9) +#define GPIO_I2C1_SDA_3 (GPIO_ALT|GPIO_AF4|GPIO_PORTB|GPIO_PIN7) +#define GPIO_I2C1_SDA_2 (GPIO_ALT|GPIO_AF4|GPIO_PORTB|GPIO_PIN9) #define GPIO_I2C1_SDA_4 (GPIO_ALT|GPIO_AF4|GPIO_PORTG|GPIO_PIN13) #define GPIO_I2C1_SMBA_1 (GPIO_ALT|GPIO_AF4|GPIO_PORTA|GPIO_PIN1) #define GPIO_I2C1_SMBA_2 (GPIO_ALT|GPIO_AF4|GPIO_PORTA|GPIO_PIN14) @@ -666,15 +666,15 @@ #define GPIO_OCTOSPIM_P2_NCS_4 (GPIO_ALT|GPIO_AF5|GPIO_PORTI|GPIO_PIN5) #define GPIO_OCTOSPIM_P2_NCS_5 (GPIO_ALT|GPIO_AF10|GPIO_PORTD|GPIO_PIN3) -/* OTG_FS - USB on-the-go full-speed */ +/* OTG_HS - USB on-the-go high-speed */ -#define GPIO_OTG_FS_DM_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN11) -#define GPIO_OTG_FS_DP_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN12) -#define GPIO_OTG_FS_ID_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN10) -#define GPIO_OTG_FS_NOE_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN13) -#define GPIO_OTG_FS_NOE_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTC|GPIO_PIN9) -#define GPIO_OTG_FS_SOF_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN8) -#define GPIO_OTG_FS_SOF_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN14) +#define GPIO_OTG_HS_DM_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN11) +#define GPIO_OTG_HS_DP_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN12) +#define GPIO_OTG_HS_ID_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN10) +#define GPIO_OTG_HS_NOE_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN13) +#define GPIO_OTG_HS_NOE_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTC|GPIO_PIN9) +#define GPIO_OTG_HS_SOF_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN8) +#define GPIO_OTG_HS_SOF_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN14) /* PSSI - Parallel synchronous slave interface */ @@ -1177,4 +1177,4 @@ #define GPIO_USART3_TX_4 (GPIO_ALT|GPIO_AF7|GPIO_PORTC|GPIO_PIN10) #define GPIO_USART3_TX_5 (GPIO_ALT|GPIO_AF7|GPIO_PORTD|GPIO_PIN8) -#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_PINMAP_H */ +#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_PINMAP_H */ diff --git a/arch/arm/src/stm32u5/hardware/stm32u585xx_rcc.h b/arch/arm/src/stm32u5/hardware/stm32u5xx_rcc.h similarity index 99% rename from arch/arm/src/stm32u5/hardware/stm32u585xx_rcc.h rename to arch/arm/src/stm32u5/hardware/stm32u5xx_rcc.h index d299821624d..5fc23eca112 100644 --- a/arch/arm/src/stm32u5/hardware/stm32u585xx_rcc.h +++ b/arch/arm/src/stm32u5/hardware/stm32u5xx_rcc.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32u5/hardware/stm32u585xx_rcc.h + * arch/arm/src/stm32u5/hardware/stm32u5xx_rcc.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585xx_RCC_H -#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585xx_RCC_H +#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5xx_RCC_H +#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5xx_RCC_H /**************************************************************************** * Included Files @@ -27,7 +27,10 @@ #include -#if defined(CONFIG_STM32U5_STM32U585XX) +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) || \ + defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) || \ + defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || \ + defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) /**************************************************************************** * Pre-processor Definitions @@ -416,6 +419,7 @@ #define RCC_AHB2ENR1_ADC1EN (1 << 10) /* Bit 10: ADC1 interface enable */ #define RCC_AHB2ENR1_DCMI_PCSSI_EN (1 << 12) /* Bit 12: DCMI and PSSI enable */ #define RCC_AHB2ENR1_OTGEN (1 << 14) /* Bit 14: OTG_FS module enable */ +#define RCC_AHB2ENR1_OTGPHYEN (1 << 15) /* Bit 14: OTG_HS module PHY enable */ #define RCC_AHB2ENR1_AESEN (1 << 16) /* Bit 16: AES Cryptographic module enable */ #define RCC_AHB2ENR1_HASHEN (1 << 17) /* Bit 17: HASH module enable */ #define RCC_AHB2ENR1_RNGEN (1 << 18) /* Bit 18: Random number generator module enable */ @@ -434,6 +438,8 @@ #define RCC_AHB2ENR2_FSMCEN (1 << 0) /* Bit 0: FSMC clock enable */ #define RCC_AHB2ENR2_OCTOSPI1EN (1 << 4) /* Bit 4: OCTOSPI1 clock enable */ #define RCC_AHB2ENR2_OCTOSPI2EN (1 << 8) /* Bit 8: OCTOSPI2 clock enable */ +#define RCC_AHB2ENR2_SRAM6EN (1 << 30) /* Bit 30: SRAM6 clock enable */ +#define RCC_AHB2ENR2_SRAM5EN (1 << 31) /* Bit 31: SRAM5 clock enable */ /* RCC AHB3 peripheral clock enable register */ @@ -537,7 +543,6 @@ # define RCC_BCDR_LSIPREDIV_NONE 0 /* LSI not divided */ # define RCC_BCDR_LSIPREDIV_128 1 /* LSI divided by 128 */ -#if 0 #define RCC_CR_MSIRGSEL (1 << 3) /* Bit 3: MSI clock range selection */ #define RCC_CR_MSIRANGE_SHIFT (4) /* Bits 7-4: MSI clock range */ #define RCC_CR_MSIRANGE_MASK (0x0f << RCC_CR_MSIRANGE_SHIFT) @@ -1246,7 +1251,6 @@ # define RCC_CCIPR2_OSPISEL_SYSCLK (0 << RCC_CCIPR2_OSPISEL_SHIFT) # define RCC_CCIPR2_OSPISEL_MSI (1 << RCC_CCIPR2_OSPISEL_SHIFT) # define RCC_CCIPR2_OSPISEL_PLL48M1CLK (2 << RCC_CCIPR2_OSPISEL_SHIFT) -#endif -#endif /* CONFIG_STM32U5_STM32U585XX */ -#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_RCC_H */ +#endif /* CONFIG_STM32U5_STM32U5XX */ +#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_RCC_H */ diff --git a/arch/arm/src/stm32u5/hardware/stm32u585xx_spi.h b/arch/arm/src/stm32u5/hardware/stm32u5xx_spi.h similarity index 97% rename from arch/arm/src/stm32u5/hardware/stm32u585xx_spi.h rename to arch/arm/src/stm32u5/hardware/stm32u5xx_spi.h index 02dbfc2faed..ab6e2495386 100644 --- a/arch/arm/src/stm32u5/hardware/stm32u585xx_spi.h +++ b/arch/arm/src/stm32u5/hardware/stm32u5xx_spi.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32u5/hardware/stm32u585xx_spi.h + * arch/arm/src/stm32u5/hardware/stm32u5xx_spi.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_SPI_H -#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_SPI_H +#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_SPI_H +#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_SPI_H /**************************************************************************** * Included Files @@ -27,7 +27,10 @@ #include -#if defined(CONFIG_STM32U5_STM32U585XX) +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) || \ + defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) || \ + defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || \ + defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) /**************************************************************************** * Pre-processor Definitions @@ -403,5 +406,5 @@ #define SPI_UDRDR_UDRDR_MASK (0xffff << SPI_UDRDR_UDRDR_SHIFT) /* Bits 16-31: read zero */ -#endif /* CONFIG_STM32U5_STM32U585XX */ -#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_SPI_H */ +#endif /* CONFIG_STM32U5_STM32U5XX ... */ +#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_SPI_H */ diff --git a/arch/arm/src/stm32u5/hardware/stm32u585xx_syscfg.h b/arch/arm/src/stm32u5/hardware/stm32u5xx_syscfg.h similarity index 92% rename from arch/arm/src/stm32u5/hardware/stm32u585xx_syscfg.h rename to arch/arm/src/stm32u5/hardware/stm32u5xx_syscfg.h index dec2aa36cc6..75baf4ee7d2 100644 --- a/arch/arm/src/stm32u5/hardware/stm32u585xx_syscfg.h +++ b/arch/arm/src/stm32u5/hardware/stm32u5xx_syscfg.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32u5/hardware/stm32u585xx_syscfg.h + * arch/arm/src/stm32u5/hardware/stm32u5xx_syscfg.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_SYSCFG_H -#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_SYSCFG_H +#ifndef __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_SYSCFG_H +#define __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_SYSCFG_H /**************************************************************************** * Included Files @@ -28,7 +28,10 @@ #include #include "chip.h" -#if defined(CONFIG_STM32U5_STM32U585XX) +#if defined(CONFIG_STM32U5_STM32U535XX) || defined(CONFIG_STM32U5_STM32U545XX) || \ + defined(CONFIG_STM32U5_STM32U575XX) || defined(CONFIG_STM32U5_STM32U585XX) || \ + defined(CONFIG_STM32U5_STM32U59XX) || defined(CONFIG_STM32U5_STM32U59AXX) || \ + defined(CONFIG_STM32U5_STM32U5A5XX) || defined(CONFIG_STM32U5_STM32U5A9XX) /**************************************************************************** * Pre-processor Definitions @@ -131,5 +134,5 @@ #define SYSCFG_RSSCMDR_SHIFT 0 #define SYSCFG_RSSCMDR_MASK (0xFFFF << SYSCFG_RSSCMDR_SHIFT) -#endif /* CONFIG_STM32U5_STM32U585XX */ -#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U585XX_SYSCFG_H */ +#endif /* CONFIG_STM32U5_STM32U5XX ... */ +#endif /* __ARCH_ARM_SRC_STM32U5_HARDWARE_STM32U5XX_SYSCFG_H */ diff --git a/arch/arm/src/stm32u5/stm32_allocateheap.c b/arch/arm/src/stm32u5/stm32_allocateheap.c index 2af9095ab94..ba636c6cdc4 100644 --- a/arch/arm/src/stm32u5/stm32_allocateheap.c +++ b/arch/arm/src/stm32u5/stm32_allocateheap.c @@ -94,7 +94,7 @@ /* Set the range of system SRAM */ -#define SRAM1_START STM32_SRAM_BASE +#define SRAM1_START STM32_SRAM1_BASE #define SRAM1_END (SRAM1_START + STM32_SRAM1_SIZE) /* Set the range of SRAM2 as well, requires a second memory region */ @@ -109,6 +109,11 @@ # define SRAM3_END (SRAM3_START + STM32_SRAM3_SIZE) #endif +#ifdef STM32_SRAM5_SIZE +# define SRAM5_START STM32_SRAM5_BASE +# define SRAM5_END (SRAM3_START + STM32_SRAM5_SIZE) +#endif + /* Some sanity checking. If multiple memory regions are defined, verify * that CONFIG_MM_REGIONS is set to match the number of memory regions * that we have been asked to add to the heap. @@ -116,12 +121,14 @@ #if CONFIG_MM_REGIONS < defined(CONFIG_STM32U5_SRAM2_HEAP) + \ defined(CONFIG_STM32U5_SRAM3_HEAP) + \ + defined(CONFIG_STM32U5_SRAM5_HEAP) + \ defined(CONFIG_STM32U5_FSMC_SRAM_HEAP) + 1 # error "You need more memory manager regions to support selected heap components" #endif #if CONFIG_MM_REGIONS > defined(CONFIG_STM32U5_SRAM2_HEAP) + \ defined(CONFIG_STM32U5_SRAM3_HEAP) + \ + defined(CONFIG_STM32U5_SRAM5_HEAP) + \ defined(CONFIG_STM32U5_FSMC_SRAM_HEAP) + 1 # warning "CONFIG_MM_REGIONS large enough but I do not know what some of the region(s) are" #endif @@ -312,13 +319,13 @@ void arm_addregion(void) { #ifdef CONFIG_STM32U5_SRAM2_HEAP -#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) +# if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) /* Allow user-mode access to the SRAM2 heap */ stm32_mpu_uheap((uintptr_t)SRAM2_START, SRAM2_END - SRAM2_START); -#endif +# endif /* Colorize the heap for debug */ @@ -332,13 +339,13 @@ void arm_addregion(void) #ifdef CONFIG_STM32U5_SRAM3_HEAP -#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) +# if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) /* Allow user-mode access to the SRAM3 heap */ stm32_mpu_uheap((uintptr_t)SRAM3_START, SRAM3_END - SRAM3_START); -#endif +# endif /* Colorize the heap for debug */ @@ -350,14 +357,34 @@ void arm_addregion(void) #endif /* SRAM3 */ +#ifdef CONFIG_STM32U5_SRAM5_HEAP + +# if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) + + /* Allow user-mode access to the SRAM5 heap */ + + stm32_mpu_uheap((uintptr_t)SRAM5_START, STM32_SRAM5_SIZE); + +# endif + + /* Colorize the heap for debug */ + + up_heap_color((void *)SRAM5_START, STM32_SRAM5_SIZE); + + /* Add the SRAM5 user heap region. */ + + kumm_addregion((void *)SRAM5_START, STM32_SRAM5_SIZE); + +#endif /* SRAM5 */ + #ifdef CONFIG_STM32U5_FSMC_SRAM_HEAP -#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) +# if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) /* Allow user-mode access to the FSMC SRAM user heap memory */ stm32_mpu_uheap((uintptr_t)CONFIG_HEAP2_BASE, CONFIG_HEAP2_SIZE); -#endif +# endif /* Colorize the heap for debug */ diff --git a/arch/arm/src/stm32u5/stm32_dbgmcu.h b/arch/arm/src/stm32u5/stm32_dbgmcu.h index 946d6986ef7..0cc7575f20e 100644 --- a/arch/arm/src/stm32u5/stm32_dbgmcu.h +++ b/arch/arm/src/stm32u5/stm32_dbgmcu.h @@ -29,8 +29,8 @@ #include "chip.h" -#if defined(CONFIG_STM32U5_STM32U585XX) -# include "hardware/stm32u585xx_dbgmcu.h" +#if defined(CONFIG_STM32U5_STM32U585XX) || defined(CONFIG_STM32U5_STM32U5A5XX) +# include "hardware/stm32u5xx_dbgmcu.h" #else # error "Unsupported STM32U5 chip" #endif diff --git a/arch/arm/src/stm32u5/stm32_flash.c b/arch/arm/src/stm32u5/stm32_flash.c index 3733d61d22d..29fd142ac93 100644 --- a/arch/arm/src/stm32u5/stm32_flash.c +++ b/arch/arm/src/stm32u5/stm32_flash.c @@ -49,6 +49,8 @@ #include "arm_internal.h" #if !defined(CONFIG_STM32U5_STM32U585XX) +#elif !defined(CONFIG_STM32U5_STM32U5A5XX) +#else # error "Unrecognized STM32 chip" #endif diff --git a/arch/arm/src/stm32u5/stm32_gpio.h b/arch/arm/src/stm32u5/stm32_gpio.h index e55640b6073..f5fa9e8f36f 100644 --- a/arch/arm/src/stm32u5/stm32_gpio.h +++ b/arch/arm/src/stm32u5/stm32_gpio.h @@ -37,7 +37,7 @@ #include "chip.h" -#if defined(CONFIG_STM32U5_STM32U585XX) +#if defined(CONFIG_STM32U5_STM32U585XX) || defined(CONFIG_STM32U5_STM32U5A5XX) # include "hardware/stm32_gpio.h" #else # error "Unsupported STM32U5 chip" diff --git a/arch/arm/src/stm32u5/stm32_i2c.c b/arch/arm/src/stm32u5/stm32_i2c.c new file mode 100644 index 00000000000..3ef32968cc5 --- /dev/null +++ b/arch/arm/src/stm32u5/stm32_i2c.c @@ -0,0 +1,3078 @@ +/**************************************************************************** + * arch/arm/src/stm32u5/stm32_i2c.c + * STM32U5 I2C driver - based on STM32F7 I2C Hardware Layer - Device Driver + * + * Original STM32U5 I2C driver: + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise + * Copyright (C) 2011-2013, 2016-2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * Author: John Wharington + * Author: Sebastien Lorquet + * Author: dev@ziggurat29.com + * + * STM32U5 I2C driver based on STM32F7 I2C driver: + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise + * + * With extensions and modifications for the F1, F2, and F4 by: + * + * Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * John Wharington + * David Sidrane + * + * Major rewrite of ISR and supporting methods, including support + * for NACK and RELOAD by: + * + * Copyright (c) 2016 Doug Vetter. All rights reserved. + * Author: Doug Vetter + * + * Port from STM32F7 to STM32U5: + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* -------------------------------------------------------------------------- + * + * STM32 L4 I2C Driver based on STM32 F7 I2C Driver: + * + * STM32 L4 and F7 peripheral differences: + * - I2C Peripheral on these families are identical (incl. errata) except + * for I2C_CR1 register bit 18: + * STM32F7: reserved + * STM32U5: WUPEN, Wakeup from Stop mode enable. Requires use of HSI + * clock for I2C (RCC_CCIPR_I2CxSEL=HSI). + * + * Supports: + * - Master operation: + * Standard-mode (up to 100 kHz) + * Fast-mode (up to 400 kHz) + * fI2CCLK clock source selection is based on RCC_CCIPR_I2CxSEL + * being set to PCLK and the calculations are based on PCLK frequency + * of 80 MHz + * + * - Multiple instances (shared bus) + * - Interrupt based operation + * - RELOAD support + * - I2C_M_NOSTART support + * + * Test Environment: + * - STM32L451CEU6 based board with I2C slaves LIS2DH accelerometer and + * BQ24296 charger + * + * Supported on STM32F7 driver, untested on STM32U5: + * - Master operation: + * Fast-mode Plus (up to 1 MHz) + * - Test Environment: + * STM32F7676ZI on ST Nucleo-144 Board (ST Part STM32F429ZIT6) + * + * Unsupported, possible future work: + * - Wakeup from Stop mode + * - More effective error reporting to higher layers + * - Slave operation + * - Support of fI2CCLK frequencies other than 80 MHz and other clock + * sources + * - Polled operation (code present but untested) + * - SMBus support + * - Multi-master support + * - IPMI + * + * Operational Status: + * + * All supported features have been tested and found to be operational. + * + * Although the RELOAD capability has been tested as it was required to + * implement the I2C_M_NOSTART flag on F3 hardware, the associated + * logic to support the transfer messages with more than 255 byte + * payloads has not been tested as the author lacked access to a real + * device supporting these types of transfers. + * + * Performance Benchmarks: TBD + * + * Time to transfer two messages, each a byte in length, in addition to the + * START condition, in interrupt mode: + * + * DEBUG enabled (development): TBDms + * Excessive delay here is caused by printing to the console and + * is of no concern. + * + * DEBUG disabled (production): TBSus + * Between Messages: TBDus + * Between Bytes: TBDus + * + * Implementation: + * + * - Device: structure as defined by the nuttx/i2c/i2c.h + * + * - Instance: represents each individual access to the I2C driver, obtained + * by the i2c_init(); it extends the Device structure from the + * nuttx/i2c/i2c.h; + * Instance points to OPS, to common I2C Hardware private data and + * contains its own private data including frequency, address and mode + * of operation. + * + * - Private: Private data of an I2C Hardware + * + * High Level Functional Desecription + * + * This driver works with I2C "messages" (struct i2c_msg_s), which carry a + * buffer intended to transfer data to, or store data read from, the I2C bus. + * + * As the hardware can only transmit or receive one byte at a time the basic + * job of the driver (and the ISR specifically) is to process each message in + * the order they are stored in the message list, one byte at a time. When + * no messages are left the ISR exits and returns the result to the caller. + * + * The order of the list of I2C messages provided to the driver is important + * and dependent upon the hardware in use. A typical I2C transaction between + * the F3 as an I2C Master and some other IC as a I2C Slave requires two + * messages that communicate the: + * + * 1) Subaddress (register offset on the slave device) + * 2) Data sent to or read from the device + * + * These messages will typically be one byte in length but may be up to 2^31 + * bytes in length. Incidentally, the maximum length is limited only because + * i2c_msg_s.length is a signed int for some odd reason. + * + * Interrupt mode relies on the following interrupt events: + * + * TXIS - Transmit interrupt + * (data transmitted to bus and acknowedged) + * NACKF - Not Acknowledge Received + * (data transmitted to bus and NOT acknowledged) + * RXNE - Receive interrupt + * (data received from bus) + * TC - Transfer Complete + * (All bytes in message transferred) + * TCR - Transfer Complete (Reload) + * (Current batch of bytes in message transferred) + * + * The driver currently supports Single Master mode only. Slave mode is not + * supported. Additionally, the driver runs in Software End Mode (AUTOEND + * disabled) so the driver is responsible for telling the hardware what to + * do at the end of a transfer. + * + * -------------------------------------------------------------------------- + * + * Configuration: + * + * To use this driver, enable the following configuration variable: + * + * CONFIG_STM32U5_I2C + * + * and one or more interfaces: + * + * CONFIG_STM32U5_I2C1 + * CONFIG_STM32U5_I2C2 + * CONFIG_STM32U5_I2C3 + * CONFIG_STM32U5_I2C4 + * + * To configure the ISR timeout using fixed values + * (CONFIG_STM32U5_I2C_DYNTIMEO=n): + * + * CONFIG_STM32U5_I2CTIMEOSEC (Timeout in seconds) + * CONFIG_STM32U5_I2CTIMEOMS (Timeout in milliseconds) + * CONFIG_STM32U5_I2CTIMEOTICKS (Timeout in ticks) + * + * To configure the ISR timeout using dynamic values + * (CONFIG_STM32U5_I2C_DYNTIMEO=y): + * + * CONFIG_STM32U5_I2C_DYNTIMEO_USECPERBYTE + * (Timeout in microseconds per byte) + * CONFIG_STM32U5_I2C_DYNTIMEO_STARTSTOP + * (Timeout for start/stop inmilliseconds) + * + * Debugging output enabled with: + * + * CONFIG_DEBUG_FEATURES and CONFIG_DEBUG_I2C_{ERROR|WARN|INFO} + * + * ISR Debugging output may be enabled with: + * + * CONFIG_DEBUG_FEATURES and CONFIG_DEBUG_I2C_INFO + * + * -------------------------------------------------------------------------- + * + * References (STM32F7): + * + * RM0316: + * ST STM32F76xxx and STM32F77xxx Reference Manual + * Document ID: DocID028270 Revision 2, April 2016. + * + * DATASHEET: + * ST STM32F777xx/STM32F778Ax/STM32F779x Datasheet + * Document ID: DocID028294, Revision 3, May 2016. + * + * ERRATA: + * STM32F76xxx/STM32F77xxx Errata sheet Rev A device limitations + * Document ID: DocID028806, Revision 2, April 2016. + * + * I2CSPEC: + * I2C Bus Specification and User Manual + * Document ID: UM10204, Revision 6, April 2014. + * + * References (STM32U5): + * + * RM0394: + * ST STM32L43xxx STM32L44xxx STM32L45xxx STM32L46xxx Reference Manual + * Document ID: DocID027295, Revision 3, April 2017. + * + * ERRATA: + * STM32L451xx Errata sheet device limitations + * Document ID: DocID030061, Revision 4, September 2017. + * + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "stm32_gpio.h" +#include "stm32_rcc.h" +#include "stm32_i2c.h" +#include "stm32_waste.h" + +/* At least one I2C peripheral must be enabled */ + +#if defined(CONFIG_STM32U5_I2C1) || defined(CONFIG_STM32U5_I2C2) || \ + defined(CONFIG_STM32U5_I2C3) || defined(CONFIG_STM32U5_I2C4) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. + * Instead, CPU-intensive polling will be used. + */ + +/* Interrupt wait timeout in seconds and milliseconds */ + +#if !defined(CONFIG_STM32U5_I2CTIMEOSEC) && !defined(CONFIG_STM32U5_I2CTIMEOMS) +# define CONFIG_STM32U5_I2CTIMEOSEC 0 +# define CONFIG_STM32U5_I2CTIMEOMS 500 /* Default is 500 milliseconds */ +# warning "Using Default 500 Ms Timeout" +#elif !defined(CONFIG_STM32U5_I2CTIMEOSEC) +# define CONFIG_STM32U5_I2CTIMEOSEC 0 /* User provided milliseconds */ +#elif !defined(CONFIG_STM32U5_I2CTIMEOMS) +# define CONFIG_STM32U5_I2CTIMEOMS 0 /* User provided seconds */ +#endif + +/* Interrupt wait time timeout in system timer ticks */ + +#ifndef CONFIG_STM32U5_I2CTIMEOTICKS +# define CONFIG_STM32U5_I2CTIMEOTICKS \ + (SEC2TICK(CONFIG_STM32U5_I2CTIMEOSEC) + MSEC2TICK(CONFIG_STM32U5_I2CTIMEOMS)) +#endif + +#ifndef CONFIG_STM32U5_I2C_DYNTIMEO_STARTSTOP +# define CONFIG_STM32U5_I2C_DYNTIMEO_STARTSTOP TICK2USEC(CONFIG_STM32U5_I2CTIMEOTICKS) +#endif + +/* Macros to convert a I2C pin to a GPIO output */ + +#define I2C_OUTPUT (GPIO_OUTPUT | GPIO_FLOAT | GPIO_OPENDRAIN | \ + GPIO_SPEED_50MHz | GPIO_OUTPUT_SET) + +#define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT) + +#define I2C_CR1_TXRX (I2C_CR1_RXIE | I2C_CR1_TXIE) +#define I2C_CR1_ALLINTS (I2C_CR1_TXRX | I2C_CR1_TCIE | I2C_CR1_ERRIE) + +/* I2C event tracing + * + * To enable tracing statements which show the details of the state machine + * enable the following configuration variable: + * + * CONFIG_I2C_TRACE + * + * Note: This facility uses syslog, which sends output to the console by + * default. No other debug configuration variables are required. + */ + +#ifndef CONFIG_I2C_TRACE +# define stm32_i2c_tracereset(p) +# define stm32_i2c_tracenew(p,s) +# define stm32_i2c_traceevent(p,e,a) +# define stm32_i2c_tracedump(p) +#endif + +#ifndef CONFIG_I2C_NTRACE +# define CONFIG_I2C_NTRACE 32 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Interrupt state */ + +enum stm32_intstate_e +{ + INTSTATE_IDLE = 0, /* No I2C activity */ + INTSTATE_WAITING, /* Waiting for completion of interrupt activity */ + INTSTATE_DONE, /* Interrupt activity complete */ +}; + +/* Trace events */ + +enum stm32_trace_e +{ + I2CEVENT_NONE = 0, + I2CEVENT_STATE_ERROR, + I2CEVENT_ISR_SHUTDOWN, + I2CEVENT_ISR_CALL, + I2CEVENT_ISR_EMPTY_CALL, + I2CEVENT_MSG_HANDLING, + I2CEVENT_POLL_NOT_READY, + I2CEVENT_EMPTY_MSG, + I2CEVENT_START, + I2CEVENT_ADDRESS_ACKED, + I2CEVENT_ADDRESS_NACKED, + I2CEVENT_NACK, + I2CEVENT_READ, + I2CEVENT_READ_ERROR, + I2CEVENT_WRITE_TO_DR, + I2CEVENT_WRITE_STOP, + I2CEVENT_WRITE_RESTART, + I2CEVENT_WRITE_NO_RESTART, + I2CEVENT_WRITE_ERROR, + I2CEVENT_WRITE_FLAG_ERROR, + I2CEVENT_TC_RESTART, + I2CEVENT_TC_NO_RESTART +}; + +/* Trace data */ + +struct stm32_trace_s +{ + uint32_t status; /* I2C 32-bit SR2|SR1 status */ + uint32_t count; /* Interrupt count when status change */ + enum stm32_intstate_e event; /* Last event that occurred with this status */ + uint32_t parm; /* Parameter associated with the event */ + clock_t time; /* First of event or first status */ +}; + +/* I2C Device hardware configuration */ + +struct stm32_i2c_config_s +{ + uint32_t base; /* I2C base address */ + uint32_t clk_bit; /* Clock enable bit */ + uint32_t reset_bit; /* Reset bit */ + uint32_t scl_pin; /* GPIO configuration for SCL as SCL */ + uint32_t sda_pin; /* GPIO configuration for SDA as SDA */ +#ifndef CONFIG_I2C_POLLED + uint32_t ev_irq; /* Event IRQ */ + uint32_t er_irq; /* Error IRQ */ +#endif +}; + +/* I2C Device Private Data */ + +struct stm32_i2c_priv_s +{ + /* Port configuration */ + + const struct stm32_i2c_config_s *config; + + int refs; /* Reference count */ + mutex_t lock; /* Mutual exclusion mutex */ +#ifndef CONFIG_I2C_POLLED + sem_t sem_isr; /* Interrupt wait semaphore */ +#endif + volatile uint8_t intstate; /* Interrupt handshake (see enum stm32_intstate_e) */ + + uint8_t msgc; /* Message count */ + struct i2c_msg_s *msgv; /* Message list */ + uint8_t *ptr; /* Current message buffer */ + uint32_t frequency; /* Current I2C frequency */ + int dcnt; /* Current message bytes remaining to transfer */ + uint16_t flags; /* Current message flags */ + bool astart; /* START sent */ + + /* I2C trace support */ + +#ifdef CONFIG_I2C_TRACE + int tndx; /* Trace array index */ + clock_t start_time; /* Time when the trace was started */ + + /* The actual trace data */ + + struct stm32_trace_s trace[CONFIG_I2C_NTRACE]; +#endif + + uint32_t status; /* End of transfer SR2|SR1 status */ + +#ifdef CONFIG_PM + struct pm_callback_s pm_cb; /* PM callbacks */ +#endif +}; + +/* I2C Device, Instance */ + +struct stm32_i2c_inst_s +{ + const struct i2c_ops_s *ops; /* Standard I2C operations */ + struct stm32_i2c_priv_s *priv; /* Common driver private data structure */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline +uint16_t stm32_i2c_getreg(struct stm32_i2c_priv_s *priv, + uint8_t offset); +static inline +void stm32_i2c_putreg(struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value); +static inline +void stm32_i2c_putreg32(struct stm32_i2c_priv_s *priv, + uint8_t offset, uint32_t value); +static inline +void stm32_i2c_modifyreg32(struct stm32_i2c_priv_s *priv, + uint8_t offset, uint32_t clearbits, + uint32_t setbits); +#ifdef CONFIG_STM32U5_I2C_DYNTIMEO +static uint32_t stm32_i2c_toticks(int msgc, struct i2c_msg_s *msgs); +#endif /* CONFIG_STM32U5_I2C_DYNTIMEO */ +static inline +int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv); +static inline +void stm32_i2c_sem_waitstop(struct stm32_i2c_priv_s *priv); +#ifdef CONFIG_I2C_TRACE +static void stm32_i2c_tracereset(struct stm32_i2c_priv_s *priv); +static void stm32_i2c_tracenew(struct stm32_i2c_priv_s *priv, + uint32_t status); +static void +stm32_i2c_traceevent(struct stm32_i2c_priv_s *priv, + enum stm32_trace_e event, uint32_t parm); +static void stm32_i2c_tracedump(struct stm32_i2c_priv_s *priv); +#endif /* CONFIG_I2C_TRACE */ +static void stm32_i2c_setclock(struct stm32_i2c_priv_s *priv, + uint32_t frequency); +static inline +void stm32_i2c_sendstart(struct stm32_i2c_priv_s *priv); +static inline void stm32_i2c_sendstop(struct stm32_i2c_priv_s *priv); +static inline +uint32_t stm32_i2c_getstatus(struct stm32_i2c_priv_s *priv); +static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv); +#ifndef CONFIG_I2C_POLLED +static int stm32_i2c_isr(int irq, void *context, void *arg); +#endif +static int stm32_i2c_init(struct stm32_i2c_priv_s *priv); +static int stm32_i2c_deinit(struct stm32_i2c_priv_s *priv); + +static int stm32_i2c_process(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count); +static int stm32_i2c_transfer(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int stm32_i2c_reset(struct i2c_master_s *dev); +#endif +#ifdef CONFIG_PM +static int stm32_i2c_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_STM32U5_I2C1 +static const struct stm32_i2c_config_s stm32_i2c1_config = +{ + .base = STM32_I2C1_BASE, + .clk_bit = RCC_APB1ENR1_I2C1EN, + .reset_bit = RCC_APB1RSTR1_I2C1RST, + .scl_pin = GPIO_I2C1_SCL, + .sda_pin = GPIO_I2C1_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = STM32_IRQ_I2C1_EV, + .er_irq = STM32_IRQ_I2C1_ER +#endif +}; + +static struct stm32_i2c_priv_s stm32_i2c1_priv = +{ + .config = &stm32_i2c1_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_i2c_pm_prepare, +#endif +}; +#endif + +#ifdef CONFIG_STM32U5_I2C2 +static const struct stm32_i2c_config_s stm32_i2c2_config = +{ + .base = STM32_I2C2_BASE, + .clk_bit = RCC_APB1ENR1_I2C2EN, + .reset_bit = RCC_APB1RSTR1_I2C2RST, + .scl_pin = GPIO_I2C2_SCL, + .sda_pin = GPIO_I2C2_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = STM32_IRQ_I2C2_EV, + .er_irq = STM32_IRQ_I2C2_ER +#endif +}; + +static struct stm32_i2c_priv_s stm32_i2c2_priv = +{ + .config = &stm32_i2c2_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_i2c_pm_prepare, +#endif +}; +#endif + +#ifdef CONFIG_STM32U5_I2C3 +static const struct stm32_i2c_config_s stm32_i2c3_config = +{ + .base = STM32_I2C3_BASE, + .clk_bit = RCC_APB1ENR1_I2C3EN, + .reset_bit = RCC_APB1RSTR1_I2C3RST, + .scl_pin = GPIO_I2C3_SCL, + .sda_pin = GPIO_I2C3_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = STM32_IRQ_I2C3_EV, + .er_irq = STM32_IRQ_I2C3_ER +#endif +}; + +static struct stm32_i2c_priv_s stm32_i2c3_priv = +{ + .config = &stm32_i2c3_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_i2c_pm_prepare, +#endif +}; +#endif + +#ifdef CONFIG_STM32U5_I2C4 +static const struct stm32_i2c_config_s stm32_i2c4_config = +{ + .base = STM32_I2C4_BASE, + .clk_bit = RCC_APB1ENR2_I2C4EN, + .reset_bit = RCC_APB1RSTR2_I2C4RST, + .scl_pin = GPIO_I2C4_SCL, + .sda_pin = GPIO_I2C4_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = STM32_IRQ_I2C4_EV, + .er_irq = STM32_IRQ_I2C4_ER +#endif +}; + +static struct stm32_i2c_priv_s stm32_i2c4_priv = +{ + .config = &stm32_i2c4_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_i2c_pm_prepare, +#endif +}; +#endif + +/* Device Structures, Instantiation */ + +static const struct i2c_ops_s stm32_i2c_ops = +{ + .transfer = stm32_i2c_transfer +#ifdef CONFIG_I2C_RESET + , .reset = stm32_i2c_reset +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_i2c_getreg + * + * Description: + * Get a 16-bit register value by offset + * + ****************************************************************************/ + +static inline +uint16_t stm32_i2c_getreg(struct stm32_i2c_priv_s *priv, + uint8_t offset) +{ + return getreg16(priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32_i2c_getreg32 + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static inline +uint32_t stm32_i2c_getreg32(struct stm32_i2c_priv_s *priv, + uint8_t offset) +{ + return getreg32(priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32_i2c_putreg + * + * Description: + * Put a 16-bit register value by offset + * + ****************************************************************************/ + +static inline void stm32_i2c_putreg(struct stm32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) +{ + putreg16(value, priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32_i2c_putreg32 + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void stm32_i2c_putreg32(struct stm32_i2c_priv_s *priv, + uint8_t offset, uint32_t value) +{ + putreg32(value, priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32_i2c_modifyreg32 + * + * Description: + * Modify a 32-bit register value by offset + * + ****************************************************************************/ + +static inline +void stm32_i2c_modifyreg32(struct stm32_i2c_priv_s *priv, + uint8_t offset, uint32_t clearbits, + uint32_t setbits) +{ + modifyreg32(priv->config->base + offset, clearbits, setbits); +} + +/**************************************************************************** + * Name: stm32_i2c_toticks + * + * Description: + * Return a micro-second delay based on the number of bytes left to be + * processed. + * + ****************************************************************************/ + +#ifdef CONFIG_STM32U5_I2C_DYNTIMEO +static uint32_t stm32_i2c_toticks(int msgc, struct i2c_msg_s *msgs) +{ + size_t bytecount = 0; + int i; + + /* Count the number of bytes left to process */ + + for (i = 0; i < msgc; i++) + { + bytecount += msgs[i].length; + } + + /* Then return a number of microseconds based on a user provided scaling + * factor. + */ + + return USEC2TICK(CONFIG_STM32U5_I2C_DYNTIMEO_USECPERBYTE * bytecount); +} +#endif + +/**************************************************************************** + * Name: stm32_i2c_enableinterrupts + * + * Description: + * Enable I2C interrupts + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static inline +void stm32_i2c_enableinterrupts(struct stm32_i2c_priv_s *priv) +{ + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, + (I2C_CR1_TXRX | I2C_CR1_NACKIE)); +} +#endif + +/**************************************************************************** + * Name: stm32_i2c_sem_waitdone + * + * Description: + * Wait for a transfer to complete + * + * There are two versions of this function. The first is included when using + * interrupts while the second is used if polling (CONFIG_I2C_POLLED=y). + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static inline +int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) +{ + irqstate_t flags; + int ret; + + flags = enter_critical_section(); + + /* Enable I2C interrupts */ + + /* The TXIE and RXIE interrupts are enabled initially in + * stm32_i2c_process. The remainder of the interrupts, including + * error-related, are enabled here. + */ + + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, + (I2C_CR1_ALLINTS & ~I2C_CR1_TXRX)); + + /* Signal the interrupt handler that we are waiting */ + + priv->intstate = INTSTATE_WAITING; + do + { + /* Wait until either the transfer is complete or the timeout expires */ + +#ifdef CONFIG_STM32U5_I2C_DYNTIMEO + ret = nxsem_tickwait_uninterruptible(&priv->sem_isr, + stm32_i2c_toticks(priv->msgc, priv->msgv)); +#else + ret = nxsem_tickwait_uninterruptible(&priv->sem_isr, + CONFIG_STM32U5_I2CTIMEOTICKS); +#endif + if (ret < 0) + { + /* Break out of the loop on irrecoverable errors. This would + * include timeouts and mystery errors reported by + * nxsem_tickwait_uninterruptible. + */ + + break; + } + } + + /* Loop until the interrupt level transfer is complete. */ + + while (priv->intstate != INTSTATE_DONE); + + /* Set the interrupt state back to IDLE */ + + priv->intstate = INTSTATE_IDLE; + + /* Disable I2C interrupts */ + + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ALLINTS, 0); + + leave_critical_section(flags); + return ret; +} +#else +static inline +int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) +{ + clock_t timeout; + clock_t start; + clock_t elapsed; + int ret; + + /* Get the timeout value */ + +#ifdef CONFIG_STM32U5_I2C_DYNTIMEO + timeout = stm32_i2c_toticks(priv->msgc, priv->msgv); +#else + timeout = CONFIG_STM32U5_I2CTIMEOTICKS; +#endif + + /* Signal the interrupt handler that we are waiting. NOTE: Interrupts + * are currently disabled but will be temporarily re-enabled below when + * nxsem_tickwait_uninterruptible() sleeps. + */ + + priv->intstate = INTSTATE_WAITING; + start = clock_systime_ticks(); + + do + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + + /* Poll by simply calling the timer interrupt handler until it + * reports that it is done. + */ + + stm32_i2c_isr_process(priv); + } + + /* Loop until the transfer is complete. */ + + while (priv->intstate != INTSTATE_DONE && elapsed < timeout); + + i2cinfo("intstate: %d elapsed: %ld threshold: %ld status: 0x%08x\n", + priv->intstate, (long)elapsed, (long)timeout, priv->status); + + /* Set the interrupt state back to IDLE */ + + ret = priv->intstate == INTSTATE_DONE ? OK : -ETIMEDOUT; + priv->intstate = INTSTATE_IDLE; + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_i2c_set_7bit_address + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32_i2c_set_7bit_address(struct stm32_i2c_priv_s *priv) +{ + stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_SADD7_MASK, + ((priv->msgv->addr & 0x7f) << I2C_CR2_SADD7_SHIFT)); +} + +/**************************************************************************** + * Name: stm32_i2c_set_bytes_to_transfer + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32_i2c_set_bytes_to_transfer(struct stm32_i2c_priv_s *priv, + uint8_t n_bytes) +{ + stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_NBYTES_MASK, + (n_bytes << I2C_CR2_NBYTES_SHIFT)); +} + +/**************************************************************************** + * Name: stm32_i2c_set_write_transfer_dir + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32_i2c_set_write_transfer_dir(struct stm32_i2c_priv_s *priv) +{ + stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_RD_WRN, 0); +} + +/**************************************************************************** + * Name: stm32_i2c_set_read_transfer_dir + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32_i2c_set_read_transfer_dir(struct stm32_i2c_priv_s *priv) +{ + stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, + 0, I2C_CR2_RD_WRN); +} + +/**************************************************************************** + * Name: stm32_i2c_enable_reload + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32_i2c_enable_reload(struct stm32_i2c_priv_s *priv) +{ + stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, + 0, I2C_CR2_RELOAD); +} + +/**************************************************************************** + * Name: stm32_i2c_disable_reload + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32_i2c_disable_reload(struct stm32_i2c_priv_s *priv) +{ + stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, + I2C_CR2_RELOAD, 0); +} + +/**************************************************************************** + * Name: stm32_i2c_sem_waitstop + * + * Description: + * Wait for a STOP to complete + * + ****************************************************************************/ + +static inline +void stm32_i2c_sem_waitstop(struct stm32_i2c_priv_s *priv) +{ + clock_t start; + clock_t elapsed; + clock_t timeout; + uint32_t cr; + uint32_t sr; + + /* Select a timeout */ + +#ifdef CONFIG_STM32U5_I2C_DYNTIMEO + timeout = USEC2TICK(CONFIG_STM32U5_I2C_DYNTIMEO_STARTSTOP); +#else + timeout = CONFIG_STM32U5_I2CTIMEOTICKS; +#endif + + /* Wait as stop might still be in progress */ + + start = clock_systime_ticks(); + do + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + + /* Check for STOP condition */ + + cr = stm32_i2c_getreg32(priv, STM32_I2C_CR2_OFFSET); + if ((cr & I2C_CR2_STOP) == 0) + { + return; + } + + /* Check for timeout error */ + + sr = stm32_i2c_getreg(priv, STM32_I2C_ISR_OFFSET); + if ((sr & I2C_INT_TIMEOUT) != 0) + { + return; + } + } + + /* Loop until the stop is complete or a timeout occurs. */ + + while (elapsed < timeout); + + /* If we get here then a timeout occurred with the STOP condition + * still pending. + */ + + i2cinfo("Timeout with CR: %04" PRIx32 " SR: %04" PRIx32 "\n", cr, sr); +} + +/**************************************************************************** + * Name: stm32_i2c_trace* + * + * Description: + * I2C trace instrumentation + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_TRACE +static void stm32_i2c_traceclear(struct stm32_i2c_priv_s *priv) +{ + struct stm32_trace_s *trace = &priv->trace[priv->tndx]; + + trace->status = 0; /* I2C 32-bit status */ + trace->count = 0; /* Interrupt count when status change */ + trace->event = I2CEVENT_NONE; /* Last event that occurred with this status */ + trace->parm = 0; /* Parameter associated with the event */ + trace->time = 0; /* Time of first status or event */ +} + +static void stm32_i2c_tracereset(struct stm32_i2c_priv_s *priv) +{ + /* Reset the trace info for a new data collection */ + + priv->tndx = 0; + priv->start_time = clock_systime_ticks(); + stm32_i2c_traceclear(priv); +} + +static void stm32_i2c_tracenew(struct stm32_i2c_priv_s *priv, + uint32_t status) +{ + struct stm32_trace_s *trace = &priv->trace[priv->tndx]; + + /* Is the current entry uninitialized? Has the status changed? */ + + if (trace->count == 0 || status != trace->status) + { + /* Yes.. Was it the status changed? */ + + if (trace->count != 0) + { + /* Yes.. bump up the trace index + * (unless we are out of trace entries) + */ + + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) + { + i2cerr("ERROR: Trace table overflow\n"); + return; + } + + priv->tndx++; + trace = &priv->trace[priv->tndx]; + } + + /* Initialize the new trace entry */ + + stm32_i2c_traceclear(priv); + trace->status = status; + trace->count = 1; + trace->time = clock_systime_ticks(); + } + else + { + /* Just increment the count of times that we have seen this status */ + + trace->count++; + } +} + +static void stm32_i2c_traceevent(struct stm32_i2c_priv_s *priv, + enum stm32_trace_e event, uint32_t parm) +{ + struct stm32_trace_s *trace; + + if (event != I2CEVENT_NONE) + { + trace = &priv->trace[priv->tndx]; + + /* Initialize the new trace entry */ + + trace->event = event; + trace->parm = parm; + + /* Bump up the trace index (unless we are out of trace entries) */ + + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) + { + i2cerr("ERROR: Trace table overflow\n"); + return; + } + + priv->tndx++; + stm32_i2c_traceclear(priv); + } +} + +static void stm32_i2c_tracedump(struct stm32_i2c_priv_s *priv) +{ + struct stm32_trace_s *trace; + int i; + + syslog(LOG_DEBUG, "Elapsed time: %d\n", + (int)(clock_systime_ticks() - priv->start_time)); + + for (i = 0; i < priv->tndx; i++) + { + trace = &priv->trace[i]; + syslog(LOG_DEBUG, + "%2d. STATUS: %08x COUNT: %3d EVENT: %2d PARM: %08x TIME: %d\n", + i + 1, trace->status, trace->count, trace->event, trace->parm, + (int)(trace->time - priv->start_time)); + } +} +#endif /* CONFIG_I2C_TRACE */ + +/**************************************************************************** + * Name: stm32_i2c_setclock + * + * Description: + * + * Sets the I2C bus clock frequency by configuring the I2C_TIMINGR + * register. + * + * This function supports bus clock frequencies of: + * + * 1000Khz (Fast Mode+) + * 400Khz (Fast Mode) + * 100Khz (Standard Mode) + * 10Khz (Standard Mode) + * + * Attempts to set a different frequency will quietly provision the default + * of 10Khz. + * + * The only differences between the various modes of operation (std, fast, + * fast+) are the bus clock speed and setup/hold times. Setup/hold times + * are specified as a MINIMUM time for the given mode, and naturally std + * mode has the longest minimum times. As a result, by provisioning + * setup/hold times for std mode they are also compatible with fast/fast+, + * though some performance degradation occurs in fast/fast+ as a result of + * the times being somewhat longer than strictly required. The values + * remain as they are because reliability is favored over performance. + * + * Clock Selection: + * + * The I2C peripheral clock can be provided by either PCLK1, SYSCLK or the + * HSI. + * + * PCLK1 >------|\ I2CCLK + * SYSCLK >------| |---------> + * HSI >------|/ + * + * PCLK is the default and is expected to be 80Mhz. + * + * SYSCLK can, in turn, be derived from the HSI, HSE, PPLCLK. + * + * HSI >------|\ + * | | SYSCLK + * PLL >------| |---------> + * | | + * HSE >------|/ + * + * + * References: + * + * App Note AN4235 and the associated software STSW-STM32126. + * + ****************************************************************************/ + +static void stm32_i2c_setclock(struct stm32_i2c_priv_s *priv, + uint32_t frequency) +{ + int i2cclk_mhz; + uint32_t pe; + uint8_t presc = 0; + uint8_t scl_delay = 0; + uint8_t sda_delay = 0; + uint8_t scl_h_period = 0; + uint8_t scl_l_period = 0; + + if (frequency != priv->frequency) + { + /* I2C peripheral must be disabled to update clocking configuration */ + + pe = (stm32_i2c_getreg32(priv, + STM32_I2C_CR1_OFFSET) & I2C_CR1_PE); + if (pe) + { + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, + I2C_CR1_PE, 0); + } + +#if defined(STM32_I2C_USE_HSI16) || (STM32_PCLK1_FREQUENCY == 16000000) + i2cclk_mhz = 16; +#elif STM32_PCLK1_FREQUENCY == 48000000 + i2cclk_mhz = 48; +#elif STM32_PCLK1_FREQUENCY == 80000000 + i2cclk_mhz = 80; +#elif STM32_PCLK1_FREQUENCY == 120000000 + i2cclk_mhz = 120; +#elif STM32_PCLK1_FREQUENCY == 160000000 + i2cclk_mhz = 160; +#else +# warning STM32_I2C_INIT: Peripheral clock is PCLK and the speed/timing calculations need to be redone. +#endif + + if (i2cclk_mhz == 80) + { + /* Default timing calculations from original STM32U5 driver: */ + + /* The Speed and timing calculation are based on the following + * fI2CCLK = PCLK and is 80 MHz + * Analog filter is on, + * Digital filter off + * Rise Time is 120 ns and fall is 10 ns + * Mode is FastMode + */ + + if (frequency == 100000) + { + /* 100 KHz values from I2C timing tool with clock 80 MHz */ + + presc = 0x01; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0xe7; /* SCLL - SCL low period in master mode */ + scl_h_period = 0x9b; /* SCLH - SCL high period in master mode */ + sda_delay = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ + scl_delay = 0x0d; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ + } + else if (frequency == 400000) + { + /* 400 KHz values from I2C timing tool for clock of 80 MHz */ + + presc = 0x01; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0x43; /* SCLL - SCL low period in master mode */ + scl_h_period = 0x13; /* SCLH - SCL high period in master mode */ + sda_delay = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ + scl_delay = 0x07; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ + } + else if (frequency == 1000000) + { + /* 1000 KHz values from I2C timing tool for clock of 80 MHz */ + + presc = 0x01; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0x14; /* SCLL - SCL low period in master mode */ + scl_h_period = 0x13; /* SCLH - SCL high period in master mode */ + sda_delay = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ + scl_delay = 0x05; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ + } + else + { + /* 10 KHz values from I2C timing tool with clock 80 MHz */ + + presc = 0x0b; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0xff; /* SCLL - SCL low period in master mode */ + scl_h_period = 0xba; /* SCLH - SCL high period in master mode */ + sda_delay = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ + scl_delay = 0x01; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ + } + } + else if (i2cclk_mhz == 120) + { + /* The Speed and timing calculation are based on the following + * fI2CCLK = PCLK and is 120 MHz + * Analog filter is on, + * Digital filter off + * Rise Time is 120 ns and fall is 25 ns + * Mode is FastMode + */ + + if (frequency == 100000) + { + /* 100 KHz values from I2C timing tool with clock 120 MHz */ + + presc = 2; + scl_delay = 14; + sda_delay = 0; + scl_h_period = 157; + scl_l_period = 230; + } + else if (frequency == 400000) + { + /* 400 KHz values from I2C timing tool for clock of 120 MHz */ + + presc = 2; + scl_delay = 8; + sda_delay = 0; + scl_h_period = 21; + scl_l_period = 66; + } + else if (frequency == 1000000) + { + /* 1000 KHz values from I2C timing tool for clock of 120 MHz */ + + presc = 2; + scl_delay = 6; + sda_delay = 0; + scl_h_period = 7; + scl_l_period = 20; + } + else + { + /* 10 KHz values not supported */ + + DEBUGPANIC(); + } + } + else if (i2cclk_mhz == 160) + { + /* The Speed and timing calculation are based on the following + * fI2CCLK = PCLK and is 120 MHz + * Analog filter is on, + * Digital filter off + * Rise Time is 120 ns and fall is 25 ns + * Mode is FastMode + */ + + if (frequency == 100000) + { + /* 100 KHz values from I2C timing tool with clock 120 MHz */ + + presc = 3; + scl_delay = 14; + sda_delay = 0; + scl_h_period = 157; + scl_l_period = 230; + } + else if (frequency == 400000) + { + /* 400 KHz values from I2C timing tool for clock of 120 MHz */ + + presc = 3; + scl_delay = 8; + sda_delay = 0; + scl_h_period = 21; + scl_l_period = 66; + } + else if (frequency == 1000000) + { + /* 1000 KHz values from I2C timing tool for clock of 120 MHz */ + + presc = 3; + scl_delay = 6; + sda_delay = 0; + scl_h_period = 7; + scl_l_period = 20; + } + else + { + /* 10 KHz values not supported */ + + DEBUGPANIC(); + } + } + else if (i2cclk_mhz == 16) + { + /* The Speed and timing calculation are based on the following + * fI2CCLK = HSI and is 16Mhz + * Analog filter is on, + * Digital filter off + * Rise Time is 120 ns and fall is 10ns + * Mode is FastMode + */ + + if (frequency == 100000) + { + presc = 0; + scl_delay = 5; + sda_delay = 0; + scl_h_period = 61; + scl_l_period = 89; + } + else if (frequency == 400000) + { + presc = 0; + scl_delay = 3; + sda_delay = 0; + scl_h_period = 6; + scl_l_period = 24; + } + else if (frequency == 1000000) + { + presc = 0; + scl_delay = 2; + sda_delay = 0; + scl_h_period = 1; + scl_l_period = 5; + } + else + { + presc = 7; + scl_delay = 0; + sda_delay = 0; + scl_h_period = 35; + scl_l_period = 162; + } + } + else if (i2cclk_mhz == 48) + { + if (frequency == 100000) + { + presc = 2; + scl_delay = 10; + sda_delay = 0; + scl_h_period = 62; + scl_l_period = 85; + } + else if (frequency == 400000) + { + presc = 1; + scl_delay = 8; + sda_delay = 0; + scl_h_period = 12; + scl_l_period = 33; + } + else if (frequency == 1000000) + { + presc = 0; + scl_delay = 5; + sda_delay = 0; + scl_h_period = 8; + scl_l_period = 22; + } + } + else + { + DEBUGPANIC(); + } + + uint32_t timingr = + (presc << I2C_TIMINGR_PRESC_SHIFT) | + (scl_delay << I2C_TIMINGR_SCLDEL_SHIFT) | + (sda_delay << I2C_TIMINGR_SDADEL_SHIFT) | + (scl_h_period << I2C_TIMINGR_SCLH_SHIFT) | + (scl_l_period << I2C_TIMINGR_SCLL_SHIFT); + + stm32_i2c_putreg32(priv, STM32_I2C_TIMINGR_OFFSET, timingr); + + if (pe) + { + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, + 0, I2C_CR1_PE); + } + + priv->frequency = frequency; + } +} + +/**************************************************************************** + * Name: stm32_i2c_sendstart + * + * Description: + * Send the START condition / force Master mode + * + * A START condition in I2C consists of a single byte that contains both the + * 7 bit slave address and a read/write bit (0 = WRITE, 1 = READ). If the + * address is recognized by one of the slave devices that slave device will + * ACK the byte so that data transfers can begin. + * + * A RESTART (or repeated START per the I2CSPEC) is simply a START condition + * issued in the middle of a transfer (i.e. after the initial START and + * before a STOP). A RESTART sends a new address byte and R/W bit to the + * bus. A RESTART is optional in most cases but mandatory in the event the + * transfer direction is changed. + * + * Most of the time reading data from an I2C slave requires a WRITE of the + * subaddress followed by a READ (and hence a RESTART in between). Writing + * to an I2C slave typically requires only WRITE operations and hence no + * RESTARTs. + * + * This function is therefore called both at the beginning of a transfer + * (START) and at appropriate times during a transfer (RESTART). + * + ****************************************************************************/ + +static inline +void stm32_i2c_sendstart(struct stm32_i2c_priv_s *priv) +{ + bool next_norestart = false; + + /* Set the private "current message" data used in protocol processing. + * + * ptr: A pointer to the start of the current message buffer. This is + * advanced after each byte in the current message is transferred. + * + * dcnt: A running counter of the bytes in the current message waiting to + * be transferred. This is decremented each time a byte is + * transferred. The hardware normally accepts a maximum of 255 bytes + * per transfer but can support more via the RELOAD mechanism. + * If dcnt initially exceeds 255, the RELOAD mechanism will be + * enabled automatically. + * + * flags: Used to characterize handling of the current message. + * + * The default flags value is 0 which specifies: + * + * - A transfer direction of WRITE (R/W bit = 0) + * - RESTARTs between all messages + * + * The following flags can be used to override this behavior as follows: + * + * - I2C_M_READ: Sets the transfer direction to READ (R/W bit = 1) + * - I2C_M_NOSTART: Prevents a RESTART from being issued prior to the + * transfer of the message (where allowed by the protocol). + * + */ + + priv->ptr = priv->msgv->buffer; + priv->dcnt = priv->msgv->length; + priv->flags = priv->msgv->flags; + + if ((priv->flags & I2C_M_NOSTART) != 0) + { + /* Flag the first byte as an address byte */ + + priv->astart = true; + } + + /* Enabling RELOAD allows the transfer of: + * + * - individual messages with a payload exceeding 255 bytes + * - multiple messages back to back without a RESTART in between + * + * so we enable it if either of those conditions exist and disable + * it otherwise. + */ + + /* Check if there are multiple messages and the next is a continuation */ + + if (priv->msgc > 1) + { + next_norestart = (((priv->msgv + 1)->flags & I2C_M_NOSTART) != 0); + } + + if (next_norestart || priv->dcnt > 255) + { + i2cinfo("RELOAD enabled: dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + stm32_i2c_enable_reload(priv); + } + else + { + i2cinfo("RELOAD disable: dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + stm32_i2c_disable_reload(priv); + } + + /* Set the number of bytes to transfer (I2C_CR2->NBYTES) to the number of + * bytes in the current message or 255, whichever is lower so as to not + * exceed the hardware maximum allowed. + */ + + if (priv->dcnt > 255) + { + stm32_i2c_set_bytes_to_transfer(priv, 255); + } + else + { + stm32_i2c_set_bytes_to_transfer(priv, priv->dcnt); + } + + /* Set the (7 bit) address. + * 10 bit addressing is not yet supported. + */ + + stm32_i2c_set_7bit_address(priv); + + /* The flag of the current message is used to determine the direction of + * transfer required for the current message. + */ + + if (priv->flags & I2C_M_READ) + { + stm32_i2c_set_read_transfer_dir(priv); + } + else + { + stm32_i2c_set_write_transfer_dir(priv); + } + + /* Set the I2C_CR2->START bit to 1 to instruct the hardware to send the + * START condition using the address and transfer direction data entered. + */ + + i2cinfo("Sending START: dcnt=%i msgc=%i flags=0x%04x\n", + priv->dcnt, priv->msgc, priv->flags); + + stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, 0, I2C_CR2_START); +} + +/**************************************************************************** + * Name: stm32_i2c_sendstop + * + * Description: + * Send the STOP conditions + * + * A STOP condition can be requested by setting the STOP bit in the I2C_CR2 + * register. Setting the STOP bit clears the TC flag and the STOP condition + * is sent on the bus. + * + ****************************************************************************/ + +static inline +void stm32_i2c_sendstop(struct stm32_i2c_priv_s *priv) +{ + i2cinfo("Sending STOP\n"); + stm32_i2c_traceevent(priv, I2CEVENT_WRITE_STOP, 0); + + stm32_i2c_modifyreg32(priv, STM32_I2C_CR2_OFFSET, + 0, I2C_CR2_STOP); +} + +/**************************************************************************** + * Name: stm32_i2c_getstatus + * + * Description: + * Get 32-bit status (SR1 and SR2 combined) + * + ****************************************************************************/ + +static inline +uint32_t stm32_i2c_getstatus(struct stm32_i2c_priv_s *priv) +{ + return getreg32(priv->config->base + STM32_I2C_ISR_OFFSET); +} + +/**************************************************************************** + * Name: stm32_i2c_clearinterrupts + * + * Description: + * Clear all interrupts + * + ****************************************************************************/ + +static inline +void stm32_i2c_clearinterrupts(struct stm32_i2c_priv_s *priv) +{ + stm32_i2c_modifyreg32(priv, STM32_I2C_ICR_OFFSET, + 0, I2C_ICR_CLEARMASK); +} + +/**************************************************************************** + * Name: stm32_i2c_isr_process + * + * Description: + * Common interrupt service routine (ISR) that handles I2C protocol logic. + * This is instantiated for each configured I2C interface + * (I2C1, I2C2, I2C3). + * + * This ISR is activated and deactivated by: + * + * stm32_i2c_process + * and + * stm32_i2c_waitdone + * + * Input Parameters: + * priv - The private struct of the I2C driver. + * + ****************************************************************************/ + +static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) +{ + uint32_t status; + + /* Get state of the I2C controller */ + + status = stm32_i2c_getreg32(priv, STM32_I2C_ISR_OFFSET); + + i2cinfo("ENTER: status = 0x%08" PRIx32 "\n", status); + + /* Update private version of the state */ + + priv->status = status; + + /* If this is a new transmission set up the trace table accordingly */ + + stm32_i2c_tracenew(priv, status); + stm32_i2c_traceevent(priv, I2CEVENT_ISR_CALL, 0); + + /* ------------------- Start of I2C protocol handling ------------------ */ + + /* I2C protocol logic follows. It's organized in an if else chain such that + * only one mode of operation is executed every time the ISR is called. + * + * If you need to add additional states to support new features be sure + * they continue the chain (i.e. begin with "else if") and are placed + * before the empty call / error states at the end of the chain. + */ + + /* NACK Handling + * + * This branch is only triggered when the NACK (Not Acknowledge Received) + * interrupt occurs. This interrupt will only fire when the + * I2C_CR1->NACKIE bit is 1. + * + * I2C_ISR->NACKF is set by hardware when a NACK is received after a byte + * is transmitted and the slave fails to acknowledge it. This is the + * opposite of, and mutually exclusive to, the I2C_ISR->TXIS event. + * + * In response to the NACK the hardware automatically triggers generation + * of a STOP condition, terminating the transfer. The only valid response + * to this state is to exit the ISR and report the failure. + * + * To differentiate an "address NACK" from a NACK that might occur during + * the transfer of other bytes the "priv->astart" parameter is + * used. This flag is set to TRUE in sendstart() and set to FALSE when + * the first TXIS event is received, which would be after the first byte + * (the address) is transmitted successfully (acknowledged). + */ + + if (status & I2C_INT_NACK) + { + if (priv->astart == true) + { + /* NACK received on first (address) byte: address is invalid */ + + i2cinfo("NACK: Address invalid: dcnt=%i " + "msgc=%i status=0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_NACKED, + priv->msgv->addr); + } + else + { + /* NACK received on regular byte */ + + i2cinfo("NACK: NACK received: dcnt=%i " + "msgc=%i status=0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_NACKED, + priv->msgv->addr); + } + + /* Set flags to terminate message transmission: + * + * set message length to -1 to indicate last byte of message sent + * set message count to 0 to indicate no more messages to send + * + * As we fall through the logic in the ISR the message handling block + * will be triggered by these flags and signal the ISR to terminate. + */ + + priv->dcnt = -1; + priv->msgc = 0; + } + + /* Transmit Interrupt Status (TXIS) Handler + * + * This branch is only triggered when the TXIS interrupt occurs. This + * interrupt will only fire when the I2C_CR1->TXIE bit is 1. + * + * This indicates the transmit data register I2C_TXDR has been emptied + * following the successful transmission of a byte and slave + * acknowledgement. In this state the I2C_TXDR register is ready to accept + * another byte for transmission. The TXIS bit will be cleared + * automatically when the next byte is written to I2C_TXDR. + * + * The number of TXIS events during the transfer corresponds to NBYTES. + * + * The TXIS flag is not set when a NACK is received. + * + * When RELOAD is disabled (RELOAD=0) and NBYTES data have been + * transferred: + * + * - In Automatic End Mode (AUTOEND=1), a STOP is automatically sent. + * + * Note: Automatic End Mode is not currently supported. + * + * - In Software End Mode (AUTOEND=0), the TC event occurs and the SCL + * line is stretched low in order to allow software actions (STOP, + * RESTART). + * + * When RELOAD is enabled (RELOAD=1) and NBYTES bytes have been transferred + * a TCR event occurs instead and that handler simply updates NBYTES which + * causes TXIS events to continue. The process repeats until all bytes in + * the message have been transferred. + */ + + else if ((priv->flags & (I2C_M_READ)) == 0 && + (status & (I2C_ISR_TXIS)) != 0) + { + /* TXIS interrupt occurred, address valid, ready to transmit */ + + stm32_i2c_traceevent(priv, I2CEVENT_WRITE, 0); + i2cinfo("TXIS: ENTER dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + + /* The first event after the address byte is sent will be either TXIS + * or NACKF so it's safe to set the astart flag to false on + * the first TXIS event to indicate that it is no longer necessary to + * check for address validity. + */ + + if (priv->astart == true) + { + i2cinfo("TXIS: Address Valid\n"); + stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED, + priv->msgv->addr); + priv->astart = false; + } + + /* If one or more bytes in the current message are ready to transmit */ + + if (priv->dcnt > 0) + { + /* Prepare to transmit the current byte */ + + stm32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt); + i2cinfo("TXIS: Write Data 0x%02x\n", *priv->ptr); + + /* Decrement byte counter */ + + priv->dcnt--; + + /* If we are about to transmit the last byte in the current + * message + */ + + if (priv->dcnt == 0) + { + /* If this is also the last message to send, disable RELOAD so + * TC fires next and issues STOP condition. If we don't do + * this TCR will fire next, and since there are no bytes to + * send we can't write NBYTES to clear TCR so it will fire + * forever. + */ + + if (priv->msgc == 1) + { + stm32_i2c_disable_reload(priv); + } + } + + /* Transmit current byte */ + + stm32_i2c_putreg(priv, STM32_I2C_TXDR_OFFSET, *priv->ptr); + + /* Advance to next byte */ + + priv->ptr++; + } + else + { + /* Unsupported state */ + + i2cerr("ERROR: TXIS Unsupported state detected, dcnt=%i, " + "status 0x%08" PRIx32 "\n", + priv->dcnt, status); + stm32_i2c_traceevent(priv, I2CEVENT_WRITE_ERROR, 0); + } + + i2cinfo("TXIS: EXIT dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + } + + /* Receive Buffer Not Empty (RXNE) State Handler + * + * This branch is only triggered when the RXNE interrupt occurs. This + * interrupt will only fire when the I2C_CR1->RXIE bit is 1. + * + * This indicates data has been received from the bus and is waiting to + * be read from the I2C_RXDR register. When I2C_RXDR is read this bit + * is automatically cleared and then an ACK or NACK is sent depending on + * whether we have more bytes to receive. + * + * When RELOAD is disabled and bytes remain to be transferred an + * acknowledge is automatically sent on the bus and the RXNE events + * continue until the last byte is received. + * + * When RELOAD is disabled (RELOAD=0) and BYTES have been transferred: + * + * - In Automatic End Mode (AUTOEND=1), a NACK and a STOP are + * automatically sent after the last received byte. + * + * Note: Automatic End Mode is not currently supported. + * + * - In Software End Mode (AUTOEND=0), a NACK is automatically sent after + * the last received byte, the TC event occurs and the SCL line is + * stretched low in order to allow software actions (STOP, RESTART). + * + * When RELOAD is enabled (RELOAD=1) and NBYTES bytes have been transferred + * a TCR event occurs and that handler simply updates NBYTES which causes + * RXNE events to continue until all bytes have been transferred. + */ + + else if ((priv->flags & (I2C_M_READ)) != 0 && (status & I2C_ISR_RXNE) != 0) + { + /* When read flag is set and the receive buffer is not empty + * (RXNE is set) then the driver can read from the data register. + */ + + stm32_i2c_traceevent(priv, I2CEVENT_READ, 0); + i2cinfo("RXNE: ENTER dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + + /* If more bytes in the current message */ + + if (priv->dcnt > 0) + { + stm32_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->dcnt); + + /* No interrupts or context switches may occur in the following + * sequence. Otherwise, additional bytes may be received. + */ + +#ifdef CONFIG_I2C_POLLED + irqstate_t state = enter_critical_section(); +#endif + /* Receive a byte */ + + *priv->ptr = stm32_i2c_getreg(priv, STM32_I2C_RXDR_OFFSET); + + i2cinfo("RXNE: Read Data 0x%02x\n", *priv->ptr); + + /* Advance buffer to the next byte in the message */ + + priv->ptr++; + + /* Signal byte received */ + + priv->dcnt--; + +#ifdef CONFIG_I2C_POLLED + leave_critical_section(state); +#endif + } + else + { + /* Unsupported state */ + + stm32_i2c_traceevent(priv, I2CEVENT_READ_ERROR, 0); + status = stm32_i2c_getreg(priv, STM32_I2C_ISR_OFFSET); + i2cerr("ERROR: RXNE Unsupported state detected, dcnt=%i, " + "status 0x%08" PRIx32 "\n", + priv->dcnt, status); + + /* Set signals that will terminate ISR and wake waiting thread */ + + priv->dcnt = -1; + priv->msgc = 0; + } + + i2cinfo("RXNE: EXIT dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + } + + /* Transfer Complete (TC) State Handler + * + * This branch is only triggered when the TC interrupt occurs. This + * interrupt will only fire when: + * + * I2C_CR1->TCIE = 1 (Transfer Complete Interrupts Enabled) + * I2C_CR2->RELOAD = 0 (Reload Mode Disabled) + * I2C_CR2->AUTOEND = 0 (Autoend Mode Disabled, i.e. Software End Mode) + * + * This event indicates that the number of bytes initially defined + * in NBYTES, meaning, the number of bytes in the current message + * (priv->dcnt) has been successfully transmitted or received. + * + * When the TC interrupt occurs we have two choices to clear it and move + * on, regardless of the transfer direction: + * + * - if more messages follow, perform a repeated START if required + * and then fall through to transmit or receive the next message. + * + * - if no messages follow, perform a STOP and set flags needed to + * exit the ISR. + * + * The fact that the hardware must either RESTART or STOP when a TC + * event occurs explains why, when messages must be sent back to back + * (i.e. without a restart by specifying the I2C_M_NOSTART flag), + * RELOAD mode must be enabled and TCR event(s) must be generated + * instead. See the TCR handler for more. + */ + + else if ((status & I2C_ISR_TC) != 0) + { + i2cinfo("TC: ENTER dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + + /* Prior message has been sent successfully. Or there could have + * been an error that set msgc to 0; So test for that case as + * we do not want to decrement msgc less then zero nor move msgv + * past the last message. + */ + + if (priv->msgc > 0) + { + priv->msgc--; + } + + /* Are there additional messages remain to be transmitted / received? */ + + if (priv->msgc > 0) + { + i2cinfo("TC: RESTART: dcnt=%i, msgc=%i\n", + priv->dcnt, priv->msgc); + stm32_i2c_traceevent(priv, I2CEVENT_TC_NO_RESTART, priv->msgc); + + /* Issue a START condition. + * + * Note that the first thing sendstart does is update the + * private structure "current message" data (ptr, dcnt, flags) + * so they all reflect the next message in the list so we + * update msgv before we get there. + */ + + /* Advance to the next message in the list */ + + priv->msgv++; + + stm32_i2c_sendstart(priv); + } + else + { + /* Issue a STOP conditions. + * + * No additional messages to transmit / receive, so the + * transfer is indeed complete. Nothing else to do but + * issue a STOP and exit. + */ + + i2cinfo("TC: STOP: dcnt=%i msgc=%i\n", + priv->dcnt, priv->msgc); + stm32_i2c_traceevent(priv, I2CEVENT_STOP, priv->dcnt); + + stm32_i2c_sendstop(priv); + + /* Set signals that will terminate ISR and wake waiting thread */ + + priv->dcnt = -1; + priv->msgc = 0; + } + + i2cinfo("TC: EXIT dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + } + + /* Transfer Complete (Reload) State Handler + * + * This branch is only triggered when the TCR interrupt occurs. This + * interrupt will only fire when: + * + * I2C_CR1->TCIE = 1 (Transfer Complete Interrupts Enabled) + * I2C_CR2->RELOAD = 1 (Reload Mode Active) + * I2C_CR2->AUTOEND = 0 (Autoend Mode Disabled, i.e. Software End Mode) + * + * This is similar to the TC event except that TCR assumes that additional + * bytes are available to transfer. So despite what its name might imply + * the transfer really isn't complete. + * + * There are two reasons RELOAD would be enabled: + * + * 1) We're trying to send a message with a payload greater than 255 bytes. + * 2) We're trying to send messages back to back, regardless of their + * payload size, to avoid a RESTART (i.e. I2C_M_NOSTART flag is set). + * + * These conditions may be true simultaneously, as would be the case if + * we're sending multiple messages with payloads > 255 bytes. So we only + * advance to the next message if we arrive here and dcnt is 0, meaning, + * we're finished with the last message and ready to move to the next. + * + * This logic supports the transfer of bytes limited only by the size of + * the i2c_msg_s length variable. The SCL line will be stretched low + * until NBYTES is written with a non-zero value, allowing the transfer + * to continue. + * + * TODO: RESTARTs are required by the I2CSPEC if the next message transfer + * direction changes. Right now the NORESTART flag overrides this + * behavior. May have to introduce logic to issue sendstart, assuming it's + * legal with the hardware in the TCR state. + */ + + else if ((status & I2C_ISR_TCR) != 0) + { + i2cinfo("TCR: ENTER dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + + /* If no more bytes in the current message to transfer */ + + if (priv->dcnt == 0) + { + /* Prior message has been sent successfully */ + + priv->msgc--; + + /* Advance to the next message in the list */ + + priv->msgv++; + + /* Update current message data */ + + priv->ptr = priv->msgv->buffer; + priv->dcnt = priv->msgv->length; + priv->flags = priv->msgv->flags; + + /* if this is the last message, disable reload so the + * TC event fires next time. + */ + + if (priv->msgc == 0) + { + i2cinfo("TCR: DISABLE RELOAD: dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + + stm32_i2c_disable_reload(priv); + } + + /* Update NBYTES with length of current message */ + + i2cinfo("TCR: NEXT MSG dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + + stm32_i2c_set_bytes_to_transfer(priv, priv->dcnt); + } + else + { + /* More bytes in the current (greater than 255 byte payload + * length) message, so set NBYTES according to the bytes + * remaining in the message, up to a maximum each cycle of 255. + */ + + if (priv->dcnt > 255) + { + i2cinfo( + "TCR: ENABLE RELOAD: NBYTES = 255 dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + + /* More than 255 bytes to transfer so the RELOAD bit is + * set in order to generate a TCR event rather than a TC + * event when 255 bytes are successfully transferred. + * This forces us to return here to update NBYTES and + * continue until NBYTES is set to less than 255 bytes, + * at which point RELOAD will be disabled and a TC + * event will (eventually) follow to officially terminate + * the transfer. + */ + + stm32_i2c_enable_reload(priv); + + stm32_i2c_set_bytes_to_transfer(priv, 255); + } + else + { + /* Less than 255 bytes left to transfer, which means we'll + * complete the transfer of all bytes in the current message + * the next time around. + * + * This means we need to disable the RELOAD functionality so + * we receive a TC event next time which will allow us to + * either RESTART and continue sending the contents of the + * next message or send a STOP condition and exit the ISR. + */ + + i2cinfo("TCR: DISABLE RELOAD: NBYTES = dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + + stm32_i2c_disable_reload(priv); + + stm32_i2c_set_bytes_to_transfer(priv, priv->dcnt); + } + + i2cinfo("TCR: EXIT dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + } + } + + /* Empty call handler + * + * Case to handle an empty call to the ISR where it has nothing to + * do and should exit immediately. + */ + + else if (priv->dcnt == -1 && priv->msgc == 0) + { + status = stm32_i2c_getreg(priv, STM32_I2C_ISR_OFFSET); + i2cwarn("WARNING: EMPTY CALL: Stopping ISR: status 0x%08" PRIx32 "\n", + status); + stm32_i2c_traceevent(priv, I2CEVENT_ISR_EMPTY_CALL, 0); + } + + /* Error handler + * + * We get to this branch only if we can't handle the current state. + * + * This should not happen in interrupt based operation. + * + * This will happen during polled operation when the device is not + * in one of the supported states when polled. + */ + + else + { +#ifdef CONFIG_I2C_POLLED + stm32_i2c_traceevent(priv, I2CEVENT_POLL_DEV_NOT_RDY, 0); +#else + /* Read rest of the state */ + + status = stm32_i2c_getreg(priv, STM32_I2C_ISR_OFFSET); + + i2cerr("ERROR: Invalid state detected, status 0x%08" PRIx32 "\n", + status); + + /* set condition to terminate ISR and wake waiting thread */ + + priv->dcnt = -1; + priv->msgc = 0; + stm32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0); +#endif + } + + /* ------------------- End of I2C protocol handling ------------------ */ + + /* Message Handling + * + * Transmission of the whole message chain has been completed. We have to + * terminate the ISR and wake up stm32_i2c_process() that is waiting for + * the ISR cycle to handle the sending/receiving of the messages. + */ + + if (priv->dcnt == -1 && priv->msgc == 0) + { + i2cinfo("MSG: Shutting down I2C ISR\n"); + + stm32_i2c_traceevent(priv, I2CEVENT_ISR_SHUTDOWN, 0); + + /* clear pointer to message content to reflect we are done + * with the current transaction. + */ + + priv->msgv = NULL; + +#ifdef CONFIG_I2C_POLLED + priv->intstate = INTSTATE_DONE; +#else + + status = stm32_i2c_getreg32(priv, STM32_I2C_ISR_OFFSET); + + /* Update private state to capture NACK which is used in combination + * with the astart flag to report the type of NACK received (address + * vs data) to the upper layers once we exit the ISR. + * + * Note: We do this prior to clearing interrupts because the NACKF + * flag will naturally be cleared by that process. + */ + + priv->status = status; + + /* Clear all interrupts */ + + stm32_i2c_modifyreg32(priv, STM32_I2C_ICR_OFFSET, + 0, I2C_ICR_CLEARMASK); + + /* If a thread is waiting then inform it transfer is complete */ + + if (priv->intstate == INTSTATE_WAITING) + { + nxsem_post(&priv->sem_isr); + priv->intstate = INTSTATE_DONE; + } +#endif + } + + status = stm32_i2c_getreg32(priv, STM32_I2C_ISR_OFFSET); + i2cinfo("EXIT: status = 0x%08" PRIx32 "\n", status); + + return OK; +} + +/**************************************************************************** + * Name: stm32_i2c_isr + * + * Description: + * Common I2C interrupt service routine + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static int stm32_i2c_isr(int irq, void *context, void *arg) +{ + struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)arg; + + DEBUGASSERT(priv != NULL); + return stm32_i2c_isr_process(priv); +} +#endif + +/**************************************************************************** + * Name: stm32_i2c_init + * + * Description: + * Setup the I2C hardware, ready for operation with defaults + * + ****************************************************************************/ + +static int stm32_i2c_init(struct stm32_i2c_priv_s *priv) +{ + /* Power-up and configure GPIOs */ + + /* Enable power and reset the peripheral */ + +#ifdef CONFIG_STM32U5_I2C4 + if (priv->config->base == STM32_I2C4_BASE) + { + modifyreg32(STM32_RCC_APB1ENR2, 0, priv->config->clk_bit); + modifyreg32(STM32_RCC_APB1RSTR2, 0, priv->config->reset_bit); + modifyreg32(STM32_RCC_APB1RSTR2, priv->config->reset_bit, 0); + } + else +#endif + { + modifyreg32(STM32_RCC_APB1ENR1, 0, priv->config->clk_bit); + modifyreg32(STM32_RCC_APB1RSTR1, 0, priv->config->reset_bit); + modifyreg32(STM32_RCC_APB1RSTR1, priv->config->reset_bit, 0); + } + + /* Configure pins */ + + if (stm32_configgpio(priv->config->scl_pin) < 0) + { + return ERROR; + } + + if (stm32_configgpio(priv->config->sda_pin) < 0) + { + stm32_unconfiggpio(priv->config->scl_pin); + return ERROR; + } + +#ifndef CONFIG_I2C_POLLED + /* Attach error and event interrupts to the ISRs */ + + irq_attach(priv->config->ev_irq, stm32_i2c_isr, priv); + irq_attach(priv->config->er_irq, stm32_i2c_isr, priv); + up_enable_irq(priv->config->ev_irq); + up_enable_irq(priv->config->er_irq); +#endif + + /* TODO: + * - Provide means to set peripheral clock source via RCC_CCIPR_I2CxSEL + * - Make clock source Kconfigurable (currently PCLK = 80 MHz) + */ + + /* Force a frequency update */ + + priv->frequency = 0; + stm32_i2c_setclock(priv, 100000); + + /* Enable I2C peripheral */ + + stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_PE); + + return OK; +} + +/**************************************************************************** + * Name: stm32_i2c_deinit + * + * Description: + * Shutdown the I2C hardware + * + ****************************************************************************/ + +static int stm32_i2c_deinit(struct stm32_i2c_priv_s *priv) +{ + /* Disable I2C */ + + stm32_i2c_putreg32(priv, STM32_I2C_CR1_OFFSET, 0); + + /* Unconfigure GPIO pins */ + + stm32_unconfiggpio(priv->config->scl_pin); + stm32_unconfiggpio(priv->config->sda_pin); + +#ifndef CONFIG_I2C_POLLED + + /* Disable and detach interrupts */ + + up_disable_irq(priv->config->ev_irq); + up_disable_irq(priv->config->er_irq); + irq_detach(priv->config->ev_irq); + irq_detach(priv->config->er_irq); +#endif + + /* Disable clocking */ + +#ifdef CONFIG_STM32U5_I2C4 + if (priv->config->base == STM32_I2C4_BASE) + { + modifyreg32(STM32_RCC_APB1ENR2, priv->config->clk_bit, 0); + } + else +#endif + { + modifyreg32(STM32_RCC_APB1ENR1, priv->config->clk_bit, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_i2c_process + * + * Description: + * Common I2C transfer logic + * + * Initiates a master mode transaction on the I2C bus to transfer the + * provided messages to and from the slave devices. + * + ****************************************************************************/ + +static int stm32_i2c_process(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count) +{ + struct stm32_i2c_inst_s *inst = (struct stm32_i2c_inst_s *)dev; + struct stm32_i2c_priv_s *priv = inst->priv; + uint32_t status = 0; + uint32_t cr1; + uint32_t cr2; + int errval = 0; + int waitrc = 0; + + DEBUGASSERT(count > 0); + + /* Wait for any STOP in progress */ + + stm32_i2c_sem_waitstop(priv); + + /* Clear any pending error interrupts */ + + stm32_i2c_clearinterrupts(priv); + + /* Old transfers are done */ + + priv->msgv = msgs; + priv->msgc = count; + + /* Reset I2C trace logic */ + + stm32_i2c_tracereset(priv); + + /* Set I2C clock frequency (on change it toggles I2C_CR1_PE !) */ + + stm32_i2c_setclock(priv, msgs->frequency); + + /* Trigger start condition, then the process moves into the ISR. I2C + * interrupts will be enabled within stm32_i2c_waitdone(). + */ + + priv->status = 0; + +#ifndef CONFIG_I2C_POLLED + /* Enable transmit and receive interrupts here so when we send the start + * condition below the ISR will fire if the data was sent and some + * response from the slave received. All other interrupts relevant to + * our needs are enabled in stm32_i2c_sem_waitdone() below. + */ + + stm32_i2c_enableinterrupts(priv); +#endif + + /* Trigger START condition generation, which also sends the slave address + * with read/write flag and the data in the first message + */ + + stm32_i2c_sendstart(priv); + + /* Wait for the ISR to tell us that the transfer is complete by attempting + * to grab the semaphore that is initially locked by the ISR. If the ISR + * does not release the lock so we can obtain it here prior to the end of + * the timeout period waitdone returns error and we report a timeout. + */ + + waitrc = stm32_i2c_sem_waitdone(priv); + + cr1 = stm32_i2c_getreg32(priv, STM32_I2C_CR1_OFFSET); + cr2 = stm32_i2c_getreg32(priv, STM32_I2C_CR2_OFFSET); +#if !defined(CONFIG_DEBUG_I2C) + UNUSED(cr1); + UNUSED(cr2); +#endif + + /* Status after a normal / good exit is usually 0x00000001, meaning the TXE + * bit is set. That occurs as a result of the I2C_TXDR register being + * empty, and it naturally will be after the last byte is transmitted. + * This bit is cleared when we attempt communications again and re-enable + * the peripheral. The priv->status field can hold additional information + * like a NACK, so we reset the status field to include that information. + */ + + status = stm32_i2c_getstatus(priv); + + /* The priv->status field can hold additional information like a NACK + * event so we include that information. + */ + + status = priv->status & 0xffffffff; + + if (waitrc < 0) + { + /* Connection timed out */ + + errval = ETIMEDOUT; + i2cerr("ERROR: Waitdone timed out CR1: 0x%08" PRIx32 + " CR2: 0x%08" PRIx32 " status: 0x%08" PRIx32 "\n", + cr1, cr2, status); + } + else + { + i2cinfo("Waitdone success: CR1: 0x%08" PRIx32 " CR2: 0x%08" PRIx32 + " status: 0x%08" PRIx32 "\n", + cr1, cr2, status); + } + + UNUSED(cr1); + UNUSED(cr2); + + i2cinfo("priv->status: 0x%08" PRIx32 "\n", priv->status); + + /* Check for error status conditions */ + + if ((status & (I2C_INT_BERR | + I2C_INT_ARLO | + I2C_INT_OVR | + I2C_INT_PECERR | + I2C_INT_TIMEOUT | + I2C_INT_NACK)) != 0) + + { + /* one or more errors in the mask are present */ + + if (status & I2C_INT_BERR) + { + /* Bus Error, ignore it because of errata (revision A,Z) */ + + i2cerr("ERROR: I2C Bus Error\n"); + + /* errval = EIO; */ + } + else if (status & I2C_INT_ARLO) + { + /* Arbitration Lost (master mode) */ + + i2cerr("ERROR: I2C Arbitration Lost\n"); + errval = EAGAIN; + } + + else if (status & I2C_INT_OVR) + { + /* Overrun/Underrun */ + + i2cerr("ERROR: I2C Overrun/Underrun\n"); + errval = EIO; + } + else if (status & I2C_INT_PECERR) + { + /* PEC Error in reception (SMBus Only) */ + + i2cerr("ERROR: I2C PEC Error\n"); + errval = EPROTO; + } + else if (status & I2C_INT_TIMEOUT) + { + /* Timeout or Tlow Error (SMBus Only) */ + + i2cerr("ERROR: I2C Timeout / Tlow Error\n"); + errval = ETIME; + } + else if (status & I2C_INT_NACK) + { + /* NACK Received, flag as "communication error on send" */ + + if (priv->astart == TRUE) + { + i2cwarn("WARNING: I2C Address NACK\n"); + errval = EADDRNOTAVAIL; + } + else + { + i2cwarn("WARNING: I2C Data NACK\n"); + errval = ECOMM; + } + } + else + { + /* Unrecognized error */ + + i2cerr("ERROR: I2C Unrecognized Error"); + errval = EINTR; + } + } + + /* This is not an error, but should not happen. The BUSY signal can be + * present if devices on the bus are in an odd state and need to be reset. + * NOTE: + * We will only see this busy indication if stm32_i2c_sem_waitdone() + * fails above; Otherwise it is cleared. + */ + + else if ((status & I2C_ISR_BUSY) != 0) + { + /* I2C Bus Busy + * + * This is a status condition rather than an error. + * + * We will only see this busy indication if stm32_i2c_sem_waitdone() + * fails above; Otherwise it is cleared by the hardware when the ISR + * wraps up the transfer with a STOP condition. + */ + + clock_t start = clock_systime_ticks(); + clock_t timeout = USEC2TICK(USEC_PER_SEC / priv->frequency) + 1; + + status = stm32_i2c_getstatus(priv); + + while (status & I2C_ISR_BUSY) + { + if ((clock_systime_ticks() - start) > timeout) + { + i2cerr("ERROR: I2C Bus busy"); + errval = EBUSY; + break; + } + + status = stm32_i2c_getstatus(priv); + } + } + + /* Dump the trace result */ + + stm32_i2c_tracedump(priv); + nxmutex_unlock(&priv->lock); + + return -errval; +} + +/**************************************************************************** + * Name: stm32_i2c_transfer + * + * Description: + * Generic I2C transfer function + * + ****************************************************************************/ + +static int stm32_i2c_transfer(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, + int count) +{ + struct stm32_i2c_priv_s *priv; + int ret; + + DEBUGASSERT(dev); + priv = ((struct stm32_i2c_inst_s *)dev)->priv; + + /* Ensure that address or flags don't change meanwhile */ + + ret = nxmutex_lock(&priv->lock); + if (ret >= 0) + { + ret = stm32_i2c_process(dev, msgs, count); + } + + return ret; +} + +/**************************************************************************** + * Name: stm32_i2c_reset + * + * Description: + * Reset an I2C bus + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int stm32_i2c_reset(struct i2c_master_s *dev) +{ + struct stm32_i2c_priv_s *priv; + unsigned int clock_count; + unsigned int stretch_count; + uint32_t scl_gpio; + uint32_t sda_gpio; + uint32_t frequency; + int ret; + + DEBUGASSERT(dev); + + /* Get I2C private structure */ + + priv = ((struct stm32_i2c_inst_s *)dev)->priv; + + /* Our caller must own a ref */ + + DEBUGASSERT(priv->refs > 0); + + /* Lock out other clients */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + ret = -EIO; + + /* Save the current frequency */ + + frequency = priv->frequency; + + /* De-init the port */ + + stm32_i2c_deinit(priv); + + /* Use GPIO configuration to un-wedge the bus */ + + scl_gpio = MKI2C_OUTPUT(priv->config->scl_pin); + sda_gpio = MKI2C_OUTPUT(priv->config->sda_pin); + + /* Let SDA go high */ + + stm32_gpiowrite(sda_gpio, 1); + + /* Clock the bus until any slaves currently driving it let it go. */ + + clock_count = 0; + while (!stm32_gpioread(sda_gpio)) + { + /* Give up if we have tried too hard */ + + if (clock_count++ > 10) + { + goto out; + } + + /* Sniff to make sure that clock stretching has finished. + * + * If the bus never relaxes, the reset has failed. + */ + + stretch_count = 0; + while (!stm32_gpioread(scl_gpio)) + { + /* Give up if we have tried too hard */ + + if (stretch_count++ > 10) + { + goto out; + } + + up_udelay(10); + } + + /* Drive SCL low */ + + stm32_gpiowrite(scl_gpio, 0); + up_udelay(10); + + /* Drive SCL high again */ + + stm32_gpiowrite(scl_gpio, 1); + up_udelay(10); + } + + /* Generate a start followed by a stop to reset slave + * state machines. + */ + + stm32_gpiowrite(sda_gpio, 0); + up_udelay(10); + stm32_gpiowrite(scl_gpio, 0); + up_udelay(10); + stm32_gpiowrite(scl_gpio, 1); + up_udelay(10); + stm32_gpiowrite(sda_gpio, 1); + up_udelay(10); + + /* Revert the GPIO configuration. */ + + stm32_unconfiggpio(sda_gpio); + stm32_unconfiggpio(scl_gpio); + + /* Re-init the port */ + + stm32_i2c_init(priv); + + /* Restore the frequency */ + + stm32_i2c_setclock(priv, frequency); + ret = OK; + +out: + + /* Release the port for re-use by other clients */ + + nxmutex_unlock(&priv->lock); + return ret; +} +#endif /* CONFIG_I2C_RESET */ + +/**************************************************************************** + * Name: stm32_i2c_pm_prepare + * + * 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. + * domain - Identifies the activity domain of the state change + * pmstate - Identifies the new PM state + * + * Returned Value: + * 0 (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 recalled 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 stm32_i2c_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + struct stm32_i2c_priv_s *priv = + (struct stm32_i2c_priv_s *)((char *)cb - + offsetof(struct stm32_i2c_priv_s, pm_cb)); + + /* 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: + + /* Check if exclusive lock for I2C bus is held. */ + + if (nxmutex_is_locked(&priv->lock)) + { + /* Exclusive lock is held, do not allow entry to deeper PM + * states. + */ + + return -EBUSY; + } + + break; + + default: + + /* Should not get here */ + + break; + } + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_i2cbus_initialize + * + * Description: + * Initialize one I2C bus + * + ****************************************************************************/ + +struct i2c_master_s *stm32_i2cbus_initialize(int port) +{ + struct stm32_i2c_priv_s *priv = NULL; /* private data of device with multiple instances */ + struct stm32_i2c_inst_s *inst = NULL; /* device, single instance */ + + /* Get I2C private structure */ + + switch (port) + { +#ifdef CONFIG_STM32U5_I2C1 + case 1: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; + break; +#endif +#ifdef CONFIG_STM32U5_I2C2 + case 2: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; + break; +#endif +#ifdef CONFIG_STM32U5_I2C3 + case 3: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c3_priv; + break; +#endif +#ifdef CONFIG_STM32U5_I2C4 + case 4: + priv = (struct stm32_i2c_priv_s *)&stm32_i2c4_priv; + break; +#endif + default: + return NULL; + } + + /* Allocate instance */ + + if (!(inst = kmm_malloc(sizeof(struct stm32_i2c_inst_s)))) + { + return NULL; + } + + /* Initialize instance */ + + inst->ops = &stm32_i2c_ops; + inst->priv = priv; + + /* Init private data for the first time, increment refs count, + * power-up hardware and configure GPIOs. + */ + + nxmutex_lock(&priv->lock); + if (priv->refs++ == 0) + { + stm32_i2c_init(priv); + +#ifdef CONFIG_PM + /* Register to receive power management callbacks */ + + DEBUGVERIFY(pm_register(&priv->pm_cb)); +#endif + } + + nxmutex_unlock(&priv->lock); + return (struct i2c_master_s *)inst; +} + +/**************************************************************************** + * Name: stm32_i2cbus_uninitialize + * + * Description: + * Uninitialize an I2C bus + * + ****************************************************************************/ + +int stm32_i2cbus_uninitialize(struct i2c_master_s *dev) +{ + struct stm32_i2c_priv_s *priv; + + DEBUGASSERT(dev); + priv = ((struct stm32_i2c_inst_s *)dev)->priv; + + /* Decrement refs and check for underflow */ + + if (priv->refs == 0) + { + return ERROR; + } + + nxmutex_lock(&priv->lock); + if (--priv->refs) + { + nxmutex_unlock(&priv->lock); + kmm_free(dev); + return OK; + } + +#ifdef CONFIG_PM + /* Unregister power management callbacks */ + + pm_unregister(&priv->pm_cb); +#endif + + /* Disable power and other HW resource (GPIO's) */ + + stm32_i2c_deinit(priv); + nxmutex_unlock(&priv->lock); + + kmm_free(dev); + return OK; +} + +#endif /* CONFIG_STM32U5_I2C1 || CONFIG_STM32U5_I2C2 || CONFIG_STM32U5_I2C3 || CONFIG_STM32U5_I2C4 */ diff --git a/arch/arm/src/stm32u5/stm32_i2c.h b/arch/arm/src/stm32u5/stm32_i2c.h new file mode 100644 index 00000000000..0fd602450e0 --- /dev/null +++ b/arch/arm/src/stm32u5/stm32_i2c.h @@ -0,0 +1,89 @@ +/**************************************************************************** + * arch/arm/src/stm32u5/stm32_i2c.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_STM32U5_STM32L4_I2C_H +#define __ARCH_ARM_SRC_STM32U5_STM32L4_I2C_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" +#include "hardware/stm32_i2c.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* If a dynamic timeout is selected, then a non-negative, non-zero micro- + * seconds per byte value must be provided as well. + */ + +#ifdef CONFIG_STM32U5_I2C_DYNTIMEO +# if CONFIG_STM32U5_I2C_DYNTIMEO_USECPERBYTE < 1 +# warning "Ignoring CONFIG_STM32U5_I2C_DYNTIMEO because of CONFIG_STM32U5_I2C_DYNTIMEO_USECPERBYTE" +# undef CONFIG_STM32U5_I2C_DYNTIMEO +# endif +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_i2cbus_initialize + * + * Description: + * Initialize the selected I2C port. And return a unique instance of struct + * struct i2c_master_s. This function may be called to obtain multiple + * instances of the interface, each of which may be set up with a + * different frequency and slave address. + * + * Input Parameters: + * Port number (for hardware that has multiple I2C interfaces) + * + * Returned Value: + * Valid I2C device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct i2c_master_s *stm32_i2cbus_initialize(int port); + +/**************************************************************************** + * Name: stm32_i2cbus_uninitialize + * + * Description: + * De-initialize the selected I2C port, and power down the device. + * + * Input Parameters: + * Device structure as returned by the stm32_i2cbus_initialize() + * + * Returned Value: + * OK on success, ERROR when internal reference count mismatch or dev + * points to invalid hardware device. + * + ****************************************************************************/ + +int stm32_i2cbus_uninitialize(struct i2c_master_s *dev); + +#endif /* __ARCH_ARM_SRC_STM32U5_STM32L4_I2C_H */ diff --git a/arch/arm/src/stm32u5/stm32_rcc.h b/arch/arm/src/stm32u5/stm32_rcc.h index 92fa7733608..b1e35f24b3c 100644 --- a/arch/arm/src/stm32u5/stm32_rcc.h +++ b/arch/arm/src/stm32u5/stm32_rcc.h @@ -30,8 +30,8 @@ #include "arm_internal.h" #include "chip.h" -#if defined(CONFIG_STM32U5_STM32U585XX) -# include "hardware/stm32u585xx_rcc.h" +#if defined(CONFIG_STM32U5_STM32U585XX) || defined(CONFIG_STM32U5_STM32U5A5XX) +# include "hardware/stm32u5xx_rcc.h" #else # error "Unsupported STM32U5 chip" #endif diff --git a/arch/arm/src/stm32u5/stm32_start.c b/arch/arm/src/stm32u5/stm32_start.c index 95594a740e9..ceac912d7d1 100644 --- a/arch/arm/src/stm32u5/stm32_start.c +++ b/arch/arm/src/stm32u5/stm32_start.c @@ -60,8 +60,8 @@ * 0x2003:ffff - End of internal SRAM2 */ -#define SRAM2_START STM32U5_SRAM2_BASE -#define SRAM2_END (SRAM2_START + STM32U5_SRAM2_SIZE) +#define SRAM2_START STM32_SRAM2_BASE +#define SRAM2_END (SRAM2_START + STM32_SRAM2_SIZE) #define HEAP_BASE ((uintptr_t)_ebss + CONFIG_IDLETHREAD_STACKSIZE) diff --git a/arch/arm/src/stm32u5/stm32_uart.h b/arch/arm/src/stm32u5/stm32_uart.h index 45fe35607c9..2da3a1c76d2 100644 --- a/arch/arm/src/stm32u5/stm32_uart.h +++ b/arch/arm/src/stm32u5/stm32_uart.h @@ -30,7 +30,7 @@ #include "chip.h" -#if defined(CONFIG_STM32U5_STM32U585XX) +#if defined(CONFIG_STM32U5_STM32U585XX) || defined(CONFIG_STM32U5_STM32U5A5XX) # include "hardware/stm32_uart.h" #else # error "Unsupported STM32U5 chip" diff --git a/arch/arm/src/stm32u5/stm32u585xx_rcc.c b/arch/arm/src/stm32u5/stm32u5xx_rcc.c similarity index 98% rename from arch/arm/src/stm32u5/stm32u585xx_rcc.c rename to arch/arm/src/stm32u5/stm32u5xx_rcc.c index ea988b07e06..716ee0472d4 100644 --- a/arch/arm/src/stm32u5/stm32u585xx_rcc.c +++ b/arch/arm/src/stm32u5/stm32u5xx_rcc.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32u5/stm32u585xx_rcc.c + * arch/arm/src/stm32u5/stm32u5xx_rcc.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -195,10 +195,14 @@ static inline void rcc_enableahb2(void) regval |= RCC_AHB2ENR1_DCMI_PSSIEN; #endif -#ifdef CONFIG_STM32U5_OTG +#ifdef CONFIG_STM32U5_OTGHS regval |= RCC_AHB2ENR1_OTGEN; #endif +#ifdef CONFIG_STM32U5_OTGHS + regval |= RCC_AHB2ENR1_OTGPHYEN; +#endif + #ifdef CONFIG_STM32U5_AES regval |= RCC_AHB2ENR1_AESEN; #endif @@ -263,6 +267,10 @@ static inline void rcc_enableahb2(void) regval |= RCC_AHB2ENR2_OCTOSPI2EN; #endif +#ifdef CONFIG_STM32U5_SRAM5 + regval |= RCC_AHB2ENR2_SRAM5EN; +#endif + putreg32(regval, STM32_RCC_AHB2ENR2); } diff --git a/boards/Kconfig b/boards/Kconfig index 94042826850..87aa420f9de 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -2428,6 +2428,14 @@ config ARCH_BOARD_B_U585I_IOT02A MCU. The STM32U585AI is a Cortex-M33 optimised for low-power operation at up to 160MHz operation with 2048Kb Flash memory and 768Kb SRAM. +config ARCH_BOARD_NUCLEO_U5A5ZJ_Q + bool "STMicro NUCLEO-U5A5ZJ-Q board" + depends on ARCH_CHIP_STM32U5A5ZJT + ---help--- + STMicro development board featuring the STM32U5A5 + MCU. The STM32U5A5 is a Cortex-M33 optimised for low-power operation + at up to 160MHz operation with 4MB Flash memory and 2.5MB SRAM. + config ARCH_BOARD_STM32L476VG_DISCO bool "STMicro STM32L476VG -Discovery board" depends on ARCH_CHIP_STM32L476RG @@ -3106,6 +3114,7 @@ config ARCH_BOARD default "b-l072z-lrwan1" if ARCH_BOARD_B_L072Z_LRWAN1 default "b-l475e-iot01a" if ARCH_BOARD_B_L475E_IOT01A default "b-u585i-iot02a" if ARCH_BOARD_B_U585I_IOT02A + default "nucleo-u5a5zj-q" if ARCH_BOARD_NUCLEO_U5A5ZJ_Q default "stm32l476vg-disco" if ARCH_BOARD_STM32L476VG_DISCO default "stm32l476-mdk" if ARCH_BOARD_STM32L476_MDK default "stm32l4r9ai-disco" if ARCH_BOARD_STM32L4R9AI_DISCO @@ -3570,6 +3579,9 @@ endif if ARCH_BOARD_B_U585I_IOT02A source "boards/arm/stm32u5/b-u585i-iot02a/Kconfig" endif +if ARCH_BOARD_NUCLEO_U5A5ZJ_Q +source "boards/arm/stm32u5/nucleo-u5a5zj-q/Kconfig" +endif if ARCH_BOARD_NUCLEO_L432KC source "boards/arm/stm32l4/nucleo-l432kc/Kconfig" endif diff --git a/boards/arm/stm32u5/b-u585i-iot02a/configs/nsh/defconfig b/boards/arm/stm32u5/b-u585i-iot02a/configs/nsh/defconfig index 8522e1d301e..d3abc806e5e 100644 --- a/boards/arm/stm32u5/b-u585i-iot02a/configs/nsh/defconfig +++ b/boards/arm/stm32u5/b-u585i-iot02a/configs/nsh/defconfig @@ -53,9 +53,7 @@ CONFIG_SCHED_WAITPID=y CONFIG_STACK_COLORATION=y CONFIG_STM32U5_PWR=y CONFIG_STM32U5_SPI1=y -CONFIG_STM32U5_SRAM1=y CONFIG_STM32U5_SRAM3=y -CONFIG_STM32U5_SRAM4=y CONFIG_STM32U5_USART1=y CONFIG_SYSTEM_NSH=y CONFIG_SYSTEM_SPITOOL=y diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/Kconfig b/boards/arm/stm32u5/nucleo-u5a5zj-q/Kconfig new file mode 100644 index 00000000000..3cb118e5aed --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/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_U5A5ZJ_Q + +endif diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/README.txt b/boards/arm/stm32u5/nucleo-u5a5zj-q/README.txt new file mode 100644 index 00000000000..738877351c7 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/README.txt @@ -0,0 +1,88 @@ +NUCLEO-U5A5ZJ-Q README +====================== + + This README file discusses the port of NuttX to the STMicroelectronics + NUCLEO-U5A5ZJ-Q board. That board features the STM32U5A5ZJT6Q MCU with 4MiB + of Flash and 2500KiB of SRAM. + +Contents +======== + + - Status + - Serial Console + - Configurations + +Status +====== + 2023-07-16: Initial port - works all ram memory and i2c(not extensively tested) + The i2c driver is based on stm32l4 one + +Clock Source +============ + + Only the low speed external (LSE) 32.768kHz crystal (X2) is installed in + default configurations. + + FUNC GPIO + --------- ---- + OSC32_IN PC14 + OSC32_OUT PC15 + --------- ---- + +Serial Consoles +=============== + + Virtual COM Port on USART1 + -------------------------- + + Default board is configured to use USART1 as console. USART1 is connected + to the ST-LINKV3E Virtual COM port as well as made available on connector + CN10 (need some rework on PCB). + + Pins and Connectors: + + FUNC GPIO Connector + Pin NAME + ---- ---- ------ -------- + TXD: PA9 CN10 14 T.VCP_TX + RXD: PA10 CN9 13 T.VCP_RX + ---- ---- ------ -------- + +Configurations +============== + + Information Common to All Configurations + ---------------------------------------- + There is only one configuration which can be selected as follow: + + tools/configure.sh nucleo-u5a5zj-q:nsh + + Before building, make sure the PATH environment variable includes the + correct path to the directory than holds your toolchain binaries. + + And then build NuttX by simply typing the following. At the conclusion of + the make, the nuttx binary will reside in an ELF file called, simply, nuttx. + + make menuconfig + make + + The that is provided above as an argument to the tools/configure.sh + must be is one of the following. + + NOTES: + + 1. These configurations use the mconf-based configuration tool. To + change any of these configurations using that tool, you should: + + a. Build and install the kconfig-mconf tool. See nuttx/README.txt + see additional README.txt files in the NuttX tools repository. + + b. Execute 'make menuconfig' in nuttx/ in order to start the + reconfiguration process. + + 2. All of these configurations are set up to build under Linux using the + "GNU Tools for ARM Embedded Processors" that is maintained by ARM + (unless stated otherwise in the description of the configuration). + + https://developer.arm.com/open-source/gnu-toolchain/gnu-rm + diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/configs/nsh/defconfig b/boards/arm/stm32u5/nucleo-u5a5zj-q/configs/nsh/defconfig new file mode 100644 index 00000000000..0d66854c170 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/configs/nsh/defconfig @@ -0,0 +1,70 @@ +# +# 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_NSH_DISABLE_DATE is not set +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-u5a5zj-q" +CONFIG_ARCH_BOARD_NUCLEO_U5A5ZJ_Q=y +CONFIG_ARCH_CHIP="stm32u5" +CONFIG_ARCH_CHIP_STM32U5=y +CONFIG_ARCH_CHIP_STM32U5A5ZJT=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_TRUSTZONE_NONSECURE=y +CONFIG_ARMV8M_USEBASEPRI=y +CONFIG_BOARD_LOOPSPERMSEC=7997 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_WARN=y +CONFIG_DEFAULT_TASK_STACKSIZE=4096 +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_INIT_ENTRYNAME="nsh" +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=2048 +CONFIG_INPUT=y +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBM=y +CONFIG_MM_REGIONS=4 +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_POSIX_SPAWN_DEFAULT_STACKSIZE=2048 +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PTHREAD_STACK_DEFAULT=2048 +CONFIG_RAM_SIZE=131072 +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_STM32U5_PWR=y +CONFIG_STM32U5_SRAM2=y +CONFIG_STM32U5_SRAM2_HEAP=y +CONFIG_STM32U5_SRAM3=y +CONFIG_STM32U5_SRAM3_HEAP=y +CONFIG_STM32U5_SRAM5=y +CONFIG_STM32U5_SRAM5_HEAP=y +CONFIG_STM32U5_USART1=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NSH_STACKSIZE=2048 +CONFIG_SYSTEM_RAMTEST=y +CONFIG_SYSTEM_RAMTEST_STACKSIZE=2048 +CONFIG_SYSTEM_TEE=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART1_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/include/board.h b/boards/arm/stm32u5/nucleo-u5a5zj-q/include/board.h new file mode 100644 index 00000000000..4ed3b213dce --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/include/board.h @@ -0,0 +1,205 @@ +/**************************************************************************** + * boards/arm/stm32u5/nucleo-u5a5zj-q/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_STM32U5_NUCLEO_U5A5ZJ_Q_INCLUDE_BOARD_H +#define __BOARDS_ARM_STM32U5_NUCLEO_U5A5ZJ_Q_INCLUDE_BOARD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#ifndef __ASSEMBLY__ +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Clocking *****************************************************************/ + +/* The B-U585I-IOT02A board supports both HSE and LSE crystals (X1 and X2). + * However, as shipped, the X1 crystal is not populated. Therefore the board + * will need to run off the 32kHz-sync'ed MSIS. + * + * System Clock source : PLL (MSIS) + * SYSCLK(Hz) : 160000000 Determined by PLL configuration + * HCLK(Hz) : 160000000 + * AHB Prescaler : 1 (STM32_RCC_CFGR2_HPRE) (160MHz) + * APB1 Prescaler : 1 (STM32_RCC_CFGR2_PPRE1) (160MHz) + * APB2 Prescaler : 1 (STM32_RCC_CFGR2_PPRE2) (160MHz) + * APB3 Prescaler : 1 (STM32_RCC_CFGR3_PPRE3) (160MHz) + * MSIS Frequency(Hz) : 4000000 (nominal) + * MSIK Frequency(Hz) : 4000000 (nominal) + * PLL_MBOOST : 1 (Embedded power distribution booster) + * PLLM : 1 (STM32_PLLCFG_PLLM) + * PLLN : 80 (STM32_PLLCFG_PLLN) + * PLLP : 2 (STM32_PLLCFG_PLLP) + * PLLQ : 2 (STM32_PLLCFG_PLLQ) + * PLLR : 2 (STM32_PLLCFG_PLLR) + * Flash Latency(WS) : 4 + */ + +/* HSI - 16 MHz RC factory-trimmed + * LSI - 32 KHz RC + * MSI - 4 MHz, autotrimmed via LSE + * HSE - not installed + * LSE - 32.768 kHz installed + */ + +#define STM32_HSI_FREQUENCY 16000000ul +#define STM32_LSI_FREQUENCY 32000 +#define STM32_LSE_FREQUENCY 32768 + +#define STM32_BOARD_USEMSIS 1 +#define STM32_BOARD_MSISRANGE RCC_ICSCR1_MSISRANGE_4MHZ +#define STM32_BOARD_MSIKRANGE RCC_ICSCR1_MSIKRANGE_4MHZ + +/* PLL1 config; we use this to generate our system clock */ + +#define STM32_RCC_PLL1CFGR_PLL1M RCC_PLL1CFGR_PLL1M(1) +#define STM32_RCC_PLL1DIVR_PLL1N RCC_PLL1DIVR_PLL1N(80) +#define STM32_RCC_PLL1DIVR_PLL1P 0 +#undef STM32_RCC_PLL1CFGR_PLL1P_ENABLED +#define STM32_RCC_PLL1DIVR_PLL1Q 0 +#undef STM32_RCC_PLL1CFGR_PLL1Q_ENABLED +#define STM32_RCC_PLL1DIVR_PLL1R RCC_PLL1DIVR_PLL1R(2) +#define STM32_RCC_PLL1CFGR_PLL1R_ENABLED + +#define STM32_SYSCLK_FREQUENCY 160000000ul + +/* Enable LSE (for the RTC and for MSIS autotrimming) */ + +#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_HCLK /* 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) + +/* Configure the APB2 prescaler */ + +#define STM32_RCC_CFGR2_PPRE2 RCC_CFGR2_PPRE2_HCLK /* PCLK2 = HCLK / 1 */ +#define STM32_PCLK2_FREQUENCY (STM32_HCLK_FREQUENCY / 1) + +#define STM32_APB2_TIM1_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM15_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM16_CLKIN (STM32_PCLK2_FREQUENCY) + +/* Configure the APB3 prescaler */ + +#define STM32_RCC_CFGR3_PPRE3 RCC_CFGR3_PPRE3_HCLK /* PCLK3 = HCLK / 1 */ +#define STM32_PCLK3_FREQUENCY (STM32_HCLK_FREQUENCY / 1) + +/* 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. + * Note: TIM1,15,16 are on APB2, others on APB1 + */ + +#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_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 + +/* DMA Channel/Stream Selections ********************************************/ + +/* Alternate function pin selections ****************************************/ + +/* USART1: Connected to STLink VCP and to CN10 with small rework of pcb. */ + +#define GPIO_USART1_RX GPIO_USART1_RX_1 /* PA10 */ +#define GPIO_USART1_TX GPIO_USART1_TX_1 /* PA9 */ + +/* SPI1: Arduino Connector CN13 */ + +#define GPIO_SPI1_NSS (GPIO_OUTPUT|GPIO_SPEED_2MHZ| \ + GPIO_PUSHPULL|GPIO_OUTPUT_SET| \ + GPIO_PORTE|GPIO_PIN12) /* PE12 */ +#define GPIO_SPI1_SCK (GPIO_SPI1_SCK_4|GPIO_SPEED_25MHZ) /* PE13 */ +#define GPIO_SPI1_MISO (GPIO_SPI1_MISO_4) /* PE14 */ +#define GPIO_SPI1_MOSI (GPIO_SPI1_MOSI_4|GPIO_SPEED_25MHZ) /* PE15 */ + +#define GPIO_I2C1_SCL GPIO_I2C1_SCL_2 | GPIO_SPEED_50MHZ | GPIO_OPENDRAIN +#define GPIO_I2C1_SDA GPIO_I2C1_SDA_2 | GPIO_SPEED_50MHZ | GPIO_OPENDRAIN + +#define GPIO_I2C2_SCL GPIO_I2C2_SCL_4 | GPIO_SPEED_50MHZ | GPIO_OPENDRAIN +#define GPIO_I2C2_SDA GPIO_I2C2_SDA_4 | GPIO_SPEED_50MHZ | GPIO_OPENDRAIN + +/**************************************************************************** + * 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 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); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_STM32U5_NUCLEO_U5A5ZJ_Q_INCLUDE_BOARD_H */ diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/scripts/Make.defs b/boards/arm/stm32u5/nucleo-u5a5zj-q/scripts/Make.defs new file mode 100644 index 00000000000..c368f3902b2 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/scripts/Make.defs @@ -0,0 +1,38 @@ +############################################################################## +# boards/arm/stm32u5/b-u585i-iot02a/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) -pipe +CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) +CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe +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/stm32u5/nucleo-u5a5zj-q/scripts/flash.ld b/boards/arm/stm32u5/nucleo-u5a5zj-q/scripts/flash.ld new file mode 100644 index 00000000000..21643acb8c9 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/scripts/flash.ld @@ -0,0 +1,103 @@ +/**************************************************************************** + * 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 STM32Uxx has 4 MiB of FLASH beginning at address 0x0800:0000 and + * 768 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 = 4096K + sram (rwx) : ORIGIN = 0x20000000, LENGTH = 768K +} + +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(.); + *(.init_array .init_array.*) + _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/stm32u5/nucleo-u5a5zj-q/scripts/tfm-ns.ld b/boards/arm/stm32u5/nucleo-u5a5zj-q/scripts/tfm-ns.ld new file mode 100644 index 00000000000..347ffc38f93 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/scripts/tfm-ns.ld @@ -0,0 +1,114 @@ +/**************************************************************************** + * boards/arm/stm32u5/b-u585i-iot02a/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 internal flash. Compare [UM2851], + * Figure 7. Furthermore, see Figure 18 for the SRAM1 area used for 'Non- + * Secure application volatile data' + * + * While the 'Non-Secure Image primary slot Area 1' is actually 640KiB 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 + * [UM2851] STMicroelectronics. UM2851: Getting started with STM32CubeU5 TFM + * application, Rev 1, June 2021 + */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x08052400, LENGTH = 0x9DC00 + 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(.); + *(.init_array .init_array.*) + _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/stm32u5/nucleo-u5a5zj-q/src/Makefile b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/Makefile new file mode 100644 index 00000000000..2dcbe5f0298 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/Makefile @@ -0,0 +1,38 @@ +############################################################################## +# boards/arm/stm32u5/nucleo-u5a5zj-q/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_spi.c + +ifeq ($(CONFIG_BOARDCTL),y) +CSRCS += stm32_appinit.c +endif + +ifeq ($(CONFIG_ARCH_BOARD_STM32U5_CUSTOM_CLOCKCONFIG),y) +CSRCS += stm32_clockconfig.c +endif + +ifeq ($(CONFIG_USBDEV),y) +CSRCS += stm32_usb.c +endif + +include $(TOPDIR)/boards/Board.mk diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/src/nucleo-u5a5zj-q.h b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/nucleo-u5a5zj-q.h new file mode 100644 index 00000000000..40dc932bc7e --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/nucleo-u5a5zj-q.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * boards/arm/stm32u5/nucleo-u5a5zj-q/src/nucleo-u5a5zj-q.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_STM32U5_NUCLEO_U5A5ZJ_Q_SRC_NUCLEO_U5A5ZJ_Q_H +#define __BOARDS_ARM_STM32U5_NUCLEO_U5A5ZJ_Q_SRC_NUCLEO_U5A5ZJ_Q_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 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Function Declarations + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI +void stm32_spidev_initialize(void); +#endif + +/**************************************************************************** + * 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_STM32U5_NUCLEO_U5A5ZJ_Q_SRC_NUCLEO_U5A5ZJ_Q_H */ diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_appinit.c b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_appinit.c new file mode 100644 index 00000000000..4d7711eb8c9 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_appinit.c @@ -0,0 +1,71 @@ +/**************************************************************************** + * boards/arm/stm32u5/nucleo-u5a5zj-q/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-u5a5zj-q.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/stm32u5/nucleo-u5a5zj-q/src/stm32_boot.c b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_boot.c new file mode 100644 index 00000000000..eeb09c00a66 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_boot.c @@ -0,0 +1,81 @@ +/**************************************************************************** + * boards/arm/stm32u5/nucleo-u5a5zj-q/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-u5a5zj-q.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_SPI + /* Configure SPI chip selects */ + + stm32_spidev_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/stm32u5/nucleo-u5a5zj-q/src/stm32_bringup.c b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_bringup.c new file mode 100644 index 00000000000..8c879c7419f --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_bringup.c @@ -0,0 +1,159 @@ +/**************************************************************************** + * boards/arm/stm32u5/nucleo-u5a5zj-q/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 +#include + +#include "nucleo-u5a5zj-q.h" + +#include + +#include + +#if defined(CONFIG_I2C) + +#include "stm32_i2c.h" +FAR struct i2c_master_s *i2c1_m; +FAR struct i2c_master_s *i2c2_m; +# ifdef CONFIG_RTC_DSXXXX +# include +# include +# endif /* CONFIG_RTC_DSXXXX */ + +#endif /* CONFIG_I2C */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#define DEVNO_ZERO 0 +#define DEVNO_ONE 1 +#define DEVNO_TWO 2 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Should not be here, but there is a bug in clock_initalize logic that + * prevents external RTC to be used when no internal RTC ! + * **************************************************************************/ +#if defined(CONFIG_RTC) && defined(CONFIG_RTC_EXTERNAL) +int up_rtc_initialize(void) +{ + return OK; +} +#endif + +/**************************************************************************** + * 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_I2C) + i2c1_m = stm32_i2cbus_initialize(1); + if (i2c1_m == NULL) + { + syslog(LOG_ERR, "ERROR: Failed to init i2c controller\n"); + return(-1); + } + + ret = i2c_register(i2c1_m, DEVNO_ONE); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register I2C%d driver: %d\n", + DEVNO_ONE, ret); + stm32_i2cbus_uninitialize(i2c1_m); + return -1; + } + +#if defined(STM32U5_I2C2) + i2c2_m = stm32_i2cbus_initialize(2); + if (i2c2_m == NULL) + { + syslog(LOG_ERR, "ERROR: Failed to init i2c controller\n"); + return(-1); + } + + ret = i2c_register(i2c2_m, DEVNO_TWO); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register I2C%d driver: %d\n", + DEVNO_TWO, ret); + stm32_i2cbus_uninitialize(i2c1_m); + stm32_i2cbus_uninitialize(i2c2_m); + return -1; + } +#endif /* STM32_I2C2 */ +#endif /* CONFIG_I2C */ + +#if defined(CONFIG_RTC) && defined(CONFIG_RTC_EXTERNAL) && defined(CONFIG_RTC_DSXXXX) + ret = dsxxxx_rtc_initialize(i2c1_m); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: dsxxxx_rtc_initialize() failed: %d\n", ret); + } + else + { + /* Synchronize the system time to the RTC time */ + + syslog(LOG_INFO, "INFO: clock sync\n"); + clock_synchronize(NULL); + } +#endif /* CONFIG_RTC */ + + UNUSED(ret); + return OK; +} diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_clockconfig.c b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_clockconfig.c new file mode 100644 index 00000000000..49422845229 --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_clockconfig.c @@ -0,0 +1,48 @@ +/**************************************************************************** + * boards/arm/stm32u5/nucleo-u5a5zj-q/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 B-U585I-IOT02A 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_STM32L5_CUSTOM_CLOCKCONFIG to avoid the standard clock + * config logic to run and instead do just nothing in this function. + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_BOARD_STM32U5_CUSTOM_CLOCKCONFIG) +void stm32_board_clockconfig(void) +{ +} +#endif diff --git a/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_spi.c b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_spi.c new file mode 100644 index 00000000000..ae72e8c637f --- /dev/null +++ b/boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_spi.c @@ -0,0 +1,184 @@ +/**************************************************************************** + * boards/arm/stm32u5/nucleo-u5a5zj-q/src/stm32_spi.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_gpio.h" +#include "stm32_spi.h" + +#include "nucleo-u5a5zj-q.h" +#include + +#ifdef CONFIG_STM32U5_SPI + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the B-U585I-IOT02A + * board. + * + ****************************************************************************/ + +void stm32_spidev_initialize(void) +{ + /* NOTE: Clocking for SPI1 and/or SPI3 was already provided in stm32_rcc.c. + * Configurations of SPI pins is performed in stm32_spi.c. + * Here, we only initialize chip select pins unique to the board + * architecture. + */ + +#ifdef CONFIG_STM32U5_SPI1 + stm32_configgpio(GPIO_SPI1_NSS); +#endif +} + +/**************************************************************************** + * Name: stm32_spi1/2/3/4/5select and stm32_spi1/2/3/4/5status + * + * Description: + * The external functions, stm32_spi1/2/3select and stm32_spi1/2/3status + * must be provided by board-specific logic. They are implementations of + * the select and status methods of the SPI interface defined by struct + * spi_ops_s (see include/nuttx/spi/spi.h). All other methods (including + * stm32_spibus_initialize()) are provided by common STM32 logic. To use + * this common SPI logic on your board: + * + * 1. Provide logic in stm32_boardinitialize() to configure SPI chip select + * pins. + * 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions + * in your board-specific logic. These functions will perform chip + * selection and status operations using GPIOs in the way your board is + * configured. + * 3. Add a calls to stm32_spibus_initialize() in your low level + * application initialization logic + * 4. The handle returned by stm32_spibus_initialize() may then be used + * to bind the SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ + +#ifdef CONFIG_STM32U5_SPI1 +void stm32_spi1select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %08lx CS: %s\n", + (unsigned long)devid, selected ? "assert" : "de-assert"); + + stm32_gpiowrite(GPIO_SPI1_NSS, !selected); +} + +uint8_t stm32_spi1status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +#ifdef CONFIG_STM32U5_SPI2 +void stm32_spi2select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %08lx CS: %s\n", + (unsigned long)devid, selected ? "assert" : "de-assert"); +} + +uint8_t stm32_spi2status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +#ifdef CONFIG_STM32U5_SPI3 +void stm32_spi3select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %08lx CS: %s\n", + (unsigned long)devid, selected ? "assert" : "de-assert"); +} + +uint8_t stm32_spi3status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +/**************************************************************************** + * Name: stm32_spi1cmddata + * + * Description: + * This function must be provided by platform-specific logic. This is an + * implementation of the cmddata method of the SPI interface defined by + * struct spi_ops_s (see include/nuttx/spi/spi.h). + * + * Input Parameters: + * + * spi - SPI device that controls the bus the device that requires the CMD/ + * DATA selection. + * devid - If there are multiple devices on the bus, this selects which one + * to select cmd or data. NOTE: This design restricts, for example, + * one one SPI display per SPI bus. + * cmd - true: select command; false: select data + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_CMDDATA +#ifdef CONFIG_STM32U5_SPI1 +int stm32_spi1cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +#ifdef CONFIG_STM32U5_SPI2 +int stm32_spi2cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +#ifdef CONFIG_STM32U5_SPI3 +int stm32_spi3cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif +#endif /* CONFIG_SPI_CMDDATA */ +#endif /* CONFIG_STM32U5_SPI */