From fa86c2b73c3c357a3bd82296d958efca509b7d85 Mon Sep 17 00:00:00 2001 From: JohnK1987 Date: Sun, 8 Sep 2024 21:58:45 +0200 Subject: [PATCH] Add support of SPI API for STM32H5 family (#324) * fix PWM pin map in context of Timer change * Note about DAC on Nucleo-H503RB * Add ADC and DAC for STM32H5 * Copyright fix * Add I2C for STM32H5 * fix I2C related code * ADC/DAC fix * Enable I2C API * Copyright fix * Add SPI for STM32H5 * Modification of stm spi API for h5 family * fix I2C device * fix I2C ASYNCH macro * fix revert back the stop variable position * Fix clock for SPI * fix some details * Rename startup_stm32h563xx.s to startup_stm32h563xx.S * Rename startup_stm32h503xx.s to startup_stm32h503xx.S --------- Co-authored-by: Jan Kamidra --- .../TARGET_STM/TARGET_STM32H5/CMakeLists.txt | 1 + ...up_stm32h503xx.s => startup_stm32h503xx.S} | 2 +- ...up_stm32h563xx.s => startup_stm32h563xx.S} | 2 +- .../TARGET_STM32H5/clock_cfg/system_clock.c | 10 ++- targets/TARGET_STM/TARGET_STM32H5/objects.h | 14 ---- targets/TARGET_STM/TARGET_STM32H5/spi_api.c | 79 +++++++++++++++++++ .../TARGET_STM/TARGET_STM32H5/spi_device.h | 30 +++++++ .../TARGET_STM/TARGET_STM32H5/stm_dma_info.h | 61 ++++++++++++++ targets/TARGET_STM/stm_spi_api.c | 28 +++++-- targets/targets.json5 | 6 +- 10 files changed, 206 insertions(+), 27 deletions(-) rename targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H503xB/TOOLCHAIN_GCC_ARM/{startup_stm32h503xx.s => startup_stm32h503xx.S} (99%) rename targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H563xI/TOOLCHAIN_GCC_ARM/{startup_stm32h563xx.s => startup_stm32h563xx.S} (99%) create mode 100644 targets/TARGET_STM/TARGET_STM32H5/spi_api.c create mode 100644 targets/TARGET_STM/TARGET_STM32H5/spi_device.h create mode 100644 targets/TARGET_STM/TARGET_STM32H5/stm_dma_info.h diff --git a/targets/TARGET_STM/TARGET_STM32H5/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32H5/CMakeLists.txt index 9f1fcbc95e6..1ffa7cc963c 100644 --- a/targets/TARGET_STM/TARGET_STM32H5/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32H5/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(mbed-stm32h5 gpio_irq_device.c i2c_device.c serial_device.c + spi_api.c pwmout_device.c ) diff --git a/targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H503xB/TOOLCHAIN_GCC_ARM/startup_stm32h503xx.s b/targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H503xB/TOOLCHAIN_GCC_ARM/startup_stm32h503xx.S similarity index 99% rename from targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H503xB/TOOLCHAIN_GCC_ARM/startup_stm32h503xx.s rename to targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H503xB/TOOLCHAIN_GCC_ARM/startup_stm32h503xx.S index 8be4f06cc2d..c7c91bbe9c5 100644 --- a/targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H503xB/TOOLCHAIN_GCC_ARM/startup_stm32h503xx.s +++ b/targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H503xB/TOOLCHAIN_GCC_ARM/startup_stm32h503xx.S @@ -541,4 +541,4 @@ g_pfnVectors: .thumb_set I3C2_ER_IRQHandler,Default_Handler .weak COMP1_IRQHandler - .thumb_set COMP1_IRQHandler,Default_Handler \ No newline at end of file + .thumb_set COMP1_IRQHandler,Default_Handler diff --git a/targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H563xI/TOOLCHAIN_GCC_ARM/startup_stm32h563xx.s b/targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H563xI/TOOLCHAIN_GCC_ARM/startup_stm32h563xx.S similarity index 99% rename from targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H563xI/TOOLCHAIN_GCC_ARM/startup_stm32h563xx.s rename to targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H563xI/TOOLCHAIN_GCC_ARM/startup_stm32h563xx.S index d85f797f651..8d6911343ea 100644 --- a/targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H563xI/TOOLCHAIN_GCC_ARM/startup_stm32h563xx.s +++ b/targets/TARGET_STM/TARGET_STM32H5/TARGET_STM32H563xI/TOOLCHAIN_GCC_ARM/startup_stm32h563xx.S @@ -688,4 +688,4 @@ g_pfnVectors: .thumb_set LPTIM5_IRQHandler,Default_Handler .weak LPTIM6_IRQHandler - .thumb_set LPTIM6_IRQHandler,Default_Handler \ No newline at end of file + .thumb_set LPTIM6_IRQHandler,Default_Handler diff --git a/targets/TARGET_STM/TARGET_STM32H5/clock_cfg/system_clock.c b/targets/TARGET_STM/TARGET_STM32H5/clock_cfg/system_clock.c index bad737e1182..4fefc44b5c2 100644 --- a/targets/TARGET_STM/TARGET_STM32H5/clock_cfg/system_clock.c +++ b/targets/TARGET_STM/TARGET_STM32H5/clock_cfg/system_clock.c @@ -123,7 +123,10 @@ else // Divisible by 5MHz RCC_OscInitStruct.PLL.PLLSource = RCC_PLL1_SOURCE_HSE; RCC_OscInitStruct.PLL.PLLP = 2; - RCC_OscInitStruct.PLL.PLLQ = 2; + // Most of the SPI busses are clocked off of PLL1Q, and the max usable frequency for SPI is about + // ~50MHz. Plus, SPI has only limited, power-of-2 prescaler options so a high input clock really hurts + // its clock resolution. So, give it a much lower input clock. + RCC_OscInitStruct.PLL.PLLQ = 10; // output freq = 50MHz RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLFRACN = 0; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1_VCORANGE_WIDE; @@ -189,7 +192,10 @@ uint8_t SetSysClock_PLL_HSI(void) RCC_OscInitStruct.PLL.PLLM = 4; RCC_OscInitStruct.PLL.PLLN = 31; RCC_OscInitStruct.PLL.PLLP = 2; - RCC_OscInitStruct.PLL.PLLQ = 2; + // Most of the SPI busses are clocked off of PLL1Q, and the max usable frequency for SPI is about + // ~50MHz. Plus, SPI has only limited, power-of-2 prescaler options so a high input clock really hurts + // its clock resolution. So, give it a much lower input clock. + RCC_OscInitStruct.PLL.PLLQ = 10; // output freq = 50MHz RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1_VCIRANGE_3; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1_VCORANGE_WIDE; diff --git a/targets/TARGET_STM/TARGET_STM32H5/objects.h b/targets/TARGET_STM/TARGET_STM32H5/objects.h index 94b1e398f8e..007a43f1a5e 100644 --- a/targets/TARGET_STM/TARGET_STM32H5/objects.h +++ b/targets/TARGET_STM/TARGET_STM32H5/objects.h @@ -51,20 +51,6 @@ struct trng_s { RNG_HandleTypeDef handle; }; -struct spi_s { - SPI_HandleTypeDef handle; - IRQn_Type spiIRQ; - SPIName spi; - PinName pin_miso; - PinName pin_mosi; - PinName pin_sclk; - PinName pin_ssel; -#if DEVICE_SPI_ASYNCH - uint32_t event; - uint8_t transfer_type; -#endif -}; - struct serial_s { UARTName uart; int index; // Used by irq diff --git a/targets/TARGET_STM/TARGET_STM32H5/spi_api.c b/targets/TARGET_STM/TARGET_STM32H5/spi_api.c new file mode 100644 index 00000000000..5881c860530 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32H5/spi_api.c @@ -0,0 +1,79 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015-2024 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "mbed_assert.h" +#include "mbed_error.h" +#include "spi_api.h" + +#if DEVICE_SPI + +#include "cmsis.h" +#include "pinmap.h" +#include "PeripheralPins.h" +#include "mbed_error.h" +#include "spi_device.h" + +#if DEVICE_SPI_ASYNCH +#define SPI_S(obj) (( struct spi_s *)(&(obj->spi))) +#else +#define SPI_S(obj) (( struct spi_s *)(obj)) +#endif + +/* + * Only the frequency is managed in the family specific part + * the rest of SPI management is common to all STM32 families + */ +int spi_get_clock_freq(spi_t *obj) +{ + struct spi_s *spiobj = SPI_S(obj); + int spi_hz = 0; + + /* Get source clock depending on SPI instance */ + switch ((int)spiobj->spi) { + case SPI_1: + spi_hz = LL_RCC_GetSPIClockFreq(LL_RCC_SPI1_CLKSOURCE); + break; + case SPI_2: + spi_hz = LL_RCC_GetSPIClockFreq(LL_RCC_SPI2_CLKSOURCE); + break; + case SPI_3: + spi_hz = LL_RCC_GetSPIClockFreq(LL_RCC_SPI3_CLKSOURCE); + break; +#if defined(SPI4) + case SPI_4: + spi_hz = LL_RCC_GetSPIClockFreq(LL_RCC_SPI4_CLKSOURCE); + break; +#endif +#if defined(SPI5) + case SPI_5: + spi_hz = LL_RCC_GetSPIClockFreq(LL_RCC_SPI5_CLKSOURCE); + break; +#endif +#if defined(SPI6) + case SPI_6: + spi_hz = LL_RCC_GetSPIClockFreq(LL_RCC_SPI6_CLKSOURCE); + break; +#endif + default: + error("CLK: SPI instance not set"); + break; + } + if (spi_hz == LL_RCC_PERIPH_FREQUENCY_NO) { + error("spi_hz not found\n"); + } + return spi_hz; +} + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32H5/spi_device.h b/targets/TARGET_STM/TARGET_STM32H5/spi_device.h new file mode 100644 index 00000000000..6225010d705 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32H5/spi_device.h @@ -0,0 +1,30 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015-2024 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_SPI_DEVICE_H +#define MBED_SPI_DEVICE_H + +#include "stm32h5xx_ll_rcc.h" +#include "stm32h5xx_ll_spi.h" + +#define SPI_IP_VERSION_V2 + +// Defines the word legnth capability of the device where Nth bit allows for N window size +#define STM32_SPI_CAPABILITY_WORD_LENGTH (0xFFFFFFF8) + +// We have DMA support +#define STM32_SPI_CAPABILITY_DMA 1 + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32H5/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32H5/stm_dma_info.h new file mode 100644 index 00000000000..05c3aa67896 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32H5/stm_dma_info.h @@ -0,0 +1,61 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016-2024 STMicroelectronics + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed 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 MBED_OS_STM_DMA_INFO_H +#define MBED_OS_STM_DMA_INFO_H + +#include "cmsis.h" +#include "stm_dma_utils.h" + +// STM32h5 devices. +// On this device, the DMA channels may be chosen arbitrarily. + +/// Mapping from SPI index to DMA link info for Tx +static const DMALinkInfo SPITxDMALinks[] = { + {1, 0, GPDMA1_REQUEST_SPI1_TX}, + {1, 2, GPDMA1_REQUEST_SPI2_TX}, + {1, 4, GPDMA1_REQUEST_SPI3_TX} +#if defined (SPI4) + ,{1, 6, GPDMA1_REQUEST_SPI4_TX} +#endif +#if defined (SPI5) + ,{2, 0, GPDMA1_REQUEST_SPI5_TX} +#endif +#if defined (SPI6) + ,{2, 2, GPDMA1_REQUEST_SPI6_TX} +#endif +}; + +/// Mapping from SPI index to DMA link info for Rx +static const DMALinkInfo SPIRxDMALinks[] = { + {1, 1, GPDMA1_REQUEST_SPI1_RX}, + {1, 3, GPDMA1_REQUEST_SPI2_RX}, + {1, 5, GPDMA1_REQUEST_SPI3_TX} +#if defined (SPI4) + ,{1, 7, GPDMA1_REQUEST_SPI4_RX} +#endif +#if defined (SPI5) + ,{2, 1, GPDMA1_REQUEST_SPI5_RX} +#endif +#if defined (SPI6) + ,{2, 3, GPDMA1_REQUEST_SPI6_RX} +#endif +}; + + + +#endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/stm_spi_api.c b/targets/TARGET_STM/stm_spi_api.c index fae3adbdf26..27fe75b477e 100644 --- a/targets/TARGET_STM/stm_spi_api.c +++ b/targets/TARGET_STM/stm_spi_api.c @@ -76,7 +76,7 @@ #define TIMEOUT_1_BYTE 10 #if defined(SPI_FLAG_FRLVL) // STM32F0 STM32F3 STM32F7 STM32L4 -#if defined(STM32U5) +#if defined(STM32U5) || defined(STM32H5) extern HAL_StatusTypeDef HAL_SPIEx_FlushRxFifo(const SPI_HandleTypeDef *hspi); #else extern HAL_StatusTypeDef HAL_SPIEx_FlushRxFifo(SPI_HandleTypeDef *hspi); @@ -291,8 +291,10 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI1; #if defined (RCC_SPI123CLKSOURCE_PLL) PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL; +#elif defined (RCC_SPI1CLKSOURCE_SYSCLK) + PeriphClkInit.Spi1ClockSelection = RCC_SPI1CLKSOURCE_SYSCLK; #else - PeriphClkInit.Spi1ClockSelection = RCC_SPI1CLKSOURCE_SYSCLK; + PeriphClkInit.Spi1ClockSelection = RCC_SPI1CLKSOURCE_PLL1Q; #endif if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { error("HAL_RCCEx_PeriphCLKConfig\n"); @@ -314,8 +316,10 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI2; #if defined (RCC_SPI123CLKSOURCE_PLL) PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL; -#else +#elif defined (RCC_SPI2CLKSOURCE_SYSCLK) PeriphClkInit.Spi2ClockSelection = RCC_SPI2CLKSOURCE_SYSCLK; +#else + PeriphClkInit.Spi2ClockSelection = RCC_SPI2CLKSOURCE_PLL1Q; #endif if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { error("HAL_RCCEx_PeriphCLKConfig\n"); @@ -337,8 +341,10 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI3; #if defined (RCC_SPI123CLKSOURCE_PLL) PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL; -#else +#elif defined (RCC_SPI2CLKSOURCE_SYSCLK) PeriphClkInit.Spi3ClockSelection = RCC_SPI3CLKSOURCE_SYSCLK; +#else + PeriphClkInit.Spi3ClockSelection = RCC_SPI3CLKSOURCE_PLL1Q; #endif if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { error("HAL_RCCEx_PeriphCLKConfig\n"); @@ -358,7 +364,11 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) if (spiobj->spi == SPI_4) { #if defined(SPI_IP_VERSION_V2) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI4; +#if defined RCC_SPI45CLKSOURCE_PCLK1 PeriphClkInit.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PCLK1; +#else + PeriphClkInit.Spi4ClockSelection = RCC_SPI4CLKSOURCE_PCLK2; +#endif if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { error("HAL_RCCEx_PeriphCLKConfig\n"); } @@ -377,7 +387,11 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) if (spiobj->spi == SPI_5) { #if defined(SPI_IP_VERSION_V2) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI5; +#if defined RCC_SPI45CLKSOURCE_PCLK1 PeriphClkInit.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PCLK1; +#else + PeriphClkInit.Spi5ClockSelection = RCC_SPI5CLKSOURCE_PCLK3; +#endif if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { error("HAL_RCCEx_PeriphCLKConfig\n"); } @@ -396,7 +410,11 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) if (spiobj->spi == SPI_6) { #if defined(SPI_IP_VERSION_V2) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI6; +#if defined RCC_SPI6CLKSOURCE_PCLK4 PeriphClkInit.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PCLK4; +#else + PeriphClkInit.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PCLK2; +#endif if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { error("HAL_RCCEx_PeriphCLKConfig\n"); } @@ -508,7 +526,7 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel SPI_INIT_DIRECT(obj, &explicit_spi_pinmap); } -#ifdef STM32_SPI_CAPABILITY_DMA +#if STM32_SPI_CAPABILITY_DMA /** * Initialize the DMA for an SPI object in the Tx direction. diff --git a/targets/targets.json5 b/targets/targets.json5 index 90e693e44b1..a130d946788 100644 --- a/targets/targets.json5 +++ b/targets/targets.json5 @@ -3093,16 +3093,14 @@ ], "device_has_add": [ "MPU", - "ANALOGOUT" + "ANALOGOUT", + "SPI_32BIT_WORDS" ], "device_has_remove": [ "FLASH", "LPTICKER", "CAN", "SERIAL_FC", - "SPI", - "SPISLAVE", - "SPI_ASYNCH", "WATCHDOG", "ETHERNET", "EMAC"