From 44a1de26c094fa535e4968dde24c6315559e17b0 Mon Sep 17 00:00:00 2001 From: wdx04 Date: Sun, 27 Apr 2025 15:38:31 +0800 Subject: [PATCH 1/7] Accelerate QSPI read/write operations by DMA Support all STM32 Families with QSPI/OSPI HAL API --- targets/TARGET_STM/TARGET_STM32F4/objects.h | 3 + .../TARGET_STM/TARGET_STM32F4/stm_dma_info.h | 5 + targets/TARGET_STM/TARGET_STM32F7/objects.h | 3 + .../TARGET_STM/TARGET_STM32F7/stm_dma_info.h | 5 + targets/TARGET_STM/TARGET_STM32G4/objects.h | 3 + .../TARGET_STM/TARGET_STM32G4/stm_dma_info.h | 6 + targets/TARGET_STM/TARGET_STM32H7/objects.h | 6 + .../TARGET_STM/TARGET_STM32H7/stm_dma_info.h | 12 + targets/TARGET_STM/TARGET_STM32L4/objects.h | 6 + .../TARGET_STM/TARGET_STM32L4/stm_dma_info.h | 11 + targets/TARGET_STM/TARGET_STM32L5/objects.h | 6 + .../TARGET_STM/TARGET_STM32L5/stm_dma_info.h | 4 + targets/TARGET_STM/TARGET_STM32U5/objects.h | 6 + .../TARGET_STM/TARGET_STM32U5/stm_dma_info.h | 5 + targets/TARGET_STM/TARGET_STM32WB/objects.h | 3 + .../TARGET_STM/TARGET_STM32WB/stm_dma_info.h | 5 + targets/TARGET_STM/ospi_api.c | 1 + targets/TARGET_STM/qspi_api.c | 312 +++++++- targets/TARGET_STM/stm_dma_ip_v1.h | 6 + targets/TARGET_STM/stm_dma_utils.c | 730 ++++++++++++------ targets/TARGET_STM/stm_dma_utils.h | 37 +- targets/TARGET_STM/stm_spi_api.c | 4 +- 22 files changed, 927 insertions(+), 252 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32F4/objects.h b/targets/TARGET_STM/TARGET_STM32F4/objects.h index 58fb19094dc..a7de253b5b7 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32F4/objects.h @@ -28,6 +28,8 @@ #include "stm32f4xx_ll_rtc.h" #include "stm32f4xx_ll_rcc.h" +#include "stm_dma_info.h" + #ifdef __cplusplus extern "C" { #endif @@ -150,6 +152,7 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; + bool dmaInitialized; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32F4/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32F4/stm_dma_info.h index ea3c6a256ee..f7894165074 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32F4/stm_dma_info.h @@ -48,4 +48,9 @@ static const DMALinkInfo SPIRxDMALinks[] = { {2, 6, 1}, // SPI6 Rx is DMA2 Stream 6 Channel 1 }; +/// Mapping from QSPI index to DMA link info +static const DMALinkInfo QSPIDMALinks[] = { + {2, 7, 3}, // QUADSPI is DMA2 Stream 7 Channel 3 +}; + #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/TARGET_STM32F7/objects.h b/targets/TARGET_STM/TARGET_STM32F7/objects.h index 9f6f2b82be0..0cf13355c3f 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/objects.h +++ b/targets/TARGET_STM/TARGET_STM32F7/objects.h @@ -42,6 +42,8 @@ #include "stm32f7xx_ll_pwr.h" #include "stm32f7xx_ll_rcc.h" +#include "stm_dma_info.h" + #ifdef __cplusplus extern "C" { #endif @@ -124,6 +126,7 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; + bool dmaInitialized; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32F7/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32F7/stm_dma_info.h index 137f854d696..179c56dc756 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32F7/stm_dma_info.h @@ -48,4 +48,9 @@ static const DMALinkInfo SPIRxDMALinks[] = { {2, 6, 1}, // SPI6 Rx is DMA2 Stream 6 Channel 1 }; +/// Mapping from QSPI index to DMA link info +static const DMALinkInfo QSPIDMALinks[] = { + {2, 7, 3}, // QUADSPI is DMA2 Stream 7 Channel 3 +}; + #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/TARGET_STM32G4/objects.h b/targets/TARGET_STM/TARGET_STM32G4/objects.h index f22b73baa9e..d984b164ba1 100644 --- a/targets/TARGET_STM/TARGET_STM32G4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32G4/objects.h @@ -26,6 +26,8 @@ #include "stm32g4xx_ll_rtc.h" #include "stm32g4xx_ll_rcc.h" +#include "stm_dma_info.h" + #ifdef __cplusplus extern "C" { #endif @@ -106,6 +108,7 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; + bool dmaInitialized; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32G4/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32G4/stm_dma_info.h index 9b7d1a1df6e..315b1a18348 100644 --- a/targets/TARGET_STM/TARGET_STM32G4/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32G4/stm_dma_info.h @@ -44,5 +44,11 @@ static const DMALinkInfo SPIRxDMALinks[] = { #endif }; +/// Mapping from QSPI index to DMA link info +static const DMALinkInfo QSPIDMALinks[] = { +#if defined(QUADSPI) + {1, 7, DMA_REQUEST_QUADSPI }, +#endif +}; #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/TARGET_STM32H7/objects.h b/targets/TARGET_STM/TARGET_STM32H7/objects.h index 5f8894d8b00..5edba2366f3 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/objects.h +++ b/targets/TARGET_STM/TARGET_STM32H7/objects.h @@ -31,6 +31,8 @@ #include "stm32h7xx_ll_pwr.h" #include "stm32h7xx_ll_system.h" +#include "stm_dma_info.h" + #ifdef __cplusplus extern "C" { #endif @@ -94,6 +96,8 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; + IRQn_Type qspiIRQ; + bool dmaInitialized; }; #endif @@ -112,6 +116,8 @@ struct ospi_s { PinName sclk; PinName ssel; PinName dqs; + IRQn_Type ospiIRQ; + bool dmaInitialized; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32H7/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32H7/stm_dma_info.h index 8a790824193..4692b1af719 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32H7/stm_dma_info.h @@ -42,5 +42,17 @@ static const DMALinkInfo SPIRxDMALinks[] = { {2, 0, DMA_REQUEST_SPI5_RX}, }; +/// Mapping from QSPI/OSPI index to DMA link info +#if defined(OCTOSPI1) +static const DMALinkInfo OSPIDMALinks[] = { + {4, 0, MDMA_REQUEST_OCTOSPI1_FIFO_TH}, + {4, 1, MDMA_REQUEST_OCTOSPI2_FIFO_TH} +}; +#else +static const DMALinkInfo QSPIDMALinks[] = { + {4, 0, MDMA_REQUEST_QUADSPI_FIFO_TH}, +}; +#endif + #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/TARGET_STM32L4/objects.h b/targets/TARGET_STM/TARGET_STM32L4/objects.h index 81022a2fc29..93d9a489448 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32L4/objects.h @@ -31,6 +31,8 @@ #include "stm32l4xx_ll_pwr.h" #include "stm32l4xx_ll_rcc.h" +#include "stm_dma_utils.h" + #ifdef __cplusplus extern "C" { #endif @@ -106,6 +108,7 @@ struct can_s { struct qspi_s { #if defined(OCTOSPI1) OSPI_HandleTypeDef handle; + IRQn_Type qspiIRQ; #else QSPI_HandleTypeDef handle; #endif @@ -116,6 +119,7 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; + bool dmaInitialized; }; #endif @@ -134,6 +138,8 @@ struct ospi_s { PinName sclk; PinName ssel; PinName dqs; + IRQn_Type ospiIRQ; + bool dmaInitialized; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32L4/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32L4/stm_dma_info.h index 7a592a572f9..c0167c607ae 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32L4/stm_dma_info.h @@ -40,6 +40,12 @@ static const DMALinkInfo SPIRxDMALinks[] = { {1, 6, DMA_REQUEST_SPI3_RX} }; +/// Mapping from OSPI index to DMA link info +static const DMALinkInfo OSPIDMALinks[] = { + {1, 7, DMA_REQUEST_OCTOSPI1}, + {2, 1, DMA_REQUEST_OCTOSPI2}, +}; + #else @@ -60,6 +66,11 @@ static const DMALinkInfo SPIRxDMALinks[] = { {2, 1, 3} // SPI3 Rx is DMA2 Ch1 Request 3 }; +/// Mapping from QSPI index to DMA link info +static const DMALinkInfo QSPIDMALinks[] = { + {2, 7, 3}, // QUADSPI is DMA2 Ch7 Request 3 +}; + #endif #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/TARGET_STM32L5/objects.h b/targets/TARGET_STM/TARGET_STM32L5/objects.h index e9e41b58436..1ac885781c5 100644 --- a/targets/TARGET_STM/TARGET_STM32L5/objects.h +++ b/targets/TARGET_STM/TARGET_STM32L5/objects.h @@ -27,6 +27,8 @@ #include "stm32l5xx_ll_pwr.h" #include "stm32l5xx_ll_rcc.h" +#include "stm_dma_info.h" + #ifdef __cplusplus extern "C" { #endif @@ -112,6 +114,8 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; + IRQn_Type qspiIRQ; + bool dmaInitialized; }; struct ospi_s { @@ -128,6 +132,8 @@ struct ospi_s { PinName sclk; PinName ssel; PinName dqs; + IRQn_Type ospiIRQ; + bool dmaInitialized; }; #ifdef __cplusplus diff --git a/targets/TARGET_STM/TARGET_STM32L5/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32L5/stm_dma_info.h index 46ade14d374..3f4e19123df 100644 --- a/targets/TARGET_STM/TARGET_STM32L5/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32L5/stm_dma_info.h @@ -38,5 +38,9 @@ static const DMALinkInfo SPIRxDMALinks[] = { {1, 6, DMA_REQUEST_SPI3_RX}, }; +/// Mapping from OSPI index to DMA link info +static const DMALinkInfo OSPIDMALinks[] = { + {1, 7, DMA_REQUEST_OCTOSPI1}, +}; #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/TARGET_STM32U5/objects.h b/targets/TARGET_STM/TARGET_STM32U5/objects.h index 9afc8983740..74240411fd4 100644 --- a/targets/TARGET_STM/TARGET_STM32U5/objects.h +++ b/targets/TARGET_STM/TARGET_STM32U5/objects.h @@ -27,6 +27,8 @@ #include "stm32u5xx_ll_pwr.h" #include "stm32u5xx_ll_rcc.h" +#include "stm_dma_info.h" + #ifdef __cplusplus extern "C" { #endif @@ -112,6 +114,8 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; + IRQn_Type qspiIRQ; + bool dmaInitialized; }; struct ospi_s { @@ -128,6 +132,8 @@ struct ospi_s { PinName sclk; PinName ssel; PinName dqs; + IRQn_Type ospiIRQ; + bool dmaInitialized; }; #ifdef __cplusplus diff --git a/targets/TARGET_STM/TARGET_STM32U5/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32U5/stm_dma_info.h index 8d170f35526..ac977e7496a 100644 --- a/targets/TARGET_STM/TARGET_STM32U5/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32U5/stm_dma_info.h @@ -38,5 +38,10 @@ static const DMALinkInfo SPIRxDMALinks[] = { {1, 5, GPDMA1_REQUEST_SPI3_TX} }; +/// Mapping from OSPI index to DMA link info +static const DMALinkInfo OSPIDMALinks[] = { + {1, 6, GPDMA1_REQUEST_OCTOSPI1}, + {1, 7, GPDMA1_REQUEST_OCTOSPI2} +}; #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/TARGET_STM32WB/objects.h b/targets/TARGET_STM/TARGET_STM32WB/objects.h index 9251bd877f1..71d22087c9c 100644 --- a/targets/TARGET_STM/TARGET_STM32WB/objects.h +++ b/targets/TARGET_STM/TARGET_STM32WB/objects.h @@ -33,6 +33,8 @@ #error "BLE FEATURE CANNOT BE REMOVED" #endif +#include "stm_dma_info.h" + #ifdef __cplusplus extern "C" { #endif @@ -98,6 +100,7 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; + bool dmaInitialized; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32WB/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32WB/stm_dma_info.h index f0a98da7682..ce044509db0 100644 --- a/targets/TARGET_STM/TARGET_STM32WB/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32WB/stm_dma_info.h @@ -40,5 +40,10 @@ static const DMALinkInfo SPIRxDMALinks[] = { #endif }; +static const DMALinkInfo QSPIDMALinks[] = { +#if defined(QUADSPI) + {1, 5, DMA_REQUEST_QUADSPI}, +#endif +}; #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/ospi_api.c b/targets/TARGET_STM/ospi_api.c index 4816fd03364..1b0e8863bc0 100644 --- a/targets/TARGET_STM/ospi_api.c +++ b/targets/TARGET_STM/ospi_api.c @@ -483,6 +483,7 @@ ospi_status_t ospi_frequency(ospi_t *obj, int hz) obj->handle.Init.ClockPrescaler = div; + HAL_OSPI_DeInit(&obj->handle); if (HAL_OSPI_Init(&obj->handle) != HAL_OK) { tr_error("HAL_OSPI_Init error"); status = OSPI_STATUS_ERROR; diff --git a/targets/TARGET_STM/qspi_api.c b/targets/TARGET_STM/qspi_api.c index c84a4b59ec1..de1e752fba1 100644 --- a/targets/TARGET_STM/qspi_api.c +++ b/targets/TARGET_STM/qspi_api.c @@ -33,6 +33,8 @@ #define TRACE_GROUP "STQS" #endif /* OCTOSPI1 */ +#include "stm_dma_info.h" + // activate / de-activate extra debug #define qspi_api_c_debug 0 @@ -40,6 +42,50 @@ /* hence 2^(31+1), then FLASH_SIZE_DEFAULT = 1<<31 */ #define QSPI_FLASH_SIZE_DEFAULT 0x80000000 +#if defined(QUADSPI) +static QSPI_HandleTypeDef * qspiHandle; // Handle of whatever QSPI structure is used for QUADSPI +void QUADSPI_IRQHandler() +{ + HAL_QSPI_IRQHandler(qspiHandle); +} + +void HAL_QSPI_ErrorCallback(QSPI_HandleTypeDef * handle) +{ + handle->State = HAL_QSPI_STATE_ERROR; +} + +void HAL_QSPI_TimeOutCallback(QSPI_HandleTypeDef * handle) +{ + handle->State = HAL_QSPI_STATE_ERROR; +} +#endif + +#if defined(OCTOSPI1) +static OSPI_HandleTypeDef * ospiHandle1; +void OCTOSPI1_IRQHandler() +{ + HAL_OSPI_IRQHandler(ospiHandle1); +} + +void HAL_OSPI_ErrorCallback(OSPI_HandleTypeDef * handle) +{ + handle->State = HAL_OSPI_STATE_ERROR; +} + +void HAL_OSPI_TimeOutCallback(OSPI_HandleTypeDef * handle) +{ + handle->State = HAL_OSPI_STATE_ERROR; +} +#endif + +#if defined(OCTOSPI2) +static OSPI_HandleTypeDef * ospiHandle2; +void OCTOSPI2_IRQHandler() +{ + HAL_OSPI_IRQHandler(ospiHandle2); +} +#endif + #if defined(OCTOSPI1) static uint32_t get_alt_bytes_size(const uint32_t num_bytes) { @@ -381,6 +427,57 @@ qspi_status_t qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTy #if defined(OCTOSPI1) + +/** + * Initialize the DMA for an QSPI object + * Does nothing if DMA is already initialized. + */ +static void qspi_init_dma(struct qspi_s * obj) +{ + if(!obj->dmaInitialized) + { + // Get DMA handle + DMALinkInfo const *dmaLink; +#if defined(OCTOSPI2) + if(obj->qspi == (QSPIName) OSPI_1) + { + dmaLink = &OSPIDMALinks[0]; + } + else + { + dmaLink = &OSPIDMALinks[1]; + } +#else + dmaLink = &OSPIDMALinks[0]; +#endif + // Initialize DMA channel + DMAHandlePointer dmaHandle = stm_init_dma_link(dmaLink, DMA_PERIPH_TO_MEMORY, false, true, 1, 1); + if(dmaHandle.hdma == NULL) + { + mbed_error(MBED_ERROR_ALREADY_IN_USE, "DMA channel already used by something else!", 0, MBED_FILENAME, __LINE__); + } +#if defined(MDMA) + __HAL_LINKDMA(&obj->handle, hmdma, *dmaHandle.hmdma); +#else + __HAL_LINKDMA(&obj->handle, hdma, *dmaHandle.hdma); +#endif + obj->dmaInitialized = true; + } +} + +// Store the qspi_s * inside an OSPI handle, for later retrieval in callbacks +static inline void store_qspi_pointer(OSPI_HandleTypeDef * ospiHandle, struct qspi_s * qspis) { + // Annoyingly, STM neglected to provide any sort of "user data" pointer inside OSPI_HandleTypeDef for use + // in callbacks. However, there are some variables in the Init struct that are never accessed after HAL_OSPI_Init(). + // So, we can reuse those to store our pointer. + ospiHandle->Init.ChipSelectHighTime = (uint32_t)qspis; +} + +// Get qspi_s * from OSPI_HandleTypeDef +static inline struct qspi_s * get_qspi_pointer(OSPI_HandleTypeDef * ospiHandle) { + return (struct qspi_s *) ospiHandle->Init.ChipSelectHighTime; +} + #if STATIC_PINMAP_READY #define QSPI_INIT_DIRECT qspi_init_direct qspi_status_t qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, uint32_t hz, uint8_t mode) @@ -419,15 +516,20 @@ static qspi_status_t _qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, // tested all combinations, take first obj->qspi = pinmap->peripheral; + obj->dmaInitialized = false; #if defined(OCTOSPI1) if (obj->qspi == QSPI_1) { obj->handle.Instance = OCTOSPI1; + obj->qspiIRQ = OCTOSPI1_IRQn; + ospiHandle1 = &obj->handle; } #endif #if defined(OCTOSPI2) if (obj->qspi == QSPI_2) { obj->handle.Instance = OCTOSPI2; + obj->qspiIRQ = OCTOSPI2_IRQn; + ospiHandle2 = &obj->handle; } #endif @@ -468,7 +570,9 @@ static qspi_status_t _qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, pin_mode(pinmap->ssel_pin, PullNone); #if defined(OCTOSPI2) +#if defined(__HAL_RCC_OSPIM_CLK_ENABLE) __HAL_RCC_OSPIM_CLK_ENABLE(); +#endif OSPIM_CfgTypeDef OSPIM_Cfg_Struct = {0}; @@ -539,6 +643,46 @@ qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinN return QSPI_INIT_DIRECT(obj, &static_pinmap, hz, mode); } #else /* OCTOSPI */ + +/** + * Initialize the DMA for an QSPI object + * Does nothing if DMA is already initialized. + */ +static void qspi_init_dma(struct qspi_s * obj) +{ + if(!obj->dmaInitialized) + { + // Get DMA handle + DMALinkInfo const *dmaLink = &QSPIDMALinks[0]; + + // Initialize DMA channel + DMAHandlePointer dmaHandle = stm_init_dma_link(dmaLink, DMA_PERIPH_TO_MEMORY, false, true, 1, 1); + if(dmaHandle.hdma == NULL) + { + mbed_error(MBED_ERROR_ALREADY_IN_USE, "DMA channel already used by something else!", 0, MBED_FILENAME, __LINE__); + } +#if defined(MDMA) + __HAL_LINKDMA(&obj->handle, hmdma, *dmaHandle.hmdma); +#else + __HAL_LINKDMA(&obj->handle, hdma, *dmaHandle.hdma); +#endif + obj->dmaInitialized = true; + } +} + +// Store the spi_s * inside an SPI handle, for later retrieval in callbacks +static inline void store_qspi_pointer(QSPI_HandleTypeDef * qspiHandle, struct qspi_s * qspis) { + // Annoyingly, STM neglected to provide any sort of "user data" pointer inside QSPI_HandleTypeDef for use + // in callbacks. However, there are some variables in the Init struct that are never accessed after HAL_QSPI_Init(). + // So, we can reuse those to store our pointer. + qspiHandle->Init.ChipSelectHighTime = (uint32_t)qspis; +} + +// Get spi_s * from SPI_HandleTypeDef +static inline struct qspi_s * get_qspi_pointer(QSPI_HandleTypeDef * qspiHandle) { + return (struct qspi_s *) qspiHandle->Init.ChipSelectHighTime; +} + #if STATIC_PINMAP_READY #define QSPI_INIT_DIRECT qspi_init_direct qspi_status_t qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, uint32_t hz, uint8_t mode) @@ -608,6 +752,8 @@ static qspi_status_t _qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, pin_function(pinmap->ssel_pin, pinmap->ssel_function); pin_mode(pinmap->ssel_pin, PullNone); + qspiHandle = &obj->handle; + return qspi_frequency(obj, hz); } @@ -649,6 +795,26 @@ qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinN qspi_status_t qspi_free(qspi_t *obj) { tr_debug("qspi_free"); + + if(obj->dmaInitialized) + { + // Get DMA handle + DMALinkInfo const *dmaLink; +#if defined(OCTOSPI2) + if(obj->qspi == (QSPIName) OSPI_1) + { + dmaLink = &OSPIDMALinks[0]; + } + else + { + dmaLink = &OSPIDMALinks[1]; + } +#else + dmaLink = &OSPIDMALinks[0]; +#endif + stm_free_dma_link(dmaLink); + } + if (HAL_OSPI_DeInit(&obj->handle) != HAL_OK) { return QSPI_STATUS_ERROR; } @@ -682,6 +848,13 @@ qspi_status_t qspi_free(qspi_t *obj) { tr_debug("qspi_free"); + if(obj->dmaInitialized) + { + // Get DMA handle + DMALinkInfo const *dmaLink = &QSPIDMALinks[0]; + stm_free_dma_link(dmaLink); + } + if (HAL_QSPI_DeInit(&obj->handle) != HAL_OK) { return QSPI_STATUS_ERROR; } @@ -720,6 +893,9 @@ qspi_status_t qspi_frequency(qspi_t *obj, int hz) tr_debug("qspi_frequency hz %d", hz); qspi_status_t status = QSPI_STATUS_OK; + // Reset flag used by store_qspi_pointer() + obj->handle.Init.ChipSelectHighTime = 3; + /* HCLK drives QSPI. QSPI clock depends on prescaler value: * 0: Freq = HCLK * 1: Freq = HCLK/2 @@ -734,11 +910,14 @@ qspi_status_t qspi_frequency(qspi_t *obj, int hz) obj->handle.Init.ClockPrescaler = div; + HAL_OSPI_DeInit(&obj->handle); if (HAL_OSPI_Init(&obj->handle) != HAL_OK) { tr_error("HAL_OSPI_Init error"); status = QSPI_STATUS_ERROR; } + store_qspi_pointer(&obj->handle, obj); + return status; } #else /* OCTOSPI */ @@ -747,6 +926,9 @@ qspi_status_t qspi_frequency(qspi_t *obj, int hz) tr_debug("qspi_frequency hz %d", hz); qspi_status_t status = QSPI_STATUS_OK; + // Reset flag used by store_qspi_pointer() + obj->handle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_5_CYCLE; + /* HCLK drives QSPI. QSPI clock depends on prescaler value: * 0: Freq = HCLK * 1: Freq = HCLK/2 @@ -769,6 +951,8 @@ qspi_status_t qspi_frequency(qspi_t *obj, int hz) status = QSPI_STATUS_ERROR; } + store_qspi_pointer(&obj->handle, obj); + return status; } #endif /* OCTOSPI */ @@ -791,9 +975,35 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void tr_error("HAL_OSPI_Command error"); status = QSPI_STATUS_ERROR; } else { - if (HAL_OSPI_Transmit(&obj->handle, (uint8_t *)data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - tr_error("HAL_OSPI_Transmit error"); - status = QSPI_STATUS_ERROR; + if(st_command.NbData >= 8) { + qspi_init_dma(obj); + NVIC_ClearPendingIRQ(obj->qspiIRQ); + NVIC_SetPriority(obj->qspiIRQ, 1); + NVIC_EnableIRQ(obj->qspiIRQ); +#if defined(__DCACHE_PRESENT) + // For chips with a cache (e.g. Cortex-M7), we need to evict the Tx fill data from cache to main memory. + // This ensures that the DMA controller can see the most up-to-date copy of the data. + SCB_CleanDCache_by_Addr((volatile void *)data, *length); +#endif + if (HAL_OSPI_Transmit_DMA(&obj->handle, (uint8_t *)data) != HAL_OK) { + tr_error("HAL_OSPI_Transmit error"); + status = QSPI_STATUS_ERROR; + } + else { + // wait until transfer complete or timeout + while(obj->handle.State == HAL_OSPI_STATE_BUSY_TX); + if(obj->handle.State != HAL_OSPI_STATE_READY) { + status = QSPI_STATUS_ERROR; + obj->handle.State = HAL_OSPI_STATE_READY; + } + } + NVIC_DisableIRQ(obj->qspiIRQ); + } + else { + if (HAL_OSPI_Transmit(&obj->handle, (uint8_t *)data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_OSPI_Transmit error"); + status = QSPI_STATUS_ERROR; + } } } @@ -815,8 +1025,33 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { status = QSPI_STATUS_ERROR; } else { - if (HAL_QSPI_Transmit(&obj->handle, (uint8_t *)data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - status = QSPI_STATUS_ERROR; + if(st_command.NbData >= 8) { + qspi_init_dma(obj); + NVIC_ClearPendingIRQ(QUADSPI_IRQn); + NVIC_SetPriority(QUADSPI_IRQn, 1); + NVIC_EnableIRQ(QUADSPI_IRQn); +#if defined(__DCACHE_PRESENT) + // For chips with a cache (e.g. Cortex-M7), we need to evict the Tx fill data from cache to main memory. + // This ensures that the DMA controller can see the most up-to-date copy of the data. + SCB_CleanDCache_by_Addr(data, *length); +#endif + if (HAL_QSPI_Transmit_DMA(&obj->handle, (uint8_t *)data) != HAL_OK) { + status = QSPI_STATUS_ERROR; + } + else { + // wait until transfer complete or timeout + while(obj->handle.State == HAL_QSPI_STATE_BUSY_INDIRECT_TX); + if(obj->handle.State != HAL_QSPI_STATE_READY) { + status = QSPI_STATUS_ERROR; + obj->handle.State = HAL_QSPI_STATE_READY; + } + } + NVIC_DisableIRQ(QUADSPI_IRQn); + } + else { + if (HAL_QSPI_Transmit(&obj->handle, (uint8_t *)data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + status = QSPI_STATUS_ERROR; + } } } @@ -840,9 +1075,38 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, tr_error("HAL_OSPI_Command error"); status = QSPI_STATUS_ERROR; } else { - if (HAL_OSPI_Receive(&obj->handle, data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - tr_error("HAL_OSPI_Receive error %d", obj->handle.ErrorCode); - status = QSPI_STATUS_ERROR; + if(st_command.NbData >= 8) { + qspi_init_dma(obj); + NVIC_ClearPendingIRQ(obj->qspiIRQ); + NVIC_SetPriority(obj->qspiIRQ, 1); + NVIC_EnableIRQ(obj->qspiIRQ); +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + if(((uint32_t) data) % __SCB_DCACHE_LINE_SIZE != 0 || (*length) % __SCB_DCACHE_LINE_SIZE != 0) { + SCB_CleanDCache_by_Addr((uint32_t*)data, *length); + } +#endif + if (HAL_OSPI_Receive_DMA(&obj->handle, data) != HAL_OK) { + tr_error("HAL_OSPI_Receive error %d", obj->handle.ErrorCode); + status = QSPI_STATUS_ERROR; + } + else { + // wait until transfer complete or timeout + while(obj->handle.State == HAL_OSPI_STATE_BUSY_RX); + if(obj->handle.State != HAL_OSPI_STATE_READY) { + status = QSPI_STATUS_ERROR; + obj->handle.State = HAL_OSPI_STATE_READY; + } + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + SCB_InvalidateDCache_by_Addr((uint32_t*)data, *length); + #endif + } + NVIC_DisableIRQ(obj->qspiIRQ); + } + else { + if (HAL_OSPI_Receive(&obj->handle, data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_OSPI_Receive error %d", obj->handle.ErrorCode); + status = QSPI_STATUS_ERROR; + } } } @@ -864,8 +1128,36 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { status = QSPI_STATUS_ERROR; } else { - if (HAL_QSPI_Receive(&obj->handle, data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - status = QSPI_STATUS_ERROR; + if(st_command.NbData >= 8) { + qspi_init_dma(obj); + NVIC_ClearPendingIRQ(QUADSPI_IRQn); + NVIC_SetPriority(QUADSPI_IRQn, 1); + NVIC_EnableIRQ(QUADSPI_IRQn); +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + if(((uint32_t) data) % __SCB_DCACHE_LINE_SIZE != 0 || (*length) % __SCB_DCACHE_LINE_SIZE != 0) { + SCB_CleanDCache_by_Addr((uint32_t*)data, *length); + } +#endif + if (HAL_QSPI_Receive_DMA(&obj->handle, data) != HAL_OK) { + status = QSPI_STATUS_ERROR; + } + else { + // wait until transfer complete or timeout +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + SCB_InvalidateDCache_by_Addr((uint32_t*)data, *length); +#endif + while(obj->handle.State == HAL_QSPI_STATE_BUSY_INDIRECT_RX); + if(obj->handle.State != HAL_QSPI_STATE_READY) { + status = QSPI_STATUS_ERROR; + obj->handle.State = HAL_QSPI_STATE_READY; + } + } + NVIC_DisableIRQ(QUADSPI_IRQn); + } + else { + if (HAL_QSPI_Receive(&obj->handle, data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + status = QSPI_STATUS_ERROR; + } } } diff --git a/targets/TARGET_STM/stm_dma_ip_v1.h b/targets/TARGET_STM/stm_dma_ip_v1.h index 4ebac97a645..ff2ed3fd24c 100644 --- a/targets/TARGET_STM/stm_dma_ip_v1.h +++ b/targets/TARGET_STM/stm_dma_ip_v1.h @@ -28,6 +28,11 @@ #define MAX_DMA_CHANNELS_PER_CONTROLLER 8 // Count DMA controllers +#ifdef MDMA +// For STM32H7, MDMA has 16 channels, while DMA1, DMA2 and BDMA all have 8 channels +#define NUM_DMA_CONTROLLERS 5 +#define MAX_MDMA_CHANNELS 16 +#else #ifdef DMA1 #ifdef DMA2 #define NUM_DMA_CONTROLLERS 2 @@ -37,6 +42,7 @@ #else #define NUM_DMA_CONTROLLERS 0 #endif +#endif // Provide an alias so that code can always use the v2 name for this structure #define DMA_Channel_TypeDef DMA_Stream_TypeDef diff --git a/targets/TARGET_STM/stm_dma_utils.c b/targets/TARGET_STM/stm_dma_utils.c index 49ea4adf952..cb7aad9b824 100644 --- a/targets/TARGET_STM/stm_dma_utils.c +++ b/targets/TARGET_STM/stm_dma_utils.c @@ -25,31 +25,47 @@ // Array to store pointer to DMA handle for each DMA channel. // Note: arrays are 0-indexed, so DMA1 Channel2 is at stmDMAHandles[0][1]. -static DMA_HandleTypeDef * stmDMAHandles[NUM_DMA_CONTROLLERS][MAX_DMA_CHANNELS_PER_CONTROLLER]; +static DMAHandlePointer stmDMAHandles[NUM_DMA_CONTROLLERS][MAX_DMA_CHANNELS_PER_CONTROLLER]; -DMA_TypeDef * stm_get_dma_instance(DMALinkInfo const * dmaLink) +DMAInstancePointer stm_get_dma_instance(DMALinkInfo const * dmaLink) { + DMAInstancePointer dma_instance; switch(dmaLink->dmaIdx) { #ifdef DMA1 case 1: - return DMA1; + dma_instance.dma = DMA1; + break; #endif #ifdef DMA2 case 2: - return DMA2; + dma_instance.dma = DMA2; + break; #endif #ifdef GPDMA1 case 1: - return GPDMA1; + dma_instance.dma = GPDMA1; + break; +#endif +#ifdef BDMA + case 3: + dma_instance.bdma = BDMA; + break; +#endif +#ifdef MDMA + case 4: + dma_instance.mdma = MDMA; + break; #endif default: mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid DMA controller", dmaLink->dmaIdx, MBED_FILENAME, __LINE__); } + return dma_instance; } -DMA_Channel_TypeDef * stm_get_dma_channel(const DMALinkInfo *dmaLink) +DMAChannelPointer stm_get_dma_channel(const DMALinkInfo *dmaLink) { + DMAChannelPointer channel_pointer; switch(dmaLink->dmaIdx) { #ifdef DMA1 @@ -58,136 +74,167 @@ DMA_Channel_TypeDef * stm_get_dma_channel(const DMALinkInfo *dmaLink) { #ifdef DMA1_Channel1 case 1: - return DMA1_Channel1; + channel_pointer.channel = DMA1_Channel1; + break; #endif #ifdef DMA1_Channel2 case 2: - return DMA1_Channel2; + channel_pointer.channel = DMA1_Channel2; + break; #endif #ifdef DMA1_Channel3 case 3: - return DMA1_Channel3; + channel_pointer.channel = DMA1_Channel3; + break; #endif #ifdef DMA1_Channel4 case 4: - return DMA1_Channel4; + channel_pointer.channel = DMA1_Channel4; + break; #endif #ifdef DMA1_Channel5 case 5: - return DMA1_Channel5; + channel_pointer.channel = DMA1_Channel5; + break; #endif #ifdef DMA1_Channel6 case 6: - return DMA1_Channel6; + channel_pointer.channel = DMA1_Channel6; + break; #endif #ifdef DMA1_Channel7 case 7: - return DMA1_Channel7; + channel_pointer.channel = DMA1_Channel7; + break; #endif #ifdef DMA1_Stream0 case 0: - return DMA1_Stream0; + channel_pointer.channel = DMA1_Stream0; + break; #endif #ifdef DMA1_Stream1 case 1: - return DMA1_Stream1; + channel_pointer.channel = DMA1_Stream1; + break; #endif #ifdef DMA1_Stream2 case 2: - return DMA1_Stream2; + channel_pointer.channel = DMA1_Stream2; + break; #endif #ifdef DMA1_Stream3 case 3: - return DMA1_Stream3; + channel_pointer.channel = DMA1_Stream3; + break; #endif #ifdef DMA1_Stream4 case 4: - return DMA1_Stream4; + channel_pointer.channel = DMA1_Stream4; + break; #endif #ifdef DMA1_Stream5 case 5: - return DMA1_Stream5; + channel_pointer.channel = DMA1_Stream5; + break; #endif #ifdef DMA1_Stream6 case 6: - return DMA1_Stream6; + channel_pointer.channel = DMA1_Stream6; + break; #endif #ifdef DMA1_Stream7 case 7: - return DMA1_Stream7; + channel_pointer.channel = DMA1_Stream7; + break; #endif default: mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid DMA channel", dmaLink->channelIdx, MBED_FILENAME, __LINE__); } + break; #endif - #ifdef DMA2 case 2: switch(dmaLink->channelIdx) { #ifdef DMA2_Channel1 case 1: - return DMA2_Channel1; + channel_pointer.channel = DMA2_Channel1; + break; #endif #ifdef DMA2_Channel2 case 2: - return DMA2_Channel2; + channel_pointer.channel = DMA2_Channel2; + break; #endif #ifdef DMA2_Channel3 case 3: - return DMA2_Channel3; + channel_pointer.channel = DMA2_Channel3; + break; #endif #ifdef DMA2_Channel4 case 4: - return DMA2_Channel4; + channel_pointer.channel = DMA2_Channel4; + break; #endif #ifdef DMA2_Channel5 case 5: - return DMA2_Channel5; + channel_pointer.channel = DMA2_Channel5; + break; #endif #ifdef DMA2_Channel6 case 6: - return DMA2_Channel6; + channel_pointer.channel = DMA2_Channel6; + break; #endif #ifdef DMA2_Channel7 case 7: - return DMA2_Channel7; + channel_pointer.channel = DMA2_Channel7; + break; #endif #ifdef DMA2_Stream0 case 0: - return DMA2_Stream0; + channel_pointer.channel = DMA2_Stream0; + break; #endif #ifdef DMA2_Stream1 case 1: - return DMA2_Stream1; + channel_pointer.channel = DMA2_Stream1; + break; #endif #ifdef DMA2_Stream2 case 2: - return DMA2_Stream2; + channel_pointer.channel = DMA2_Stream2; + break; #endif #ifdef DMA2_Stream3 case 3: - return DMA2_Stream3; + channel_pointer.channel = DMA2_Stream3; + break; #endif #ifdef DMA2_Stream4 case 4: - return DMA2_Stream4; + channel_pointer.channel = DMA2_Stream4; + break; #endif #ifdef DMA2_Stream5 case 5: - return DMA2_Stream5; + channel_pointer.channel = DMA2_Stream5; + break; #endif #ifdef DMA2_Stream6 case 6: - return DMA2_Stream6; + channel_pointer.channel = DMA2_Stream6; + break; #endif #ifdef DMA2_Stream7 case 7: - return DMA2_Stream7; + channel_pointer.channel = DMA2_Stream7; + break; #endif default: mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid DMA channel", dmaLink->channelIdx, MBED_FILENAME, __LINE__); } + break; #endif #ifdef GPDMA1 case 1: @@ -195,76 +242,184 @@ DMA_Channel_TypeDef * stm_get_dma_channel(const DMALinkInfo *dmaLink) { #ifdef GPDMA1_Channel0 case 0: - return GPDMA1_Channel0; + channel_pointer.channel = GPDMA1_Channel0; + break; #endif #ifdef GPDMA1_Channel1 case 1: - return GPDMA1_Channel1; + channel_pointer.channel = GPDMA1_Channel1; + break; #endif #ifdef GPDMA1_Channel2 case 2: - return GPDMA1_Channel2; + channel_pointer.channel = GPDMA1_Channel2; + break; #endif #ifdef GPDMA1_Channel3 case 3: - return GPDMA1_Channel3; + channel_pointer.channel = GPDMA1_Channel3; + break; #endif #ifdef GPDMA1_Channel4 case 4: - return GPDMA1_Channel4; + channel_pointer.channel = GPDMA1_Channel4; + break; #endif #ifdef GPDMA1_Channel5 case 5: - return GPDMA1_Channel5; + channel_pointer.channel = GPDMA1_Channel5; + break; #endif #ifdef GPDMA1_Channel6 case 6: - return GPDMA1_Channel6; + channel_pointer.channel = GPDMA1_Channel6; + break; #endif #ifdef GPDMA1_Channel7 case 7: - return GPDMA1_Channel7; + channel_pointer.channel = GPDMA1_Channel7; + break; #endif #ifdef GPDMA1_Channel8 case 8: - return GPDMA1_Channel8; + channel_pointer.channel = GPDMA1_Channel8; + break; #endif #ifdef GPDMA1_Channel9 case 9: - return GPDMA1_Channel9; + channel_pointer.channel = GPDMA1_Channel9; + break; #endif #ifdef GPDMA1_Channel10 case 10: - return GPDMA1_Channel10; + channel_pointer.channel = GPDMA1_Channel10; + break; #endif #ifdef GPDMA1_Channel11 case 11: - return GPDMA1_Channel11; + channel_pointer.channel = GPDMA1_Channel11; + break; #endif #ifdef GPDMA1_Channel12 case 12: - return GPDMA1_Channel12; + channel_pointer.channel = GPDMA1_Channel12; + break; #endif #ifdef GPDMA1_Channel13 case 13: - return GPDMA1_Channel13; + channel_pointer.channel = GPDMA1_Channel13; + break; #endif #ifdef GPDMA1_Channel14 case 14: - return GPDMA1_Channel14; + channel_pointer.channel = GPDMA1_Channel14; + break; #endif #ifdef GPDMA1_Channel15 case 15: - return GPDMA1_Channel15; + channel_pointer.channel = GPDMA1_Channel15; + break; #endif default: mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid DMA channel", dmaLink->channelIdx, MBED_FILENAME, __LINE__); } + break; +#endif +#ifdef BDMA + case 3: + switch(dmaLink->channelIdx) + { + case 0: + channel_pointer.bchannel = BDMA_Channel0; + break; + case 1: + channel_pointer.bchannel = BDMA_Channel1; + break; + case 2: + channel_pointer.bchannel = BDMA_Channel2; + break; + case 3: + channel_pointer.bchannel = BDMA_Channel3; + break; + case 4: + channel_pointer.bchannel = BDMA_Channel4; + break; + case 5: + channel_pointer.bchannel = BDMA_Channel5; + break; + case 6: + channel_pointer.bchannel = BDMA_Channel6; + break; + case 7: + channel_pointer.bchannel = BDMA_Channel7; + break; + default: + mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid BDMA channel", dmaLink->channelIdx, MBED_FILENAME, __LINE__); + } + break; +#endif +#ifdef MDMA + case 4: + switch(dmaLink->channelIdx) + { + case 0: + channel_pointer.mchannel = MDMA_Channel0; + break; + case 1: + channel_pointer.mchannel = MDMA_Channel1; + break; + case 2: + channel_pointer.mchannel = MDMA_Channel2; + break; + case 3: + channel_pointer.mchannel = MDMA_Channel3; + break; + case 4: + channel_pointer.mchannel = MDMA_Channel4; + break; + case 5: + channel_pointer.mchannel = MDMA_Channel5; + break; + case 6: + channel_pointer.mchannel = MDMA_Channel6; + break; + case 7: + channel_pointer.mchannel = MDMA_Channel7; + break; + case 8: + channel_pointer.mchannel = MDMA_Channel8; + break; + case 9: + channel_pointer.mchannel = MDMA_Channel9; + break; + case 10: + channel_pointer.mchannel = MDMA_Channel10; + break; + case 11: + channel_pointer.mchannel = MDMA_Channel11; + break; + case 12: + channel_pointer.mchannel = MDMA_Channel12; + break; + case 13: + channel_pointer.mchannel = MDMA_Channel13; + break; + case 14: + channel_pointer.mchannel = MDMA_Channel14; + break; + case 15: + channel_pointer.mchannel = MDMA_Channel15; + break; + default: + mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid MDMA channel", dmaLink->channelIdx, MBED_FILENAME, __LINE__); + } + break; #endif default: mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid DMA controller", dmaLink->dmaIdx, MBED_FILENAME, __LINE__); } + return channel_pointer; } IRQn_Type stm_get_dma_irqn(const DMALinkInfo *dmaLink) @@ -566,13 +721,18 @@ IRQn_Type stm_get_dma_irqn(const DMALinkInfo *dmaLink) mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid DMA channel", dmaLink->channelIdx, MBED_FILENAME, __LINE__); } #endif + +#ifdef MDMA + case 4: + return MDMA_IRQn; +#endif default: mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid DMA controller", dmaLink->dmaIdx, MBED_FILENAME, __LINE__); } } -bool stm_set_dma_handle_for_link(DMALinkInfo const * dmaLink, DMA_HandleTypeDef *handle) +bool stm_set_dma_handle_for_link(DMALinkInfo const * dmaLink, DMAHandlePointer handle) { #ifdef DMA_IP_VERSION_V2 // Channels start from 1 in IP v2 only @@ -580,7 +740,7 @@ bool stm_set_dma_handle_for_link(DMALinkInfo const * dmaLink, DMA_HandleTypeDef #else uint8_t channelIdx = dmaLink->channelIdx; #endif - if(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx] != NULL && handle != NULL) + if(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx].hdma != NULL && handle.hdma != NULL) { return false; } @@ -588,7 +748,7 @@ bool stm_set_dma_handle_for_link(DMALinkInfo const * dmaLink, DMA_HandleTypeDef return true; } -DMA_HandleTypeDef *stm_get_dma_handle_for_link(DMALinkInfo const * dmaLink) +DMAHandlePointer stm_get_dma_handle_for_link(DMALinkInfo const * dmaLink) { #ifdef DMA_IP_VERSION_V2 // Channels start from 1 in IP v2 only @@ -599,9 +759,11 @@ DMA_HandleTypeDef *stm_get_dma_handle_for_link(DMALinkInfo const * dmaLink) return stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx]; } -DMA_HandleTypeDef *stm_init_dma_link(const DMALinkInfo *dmaLink, uint32_t direction, bool periphInc, bool memInc, +DMAHandlePointer stm_init_dma_link(const DMALinkInfo *dmaLink, uint32_t direction, bool periphInc, bool memInc, uint8_t periphDataAlignment, uint8_t memDataAlignment){ + DMAHandlePointer dmaHandlePointer; + dmaHandlePointer.hdma = NULL; #ifdef DMA_IP_VERSION_V2 // Channels start from 1 in IP v2 only uint8_t channelIdx = dmaLink->channelIdx - 1; @@ -609,10 +771,10 @@ DMA_HandleTypeDef *stm_init_dma_link(const DMALinkInfo *dmaLink, uint32_t direct uint8_t channelIdx = dmaLink->channelIdx; #endif - if(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx] != NULL) + if(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx].hdma != NULL) { // Channel already allocated (e.g. two SPI busses which use the same DMA request tried to be initialized) - return NULL; + return dmaHandlePointer; } // Enable DMA mux clock for devices with it @@ -642,6 +804,11 @@ DMA_HandleTypeDef *stm_init_dma_link(const DMALinkInfo *dmaLink, uint32_t direct case 3: __HAL_RCC_BDMA_CLK_ENABLE(); break; +#endif +#ifdef MDMA + case 4: + __HAL_RCC_MDMA_CLK_ENABLE(); + break; #endif default: mbed_error(MBED_ERROR_ITEM_NOT_FOUND, "Invalid DMA controller", dmaLink->dmaIdx, MBED_FILENAME, __LINE__); @@ -650,155 +817,216 @@ DMA_HandleTypeDef *stm_init_dma_link(const DMALinkInfo *dmaLink, uint32_t direct // Allocate DMA handle. // Yes it's a little gross that we have to allocate on the heap, but this structure uses quite a lot of memory, // so we don't want to allocate DMA handles until they're needed. - DMA_HandleTypeDef * dmaHandle = malloc(sizeof(DMA_HandleTypeDef)); - memset(dmaHandle, 0, sizeof(DMA_HandleTypeDef)); - stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx] = dmaHandle; - - // Configure handle - dmaHandle->Instance = stm_get_dma_channel(dmaLink); -#if STM_DEVICE_HAS_DMA_SOURCE_SELECTION - - // Most devices with IP v1 call this member "Channel" and most with IP v2 call it "Request". - // But not STM32H7! -#if defined(DMA_IP_VERSION_V1) && !defined(TARGET_MCU_STM32H7) - dmaHandle->Init.Channel = dmaLink->sourceNumber << DMA_SxCR_CHSEL_Pos; -#else - dmaHandle->Init.Request = dmaLink->sourceNumber; -#endif + if(dmaLink->dmaIdx < 4) + { + DMA_HandleTypeDef * dmaHandle = malloc(sizeof(DMA_HandleTypeDef)); + dmaHandlePointer.hdma = dmaHandle; + memset(dmaHandle, 0, sizeof(DMA_HandleTypeDef)); + stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx] = dmaHandlePointer; + + // Configure handle + dmaHandle->Instance = stm_get_dma_channel(dmaLink).channel; + #if STM_DEVICE_HAS_DMA_SOURCE_SELECTION + + // Most devices with IP v1 call this member "Channel" and most with IP v2 call it "Request". + // But not STM32H7! + #if defined(DMA_IP_VERSION_V1) && !defined(TARGET_MCU_STM32H7) + dmaHandle->Init.Channel = dmaLink->sourceNumber << DMA_SxCR_CHSEL_Pos; + #else + dmaHandle->Init.Request = dmaLink->sourceNumber; + #endif + + #endif + dmaHandle->Init.Direction = direction; + + // IP v3 uses different fields for... basically everything in this struct + #ifdef DMA_IP_VERSION_V3 + if(direction == DMA_MEMORY_TO_PERIPH || direction == DMA_MEMORY_TO_MEMORY) + { + // Source is memory + dmaHandle->Init.SrcInc = memInc ? DMA_SINC_INCREMENTED : DMA_SINC_FIXED; + + switch(memDataAlignment) { + case 4: + dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; + break; + case 2: + dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD; + break; + case 1: + default: + dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE; + break; -#endif - dmaHandle->Init.Direction = direction; + } + } + else { + // Source is a peripheral + dmaHandle->Init.SrcInc = periphInc ? DMA_SINC_INCREMENTED : DMA_SINC_FIXED; - // IP v3 uses different fields for... basically everything in this struct -#ifdef DMA_IP_VERSION_V3 - if(direction == DMA_MEMORY_TO_PERIPH || direction == DMA_MEMORY_TO_MEMORY) - { - // Source is memory - dmaHandle->Init.SrcInc = memInc ? DMA_SINC_INCREMENTED : DMA_SINC_FIXED; + switch(periphDataAlignment) { + case 4: + dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; + break; + case 2: + dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD; + break; + case 1: + default: + dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE; + break; - switch(memDataAlignment) { - case 4: - dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; - break; - case 2: - dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD; - break; - case 1: - default: - dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE; - break; + } + } + + if(direction == DMA_PERIPH_TO_MEMORY || direction == DMA_MEMORY_TO_MEMORY) + { + // Destination is memory + dmaHandle->Init.DestInc = memInc ? DMA_DINC_INCREMENTED : DMA_DINC_FIXED; + + switch(memDataAlignment) { + case 4: + dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; + break; + case 2: + dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD; + break; + case 1: + default: + dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE; + break; + } } - } - else { - // Source is a peripheral - dmaHandle->Init.SrcInc = periphInc ? DMA_SINC_INCREMENTED : DMA_SINC_FIXED; + else { + // Destination is a peripheral + dmaHandle->Init.DestInc = periphInc ? DMA_DINC_INCREMENTED : DMA_DINC_FIXED; - switch(periphDataAlignment) { - case 4: - dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; - break; - case 2: - dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD; - break; - case 1: - default: - dmaHandle->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE; - break; + switch(periphDataAlignment) { + case 4: + dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; + break; + case 2: + dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD; + break; + case 1: + default: + dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE; + break; + } } - } - if(direction == DMA_PERIPH_TO_MEMORY || direction == DMA_MEMORY_TO_MEMORY) - { - // Destination is memory - dmaHandle->Init.DestInc = memInc ? DMA_DINC_INCREMENTED : DMA_DINC_FIXED; + dmaHandle->Init.SrcBurstLength = 1; + dmaHandle->Init.DestBurstLength = 1; + dmaHandle->Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST; + dmaHandle->Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; + dmaHandle->Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT1|DMA_DEST_ALLOCATED_PORT0; + dmaHandle->Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; - switch(memDataAlignment) { + #else + dmaHandle->Init.PeriphInc = periphInc ? DMA_PINC_ENABLE : DMA_PINC_DISABLE; + dmaHandle->Init.MemInc = memInc ? DMA_MINC_ENABLE : DMA_MINC_DISABLE; + dmaHandle->Init.Priority = DMA_PRIORITY_MEDIUM; + + switch(periphDataAlignment) { case 4: - dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; + dmaHandle->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; break; case 2: - dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD; + dmaHandle->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; break; case 1: default: - dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE; + dmaHandle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; break; } - } - else { - // Destination is a peripheral - dmaHandle->Init.DestInc = periphInc ? DMA_DINC_INCREMENTED : DMA_DINC_FIXED; - switch(periphDataAlignment) { + switch(memDataAlignment) { case 4: - dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; + dmaHandle->Init.MemDataAlignment = DMA_MDATAALIGN_WORD; break; case 2: - dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD; + dmaHandle->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; break; case 1: default: - dmaHandle->Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE; + dmaHandle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; break; } - } - dmaHandle->Init.SrcBurstLength = 1; - dmaHandle->Init.DestBurstLength = 1; - dmaHandle->Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST; - dmaHandle->Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; - dmaHandle->Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT1|DMA_DEST_ALLOCATED_PORT0; - dmaHandle->Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; + #endif -#else - dmaHandle->Init.PeriphInc = periphInc ? DMA_PINC_ENABLE : DMA_PINC_DISABLE; - dmaHandle->Init.MemInc = memInc ? DMA_MINC_ENABLE : DMA_MINC_DISABLE; - dmaHandle->Init.Priority = DMA_PRIORITY_MEDIUM; + dmaHandle->Init.Mode = DMA_NORMAL; - switch(periphDataAlignment) { + HAL_DMA_Init(dmaHandle); + } +#if defined(MDMA) + else + { + MDMA_HandleTypeDef * dmaHandle = malloc(sizeof(MDMA_HandleTypeDef)); + dmaHandlePointer.hmdma = dmaHandle; + memset(dmaHandle, 0, sizeof(MDMA_HandleTypeDef)); + stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx] = dmaHandlePointer; + + dmaHandle->Init.Request = dmaLink->sourceNumber; + dmaHandle->Init.TransferTriggerMode = MDMA_BUFFER_TRANSFER; + dmaHandle->Init.Priority = MDMA_PRIORITY_HIGH; + dmaHandle->Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE; + + dmaHandle->Init.SourceInc = periphInc ? MDMA_SRC_INC_BYTE: MDMA_SRC_INC_DISABLE; + dmaHandle->Init.DestinationInc = memInc ? MDMA_DEST_INC_BYTE: MDMA_DEST_INC_DISABLE; + switch(periphDataAlignment) + { + case 8: + dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_DOUBLEWORD; + break; case 4: - dmaHandle->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_WORD; break; case 2: - dmaHandle->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_HALFWORD; break; case 1: - default: - dmaHandle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE; + break; + } + switch(memDataAlignment) + { + case 8: + dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_DOUBLEWORD; break; - - } - - switch(memDataAlignment) { case 4: - dmaHandle->Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_WORD; break; case 2: - dmaHandle->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_HALFWORD; break; case 1: - default: - dmaHandle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_BYTE; break; + } + dmaHandle->Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE; + dmaHandle->Init.BufferTransferLength = 64; + dmaHandle->Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE; + dmaHandle->Init.DestBurst = MDMA_DEST_BURST_SINGLE; - } - -#endif - - dmaHandle->Init.Mode = DMA_NORMAL; + dmaHandle->Init.SourceBlockAddressOffset = 0; + dmaHandle->Init.DestBlockAddressOffset = 0; - HAL_DMA_Init(dmaHandle); + dmaHandle->Instance = stm_get_dma_channel(dmaLink).mchannel; + HAL_MDMA_Init(dmaHandle); + } +#endif // Set up interrupt IRQn_Type irqNum = stm_get_dma_irqn(dmaLink); NVIC_EnableIRQ(irqNum); NVIC_SetPriority(irqNum, 7); - return dmaHandle; + return dmaHandlePointer; } void stm_free_dma_link(const DMALinkInfo *dmaLink) @@ -813,12 +1041,29 @@ void stm_free_dma_link(const DMALinkInfo *dmaLink) uint8_t channelIdx = dmaLink->channelIdx; #endif - // Deinit hardware channel - HAL_DMA_DeInit(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx]); + if(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx].hdma == NULL) + { + return; + } - // Free memory - free(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx]); - stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx] = NULL; + // Deinit hardware channel + switch(dmaLink->dmaIdx) + { + case 1: + case 2: + case 3: + HAL_DMA_DeInit(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx].hdma); + break; +#ifdef MDMA + case 4: + HAL_MDMA_DeInit(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx].hmdma); + break; +#endif + } + IRQn_Type irqNum = stm_get_dma_irqn(dmaLink); + NVIC_DisableIRQ(irqNum); + free(stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx].hdma); + stmDMAHandles[dmaLink->dmaIdx - 1][channelIdx].hdma = NULL; } #ifdef DMA_IP_VERSION_V2 @@ -826,7 +1071,7 @@ void stm_free_dma_link(const DMALinkInfo *dmaLink) #ifdef DMA1_Channel1 void DMA1_Channel1_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][0]); + HAL_DMA_IRQHandler(stmDMAHandles[0][0].hdma); } #endif @@ -836,20 +1081,20 @@ void DMA1_Channel1_IRQHandler(void) void DMA1_Channel2_3_IRQHandler(void) { if(stmDMAHandles[0][1] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][1]); + HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } if(stmDMAHandles[0][2] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][2]); + HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } } void DMA1_Channel4_5_IRQHandler(void) { if(stmDMAHandles[0][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } if(stmDMAHandles[0][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } } @@ -858,10 +1103,10 @@ void DMA1_Channel4_5_IRQHandler(void) void DMA1_Channel2_3_IRQHandler(void) { if(stmDMAHandles[0][1] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][1]); + HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } if(stmDMAHandles[0][2] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][2]); + HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } } @@ -869,57 +1114,57 @@ void DMA1_Channel2_3_IRQHandler(void) void DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX1_OVR_IRQHandler(void) { if(stmDMAHandles[0][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } if(stmDMAHandles[0][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } if(stmDMAHandles[0][5] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][5]); + HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } if(stmDMAHandles[0][6] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][6]); + HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } if(stmDMAHandles[1][0] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][0]); + HAL_DMA_IRQHandler(stmDMAHandles[1][0].hdma); } if(stmDMAHandles[1][1] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][1]); + HAL_DMA_IRQHandler(stmDMAHandles[1][1].hdma); } if(stmDMAHandles[1][2] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][2]); + HAL_DMA_IRQHandler(stmDMAHandles[1][2].hdma); } if(stmDMAHandles[1][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][3]); + HAL_DMA_IRQHandler(stmDMAHandles[1][3].hdma); } if(stmDMAHandles[1][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][4]); + HAL_DMA_IRQHandler(stmDMAHandles[1][4].hdma); } } #elif defined(DMA1_Channel7) void DMA1_Ch4_7_DMAMUX1_OVR_IRQHandler(void) { if(stmDMAHandles[0][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } if(stmDMAHandles[0][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } if(stmDMAHandles[0][5] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][5]); + HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } if(stmDMAHandles[0][6] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][6]); + HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } } #else void DMA1_Ch4_5_DMAMUX1_OVR_IRQHandler(void) { if(stmDMAHandles[0][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } if(stmDMAHandles[0][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } } #endif @@ -929,26 +1174,26 @@ void DMA1_Ch4_5_DMAMUX1_OVR_IRQHandler(void) void DMA1_Channel2_3_IRQHandler(void) { if(stmDMAHandles[0][1] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][1]); + HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } if(stmDMAHandles[0][2] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][2]); + HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } } void DMA1_Channel4_5_6_7_IRQHandler(void) { if(stmDMAHandles[0][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } if(stmDMAHandles[0][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } if(stmDMAHandles[0][5] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][5]); + HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } if(stmDMAHandles[0][6] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][6]); + HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } } @@ -957,42 +1202,42 @@ void DMA1_Channel4_5_6_7_IRQHandler(void) #ifdef DMA1_Channel2 void DMA1_Channel2_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][1]); + HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } #endif #ifdef DMA1_Channel3 void DMA1_Channel3_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][2]); + HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } #endif #ifdef DMA1_Channel4 void DMA1_Channel4_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } #endif #ifdef DMA1_Channel5 void DMA1_Channel5_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } #endif #ifdef DMA1_Channel6 void DMA1_Channel6_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][5]); + HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } #endif #ifdef DMA1_Channel7 void DMA1_Channel7_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][6]); + HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } #endif #endif @@ -1000,49 +1245,49 @@ void DMA1_Channel7_IRQHandler(void) #ifdef DMA2_Channel1 void DMA2_Channel1_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][0]); + HAL_DMA_IRQHandler(stmDMAHandles[1][0].hdma); } #endif #ifdef DMA2_Channel2 void DMA2_Channel2_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][1]); + HAL_DMA_IRQHandler(stmDMAHandles[1][1].hdma); } #endif #ifdef DMA2_Channel3 void DMA2_Channel3_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][2]); + HAL_DMA_IRQHandler(stmDMAHandles[1][2].hdma); } #endif #ifdef DMA2_Channel4 void DMA2_Channel4_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][3]); + HAL_DMA_IRQHandler(stmDMAHandles[1][3].hdma); } #endif #ifdef DMA2_Channel5 void DMA2_Channel5_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][4]); + HAL_DMA_IRQHandler(stmDMAHandles[1][4].hdma); } #endif #ifdef DMA2_Channel6 void DMA2_Channel6_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][5]); + HAL_DMA_IRQHandler(stmDMAHandles[1][5].hdma); } #endif #ifdef DMA2_Channel7 void DMA2_Channel7_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][6]); + HAL_DMA_IRQHandler(stmDMAHandles[1][6].hdma); } #endif #endif // DMA_IP_VERSION_V2 @@ -1051,56 +1296,56 @@ void DMA2_Channel7_IRQHandler(void) #ifdef DMA1_Stream0 void DMA1_Stream0_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][0]); + HAL_DMA_IRQHandler(stmDMAHandles[0][0].hdma); } #endif #ifdef DMA1_Stream1 void DMA1_Stream1_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][1]); + HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } #endif #ifdef DMA1_Stream2 void DMA1_Stream2_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][2]); + HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } #endif #ifdef DMA1_Stream3 void DMA1_Stream3_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } #endif #ifdef DMA1_Stream4 void DMA1_Stream4_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } #endif #ifdef DMA1_Stream5 void DMA1_Stream5_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][5]); + HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } #endif #ifdef DMA1_Stream6 void DMA1_Stream6_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][6]); + HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } #endif #ifdef DMA1_Stream7 void DMA1_Stream7_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][7]); + HAL_DMA_IRQHandler(stmDMAHandles[0][7].hdma); } #endif @@ -1108,56 +1353,56 @@ void DMA1_Stream7_IRQHandler(void) void DMA2_Stream0_IRQHandler(void) { // Note: Unlike both IP v2 and IP v3, IP v1 channels are 0-indexed. - HAL_DMA_IRQHandler(stmDMAHandles[1][0]); + HAL_DMA_IRQHandler(stmDMAHandles[1][0].hdma); } #endif #ifdef DMA2_Stream1 void DMA2_Stream1_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][1]); + HAL_DMA_IRQHandler(stmDMAHandles[1][1].hdma); } #endif #ifdef DMA2_Stream2 void DMA2_Stream2_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][2]); + HAL_DMA_IRQHandler(stmDMAHandles[1][2].hdma); } #endif #ifdef DMA2_Stream3 void DMA2_Stream3_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][3]); + HAL_DMA_IRQHandler(stmDMAHandles[1][3].hdma); } #endif #ifdef DMA2_Stream4 void DMA2_Stream4_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][4]); + HAL_DMA_IRQHandler(stmDMAHandles[1][4].hdma); } #endif #ifdef DMA2_Stream5 void DMA2_Stream5_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][5]); + HAL_DMA_IRQHandler(stmDMAHandles[1][5].hdma); } #endif #ifdef DMA2_Stream6 void DMA2_Stream6_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][6]); + HAL_DMA_IRQHandler(stmDMAHandles[1][6].hdma); } #endif #ifdef DMA2_Stream7 void DMA2_Stream7_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[1][7]); + HAL_DMA_IRQHandler(stmDMAHandles[1][7].hdma); } #endif #endif // DMA_IP_VERSION_V1 @@ -1166,112 +1411,127 @@ void DMA2_Stream7_IRQHandler(void) #ifdef GPDMA1_Channel0 void GPDMA1_Channel0_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][0]); + HAL_DMA_IRQHandler(stmDMAHandles[0][0].hdma); } #endif #ifdef GPDMA1_Channel1 void GPDMA1_Channel1_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][1]); + HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } #endif #ifdef GPDMA1_Channel2 void GPDMA1_Channel2_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][2]); + HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } #endif #ifdef GPDMA1_Channel3 void GPDMA1_Channel3_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } #endif #ifdef GPDMA1_Channel4 void GPDMA1_Channel4_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } #endif #ifdef GPDMA1_Channel5 void GPDMA1_Channel5_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][5]); + HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } #endif #ifdef GPDMA1_Channel6 void GPDMA1_Channel6_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][6]); + HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } #endif #ifdef GPDMA1_Channel7 void GPDMA1_Channel7_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][7]); + HAL_DMA_IRQHandler(stmDMAHandles[0][7].hdma); } #endif #ifdef GPDMA1_Channel8 void GPDMA1_Channel8_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][8]); + HAL_DMA_IRQHandler(stmDMAHandles[0][8].hdma); } #endif #ifdef GPDMA1_Channel9 void GPDMA1_Channel9_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][9]); + HAL_DMA_IRQHandler(stmDMAHandles[0][9].hdma); } #endif #ifdef GPDMA1_Channel10 void GPDMA1_Channel10_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][10]); + HAL_DMA_IRQHandler(stmDMAHandles[0][10].hdma); } #endif #ifdef GPDMA1_Channel11 void GPDMA1_Channel11_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][11]); + HAL_DMA_IRQHandler(stmDMAHandles[0][11].hdma); } #endif #ifdef GPDMA1_Channel12 void GPDMA1_Channel12_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][12]); + HAL_DMA_IRQHandler(stmDMAHandles[0][12].hdma); } #endif #ifdef GPDMA1_Channel13 void GPDMA1_Channel13_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][13]); + HAL_DMA_IRQHandler(stmDMAHandles[0][13].hdma); } #endif #ifdef GPDMA1_Channel14 void GPDMA1_Channel14_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][14]); + HAL_DMA_IRQHandler(stmDMAHandles[0][14].hdma); } #endif #ifdef GPDMA1_Channel15 void GPDMA1_Channel15_IRQHandler(void) { - HAL_DMA_IRQHandler(stmDMAHandles[0][15]); + HAL_DMA_IRQHandler(stmDMAHandles[0][15].hdma); } #endif -#endif // DMA_IP_VERSION_V3 \ No newline at end of file + +#endif // DMA_IP_VERSION_V3 + +#ifdef MDMA +void MDMA_IRQHandler(void) +{ + DMAHandlePointer *stmMDMAHandle = stmDMAHandles[3]; + for(size_t i = 0; i < MAX_MDMA_CHANNELS; i++) + { + if(stmMDMAHandle[i].hmdma != NULL) + { + HAL_MDMA_IRQHandler(stmMDMAHandle[i].hmdma); + } + } +} +#endif \ No newline at end of file diff --git a/targets/TARGET_STM/stm_dma_utils.h b/targets/TARGET_STM/stm_dma_utils.h index 16a549bf0cd..d7287a56e4f 100644 --- a/targets/TARGET_STM/stm_dma_utils.h +++ b/targets/TARGET_STM/stm_dma_utils.h @@ -69,19 +69,46 @@ typedef struct DMALinkInfo { #endif } DMALinkInfo; +typedef union DMAInstancePointer { + DMA_TypeDef *dma; +#ifdef BDMA + BDMA_TypeDef *bdma; +#endif +#ifdef MDMA + MDMA_TypeDef *mdma; +#endif +} DMAInstancePointer; + +typedef union DMAHandlePointer { + DMA_HandleTypeDef *hdma; +#ifdef MDMA + MDMA_HandleTypeDef *hmdma; +#endif +} DMAHandlePointer; + +typedef union DMAChannelPointer { + DMA_Channel_TypeDef *channel; +#ifdef BDMA + BDMA_Channel_TypeDef *bchannel; +#endif +#ifdef MDMA + MDMA_Channel_TypeDef *mchannel; +#endif +} DMAChannelPointer; + /** * @brief Get the DMA instance for a DMA link * * @param dmaLink DMA instance */ -DMA_TypeDef * stm_get_dma_instance(DMALinkInfo const * dmaLink); +DMAInstancePointer stm_get_dma_instance(DMALinkInfo const * dmaLink); /** * @brief Get the DMA channel instance for a DMA link * * @param dmaLink DMA link instance */ -DMA_Channel_TypeDef * stm_get_dma_channel(DMALinkInfo const * dmaLink); +DMAChannelPointer stm_get_dma_channel(DMALinkInfo const * dmaLink); /** * @brief Get the interrupt number for a DMA link @@ -99,7 +126,7 @@ IRQn_Type stm_get_dma_irqn(const DMALinkInfo *dmaLink); * @return true if the handle is stored successfully * @return false if handle is not NULL and the DMA channel used by the link has already been used */ -bool stm_set_dma_handle_for_link(DMALinkInfo const * dmaLink, DMA_HandleTypeDef *handle); +bool stm_set_dma_handle_for_link(DMALinkInfo const * dmaLink, DMAHandlePointer handle); /** * @brief Get the handle of a DMA link @@ -109,7 +136,7 @@ bool stm_set_dma_handle_for_link(DMALinkInfo const * dmaLink, DMA_HandleTypeDef * @return Pointer to DMA handle * @return NULL if the DMA channel used by the link is not allocated */ -DMA_HandleTypeDef * stm_get_dma_handle_for_link(DMALinkInfo const * dmaLink); +DMAHandlePointer stm_get_dma_handle_for_link(DMALinkInfo const * dmaLink); /** * @brief Initialize a DMA link for use. @@ -127,7 +154,7 @@ DMA_HandleTypeDef * stm_get_dma_handle_for_link(DMALinkInfo const * dmaLink); * @return Pointer to DMA handle allocated by this module. * @return NULL if the DMA channel used by the link has already been allocated by something else. */ -DMA_HandleTypeDef * stm_init_dma_link(DMALinkInfo const * dmaLink, uint32_t direction, bool periphInc, bool memInc, uint8_t periphDataAlignment, uint8_t memDataAlignment); +DMAHandlePointer stm_init_dma_link(DMALinkInfo const * dmaLink, uint32_t direction, bool periphInc, bool memInc, uint8_t periphDataAlignment, uint8_t memDataAlignment); /** * @brief Free a DMA link. diff --git a/targets/TARGET_STM/stm_spi_api.c b/targets/TARGET_STM/stm_spi_api.c index e5a969f906f..7c40938db5b 100644 --- a/targets/TARGET_STM/stm_spi_api.c +++ b/targets/TARGET_STM/stm_spi_api.c @@ -541,7 +541,7 @@ static void spi_init_tx_dma(struct spi_s * obj) DMALinkInfo const *dmaLink = &SPITxDMALinks[obj->spiIndex - 1]; // Initialize DMA channel - DMA_HandleTypeDef *dmaHandle = stm_init_dma_link(dmaLink, DMA_MEMORY_TO_PERIPH, false, true, 1, 1); + DMA_HandleTypeDef *dmaHandle = stm_init_dma_link(dmaLink, DMA_MEMORY_TO_PERIPH, false, true, 1, 1).hdma; if(dmaHandle == NULL) { @@ -574,7 +574,7 @@ static void spi_init_rx_dma(struct spi_s * obj) DMALinkInfo const *dmaLink = &SPIRxDMALinks[obj->spiIndex - 1]; // Initialize DMA channel - DMA_HandleTypeDef *dmaHandle = stm_init_dma_link(dmaLink, DMA_PERIPH_TO_MEMORY, false, true, 1, 1); + DMA_HandleTypeDef *dmaHandle = stm_init_dma_link(dmaLink, DMA_PERIPH_TO_MEMORY, false, true, 1, 1).hdma; if(dmaHandle == NULL) { From 8fad66e3461d8692670d3b3ca425b3b45d8f83d1 Mon Sep 17 00:00:00 2001 From: wdx04 Date: Mon, 28 Apr 2025 21:05:34 +0800 Subject: [PATCH 2/7] fix stm_dma_utils compliation errors for MCUs with shared IRQs --- targets/TARGET_STM/stm_dma_utils.c | 54 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/targets/TARGET_STM/stm_dma_utils.c b/targets/TARGET_STM/stm_dma_utils.c index cb7aad9b824..7eb2707416c 100644 --- a/targets/TARGET_STM/stm_dma_utils.c +++ b/targets/TARGET_STM/stm_dma_utils.c @@ -1080,20 +1080,20 @@ void DMA1_Channel1_IRQHandler(void) void DMA1_Channel2_3_IRQHandler(void) { - if(stmDMAHandles[0][1] != NULL) { + if(stmDMAHandles[0][1].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } - if(stmDMAHandles[0][2] != NULL) { + if(stmDMAHandles[0][2].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } } void DMA1_Channel4_5_IRQHandler(void) { - if(stmDMAHandles[0][3] != NULL) { + if(stmDMAHandles[0][3].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } - if(stmDMAHandles[0][4] != NULL) { + if(stmDMAHandles[0][4].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } } @@ -1102,10 +1102,10 @@ void DMA1_Channel4_5_IRQHandler(void) void DMA1_Channel2_3_IRQHandler(void) { - if(stmDMAHandles[0][1] != NULL) { + if(stmDMAHandles[0][1].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } - if(stmDMAHandles[0][2] != NULL) { + if(stmDMAHandles[0][2].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } } @@ -1113,57 +1113,57 @@ void DMA1_Channel2_3_IRQHandler(void) #ifdef DMA2 void DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX1_OVR_IRQHandler(void) { - if(stmDMAHandles[0][3] != NULL) { + if(stmDMAHandles[0][3].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } - if(stmDMAHandles[0][4] != NULL) { + if(stmDMAHandles[0][4].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } - if(stmDMAHandles[0][5] != NULL) { + if(stmDMAHandles[0][5].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } - if(stmDMAHandles[0][6] != NULL) { + if(stmDMAHandles[0][6].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } - if(stmDMAHandles[1][0] != NULL) { + if(stmDMAHandles[1][0].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[1][0].hdma); } - if(stmDMAHandles[1][1] != NULL) { + if(stmDMAHandles[1][1].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[1][1].hdma); } - if(stmDMAHandles[1][2] != NULL) { + if(stmDMAHandles[1][2].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[1][2].hdma); } - if(stmDMAHandles[1][3] != NULL) { + if(stmDMAHandles[1][3].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[1][3].hdma); } - if(stmDMAHandles[1][4] != NULL) { + if(stmDMAHandles[1][4].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[1][4].hdma); } } #elif defined(DMA1_Channel7) void DMA1_Ch4_7_DMAMUX1_OVR_IRQHandler(void) { - if(stmDMAHandles[0][3] != NULL) { + if(stmDMAHandles[0][3].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } - if(stmDMAHandles[0][4] != NULL) { + if(stmDMAHandles[0][4].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } - if(stmDMAHandles[0][5] != NULL) { + if(stmDMAHandles[0][5].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } - if(stmDMAHandles[0][6] != NULL) { + if(stmDMAHandles[0][6].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } } #else void DMA1_Ch4_5_DMAMUX1_OVR_IRQHandler(void) { - if(stmDMAHandles[0][3] != NULL) { + if(stmDMAHandles[0][3].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } - if(stmDMAHandles[0][4] != NULL) { + if(stmDMAHandles[0][4].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } } @@ -1173,26 +1173,26 @@ void DMA1_Ch4_5_DMAMUX1_OVR_IRQHandler(void) void DMA1_Channel2_3_IRQHandler(void) { - if(stmDMAHandles[0][1] != NULL) { + if(stmDMAHandles[0][1].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } - if(stmDMAHandles[0][2] != NULL) { + if(stmDMAHandles[0][2].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } } void DMA1_Channel4_5_6_7_IRQHandler(void) { - if(stmDMAHandles[0][3] != NULL) { + if(stmDMAHandles[0][3].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } - if(stmDMAHandles[0][4] != NULL) { + if(stmDMAHandles[0][4].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } - if(stmDMAHandles[0][5] != NULL) { + if(stmDMAHandles[0][5].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } - if(stmDMAHandles[0][6] != NULL) { + if(stmDMAHandles[0][6].hdma != NULL) { HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } } From 59be34a246f4d9bbacd2191b1de6ac16e997c7cd Mon Sep 17 00:00:00 2001 From: wdx04 Date: Sat, 10 May 2025 21:11:41 +0800 Subject: [PATCH 3/7] changed sourceinc/destinationinc settings for MDMA wait on a sempahore for QSPI DMA operations changed FATFileSystem to use 32byte-aligned allocation enhanced D-Cache consistency for STM32F7/H7 families --- .../filesystem/fat/source/FATFileSystem.cpp | 4 + targets/TARGET_STM/TARGET_STM32F4/objects.h | 4 + targets/TARGET_STM/TARGET_STM32F7/objects.h | 4 + targets/TARGET_STM/TARGET_STM32G4/objects.h | 4 + targets/TARGET_STM/TARGET_STM32H7/objects.h | 10 +- .../TARGET_STM/TARGET_STM32H7/stm_dma_info.h | 6 +- targets/TARGET_STM/TARGET_STM32L4/objects.h | 10 +- targets/TARGET_STM/TARGET_STM32L5/objects.h | 10 +- targets/TARGET_STM/TARGET_STM32U5/objects.h | 10 +- targets/TARGET_STM/TARGET_STM32WB/objects.h | 4 + targets/TARGET_STM/qspi_api.c | 299 ++++++++++++++---- targets/TARGET_STM/stm_dma_ip_v1.h | 2 + targets/TARGET_STM/stm_dma_utils.c | 63 +++- 13 files changed, 362 insertions(+), 68 deletions(-) diff --git a/storage/filesystem/fat/source/FATFileSystem.cpp b/storage/filesystem/fat/source/FATFileSystem.cpp index 72d4157b62e..cb4390d82b5 100644 --- a/storage/filesystem/fat/source/FATFileSystem.cpp +++ b/storage/filesystem/fat/source/FATFileSystem.cpp @@ -155,7 +155,11 @@ extern "C" DWORD get_fattime(void) extern "C" void *ff_memalloc(UINT size) { +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + return aligned_alloc(32U, size); +#else return malloc(size); +#endif } extern "C" void ff_memfree(void *p) diff --git a/targets/TARGET_STM/TARGET_STM32F4/objects.h b/targets/TARGET_STM/TARGET_STM32F4/objects.h index a7de253b5b7..6313c81568b 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32F4/objects.h @@ -29,6 +29,8 @@ #include "stm32f4xx_ll_rcc.h" #include "stm_dma_info.h" +#include "cmsis_os.h" +#include "cmsis_os2.h" #ifdef __cplusplus extern "C" { @@ -153,6 +155,8 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32F7/objects.h b/targets/TARGET_STM/TARGET_STM32F7/objects.h index 0cf13355c3f..34e0e6a1686 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/objects.h +++ b/targets/TARGET_STM/TARGET_STM32F7/objects.h @@ -43,6 +43,8 @@ #include "stm32f7xx_ll_rcc.h" #include "stm_dma_info.h" +#include "cmsis_os.h" +#include "cmsis_os2.h" #ifdef __cplusplus extern "C" { @@ -127,6 +129,8 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32G4/objects.h b/targets/TARGET_STM/TARGET_STM32G4/objects.h index d984b164ba1..4b90fd157db 100644 --- a/targets/TARGET_STM/TARGET_STM32G4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32G4/objects.h @@ -27,6 +27,8 @@ #include "stm32g4xx_ll_rcc.h" #include "stm_dma_info.h" +#include "cmsis_os.h" +#include "cmsis_os2.h" #ifdef __cplusplus extern "C" { @@ -109,6 +111,8 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32H7/objects.h b/targets/TARGET_STM/TARGET_STM32H7/objects.h index 5edba2366f3..7b12f1ec4db 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/objects.h +++ b/targets/TARGET_STM/TARGET_STM32H7/objects.h @@ -32,6 +32,8 @@ #include "stm32h7xx_ll_system.h" #include "stm_dma_info.h" +#include "cmsis_os.h" +#include "cmsis_os2.h" #ifdef __cplusplus extern "C" { @@ -86,6 +88,7 @@ struct analogin_s { struct qspi_s { #if defined(OCTOSPI1) OSPI_HandleTypeDef handle; + IRQn_Type qspiIRQ; #else QSPI_HandleTypeDef handle; #endif @@ -96,14 +99,16 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; - IRQn_Type qspiIRQ; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #endif #if DEVICE_OSPI struct ospi_s { OSPI_HandleTypeDef handle; + IRQn_Type ospiIRQ; OSPIName ospi; PinName io0; PinName io1; @@ -116,8 +121,9 @@ struct ospi_s { PinName sclk; PinName ssel; PinName dqs; - IRQn_Type ospiIRQ; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32H7/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32H7/stm_dma_info.h index 4692b1af719..d5210b2ffda 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32H7/stm_dma_info.h @@ -45,12 +45,12 @@ static const DMALinkInfo SPIRxDMALinks[] = { /// Mapping from QSPI/OSPI index to DMA link info #if defined(OCTOSPI1) static const DMALinkInfo OSPIDMALinks[] = { - {4, 0, MDMA_REQUEST_OCTOSPI1_FIFO_TH}, - {4, 1, MDMA_REQUEST_OCTOSPI2_FIFO_TH} + {MDMA_IDX, 0, MDMA_REQUEST_OCTOSPI1_FIFO_TH}, + {MDMA_IDX, 1, MDMA_REQUEST_OCTOSPI2_FIFO_TH} }; #else static const DMALinkInfo QSPIDMALinks[] = { - {4, 0, MDMA_REQUEST_QUADSPI_FIFO_TH}, + {MDMA_IDX, 0, MDMA_REQUEST_QUADSPI_FIFO_TH}, }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32L4/objects.h b/targets/TARGET_STM/TARGET_STM32L4/objects.h index 93d9a489448..6d9ca6d7dde 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32L4/objects.h @@ -32,6 +32,8 @@ #include "stm32l4xx_ll_rcc.h" #include "stm_dma_utils.h" +#include "cmsis_os.h" +#include "cmsis_os2.h" #ifdef __cplusplus extern "C" { @@ -120,12 +122,15 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #endif #if DEVICE_OSPI struct ospi_s { OSPI_HandleTypeDef handle; + IRQn_Type ospiIRQ; OSPIName ospi; PinName io0; PinName io1; @@ -138,8 +143,9 @@ struct ospi_s { PinName sclk; PinName ssel; PinName dqs; - IRQn_Type ospiIRQ; - bool dmaInitialized; + bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/objects.h b/targets/TARGET_STM/TARGET_STM32L5/objects.h index 1ac885781c5..c595768dc4a 100644 --- a/targets/TARGET_STM/TARGET_STM32L5/objects.h +++ b/targets/TARGET_STM/TARGET_STM32L5/objects.h @@ -28,6 +28,8 @@ #include "stm32l5xx_ll_rcc.h" #include "stm_dma_info.h" +#include "cmsis_os.h" +#include "cmsis_os2.h" #ifdef __cplusplus extern "C" { @@ -107,6 +109,7 @@ struct can_s { struct qspi_s { OSPI_HandleTypeDef handle; + IRQn_Type qspiIRQ; QSPIName qspi; PinName io0; PinName io1; @@ -114,12 +117,14 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; - IRQn_Type qspiIRQ; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; struct ospi_s { OSPI_HandleTypeDef handle; + IRQn_Type ospiIRQ; OSPIName ospi; PinName io0; PinName io1; @@ -132,8 +137,9 @@ struct ospi_s { PinName sclk; PinName ssel; PinName dqs; - IRQn_Type ospiIRQ; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #ifdef __cplusplus diff --git a/targets/TARGET_STM/TARGET_STM32U5/objects.h b/targets/TARGET_STM/TARGET_STM32U5/objects.h index 74240411fd4..072c03f18a8 100644 --- a/targets/TARGET_STM/TARGET_STM32U5/objects.h +++ b/targets/TARGET_STM/TARGET_STM32U5/objects.h @@ -28,6 +28,8 @@ #include "stm32u5xx_ll_rcc.h" #include "stm_dma_info.h" +#include "cmsis_os.h" +#include "cmsis_os2.h" #ifdef __cplusplus extern "C" { @@ -107,6 +109,7 @@ struct can_s { struct qspi_s { OSPI_HandleTypeDef handle; + IRQn_Type qspiIRQ; QSPIName qspi; PinName io0; PinName io1; @@ -114,12 +117,14 @@ struct qspi_s { PinName io3; PinName sclk; PinName ssel; - IRQn_Type qspiIRQ; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; struct ospi_s { OSPI_HandleTypeDef handle; + IRQn_Type ospiIRQ; OSPIName ospi; PinName io0; PinName io1; @@ -132,8 +137,9 @@ struct ospi_s { PinName sclk; PinName ssel; PinName dqs; - IRQn_Type ospiIRQ; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #ifdef __cplusplus diff --git a/targets/TARGET_STM/TARGET_STM32WB/objects.h b/targets/TARGET_STM/TARGET_STM32WB/objects.h index 71d22087c9c..375c7fd55da 100644 --- a/targets/TARGET_STM/TARGET_STM32WB/objects.h +++ b/targets/TARGET_STM/TARGET_STM32WB/objects.h @@ -34,6 +34,8 @@ #endif #include "stm_dma_info.h" +#include "cmsis_os.h" +#include "cmsis_os2.h" #ifdef __cplusplus extern "C" { @@ -101,6 +103,8 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; + osSemaphoreId_t semaphoreId; + osRtxSemaphore_t semaphoreMem; }; #endif diff --git a/targets/TARGET_STM/qspi_api.c b/targets/TARGET_STM/qspi_api.c index de1e752fba1..7dcdc3908cc 100644 --- a/targets/TARGET_STM/qspi_api.c +++ b/targets/TARGET_STM/qspi_api.c @@ -44,42 +44,95 @@ #if defined(QUADSPI) static QSPI_HandleTypeDef * qspiHandle; // Handle of whatever QSPI structure is used for QUADSPI + +// Store the spi_s * inside an SPI handle, for later retrieval in callbacks +static inline void store_qspi_pointer(QSPI_HandleTypeDef * qspiHandle, struct qspi_s * qspis) { + // Annoyingly, STM neglected to provide any sort of "user data" pointer inside QSPI_HandleTypeDef for use + // in callbacks. However, there are some variables in the Init struct that are never accessed after HAL_QSPI_Init(). + // So, we can reuse those to store our pointer. + qspiHandle->Init.ChipSelectHighTime = (uint32_t)qspis; +} + +// Get spi_s * from SPI_HandleTypeDef +static inline struct qspi_s * get_qspi_pointer(QSPI_HandleTypeDef * qspiHandle) { + return (struct qspi_s *) qspiHandle->Init.ChipSelectHighTime; +} + void QUADSPI_IRQHandler() { HAL_QSPI_IRQHandler(qspiHandle); } +void HAL_QSPI_TxCpltCallback(QSPI_HandleTypeDef * handle) +{ + osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); +} + +void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef * handle) +{ + osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); +} + void HAL_QSPI_ErrorCallback(QSPI_HandleTypeDef * handle) { handle->State = HAL_QSPI_STATE_ERROR; + osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); } void HAL_QSPI_TimeOutCallback(QSPI_HandleTypeDef * handle) { handle->State = HAL_QSPI_STATE_ERROR; + osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); } #endif #if defined(OCTOSPI1) static OSPI_HandleTypeDef * ospiHandle1; + +// Store the qspi_s * inside an OSPI handle, for later retrieval in callbacks +static inline void store_qspi_pointer(OSPI_HandleTypeDef * ospiHandle, struct qspi_s * qspis) { + // Annoyingly, STM neglected to provide any sort of "user data" pointer inside OSPI_HandleTypeDef for use + // in callbacks. However, there are some variables in the Init struct that are never accessed after HAL_OSPI_Init(). + // So, we can reuse those to store our pointer. + ospiHandle->Init.ChipSelectHighTime = (uint32_t)qspis; +} + +// Get qspi_s * from OSPI_HandleTypeDef +static inline struct qspi_s * get_qspi_pointer(OSPI_HandleTypeDef * ospiHandle) { + return (struct qspi_s *) ospiHandle->Init.ChipSelectHighTime; +} + void OCTOSPI1_IRQHandler() { HAL_OSPI_IRQHandler(ospiHandle1); } +void HAL_OSPI_TxCpltCallback(OSPI_HandleTypeDef * handle) +{ + osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); +} + +void HAL_OSPI_RxCpltCallback(OSPI_HandleTypeDef * handle) +{ + osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); +} + void HAL_OSPI_ErrorCallback(OSPI_HandleTypeDef * handle) { handle->State = HAL_OSPI_STATE_ERROR; + osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); } void HAL_OSPI_TimeOutCallback(OSPI_HandleTypeDef * handle) { handle->State = HAL_OSPI_STATE_ERROR; + osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); } #endif #if defined(OCTOSPI2) static OSPI_HandleTypeDef * ospiHandle2; + void OCTOSPI2_IRQHandler() { HAL_OSPI_IRQHandler(ospiHandle2); @@ -462,22 +515,13 @@ static void qspi_init_dma(struct qspi_s * obj) __HAL_LINKDMA(&obj->handle, hdma, *dmaHandle.hdma); #endif obj->dmaInitialized = true; + osSemaphoreAttr_t attr = { 0 }; + attr.cb_mem = &obj->semaphoreMem; + attr.cb_size = sizeof(osRtxSemaphore_t); + obj->semaphoreId = osSemaphoreNew(1, 0, &attr); } } -// Store the qspi_s * inside an OSPI handle, for later retrieval in callbacks -static inline void store_qspi_pointer(OSPI_HandleTypeDef * ospiHandle, struct qspi_s * qspis) { - // Annoyingly, STM neglected to provide any sort of "user data" pointer inside OSPI_HandleTypeDef for use - // in callbacks. However, there are some variables in the Init struct that are never accessed after HAL_OSPI_Init(). - // So, we can reuse those to store our pointer. - ospiHandle->Init.ChipSelectHighTime = (uint32_t)qspis; -} - -// Get qspi_s * from OSPI_HandleTypeDef -static inline struct qspi_s * get_qspi_pointer(OSPI_HandleTypeDef * ospiHandle) { - return (struct qspi_s *) ospiHandle->Init.ChipSelectHighTime; -} - #if STATIC_PINMAP_READY #define QSPI_INIT_DIRECT qspi_init_direct qspi_status_t qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, uint32_t hz, uint8_t mode) @@ -667,22 +711,13 @@ static void qspi_init_dma(struct qspi_s * obj) __HAL_LINKDMA(&obj->handle, hdma, *dmaHandle.hdma); #endif obj->dmaInitialized = true; + osSemaphoreAttr_t attr = { 0 }; + attr.cb_mem = &obj->semaphoreMem; + attr.cb_size = sizeof(osRtxSemaphore_t); + obj->semaphoreId = osSemaphoreNew(1, 0, &attr); } } -// Store the spi_s * inside an SPI handle, for later retrieval in callbacks -static inline void store_qspi_pointer(QSPI_HandleTypeDef * qspiHandle, struct qspi_s * qspis) { - // Annoyingly, STM neglected to provide any sort of "user data" pointer inside QSPI_HandleTypeDef for use - // in callbacks. However, there are some variables in the Init struct that are never accessed after HAL_QSPI_Init(). - // So, we can reuse those to store our pointer. - qspiHandle->Init.ChipSelectHighTime = (uint32_t)qspis; -} - -// Get spi_s * from SPI_HandleTypeDef -static inline struct qspi_s * get_qspi_pointer(QSPI_HandleTypeDef * qspiHandle) { - return (struct qspi_s *) qspiHandle->Init.ChipSelectHighTime; -} - #if STATIC_PINMAP_READY #define QSPI_INIT_DIRECT qspi_init_direct qspi_status_t qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, uint32_t hz, uint8_t mode) @@ -853,6 +888,9 @@ qspi_status_t qspi_free(qspi_t *obj) // Get DMA handle DMALinkInfo const *dmaLink = &QSPIDMALinks[0]; stm_free_dma_link(dmaLink); + + // Free semaphore + osSemaphoreRelease(obj->semaphoreId); } if (HAL_QSPI_DeInit(&obj->handle) != HAL_OK) { @@ -975,7 +1013,7 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void tr_error("HAL_OSPI_Command error"); status = QSPI_STATUS_ERROR; } else { - if(st_command.NbData >= 8) { + if(st_command.NbData >= 32) { qspi_init_dma(obj); NVIC_ClearPendingIRQ(obj->qspiIRQ); NVIC_SetPriority(obj->qspiIRQ, 1); @@ -991,7 +1029,7 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void } else { // wait until transfer complete or timeout - while(obj->handle.State == HAL_OSPI_STATE_BUSY_TX); + osSemaphoreAcquire(obj->semaphoreId, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); if(obj->handle.State != HAL_OSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_OSPI_STATE_READY; @@ -1025,7 +1063,7 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { status = QSPI_STATUS_ERROR; } else { - if(st_command.NbData >= 8) { + if(st_command.NbData >= 32) { qspi_init_dma(obj); NVIC_ClearPendingIRQ(QUADSPI_IRQn); NVIC_SetPriority(QUADSPI_IRQn, 1); @@ -1033,14 +1071,14 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void #if defined(__DCACHE_PRESENT) // For chips with a cache (e.g. Cortex-M7), we need to evict the Tx fill data from cache to main memory. // This ensures that the DMA controller can see the most up-to-date copy of the data. - SCB_CleanDCache_by_Addr(data, *length); + SCB_CleanDCache_by_Addr((volatile void *)data, *length); #endif if (HAL_QSPI_Transmit_DMA(&obj->handle, (uint8_t *)data) != HAL_OK) { status = QSPI_STATUS_ERROR; } else { // wait until transfer complete or timeout - while(obj->handle.State == HAL_QSPI_STATE_BUSY_INDIRECT_TX); + osSemaphoreAcquire(obj->semaphoreId, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); if(obj->handle.State != HAL_QSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_QSPI_STATE_READY; @@ -1069,36 +1107,112 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, return status; } +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + size_t pre_aligned_size = 0, aligned_size = 0, post_aligned_size = 0; + if(*length < __SCB_DCACHE_LINE_SIZE) + { + pre_aligned_size = *length; + } + else + { + size_t address_remainder = (size_t) data % __SCB_DCACHE_LINE_SIZE; + if(address_remainder == 0) + { + aligned_size = *length & ~(__SCB_DCACHE_LINE_SIZE - 1); + post_aligned_size = *length - aligned_size; + } + else + { + pre_aligned_size = __SCB_DCACHE_LINE_SIZE - address_remainder; + aligned_size = (*length - pre_aligned_size) & ~(__SCB_DCACHE_LINE_SIZE - 1); + post_aligned_size = *length - pre_aligned_size - aligned_size; + } + if(aligned_size == 0) + { + pre_aligned_size = *length; + post_aligned_size = 0; + } + } + if(pre_aligned_size > 0) + { + st_command.NbData = pre_aligned_size; + if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_OSPI_Command error"); + status = QSPI_STATUS_ERROR; + } else { + if (HAL_OSPI_Receive(&obj->handle, data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_OSPI_Receive error %d", obj->handle.ErrorCode); + status = QSPI_STATUS_ERROR; + } + } + st_command.Address += pre_aligned_size; + data += pre_aligned_size; + } + if(status == QSPI_STATUS_OK && aligned_size > 0) + { + st_command.NbData = aligned_size; + if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_OSPI_Command error"); + status = QSPI_STATUS_ERROR; + } else { + qspi_init_dma(obj); + NVIC_ClearPendingIRQ(obj->qspiIRQ); + NVIC_SetPriority(obj->qspiIRQ, 1); + NVIC_EnableIRQ(obj->qspiIRQ); + SCB_CleanInvalidateDCache_by_Addr((volatile void *)data, *length); + if (HAL_OSPI_Receive_DMA(&obj->handle, data) != HAL_OK) { + tr_error("HAL_OSPI_Receive error %d", obj->handle.ErrorCode); + status = QSPI_STATUS_ERROR; + } + else { + // wait until transfer complete or timeout + osSemaphoreAcquire(obj->semaphoreId, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); + if(obj->handle.State != HAL_OSPI_STATE_READY) { + status = QSPI_STATUS_ERROR; + obj->handle.State = HAL_OSPI_STATE_READY; + } + } + NVIC_DisableIRQ(obj->qspiIRQ); + } + st_command.Address += aligned_size; + data += aligned_size; + } + if(status == QSPI_STATUS_OK && post_aligned_size > 0) + { + st_command.NbData = post_aligned_size; + if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_OSPI_Command error"); + status = QSPI_STATUS_ERROR; + } else { + if (HAL_OSPI_Receive(&obj->handle, data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_OSPI_Receive error %d", obj->handle.ErrorCode); + status = QSPI_STATUS_ERROR; + } + } + } +#else st_command.NbData = *length; if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { tr_error("HAL_OSPI_Command error"); status = QSPI_STATUS_ERROR; } else { - if(st_command.NbData >= 8) { + if(st_command.NbData >= 32) { qspi_init_dma(obj); NVIC_ClearPendingIRQ(obj->qspiIRQ); NVIC_SetPriority(obj->qspiIRQ, 1); NVIC_EnableIRQ(obj->qspiIRQ); -#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) - if(((uint32_t) data) % __SCB_DCACHE_LINE_SIZE != 0 || (*length) % __SCB_DCACHE_LINE_SIZE != 0) { - SCB_CleanDCache_by_Addr((uint32_t*)data, *length); - } -#endif if (HAL_OSPI_Receive_DMA(&obj->handle, data) != HAL_OK) { tr_error("HAL_OSPI_Receive error %d", obj->handle.ErrorCode); status = QSPI_STATUS_ERROR; } else { // wait until transfer complete or timeout - while(obj->handle.State == HAL_OSPI_STATE_BUSY_RX); + osSemaphoreAcquire(obj->semaphoreId, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); if(obj->handle.State != HAL_OSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_OSPI_STATE_READY; } - #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) - SCB_InvalidateDCache_by_Addr((uint32_t*)data, *length); - #endif } NVIC_DisableIRQ(obj->qspiIRQ); } @@ -1109,7 +1223,7 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, } } } - +#endif debug_if(qspi_api_c_debug, "qspi_read size %u\n", *length); return status; @@ -1123,30 +1237,108 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, return status; } +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + size_t pre_aligned_size = 0, aligned_size = 0, post_aligned_size = 0; + if(*length < __SCB_DCACHE_LINE_SIZE) + { + pre_aligned_size = *length; + } + else + { + size_t address_remainder = (size_t) data % __SCB_DCACHE_LINE_SIZE; + if(address_remainder == 0) + { + aligned_size = *length & ~(__SCB_DCACHE_LINE_SIZE - 1); + post_aligned_size = *length - aligned_size; + } + else + { + pre_aligned_size = __SCB_DCACHE_LINE_SIZE - address_remainder; + aligned_size = (*length - pre_aligned_size) & ~(__SCB_DCACHE_LINE_SIZE - 1); + post_aligned_size = *length - pre_aligned_size - aligned_size; + } + if(aligned_size == 0) + { + pre_aligned_size = *length; + post_aligned_size = 0; + } + } + if(pre_aligned_size > 0) + { + st_command.NbData = pre_aligned_size; + if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_QSPI_Command error"); + status = QSPI_STATUS_ERROR; + } else { + if (HAL_QSPI_Receive(&obj->handle, data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_QSPI_Receive error %d", obj->handle.ErrorCode); + status = QSPI_STATUS_ERROR; + } + } + st_command.Address += pre_aligned_size; + data += pre_aligned_size; + } + if(status == QSPI_STATUS_OK && aligned_size > 0) + { + st_command.NbData = aligned_size; + if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_QSPI_Command error"); + status = QSPI_STATUS_ERROR; + } else { + qspi_init_dma(obj); + NVIC_ClearPendingIRQ(QUADSPI_IRQn); + NVIC_SetPriority(QUADSPI_IRQn, 1); + NVIC_EnableIRQ(QUADSPI_IRQn); + SCB_CleanInvalidateDCache_by_Addr((volatile void *)data, *length); + if (HAL_QSPI_Receive_DMA(&obj->handle, data) != HAL_OK) { + tr_error("HAL_QSPI_Receive error %d", obj->handle.ErrorCode); + status = QSPI_STATUS_ERROR; + } + else { + // wait until transfer complete or timeout + osSemaphoreAcquire(obj->semaphoreId, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); + if(obj->handle.State != HAL_QSPI_STATE_READY) { + status = QSPI_STATUS_ERROR; + obj->handle.State = HAL_QSPI_STATE_READY; + } + } + NVIC_DisableIRQ(QUADSPI_IRQn); + } + st_command.Address += aligned_size; + data += aligned_size; + } + if(status == QSPI_STATUS_OK && post_aligned_size > 0) + { + st_command.NbData = post_aligned_size; + if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_QSPI_Command error"); + status = QSPI_STATUS_ERROR; + } else { + if (HAL_QSPI_Receive(&obj->handle, data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_QSPI_Receive error %d", obj->handle.ErrorCode); + status = QSPI_STATUS_ERROR; + } + } + } +#else st_command.NbData = *length; if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_QSPI_Command error"); status = QSPI_STATUS_ERROR; } else { - if(st_command.NbData >= 8) { + if(st_command.NbData >= 32) { qspi_init_dma(obj); NVIC_ClearPendingIRQ(QUADSPI_IRQn); NVIC_SetPriority(QUADSPI_IRQn, 1); NVIC_EnableIRQ(QUADSPI_IRQn); -#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) - if(((uint32_t) data) % __SCB_DCACHE_LINE_SIZE != 0 || (*length) % __SCB_DCACHE_LINE_SIZE != 0) { - SCB_CleanDCache_by_Addr((uint32_t*)data, *length); - } -#endif if (HAL_QSPI_Receive_DMA(&obj->handle, data) != HAL_OK) { + tr_error("HAL_QSPI_Receive error %d", obj->handle.ErrorCode); status = QSPI_STATUS_ERROR; } else { // wait until transfer complete or timeout -#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) - SCB_InvalidateDCache_by_Addr((uint32_t*)data, *length); -#endif - while(obj->handle.State == HAL_QSPI_STATE_BUSY_INDIRECT_RX); + osSemaphoreAcquire(obj->semaphoreId, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); if(obj->handle.State != HAL_QSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_QSPI_STATE_READY; @@ -1156,11 +1348,12 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, } else { if (HAL_QSPI_Receive(&obj->handle, data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + tr_error("HAL_QSPI_Receive error %d", obj->handle.ErrorCode); status = QSPI_STATUS_ERROR; } } } - +#endif debug_if(qspi_api_c_debug, "qspi_read size %u\n", *length); return status; diff --git a/targets/TARGET_STM/stm_dma_ip_v1.h b/targets/TARGET_STM/stm_dma_ip_v1.h index ff2ed3fd24c..15b1836c21b 100644 --- a/targets/TARGET_STM/stm_dma_ip_v1.h +++ b/targets/TARGET_STM/stm_dma_ip_v1.h @@ -32,6 +32,8 @@ // For STM32H7, MDMA has 16 channels, while DMA1, DMA2 and BDMA all have 8 channels #define NUM_DMA_CONTROLLERS 5 #define MAX_MDMA_CHANNELS 16 +#define BDMA_IDX 3 +#define MDMA_IDX 4 #else #ifdef DMA1 #ifdef DMA2 diff --git a/targets/TARGET_STM/stm_dma_utils.c b/targets/TARGET_STM/stm_dma_utils.c index 7eb2707416c..70cf293db6c 100644 --- a/targets/TARGET_STM/stm_dma_utils.c +++ b/targets/TARGET_STM/stm_dma_utils.c @@ -976,10 +976,33 @@ DMAHandlePointer stm_init_dma_link(const DMALinkInfo *dmaLink, uint32_t directio dmaHandle->Init.Priority = MDMA_PRIORITY_HIGH; dmaHandle->Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE; - dmaHandle->Init.SourceInc = periphInc ? MDMA_SRC_INC_BYTE: MDMA_SRC_INC_DISABLE; - dmaHandle->Init.DestinationInc = memInc ? MDMA_DEST_INC_BYTE: MDMA_DEST_INC_DISABLE; - switch(periphDataAlignment) + if(direction == DMA_MEMORY_TO_PERIPH || direction == DMA_MEMORY_TO_MEMORY) { + // Source is memory + dmaHandle->Init.SourceInc = memInc ? MDMA_SRC_INC_BYTE: MDMA_SRC_INC_DISABLE; + + switch(memDataAlignment) { + case 8: + dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_DOUBLEWORD; + break; + case 4: + dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_WORD; + break; + case 2: + dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_HALFWORD; + break; + case 1: + default: + dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE; + break; + + } + } + else { + // Source is a peripheral + dmaHandle->Init.SourceInc = periphInc ? MDMA_SRC_INC_BYTE: MDMA_SRC_INC_DISABLE; + + switch(periphDataAlignment) { case 8: dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_DOUBLEWORD; break; @@ -990,11 +1013,19 @@ DMAHandlePointer stm_init_dma_link(const DMALinkInfo *dmaLink, uint32_t directio dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_HALFWORD; break; case 1: + default: dmaHandle->Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE; break; + + } } - switch(memDataAlignment) + + if(direction == DMA_PERIPH_TO_MEMORY || direction == DMA_MEMORY_TO_MEMORY) { + // Destination is memory + dmaHandle->Init.DestinationInc = memInc ? MDMA_DEST_INC_BYTE: MDMA_DEST_INC_DISABLE; + + switch(memDataAlignment) { case 8: dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_DOUBLEWORD; break; @@ -1005,8 +1036,32 @@ DMAHandlePointer stm_init_dma_link(const DMALinkInfo *dmaLink, uint32_t directio dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_HALFWORD; break; case 1: + default: dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_BYTE; break; + + } + } + else { + // Destination is a peripheral + dmaHandle->Init.DestinationInc = periphInc ? MDMA_DEST_INC_BYTE: MDMA_DEST_INC_DISABLE; + + switch(periphDataAlignment) { + case 8: + dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_DOUBLEWORD; + break; + case 4: + dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_WORD; + break; + case 2: + dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_HALFWORD; + break; + case 1: + default: + dmaHandle->Init.DestDataSize = MDMA_DEST_DATASIZE_BYTE; + break; + + } } dmaHandle->Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE; dmaHandle->Init.BufferTransferLength = 64; From c2d23023d3ecb9f0798438af5e821c946272939e Mon Sep 17 00:00:00 2001 From: wdx04 Date: Sat, 10 May 2025 21:29:23 +0800 Subject: [PATCH 4/7] fixed compliation errors after merging --- targets/TARGET_STM/qspi_api.c | 4 ++-- targets/TARGET_STM/stm_dma_utils.c | 34 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/targets/TARGET_STM/qspi_api.c b/targets/TARGET_STM/qspi_api.c index 8e00b84f481..ea2742d77b0 100644 --- a/targets/TARGET_STM/qspi_api.c +++ b/targets/TARGET_STM/qspi_api.c @@ -504,7 +504,7 @@ static void qspi_init_dma(struct qspi_s * obj) dmaLink = &OSPIDMALinks[0]; #endif // Initialize DMA channel - DMAHandlePointer dmaHandle = stm_init_dma_link(dmaLink, DMA_PERIPH_TO_MEMORY, false, true, 1, 1); + DMAHandlePointer dmaHandle = stm_init_dma_link(dmaLink, DMA_PERIPH_TO_MEMORY, false, true, 1, 1, DMA_NORMAL); if(dmaHandle.hdma == NULL) { mbed_error(MBED_ERROR_ALREADY_IN_USE, "DMA channel already used by something else!", 0, MBED_FILENAME, __LINE__); @@ -700,7 +700,7 @@ static void qspi_init_dma(struct qspi_s * obj) DMALinkInfo const *dmaLink = &QSPIDMALinks[0]; // Initialize DMA channel - DMAHandlePointer dmaHandle = stm_init_dma_link(dmaLink, DMA_PERIPH_TO_MEMORY, false, true, 1, 1); + DMAHandlePointer dmaHandle = stm_init_dma_link(dmaLink, DMA_PERIPH_TO_MEMORY, false, true, 1, 1, DMA_NORMAL); if(dmaHandle.hdma == NULL) { mbed_error(MBED_ERROR_ALREADY_IN_USE, "DMA channel already used by something else!", 0, MBED_FILENAME, __LINE__); diff --git a/targets/TARGET_STM/stm_dma_utils.c b/targets/TARGET_STM/stm_dma_utils.c index 2b14703adf0..204656ab968 100644 --- a/targets/TARGET_STM/stm_dma_utils.c +++ b/targets/TARGET_STM/stm_dma_utils.c @@ -1227,10 +1227,10 @@ void DMA1_Ch4_5_DMAMUX1_OVR_IRQHandler(void) void DMA1_Channel2_3_IRQHandler(void) { if(stmDMAHandles[0][1] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][1]); + HAL_DMA_IRQHandler(stmDMAHandles[0][1].hdma); } if(stmDMAHandles[0][2] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][2]); + HAL_DMA_IRQHandler(stmDMAHandles[0][2].hdma); } } @@ -1238,57 +1238,57 @@ void DMA1_Channel2_3_IRQHandler(void) void DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX_OVR_IRQHandler(void) { if(stmDMAHandles[0][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } if(stmDMAHandles[0][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } if(stmDMAHandles[0][5] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][5]); + HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } if(stmDMAHandles[0][6] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][6]); + HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } if(stmDMAHandles[1][0] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][0]); + HAL_DMA_IRQHandler(stmDMAHandles[1][0].hdma); } if(stmDMAHandles[1][1] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][1]); + HAL_DMA_IRQHandler(stmDMAHandles[1][1].hdma); } if(stmDMAHandles[1][2] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][2]); + HAL_DMA_IRQHandler(stmDMAHandles[1][2].hdma); } if(stmDMAHandles[1][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][3]); + HAL_DMA_IRQHandler(stmDMAHandles[1][3].hdma); } if(stmDMAHandles[1][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[1][4]); + HAL_DMA_IRQHandler(stmDMAHandles[1][4].hdma); } } #elif defined(DMA1_Channel7) void DMA1_Ch4_7_DMAMUX_OVR_IRQHandler(void) { if(stmDMAHandles[0][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } if(stmDMAHandles[0][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } if(stmDMAHandles[0][5] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][5]); + HAL_DMA_IRQHandler(stmDMAHandles[0][5].hdma); } if(stmDMAHandles[0][6] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][6]); + HAL_DMA_IRQHandler(stmDMAHandles[0][6].hdma); } } #else void DMA1_Ch4_5_DMAMUX_OVR_IRQHandler(void) { if(stmDMAHandles[0][3] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][3]); + HAL_DMA_IRQHandler(stmDMAHandles[0][3].hdma); } if(stmDMAHandles[0][4] != NULL) { - HAL_DMA_IRQHandler(stmDMAHandles[0][4]); + HAL_DMA_IRQHandler(stmDMAHandles[0][4].hdma); } } #endif From 5e03d61a9379da8a5c6dad6ba0f7553ed409ee9f Mon Sep 17 00:00:00 2001 From: wdx04 Date: Mon, 12 May 2025 21:17:31 +0800 Subject: [PATCH 5/7] do not use semaphore when RTOS is not available --- targets/TARGET_STM/TARGET_STM32F4/objects.h | 4 ++ targets/TARGET_STM/TARGET_STM32F7/objects.h | 4 ++ targets/TARGET_STM/TARGET_STM32G4/objects.h | 4 ++ targets/TARGET_STM/TARGET_STM32H7/objects.h | 6 +++ targets/TARGET_STM/TARGET_STM32L4/objects.h | 6 +++ targets/TARGET_STM/TARGET_STM32L5/objects.h | 6 +++ targets/TARGET_STM/TARGET_STM32U5/objects.h | 6 +++ .../TARGET_STM/TARGET_STM32U5/stm_dma_info.h | 2 + targets/TARGET_STM/TARGET_STM32WB/objects.h | 4 ++ targets/TARGET_STM/qspi_api.c | 42 +++++++++++++++++++ 10 files changed, 84 insertions(+) diff --git a/targets/TARGET_STM/TARGET_STM32F4/objects.h b/targets/TARGET_STM/TARGET_STM32F4/objects.h index 6313c81568b..1b32200e2ec 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32F4/objects.h @@ -29,8 +29,10 @@ #include "stm32f4xx_ll_rcc.h" #include "stm_dma_info.h" +#if MBED_CONF_RTOS_PRESENT #include "cmsis_os.h" #include "cmsis_os2.h" +#endif #ifdef __cplusplus extern "C" { @@ -155,8 +157,10 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32F7/objects.h b/targets/TARGET_STM/TARGET_STM32F7/objects.h index 34e0e6a1686..44f0b3e0e38 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/objects.h +++ b/targets/TARGET_STM/TARGET_STM32F7/objects.h @@ -43,8 +43,10 @@ #include "stm32f7xx_ll_rcc.h" #include "stm_dma_info.h" +#if MBED_CONF_RTOS_PRESENT #include "cmsis_os.h" #include "cmsis_os2.h" +#endif #ifdef __cplusplus extern "C" { @@ -129,8 +131,10 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32G4/objects.h b/targets/TARGET_STM/TARGET_STM32G4/objects.h index 4b90fd157db..f70dd1a8f77 100644 --- a/targets/TARGET_STM/TARGET_STM32G4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32G4/objects.h @@ -27,8 +27,10 @@ #include "stm32g4xx_ll_rcc.h" #include "stm_dma_info.h" +#if MBED_CONF_RTOS_PRESENT #include "cmsis_os.h" #include "cmsis_os2.h" +#endif #ifdef __cplusplus extern "C" { @@ -111,8 +113,10 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32H7/objects.h b/targets/TARGET_STM/TARGET_STM32H7/objects.h index 7b12f1ec4db..b29885e16c1 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/objects.h +++ b/targets/TARGET_STM/TARGET_STM32H7/objects.h @@ -32,8 +32,10 @@ #include "stm32h7xx_ll_system.h" #include "stm_dma_info.h" +#if MBED_CONF_RTOS_PRESENT #include "cmsis_os.h" #include "cmsis_os2.h" +#endif #ifdef __cplusplus extern "C" { @@ -100,8 +102,10 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #endif @@ -122,8 +126,10 @@ struct ospi_s { PinName ssel; PinName dqs; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32L4/objects.h b/targets/TARGET_STM/TARGET_STM32L4/objects.h index 6d9ca6d7dde..45b86bb0e96 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/objects.h +++ b/targets/TARGET_STM/TARGET_STM32L4/objects.h @@ -32,8 +32,10 @@ #include "stm32l4xx_ll_rcc.h" #include "stm_dma_utils.h" +#if MBED_CONF_RTOS_PRESENT #include "cmsis_os.h" #include "cmsis_os2.h" +#endif #ifdef __cplusplus extern "C" { @@ -122,8 +124,10 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #endif @@ -144,8 +148,10 @@ struct ospi_s { PinName ssel; PinName dqs; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/objects.h b/targets/TARGET_STM/TARGET_STM32L5/objects.h index c595768dc4a..72127a375ac 100644 --- a/targets/TARGET_STM/TARGET_STM32L5/objects.h +++ b/targets/TARGET_STM/TARGET_STM32L5/objects.h @@ -28,8 +28,10 @@ #include "stm32l5xx_ll_rcc.h" #include "stm_dma_info.h" +#if MBED_CONF_RTOS_PRESENT #include "cmsis_os.h" #include "cmsis_os2.h" +#endif #ifdef __cplusplus extern "C" { @@ -118,8 +120,10 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; struct ospi_s { @@ -138,8 +142,10 @@ struct ospi_s { PinName ssel; PinName dqs; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #ifdef __cplusplus diff --git a/targets/TARGET_STM/TARGET_STM32U5/objects.h b/targets/TARGET_STM/TARGET_STM32U5/objects.h index 072c03f18a8..1d655949b1a 100644 --- a/targets/TARGET_STM/TARGET_STM32U5/objects.h +++ b/targets/TARGET_STM/TARGET_STM32U5/objects.h @@ -28,8 +28,10 @@ #include "stm32u5xx_ll_rcc.h" #include "stm_dma_info.h" +#if MBED_CONF_RTOS_PRESENT #include "cmsis_os.h" #include "cmsis_os2.h" +#endif #ifdef __cplusplus extern "C" { @@ -118,8 +120,10 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; struct ospi_s { @@ -138,8 +142,10 @@ struct ospi_s { PinName ssel; PinName dqs; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #ifdef __cplusplus diff --git a/targets/TARGET_STM/TARGET_STM32U5/stm_dma_info.h b/targets/TARGET_STM/TARGET_STM32U5/stm_dma_info.h index ac977e7496a..53d75bdee74 100644 --- a/targets/TARGET_STM/TARGET_STM32U5/stm_dma_info.h +++ b/targets/TARGET_STM/TARGET_STM32U5/stm_dma_info.h @@ -41,7 +41,9 @@ static const DMALinkInfo SPIRxDMALinks[] = { /// Mapping from OSPI index to DMA link info static const DMALinkInfo OSPIDMALinks[] = { {1, 6, GPDMA1_REQUEST_OCTOSPI1}, +#if defined(OCTOSPI2) {1, 7, GPDMA1_REQUEST_OCTOSPI2} +#endif }; #endif //MBED_OS_STM_DMA_INFO_H diff --git a/targets/TARGET_STM/TARGET_STM32WB/objects.h b/targets/TARGET_STM/TARGET_STM32WB/objects.h index 375c7fd55da..a0372a67524 100644 --- a/targets/TARGET_STM/TARGET_STM32WB/objects.h +++ b/targets/TARGET_STM/TARGET_STM32WB/objects.h @@ -34,8 +34,10 @@ #endif #include "stm_dma_info.h" +#if MBED_CONF_RTOS_PRESENT #include "cmsis_os.h" #include "cmsis_os2.h" +#endif #ifdef __cplusplus extern "C" { @@ -103,8 +105,10 @@ struct qspi_s { PinName sclk; PinName ssel; bool dmaInitialized; +#if MBED_CONF_RTOS_PRESENT osSemaphoreId_t semaphoreId; osRtxSemaphore_t semaphoreMem; +#endif }; #endif diff --git a/targets/TARGET_STM/qspi_api.c b/targets/TARGET_STM/qspi_api.c index ea2742d77b0..7dbec30966c 100644 --- a/targets/TARGET_STM/qspi_api.c +++ b/targets/TARGET_STM/qspi_api.c @@ -63,6 +63,7 @@ void QUADSPI_IRQHandler() HAL_QSPI_IRQHandler(qspiHandle); } +#if MBED_CONF_RTOS_PRESENT void HAL_QSPI_TxCpltCallback(QSPI_HandleTypeDef * handle) { osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); @@ -72,17 +73,22 @@ void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef * handle) { osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); } +#endif void HAL_QSPI_ErrorCallback(QSPI_HandleTypeDef * handle) { handle->State = HAL_QSPI_STATE_ERROR; +#if MBED_CONF_RTOS_PRESENT osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); +#endif } void HAL_QSPI_TimeOutCallback(QSPI_HandleTypeDef * handle) { handle->State = HAL_QSPI_STATE_ERROR; +#if MBED_CONF_RTOS_PRESENT osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); +#endif } #endif @@ -107,6 +113,7 @@ void OCTOSPI1_IRQHandler() HAL_OSPI_IRQHandler(ospiHandle1); } +#if MBED_CONF_RTOS_PRESENT void HAL_OSPI_TxCpltCallback(OSPI_HandleTypeDef * handle) { osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); @@ -116,17 +123,22 @@ void HAL_OSPI_RxCpltCallback(OSPI_HandleTypeDef * handle) { osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); } +#endif void HAL_OSPI_ErrorCallback(OSPI_HandleTypeDef * handle) { handle->State = HAL_OSPI_STATE_ERROR; +#if MBED_CONF_RTOS_PRESENT osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); +#endif } void HAL_OSPI_TimeOutCallback(OSPI_HandleTypeDef * handle) { handle->State = HAL_OSPI_STATE_ERROR; +#if MBED_CONF_RTOS_PRESENT osSemaphoreRelease(get_qspi_pointer(handle)->semaphoreId); +#endif } #endif @@ -515,10 +527,12 @@ static void qspi_init_dma(struct qspi_s * obj) __HAL_LINKDMA(&obj->handle, hdma, *dmaHandle.hdma); #endif obj->dmaInitialized = true; +#if MBED_CONF_RTOS_PRESENT osSemaphoreAttr_t attr = { 0 }; attr.cb_mem = &obj->semaphoreMem; attr.cb_size = sizeof(osRtxSemaphore_t); obj->semaphoreId = osSemaphoreNew(1, 0, &attr); +#endif } } @@ -711,10 +725,12 @@ static void qspi_init_dma(struct qspi_s * obj) __HAL_LINKDMA(&obj->handle, hdma, *dmaHandle.hdma); #endif obj->dmaInitialized = true; +#if MBED_CONF_RTOS_PRESENT osSemaphoreAttr_t attr = { 0 }; attr.cb_mem = &obj->semaphoreMem; attr.cb_size = sizeof(osRtxSemaphore_t); obj->semaphoreId = osSemaphoreNew(1, 0, &attr); +#endif } } @@ -889,8 +905,10 @@ qspi_status_t qspi_free(qspi_t *obj) DMALinkInfo const *dmaLink = &QSPIDMALinks[0]; stm_free_dma_link(dmaLink); +#if MBED_CONF_RTOS_PRESENT // Free semaphore osSemaphoreRelease(obj->semaphoreId); +#endif } if (HAL_QSPI_DeInit(&obj->handle) != HAL_OK) { @@ -1029,7 +1047,11 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void } else { // wait until transfer complete or timeout +#if MBED_CONF_RTOS_PRESENT osSemaphoreAcquire(obj->semaphoreId, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); +#else + while(obj->handle.State == HAL_OSPI_STATE_BUSY_TX); +#endif if(obj->handle.State != HAL_OSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_OSPI_STATE_READY; @@ -1078,7 +1100,11 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void } else { // wait until transfer complete or timeout +#if MBED_CONF_RTOS_PRESENT osSemaphoreAcquire(obj->semaphoreId, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); +#else + while(obj->handle.State == HAL_QSPI_STATE_BUSY_INDIRECT_TX); +#endif if(obj->handle.State != HAL_QSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_QSPI_STATE_READY; @@ -1166,7 +1192,11 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, } else { // wait until transfer complete or timeout +#if MBED_CONF_RTOS_PRESENT osSemaphoreAcquire(obj->semaphoreId, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); +#else + while(obj->handle.State == HAL_OSPI_STATE_BUSY_RX); +#endif if(obj->handle.State != HAL_OSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_OSPI_STATE_READY; @@ -1208,7 +1238,11 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, } else { // wait until transfer complete or timeout +#if MBED_CONF_RTOS_PRESENT osSemaphoreAcquire(obj->semaphoreId, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); +#else + while(obj->handle.State == HAL_OSPI_STATE_BUSY_RX); +#endif if(obj->handle.State != HAL_OSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_OSPI_STATE_READY; @@ -1296,7 +1330,11 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, } else { // wait until transfer complete or timeout +#if MBED_CONF_RTOS_PRESENT osSemaphoreAcquire(obj->semaphoreId, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); +#else + while(obj->handle.State == HAL_QSPI_STATE_BUSY_INDIRECT_RX); +#endif if(obj->handle.State != HAL_QSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_QSPI_STATE_READY; @@ -1338,7 +1376,11 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, } else { // wait until transfer complete or timeout +#if MBED_CONF_RTOS_PRESENT osSemaphoreAcquire(obj->semaphoreId, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); +#else + while(obj->handle.State == HAL_QSPI_STATE_BUSY_INDIRECT_RX); +#endif if(obj->handle.State != HAL_QSPI_STATE_READY) { status = QSPI_STATUS_ERROR; obj->handle.State = HAL_QSPI_STATE_READY; From 853be94b0eb9c97660b65564de867bcc5ce0b0fb Mon Sep 17 00:00:00 2001 From: wdx04 <25487439@qq.com> Date: Fri, 23 May 2025 14:59:33 +0800 Subject: [PATCH 6/7] use macro __SCB_DCACHE_LINE_SIZE to allocate cache-aligned buffer for FATFileSystem added a split_buffer_by_cacheline function to split a buffer into cache-aligned parts and cache-unaligned parts added a QSPI_DMA_THRESHOLD_BYTES macro to define the minimum number of bytes to be transferred using DMA --- .../filesystem/fat/source/FATFileSystem.cpp | 2 +- targets/TARGET_STM/qspi_api.c | 90 +++++++++---------- 2 files changed, 41 insertions(+), 51 deletions(-) diff --git a/storage/filesystem/fat/source/FATFileSystem.cpp b/storage/filesystem/fat/source/FATFileSystem.cpp index cb4390d82b5..8044bc48112 100644 --- a/storage/filesystem/fat/source/FATFileSystem.cpp +++ b/storage/filesystem/fat/source/FATFileSystem.cpp @@ -156,7 +156,7 @@ extern "C" DWORD get_fattime(void) extern "C" void *ff_memalloc(UINT size) { #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) - return aligned_alloc(32U, size); + return aligned_alloc(__SCB_DCACHE_LINE_SIZE, size); #else return malloc(size); #endif diff --git a/targets/TARGET_STM/qspi_api.c b/targets/TARGET_STM/qspi_api.c index 7dbec30966c..331212282cf 100644 --- a/targets/TARGET_STM/qspi_api.c +++ b/targets/TARGET_STM/qspi_api.c @@ -42,6 +42,11 @@ /* hence 2^(31+1), then FLASH_SIZE_DEFAULT = 1<<31 */ #define QSPI_FLASH_SIZE_DEFAULT 0x80000000 +/* Minimum number of bytes to be transferred using DMA, when DCACHE is not available */ +/* When less than 32 bytes of data is transferred at a time, using DMA may actually be slower than polling */ +/* When DACHE is available, DMA will be used when the buffer contains at least one cache-aligned block */ +#define QSPI_DMA_THRESHOLD_BYTES 32 + #if defined(QUADSPI) static QSPI_HandleTypeDef * qspiHandle; // Handle of whatever QSPI structure is used for QUADSPI @@ -1031,7 +1036,7 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void tr_error("HAL_OSPI_Command error"); status = QSPI_STATUS_ERROR; } else { - if(st_command.NbData >= 32) { + if(st_command.NbData >= QSPI_DMA_THRESHOLD_BYTES) { qspi_init_dma(obj); NVIC_ClearPendingIRQ(obj->qspiIRQ); NVIC_SetPriority(obj->qspiIRQ, 1); @@ -1085,7 +1090,7 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { status = QSPI_STATUS_ERROR; } else { - if(st_command.NbData >= 32) { + if(st_command.NbData >= QSPI_DMA_THRESHOLD_BYTES) { qspi_init_dma(obj); NVIC_ClearPendingIRQ(QUADSPI_IRQn); NVIC_SetPriority(QUADSPI_IRQn, 1); @@ -1123,42 +1128,50 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void } #endif /* OCTOSPI */ - -#if defined(OCTOSPI1) -qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length) +static void split_buffer_by_cacheline(void *buffer, const size_t *length, size_t *pre_aligned_size, size_t *aligned_size, size_t *post_aligned_size) { - OSPI_RegularCmdTypeDef st_command; - qspi_status_t status = qspi_prepare_command(command, &st_command); - if (status != QSPI_STATUS_OK) { - return status; - } - -#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) - size_t pre_aligned_size = 0, aligned_size = 0, post_aligned_size = 0; + *pre_aligned_size = 0; + *aligned_size = 0; + *post_aligned_size = 0; if(*length < __SCB_DCACHE_LINE_SIZE) { - pre_aligned_size = *length; + *pre_aligned_size = *length; } else { - size_t address_remainder = (size_t) data % __SCB_DCACHE_LINE_SIZE; + size_t address_remainder = (size_t) buffer % __SCB_DCACHE_LINE_SIZE; if(address_remainder == 0) { - aligned_size = *length & ~(__SCB_DCACHE_LINE_SIZE - 1); - post_aligned_size = *length - aligned_size; + *aligned_size = *length & ~(__SCB_DCACHE_LINE_SIZE - 1); + *post_aligned_size = *length - *aligned_size; } else { - pre_aligned_size = __SCB_DCACHE_LINE_SIZE - address_remainder; - aligned_size = (*length - pre_aligned_size) & ~(__SCB_DCACHE_LINE_SIZE - 1); - post_aligned_size = *length - pre_aligned_size - aligned_size; + *pre_aligned_size = __SCB_DCACHE_LINE_SIZE - address_remainder; + *aligned_size = (*length - *pre_aligned_size) & ~(__SCB_DCACHE_LINE_SIZE - 1); + *post_aligned_size = *length - *pre_aligned_size - *aligned_size; } - if(aligned_size == 0) + if(*aligned_size == 0) { - pre_aligned_size = *length; - post_aligned_size = 0; + *pre_aligned_size = *length; + *post_aligned_size = 0; } } +} + + +#if defined(OCTOSPI1) +qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length) +{ + OSPI_RegularCmdTypeDef st_command; + qspi_status_t status = qspi_prepare_command(command, &st_command); + if (status != QSPI_STATUS_OK) { + return status; + } + +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + size_t pre_aligned_size, aligned_size, post_aligned_size; + split_buffer_by_cacheline(data, length, &pre_aligned_size, &aligned_size, &post_aligned_size); if(pre_aligned_size > 0) { st_command.NbData = pre_aligned_size; @@ -1227,7 +1240,7 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, tr_error("HAL_OSPI_Command error"); status = QSPI_STATUS_ERROR; } else { - if(st_command.NbData >= 32) { + if(st_command.NbData >= QSPI_DMA_THRESHOLD_BYTES) { qspi_init_dma(obj); NVIC_ClearPendingIRQ(obj->qspiIRQ); NVIC_SetPriority(obj->qspiIRQ, 1); @@ -1272,31 +1285,8 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, } #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) - size_t pre_aligned_size = 0, aligned_size = 0, post_aligned_size = 0; - if(*length < __SCB_DCACHE_LINE_SIZE) - { - pre_aligned_size = *length; - } - else - { - size_t address_remainder = (size_t) data % __SCB_DCACHE_LINE_SIZE; - if(address_remainder == 0) - { - aligned_size = *length & ~(__SCB_DCACHE_LINE_SIZE - 1); - post_aligned_size = *length - aligned_size; - } - else - { - pre_aligned_size = __SCB_DCACHE_LINE_SIZE - address_remainder; - aligned_size = (*length - pre_aligned_size) & ~(__SCB_DCACHE_LINE_SIZE - 1); - post_aligned_size = *length - pre_aligned_size - aligned_size; - } - if(aligned_size == 0) - { - pre_aligned_size = *length; - post_aligned_size = 0; - } - } + size_t pre_aligned_size, aligned_size, post_aligned_size; + split_buffer_by_cacheline(data, length, &pre_aligned_size, &aligned_size, &post_aligned_size); if(pre_aligned_size > 0) { st_command.NbData = pre_aligned_size; @@ -1365,7 +1355,7 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, tr_error("HAL_QSPI_Command error"); status = QSPI_STATUS_ERROR; } else { - if(st_command.NbData >= 32) { + if(st_command.NbData >= QSPI_DMA_THRESHOLD_BYTES) { qspi_init_dma(obj); NVIC_ClearPendingIRQ(QUADSPI_IRQn); NVIC_SetPriority(QUADSPI_IRQn, 1); From 92955b724d005047144636887ec67d1315d1bcad Mon Sep 17 00:00:00 2001 From: wdx04 <25487439@qq.com> Date: Fri, 23 May 2025 15:04:04 +0800 Subject: [PATCH 7/7] define split_buffer_by_cacheline only when DCACHE is available --- targets/TARGET_STM/qspi_api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/targets/TARGET_STM/qspi_api.c b/targets/TARGET_STM/qspi_api.c index 331212282cf..c6a4d322719 100644 --- a/targets/TARGET_STM/qspi_api.c +++ b/targets/TARGET_STM/qspi_api.c @@ -1128,6 +1128,7 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void } #endif /* OCTOSPI */ +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) static void split_buffer_by_cacheline(void *buffer, const size_t *length, size_t *pre_aligned_size, size_t *aligned_size, size_t *post_aligned_size) { *pre_aligned_size = 0; @@ -1158,6 +1159,7 @@ static void split_buffer_by_cacheline(void *buffer, const size_t *length, size_t } } } +#endif #if defined(OCTOSPI1)