DMA SPI support for STM32 devices (#162)

* Start on STM32 DMA SPI

* Update all objects.hs, add interrupt function

* Initial DMA code should be ready to test out...

* Fix SPI interrupt-mode IRQ handlers, add SPI::transfer_and_wait

* Fix CMake error when building for STM32WL processors

* Now builds on all STM devices!

* Properly support STM32U5 / DMA IP v3

* Start on STM32F4 support, fix hardfault on IP v1 and v3 due to incorrect indexing

* Fix Rx-only transfers, add abort code, fix incorrect channel assignments for DMA IP v1 devices

* Start on STM32H7 SPI DMA

* Fixes for H7: Correctly manage data cache, keep SPI ISR enabled

* Implement DMA SPI header constants for all remaining STM32 families.  Also add support for freeing DMA channels

* Try and fix build on STM32G0

* Fix build on STM32G0

* Add SPI_32BIT_WORDS label, start on fixing SPI docs

* SPI: Implement reference counting so that DMA channels get freed properly

* Fix issue where SPI data could get corrupted (by TI mode turning on) depending on memory layout (if your spis pointer & 0x10 was nonzero)

* Mark DMA channels as unallocated when SPI bus is freed

* Simplify spi_abort_asynch()

* Fix some rebase issues, fix failing to allocate DMA channel on STM32U5

* Fix DMA getting stuck on STM32F4, F7, and F2
pull/15494/head
Jamie Smith 2023-11-02 20:16:45 -07:00 committed by GitHub
parent 7e9d658ae9
commit 28815b13d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 2642 additions and 265 deletions

View File

@ -245,7 +245,7 @@ void I2C::abort_transfer(void)
I2C::Result I2C::transfer_and_wait(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout, bool repeated) I2C::Result I2C::transfer_and_wait(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout, bool repeated)
{ {
// Use EventFlags to suspend the thread until the transfer finishes // Use EventFlags to suspend the thread until the transfer finishes
rtos::EventFlags transferResultFlags("I2C::Result EvFlags"); rtos::EventFlags transferResultFlags("I2C::transfer_and_wait EvFlags");
// Simple callback from the transfer that sets the EventFlags using the I2C result event // Simple callback from the transfer that sets the EventFlags using the I2C result event
event_callback_t transferCallback([&](int event) { event_callback_t transferCallback([&](int event) {

View File

@ -261,6 +261,9 @@ int spi_master_write(spi_t *obj, int value);
* tx_length and rx_length. The bytes written will be padded with the * tx_length and rx_length. The bytes written will be padded with the
* value 0xff. * value 0xff.
* *
* Note: Even if the word size / bits per frame is not 8, \c rx_length and \c tx_length
* still give lengths in bytes of input data, not numbers of words.
*
* @param[in] obj The SPI peripheral to use for sending * @param[in] obj The SPI peripheral to use for sending
* @param[in] tx_buffer Pointer to the byte-array of data to write to the device * @param[in] tx_buffer Pointer to the byte-array of data to write to the device
* @param[in] tx_length Number of bytes to write, may be zero * @param[in] tx_length Number of bytes to write, may be zero

View File

@ -52,6 +52,7 @@ target_sources(mbed-stm
trng_api.c trng_api.c
us_ticker.c us_ticker.c
watchdog_api.c watchdog_api.c
stm_dma_utils.c
) )
target_link_libraries(mbed-stm INTERFACE mbed-cmsis-cortex-m) target_link_libraries(mbed-stm INTERFACE mbed-cmsis-cortex-m)

View File

@ -44,20 +44,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -21,4 +21,7 @@
// Defines the word length capability of the device where Nth bit allows for N window size // Defines the word length capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,38 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// See STM32F0 reference manual Table 26.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 3}, // SPI1 Tx is DMA1 Channel 3
{1, 5}, // SPI2 Tx is DMA1 Channel 5
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2}, // SPI1 Rx is DMA1 Channel 2
{1, 4}, // SPI2 Rx is DMA1 Channel 4
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -89,20 +89,6 @@ struct serial_s {
#endif #endif
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct i2c_s { struct i2c_s {
/* The 1st 2 members I2CName i2c /* The 1st 2 members I2CName i2c
* and I2C_HandleTypeDef handle should * and I2C_HandleTypeDef handle should

View File

@ -35,4 +35,7 @@
// Defines the word length capability of the device where Nth bit allows for N window size // Defines the word length capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,40 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// See STM32F1 reference manual Tables 78 and 79.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 3}, // SPI1 Tx is DMA1 Channel 3
{1, 5}, // SPI2 Tx is DMA1 Channel 5
{2, 2}, // SPI3 Tx is DMA2 Channel 2
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2}, // SPI1 Rx is DMA1 Channel 2
{1, 4}, // SPI2 Rx is DMA1 Channel 4
{2, 1}, // SPI3 Rx is DMA2 Channel 1
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -202,7 +202,18 @@ HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_
/* Enable Common interrupts*/ /* Enable Common interrupts*/
hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME; hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;
hdma->Instance->FCR |= DMA_IT_FE;
/* Mbed CE mod: Only enable the FIFO Error interrupt if the FIFO is actually enabled.
* If it's not enabled, then this interrupt can trigger spuriously from memory bus
* stalls that the DMA engine encounters, and this creates random DMA failures.
* Reference forum thread here:
* https://community.st.com/t5/stm32-mcus-products/spi-dma-fifo-error-issue-feifx/td-p/537074
* also: https://community.st.com/t5/stm32-mcus-touch-gfx-and-gui/spi-dma-error-is-occurred-when-the-other-dma-memory-to-memory-is/td-p/191590
*/
if(hdma->Instance->FCR & DMA_SxFCR_DMDIS)
{
hdma->Instance->FCR |= DMA_IT_FE;
}
if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL)) if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL))
{ {

View File

@ -95,20 +95,6 @@ struct serial_s {
#endif #endif
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct i2c_s { struct i2c_s {
/* The 1st 2 members I2CName i2c /* The 1st 2 members I2CName i2c
* and I2C_HandleTypeDef handle should * and I2C_HandleTypeDef handle should

View File

@ -35,4 +35,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,40 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// See STM32F2 reference manual Tables 22 and 23
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{2, 3, 3}, // SPI1 Tx is DMA2 Stream 3 Channel 3
{1, 4, 0}, // SPI2 Tx is DMA1 Stream 4 Channel 0
{1, 5, 0} // SPI3 Tx is DMA1 Stream 5 Channel 0
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{2, 0, 3}, // SPI1 Rx is DMA2 Stream 0 Channel 3
{1, 3, 0}, // SPI2 Rx is DMA1 Stream 3 Channel 0
{1, 0, 0} // SPI3 Rx is DMA2 Stream 0 Channel 0
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -57,20 +57,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -35,4 +35,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,42 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// See STM32F3 reference manual Tables 78 and 79.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 3}, // SPI1 Tx is DMA1 Channel 3
{1, 5}, // SPI2 Tx is DMA1 Channel 5
{2, 2}, // SPI3 Tx is DMA2 Channel 2
{2, 5}, // SPI4 Tx is DMA2 Channel 5
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2}, // SPI1 Rx is DMA1 Channel 2
{1, 4}, // SPI2 Rx is DMA1 Channel 4
{2, 1}, // SPI3 Rx is DMA2 Channel 1
{2, 4}, // SPI4 Rx is DMA2 Channel 4
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -202,7 +202,18 @@ HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_
/* Enable Common interrupts*/ /* Enable Common interrupts*/
hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME; hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;
hdma->Instance->FCR |= DMA_IT_FE;
/* Mbed CE mod: Only enable the FIFO Error interrupt if the FIFO is actually enabled.
* If it's not enabled, then this interrupt can trigger spuriously from memory bus
* stalls that the DMA engine encounters, and this creates random DMA failures.
* Reference forum thread here:
* https://community.st.com/t5/stm32-mcus-products/spi-dma-fifo-error-issue-feifx/td-p/537074
* also: https://community.st.com/t5/stm32-mcus-touch-gfx-and-gui/spi-dma-error-is-occurred-when-the-other-dma-memory-to-memory-is/td-p/191590
*/
if(hdma->Instance->FCR & DMA_SxFCR_DMDIS)
{
hdma->Instance->FCR |= DMA_IT_FE;
}
if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL)) if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL))
{ {

View File

@ -76,20 +76,6 @@ struct serial_s {
#endif #endif
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct i2c_s { struct i2c_s {
/* The 1st 2 members I2CName i2c /* The 1st 2 members I2CName i2c
* and I2C_HandleTypeDef handle should * and I2C_HandleTypeDef handle should

View File

@ -21,4 +21,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,51 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// See STM32F4 reference manual Tables 42 and 43.
// Note: For each SPI and each direction, there are two possible assignments to a DMA channel.
// We need to assign them here so that no combination would ever conflict and use the same DMA channel.
// Exception: SPI5 and SPI6 use the same DMA channels in hardware and there's no way to deconflict them.
// So, SPI5 and SPI6 cannot be used with DMA at the same time.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{2, 3, 3}, // SPI1 Tx is DMA2 Stream 3 Channel 3
{1, 4, 0}, // SPI2 Tx is DMA1 Stream 4 Channel 0
{1, 5, 0}, // SPI3 Tx is DMA1 Stream 5 Channel 0
{2, 1, 4}, // SPI4 Tx is DMA2 Stream 1 Channel 4
{2, 6, 7}, // SPI5 Tx is DMA2 Stream 6 Channel 7
{2, 5, 1}, // SPI6 Tx is DMA2 Stream 5 Channel 1
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{2, 2, 3}, // SPI1 Rx is DMA2 Stream 2 Channel 3
{1, 3, 0}, // SPI2 Rx is DMA1 Stream 3 Channel 0
{1, 0, 0}, // SPI3 Rx is DMA1 Stream 0 Channel 0
{2, 0, 4}, // SPI4 Rx is DMA2 Stream 0 Channel 4
{2, 5, 7}, // SPI5 Rx is DMA2 Stream 5 Channel 7
{2, 6, 1}, // SPI6 Rx is DMA2 Stream 6 Channel 1
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -479,8 +479,19 @@ HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress,
/* Enable Common interrupts*/ /* Enable Common interrupts*/
hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME; hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;
hdma->Instance->FCR |= DMA_IT_FE;
/* Mbed CE mod: Only enable the FIFO Error interrupt if the FIFO is actually enabled.
* If it's not enabled, then this interrupt can trigger spuriously from memory bus
* stalls that the DMA engine encounters, and this creates random DMA failures.
* Reference forum thread here:
* https://community.st.com/t5/stm32-mcus-products/spi-dma-fifo-error-issue-feifx/td-p/537074
* also: https://community.st.com/t5/stm32-mcus-touch-gfx-and-gui/spi-dma-error-is-occurred-when-the-other-dma-memory-to-memory-is/td-p/191590
*/
if(hdma->Instance->FCR & DMA_SxFCR_DMDIS)
{
hdma->Instance->FCR |= DMA_IT_FE;
}
if(hdma->XferHalfCpltCallback != NULL) if(hdma->XferHalfCpltCallback != NULL)
{ {
hdma->Instance->CR |= DMA_IT_HT; hdma->Instance->CR |= DMA_IT_HT;

View File

@ -197,7 +197,18 @@ HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_
/* Enable Common interrupts*/ /* Enable Common interrupts*/
hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME; hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;
hdma->Instance->FCR |= DMA_IT_FE;
/* Mbed CE mod: Only enable the FIFO Error interrupt if the FIFO is actually enabled.
* If it's not enabled, then this interrupt can trigger spuriously from memory bus
* stalls that the DMA engine encounters, and this creates random DMA failures.
* Reference forum thread here:
* https://community.st.com/t5/stm32-mcus-products/spi-dma-fifo-error-issue-feifx/td-p/537074
* also: https://community.st.com/t5/stm32-mcus-touch-gfx-and-gui/spi-dma-error-is-occurred-when-the-other-dma-memory-to-memory-is/td-p/191590
*/
if(hdma->Instance->FCR & DMA_SxFCR_DMDIS)
{
hdma->Instance->FCR |= DMA_IT_FE;
}
if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL)) if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL))
{ {

View File

@ -75,20 +75,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -35,4 +35,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,51 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// See STM32F7 reference manual Tables 27 and 28.
// Note: For each SPI and each direction, there are two possible assignments to a DMA channel.
// We need to assign them here so that no combination would ever conflict and use the same DMA channel.
// Exception: SPI5 and SPI6 use the same DMA channels in hardware and there's no way to deconflict them.
// So, SPI5 and SPI6 cannot be used with DMA at the same time.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{2, 3, 3}, // SPI1 Tx is DMA2 Stream 3 Channel 3
{1, 4, 0}, // SPI2 Tx is DMA1 Stream 4 Channel 0
{1, 5, 0}, // SPI3 Tx is DMA1 Stream 5 Channel 0
{2, 1, 4}, // SPI4 Tx is DMA2 Stream 1 Channel 4
{2, 6, 7}, // SPI5 Tx is DMA2 Stream 6 Channel 7
{2, 5, 1}, // SPI6 Tx is DMA2 Stream 5 Channel 1
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{2, 2, 3}, // SPI1 Rx is DMA2 Stream 2 Channel 3
{1, 3, 0}, // SPI2 Rx is DMA1 Stream 3 Channel 0
{1, 0, 0}, // SPI3 Rx is DMA1 Stream 0 Channel 0
{2, 0, 4}, // SPI4 Rx is DMA2 Stream 0 Channel 4
{2, 5, 7}, // SPI5 Rx is DMA2 Stream 5 Channel 7
{2, 6, 1}, // SPI6 Rx is DMA2 Stream 6 Channel 1
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -56,20 +56,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -0,0 +1,52 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// STM32G0 devices, with DMAMUX feature.
// On this device, the DMA channels may be chosen arbitrarily.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 1, DMA_REQUEST_SPI1_TX},
{1, 3, DMA_REQUEST_SPI2_TX},
#ifdef DMA2
// For better performance, on devices with DMA2 (STM32G0Bxx/Cxx), put SPI3 on DMA2
{2, 1, DMA_REQUEST_SPI3_TX}
#else
{1, 5, DMA_REQUEST_SPI3_TX}
#endif
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2, DMA_REQUEST_SPI1_RX},
{1, 4, DMA_REQUEST_SPI2_RX},
#ifdef DMA2
// For better performance, on devices with DMA2 (STM32G0Bxx/Cxx), put SPI3 on DMA2
{2, 2, DMA_REQUEST_SPI3_RX}
#else
{1, 6, DMA_REQUEST_SPI3_RX}
#endif
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -55,20 +55,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -21,4 +21,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,48 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// STM32G4 devices, with DMAMUX feature.
// On this device, the DMA channels may be chosen arbitrarily.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 1, DMA_REQUEST_SPI1_TX},
{1, 3, DMA_REQUEST_SPI2_TX},
{1, 5, DMA_REQUEST_SPI3_TX},
#ifdef SPI4
{2, 1, DMA_REQUEST_SPI4_TX}
#endif
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2, DMA_REQUEST_SPI1_RX},
{1, 4, DMA_REQUEST_SPI2_RX},
{1, 6, DMA_REQUEST_SPI3_RX},
#ifdef SPI4
{2, 2, DMA_REQUEST_SPI4_RX}
#endif
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -64,20 +64,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -24,4 +24,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0xFFFFFFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0xFFFFFFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,46 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// STM32H7 devices, with DMAMUX feature.
// On this device, the DMA channels may be chosen arbitrarily.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 1, DMA_REQUEST_SPI1_TX},
{1, 3, DMA_REQUEST_SPI2_TX},
{1, 5, DMA_REQUEST_SPI3_TX},
{1, 7, DMA_REQUEST_SPI4_TX},
{2, 1, DMA_REQUEST_SPI5_TX},
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 0, DMA_REQUEST_SPI1_RX},
{1, 2, DMA_REQUEST_SPI2_RX},
{1, 4, DMA_REQUEST_SPI3_RX},
{1, 6, DMA_REQUEST_SPI4_RX},
{2, 0, DMA_REQUEST_SPI5_RX},
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -58,20 +58,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -20,4 +20,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,38 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// See STM32L0 reference manual Table 51
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 3, 1}, // SPI1 Tx is DMA1 Channel 3 Request 1
{1, 5, 2}, // SPI2 Tx is DMA1 Channel 5 Request 2
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2, 1}, // SPI1 Rx is DMA1 Channel 2 Request 1
{1, 4, 2}, // SPI2 Tx is DMA1 Channel 4 Request 2
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -76,20 +76,6 @@ struct serial_s {
#endif #endif
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct i2c_s { struct i2c_s {
/* The 1st 2 members I2CName i2c /* The 1st 2 members I2CName i2c
* and I2C_HandleTypeDef handle should * and I2C_HandleTypeDef handle should

View File

@ -21,4 +21,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x00008080)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,40 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// See STM32L1 reference manual Tables 55 and 56
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 3}, // SPI1 Tx is DMA1 Channel 3
{1, 5}, // SPI2 Tx is DMA1 Channel 5
{2, 2}, // SPI3 Tx is DMA2 Channel 2
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2}, // SPI1 Rx is DMA1 Channel 2
{1, 4}, // SPI2 Rx is DMA1 Channel 4
{2, 1}, // SPI3 Rx is DMA2 Channel 1
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -54,20 +54,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -23,4 +23,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,65 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
#ifdef DMAMUX1
// STM32L4+ devices, with DMAMUX feature.
// On this device, the DMA channels may be chosen arbitrarily.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 1, DMA_REQUEST_SPI1_TX},
{1, 3, DMA_REQUEST_SPI2_TX},
{1, 5, DMA_REQUEST_SPI3_TX}
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2, DMA_REQUEST_SPI1_RX},
{1, 4, DMA_REQUEST_SPI2_RX},
{1, 6, DMA_REQUEST_SPI3_RX}
};
#else
// Base model STM32L4 devices, with fixed DMA line mapping
// See STM32L4 reference manual Tables 41 and 42.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 3, 1}, // SPI1 Tx is DMA1 Ch3 Request 1
{1, 5, 1}, // SPI2 Tx is DMA1 Ch5 Request 1
{2, 2, 3} // SPI3 Tx is DMA2 Ch2 Request 3
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2, 1}, // SPI1 Rx is DMA1 Ch2 Request 1
{1, 4, 1}, // SPI2 Rx is DMA1 Ch4 Request 1
{2, 1, 3} // SPI3 Rx is DMA2 Ch1 Request 3
};
#endif
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -64,20 +64,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -21,4 +21,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,42 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// STM32L5 devices, with DMAMUX feature.
// On this device, the DMA channels may be chosen arbitrarily.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 1, DMA_REQUEST_SPI1_TX},
{1, 3, DMA_REQUEST_SPI2_TX},
{1, 5, DMA_REQUEST_SPI3_TX},
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2, DMA_REQUEST_SPI1_RX},
{1, 4, DMA_REQUEST_SPI2_RX},
{1, 6, DMA_REQUEST_SPI3_RX},
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -64,20 +64,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -23,4 +23,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,42 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// STM32U5+ devices.
// On this device, the DMA channels may be chosen arbitrarily.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 0, GPDMA1_REQUEST_SPI1_TX},
{1, 2, GPDMA1_REQUEST_SPI2_TX},
{1, 4, GPDMA1_REQUEST_SPI3_TX}
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 1, GPDMA1_REQUEST_SPI1_RX},
{1, 3, GPDMA1_REQUEST_SPI2_RX},
{1, 5, GPDMA1_REQUEST_SPI3_TX}
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -47,20 +47,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -23,4 +23,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,44 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// STM32WB devices, with DMAMUX feature.
// On this device, the DMA channels may be chosen arbitrarily.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 1, DMA_REQUEST_SPI1_TX},
#ifdef SPI2
{1, 3, DMA_REQUEST_SPI2_TX}
#endif
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2, DMA_REQUEST_SPI1_RX},
#ifdef SPI4
{1, 4, DMA_REQUEST_SPI2_RX}
#endif
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -50,20 +50,6 @@ struct pwmout_s {
uint8_t inverted; uint8_t inverted;
}; };
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
#endif
};
struct serial_s { struct serial_s {
UARTName uart; UARTName uart;
int index; // Used by irq int index; // Used by irq

View File

@ -21,4 +21,7 @@
// Defines the word legnth capability of the device where Nth bit allows for N window size // Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8) #define STM32_SPI_CAPABILITY_WORD_LENGTH (0x0000FFF8)
// We have DMA support
#define STM32_SPI_CAPABILITY_DMA 1
#endif #endif

View File

@ -0,0 +1,40 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_INFO_H
#define MBED_OS_STM_DMA_INFO_H
#include "cmsis.h"
#include "stm_dma_utils.h"
// STM32WB devices, with DMAMUX feature.
// On this device, the DMA channels may be chosen arbitrarily.
/// Mapping from SPI index to DMA link info for Tx
static const DMALinkInfo SPITxDMALinks[] = {
{1, 1, DMA_REQUEST_SPI1_TX},
{1, 3, DMA_REQUEST_SPI2_TX}
};
/// Mapping from SPI index to DMA link info for Rx
static const DMALinkInfo SPIRxDMALinks[] = {
{1, 2, DMA_REQUEST_SPI1_RX},
{1, 4, DMA_REQUEST_SPI2_RX}
};
#endif //MBED_OS_STM_DMA_INFO_H

View File

@ -37,6 +37,7 @@
#include "objects.h" #include "objects.h"
#include "stm_i2c_api.h" #include "stm_i2c_api.h"
#include "stm_spi_api.h"
#if DEVICE_USTICKER #if DEVICE_USTICKER
#include "us_ticker_defines.h" #include "us_ticker_defines.h"

View File

@ -0,0 +1,53 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This header contains constants and defines specific to processors with the v1 DMA IP.
* The v1 IP has DMA controllers with multiple streams, where each "stream" has a "channel selection"
* to determine what triggers DMA requests.
*/
#ifndef MBED_OS_STM_DMA_IP_V1_H
#define MBED_OS_STM_DMA_IP_V1_H
// Devices with DMA IP v1 have at most 8 channels per controller.
#define MAX_DMA_CHANNELS_PER_CONTROLLER 8
// Count DMA controllers
#ifdef DMA1
#ifdef DMA2
#define NUM_DMA_CONTROLLERS 2
#else
#define NUM_DMA_CONTROLLERS 1
#endif
#else
#define NUM_DMA_CONTROLLERS 0
#endif
// Provide an alias so that code can always use the v2 name for this structure
#define DMA_Channel_TypeDef DMA_Stream_TypeDef
// On some smaller devices, e.g. STM32L1 family, DMA channels are simply logically ORed rather than
// muxed, so we don't need the "sourceNumber" field.
// We can check if this is the case by the absence of specific peripherals/registers.
#if defined(DMAMUX1_BASE) || defined(DMA_SxCR_CHSEL_Msk)
#define STM_DEVICE_HAS_DMA_SOURCE_SELECTION 1
#else
#define STM_DEVICE_HAS_DMA_SOURCE_SELECTION 0
#endif
#endif //MBED_OS_STM_DMA_IP_V1_H

View File

@ -0,0 +1,61 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This header contains constants and defines specific to processors with the v2 DMA IP.
*
* The v2 DMA IP has DMA controllers with multiple channels, where each channel has a request source
* that determines what triggers DMA transactions
*/
#ifndef MBED_OS_STM_DMA_IP_V2_H
#define MBED_OS_STM_DMA_IP_V2_H
#ifdef TARGET_MCU_STM32F0
// STM32F0 is weird and does its own thing.
// Only 5 channels usable, the other 2 lack interrupts
#define MAX_DMA_CHANNELS_PER_CONTROLLER 5
#else
// Devices with DMA IP v2 have at most 7 channels per controller.
#define MAX_DMA_CHANNELS_PER_CONTROLLER 7
#endif
// Count DMA controllers
#ifdef DMA1
#ifdef DMA2
#define NUM_DMA_CONTROLLERS 2
#else
#define NUM_DMA_CONTROLLERS 1
#endif
#else
#define NUM_DMA_CONTROLLERS 0
#endif
// On some smaller devices, e.g. STM32L1 family, DMA channels are simply logically ORed rather than
// muxed, so we don't need the "sourceNumber" field.
// We can check if this is the case by the absence of specific peripherals/registers.
#if defined(DMA1_CSELR) || defined(DMAMUX1_BASE)
#define STM_DEVICE_HAS_DMA_SOURCE_SELECTION 1
#else
#define STM_DEVICE_HAS_DMA_SOURCE_SELECTION 0
#endif
#endif //MBED_OS_STM_DMA_IP_V2_H

View File

@ -0,0 +1,37 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This header contains constants and defines specific to processors with the v3 DMA IP.
*
* The v3 DMA IP has one DMA controller with multiple channels, where each channel has a request source
* that determines what triggers DMA transactions. Any DMA channel can connect to any request source,
* unlike many other STM32 chips.
*/
#ifndef MBED_OS_STM_DMA_IP_V3_H
#define MBED_OS_STM_DMA_IP_V3_H
// Devices with DMA IP v3 have at most 16 channels per controller.
#define MAX_DMA_CHANNELS_PER_CONTROLLER 16
#define NUM_DMA_CONTROLLERS 1
// Currently all known IPv3 devices have source selection
#define STM_DEVICE_HAS_DMA_SOURCE_SELECTION 1
#endif //MBED_OS_STM_DMA_IP_V3_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_DMA_UTILS_H
#define MBED_OS_STM_DMA_UTILS_H
#include <inttypes.h>
#include <stdbool.h>
#include "cmsis.h"
// determine DMA IP version using the available constants in the chip header
#if defined(GPDMA1)
#define DMA_IP_VERSION_V3 1
#elif defined(DMA1_Channel1)
#define DMA_IP_VERSION_V2 1
#else
#define DMA_IP_VERSION_V1 1
#endif
// Include correct header for the IP version
#ifdef DMA_IP_VERSION_V3
#include "stm_dma_ip_v3.h"
#elif defined(DMA_IP_VERSION_V2)
#include "stm_dma_ip_v2.h"
#else
#include "stm_dma_ip_v1.h"
#endif
/*
* Structure containing info about a peripheral's link to the DMA controller.
*/
typedef struct DMALinkInfo {
/// Index of the DMA module that the DMA link uses.
/// Note: 1-indexed.
uint8_t dmaIdx;
/// Index of the channel on the DMA module.
/// Note that some STMicro chips have a DMA mux allowing any DMA peripheral to be used with
/// any channel, and others have a semi-fixed architecture with just some basic multiplexing.
/// Note: May be 1 or 0 indexed depending on processor
uint8_t channelIdx;
#if STM_DEVICE_HAS_DMA_SOURCE_SELECTION
/// Request source number. This is either a DMA mux input number, or a mux selection number
/// on devices without a DMA mux.
/// Note: 0-indexed.
uint8_t sourceNumber;
#endif
} DMALinkInfo;
/**
* @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);
/**
* @brief Get the interrupt number for a DMA link
*
* @param dmaLink DMA link instance
*/
IRQn_Type stm_get_dma_irqn(const DMALinkInfo *dmaLink);
/**
* @brief Initialize a DMA link for use.
*
* This enables and sets up the interrupt, allocates a DMA handle, and returns the handle pointer.
* Arguments are based on the parameters used for the DMA_InitTypeDef structure.
*
* @param dmaLink DMA link instance
* @param direction \c DMA_PERIPH_TO_MEMORY, \c DMA_MEMORY_TO_PERIPH, or \c DMA_MEMORY_TO_MEMORY
* @param periphInc Whether the Peripheral address register should be incremented or not.
* @param memInc Whether the Memory address register should be incremented or not.
* @param periphDataAlignment Alignment value of the peripheral data. 1, 2, or 4.
* @param memDataAlignment \c DMA_MDATAALIGN_BYTE, \c DMA_MDATAALIGN_HALFWORD, or \c DMA_MDATAALIGN_WORD
*
* @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);
/**
* @brief Free a DMA link.
*
* This frees memory associated with it and unlocks the hardware DMA channel so that it can be used by somebody else.
*
* @param dmaLink DMA link ponter to free.
*/
void stm_free_dma_link(DMALinkInfo const * dmaLink);
#endif //MBED_OS_STM_DMA_UTILS_H

View File

@ -42,6 +42,11 @@
#include "pinmap.h" #include "pinmap.h"
#include "PeripheralPins.h" #include "PeripheralPins.h"
#include "spi_device.h" #include "spi_device.h"
#include "stm_spi_api.h"
#ifdef STM32_SPI_CAPABILITY_DMA
#include "stm_dma_info.h"
#endif
#if DEVICE_SPI_ASYNCH #if DEVICE_SPI_ASYNCH
#define SPI_INST(obj) ((SPI_TypeDef *)(obj->spi.spi)) #define SPI_INST(obj) ((SPI_TypeDef *)(obj->spi.spi))
@ -85,6 +90,55 @@ extern HAL_StatusTypeDef HAL_SPIEx_FlushRxFifo(SPI_HandleTypeDef *hspi);
#define HAS_32BIT_SPI_TRANSFERS 1 #define HAS_32BIT_SPI_TRANSFERS 1
#endif // SPI_DATASIZE_X #endif // SPI_DATASIZE_X
// SPI IRQ handlers
#if defined SPI1_BASE
static SPI_HandleTypeDef * spi1Handle; // Handle of whatever SPI structure is used for SPI1
void SPI1_IRQHandler()
{
HAL_SPI_IRQHandler(spi1Handle);
}
#endif
#if defined SPI2_BASE
static SPI_HandleTypeDef * spi2Handle; // Handle of whatever SPI structure is used for SPI2
void SPI2_IRQHandler()
{
HAL_SPI_IRQHandler(spi2Handle);
}
#endif
#if defined SPI3_BASE
static SPI_HandleTypeDef * spi3Handle; // Handle of whatever SPI structure is used for SPI3
void SPI3_IRQHandler()
{
HAL_SPI_IRQHandler(spi3Handle);
}
#endif
#if defined SPI4_BASE
static SPI_HandleTypeDef * spi4Handle; // Handle of whatever SPI structure is used for SPI4
void SPI4_IRQHandler()
{
HAL_SPI_IRQHandler(spi4Handle);
}
#endif
#if defined SPI5_BASE
static SPI_HandleTypeDef * spi5Handle; // Handle of whatever SPI structure is used for SPI5
void SPI5_IRQHandler()
{
HAL_SPI_IRQHandler(spi5Handle);
}
#endif
#if defined SPI6_BASE
static SPI_HandleTypeDef * spi6Handle; // Handle of whatever SPI structure is used for SPI6
void SPI6_IRQHandler()
{
HAL_SPI_IRQHandler(spi6Handle);
}
#endif
/** /**
* Flush RX FIFO/input register of SPI interface and clear overrun flag. * Flush RX FIFO/input register of SPI interface and clear overrun flag.
*/ */
@ -96,6 +150,20 @@ static inline void spi_flush_rx(spi_t *obj)
LL_SPI_ClearFlag_OVR(SPI_INST(obj)); LL_SPI_ClearFlag_OVR(SPI_INST(obj));
} }
// Store the spi_s * inside an SPI handle, for later retrieval in callbacks
static inline void store_spis_pointer(SPI_HandleTypeDef * spiHandle, struct spi_s * spis) {
// Annoyingly, STM neglected to provide any sort of "user data" pointer inside SPI_HandleTypeDef for use
// in callbacks. However, there are some variables in the Init struct that are never accessed after HAL_SPI_Init().
// So, we can reuse those to store our pointer.
spiHandle->Init.TIMode = (uint32_t)spis;
}
// Get spi_s * from SPI_HandleTypeDef
static inline struct spi_s * get_spis_pointer(SPI_HandleTypeDef * spiHandle) {
return (struct spi_s *) spiHandle->Init.TIMode;
}
void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap) void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap)
{ {
if (slave) { if (slave) {
@ -149,10 +217,16 @@ void init_spi(spi_t *obj)
__HAL_SPI_DISABLE(handle); __HAL_SPI_DISABLE(handle);
// Reset flag used by store_spis_pointer()
handle->Init.TIMode = SPI_TIMODE_DISABLE;
DEBUG_PRINTF("init_spi: instance=0x%8X\r\n", (int)handle->Instance); DEBUG_PRINTF("init_spi: instance=0x%8X\r\n", (int)handle->Instance);
if (HAL_SPI_Init(handle) != HAL_OK) { if (HAL_SPI_Init(handle) != HAL_OK) {
error("Cannot initialize SPI"); error("Cannot initialize SPI");
} }
store_spis_pointer(handle, spiobj);
/* In some cases after SPI object re-creation SPI overrun flag may not /* In some cases after SPI object re-creation SPI overrun flag may not
* be cleared, so clear RX data explicitly to prevent any transmissions errors */ * be cleared, so clear RX data explicitly to prevent any transmissions errors */
spi_flush_rx(obj); spi_flush_rx(obj);
@ -205,6 +279,10 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
#endif /* SPI_IP_VERSION_V2 */ #endif /* SPI_IP_VERSION_V2 */
#ifdef DEVICE_SPI_ASYNCH
spiobj->driverCallback = NULL;
#endif
#if defined SPI1_BASE #if defined SPI1_BASE
// Enable SPI clock // Enable SPI clock
if (spiobj->spi == SPI_1) { if (spiobj->spi == SPI_1) {
@ -224,6 +302,8 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
__HAL_RCC_SPI1_RELEASE_RESET(); __HAL_RCC_SPI1_RELEASE_RESET();
__HAL_RCC_SPI1_CLK_ENABLE(); __HAL_RCC_SPI1_CLK_ENABLE();
spiobj->spiIRQ = SPI1_IRQn; spiobj->spiIRQ = SPI1_IRQn;
spiobj->spiIndex = 1;
spi1Handle = &spiobj->handle;
} }
#endif #endif
@ -245,6 +325,8 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
__HAL_RCC_SPI2_RELEASE_RESET(); __HAL_RCC_SPI2_RELEASE_RESET();
__HAL_RCC_SPI2_CLK_ENABLE(); __HAL_RCC_SPI2_CLK_ENABLE();
spiobj->spiIRQ = SPI2_IRQn; spiobj->spiIRQ = SPI2_IRQn;
spiobj->spiIndex = 2;
spi2Handle = &spiobj->handle;
} }
#endif #endif
@ -266,6 +348,8 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
__HAL_RCC_SPI3_RELEASE_RESET(); __HAL_RCC_SPI3_RELEASE_RESET();
__HAL_RCC_SPI3_CLK_ENABLE(); __HAL_RCC_SPI3_CLK_ENABLE();
spiobj->spiIRQ = SPI3_IRQn; spiobj->spiIRQ = SPI3_IRQn;
spiobj->spiIndex = 3;
spi3Handle = &spiobj->handle;
} }
#endif #endif
@ -283,6 +367,8 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
__HAL_RCC_SPI4_RELEASE_RESET(); __HAL_RCC_SPI4_RELEASE_RESET();
__HAL_RCC_SPI4_CLK_ENABLE(); __HAL_RCC_SPI4_CLK_ENABLE();
spiobj->spiIRQ = SPI4_IRQn; spiobj->spiIRQ = SPI4_IRQn;
spiobj->spiIndex = 4;
spi4Handle = &spiobj->handle;
} }
#endif #endif
@ -300,6 +386,8 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
__HAL_RCC_SPI5_RELEASE_RESET(); __HAL_RCC_SPI5_RELEASE_RESET();
__HAL_RCC_SPI5_CLK_ENABLE(); __HAL_RCC_SPI5_CLK_ENABLE();
spiobj->spiIRQ = SPI5_IRQn; spiobj->spiIRQ = SPI5_IRQn;
spiobj->spiIndex = 5;
spi5Handle = &spiobj->handle;
} }
#endif #endif
@ -317,6 +405,8 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
__HAL_RCC_SPI6_RELEASE_RESET(); __HAL_RCC_SPI6_RELEASE_RESET();
__HAL_RCC_SPI6_CLK_ENABLE(); __HAL_RCC_SPI6_CLK_ENABLE();
spiobj->spiIRQ = SPI6_IRQn; spiobj->spiIRQ = SPI6_IRQn;
spiobj->spiIndex = 6;
spi6Handle = &spiobj->handle;
} }
#endif #endif
@ -368,7 +458,6 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
#endif #endif
handle->Init.DataSize = SPI_DATASIZE_8BIT; handle->Init.DataSize = SPI_DATASIZE_8BIT;
handle->Init.FirstBit = SPI_FIRSTBIT_MSB; handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
handle->Init.TIMode = SPI_TIMODE_DISABLE;
#if defined (SPI_IP_VERSION_V2) #if defined (SPI_IP_VERSION_V2)
handle->Init.NSSPolarity = SPI_NSS_POLARITY_LOW; handle->Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
@ -418,6 +507,76 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
SPI_INIT_DIRECT(obj, &explicit_spi_pinmap); SPI_INIT_DIRECT(obj, &explicit_spi_pinmap);
} }
#ifdef STM32_SPI_CAPABILITY_DMA
/**
* Initialize the DMA for an SPI object in the Tx direction.
* Does nothing if DMA is already initialized.
*/
static void spi_init_tx_dma(struct spi_s * obj)
{
if(!obj->txDMAInitialized)
{
#ifdef TARGET_MCU_STM32H7
// For STM32H7, SPI6 does not support DMA through the normal mechanism -- it would require use of the BDMA
// controller, which we don't currently support, and which can only access data in SRAM4.
if(obj->spiIndex == 6)
{
mbed_error(MBED_ERROR_UNSUPPORTED, "DMA not supported on SPI6!", 0, MBED_FILENAME, __LINE__);
}
#endif
// Get DMA handle
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);
if(dmaHandle == NULL)
{
mbed_error(MBED_ERROR_ALREADY_IN_USE, "Tx DMA channel already used by something else!", 0, MBED_FILENAME, __LINE__);
}
__HAL_LINKDMA(&obj->handle, hdmatx, *dmaHandle);
obj->txDMAInitialized = true;
}
}
/**
* Initialize the DMA for an SPI object in the Rx direction.
* Does nothing if DMA is already initialized.
*/
static void spi_init_rx_dma(struct spi_s * obj)
{
if(!obj->rxDMAInitialized)
{
#ifdef TARGET_MCU_STM32H7
// For STM32H7, SPI6 does not support DMA through the normal mechanism -- it would require use of the BDMA
// controller, which we don't currently support, and which can only access data in SRAM4.
if(obj->spiIndex == 6)
{
mbed_error(MBED_ERROR_UNSUPPORTED, "DMA not supported on SPI6!", 0, MBED_FILENAME, __LINE__);
}
#endif
// Get DMA handle
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);
if(dmaHandle == NULL)
{
mbed_error(MBED_ERROR_ALREADY_IN_USE, "Rx DMA channel already used by something else!", 0, MBED_FILENAME, __LINE__);
}
__HAL_LINKDMA(&obj->handle, hdmarx, *dmaHandle);
obj->rxDMAInitialized = true;
}
}
#endif
void spi_free(spi_t *obj) void spi_free(spi_t *obj)
{ {
struct spi_s *spiobj = SPI_S(obj); struct spi_s *spiobj = SPI_S(obj);
@ -425,6 +584,20 @@ void spi_free(spi_t *obj)
DEBUG_PRINTF("spi_free\r\n"); DEBUG_PRINTF("spi_free\r\n");
#if STM32_SPI_CAPABILITY_DMA
// Free DMA channels if allocated
if(spiobj->txDMAInitialized)
{
stm_free_dma_link(&SPITxDMALinks[spiobj->spiIndex - 1]);
spiobj->txDMAInitialized = false;
}
if(spiobj->rxDMAInitialized)
{
stm_free_dma_link(&SPIRxDMALinks[spiobj->spiIndex - 1]);
spiobj->rxDMAInitialized = false;
}
#endif
__HAL_SPI_DISABLE(handle); __HAL_SPI_DISABLE(handle);
HAL_SPI_DeInit(handle); HAL_SPI_DeInit(handle);
@ -1362,7 +1535,7 @@ typedef enum {
/// @returns the number of bytes transferred, or `0` if nothing transferred /// @returns the number of bytes transferred, or `0` if nothing transferred
static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer_type, const void *tx, void *rx, size_t length) static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer_type, const void *tx, void *rx, size_t length, DMAUsage hint)
{ {
struct spi_s *spiobj = SPI_S(obj); struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle); SPI_HandleTypeDef *handle = &(spiobj->handle);
@ -1373,19 +1546,59 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
// so the number of transfers depends on the container size // so the number of transfers depends on the container size
size_t words; size_t words;
DEBUG_PRINTF("SPI inst=0x%8X Start: %u, %u\r\n", (int)handle->Instance, transfer_type, length);
obj->spi.transfer_type = transfer_type; obj->spi.transfer_type = transfer_type;
words = length >> bitshift; words = length >> bitshift;
// enable the interrupt bool useDMA = false;
#if STM32_SPI_CAPABILITY_DMA
if (hint != DMA_USAGE_NEVER)
{
// Initialize DMA channel(s) needed
switch (transfer_type)
{
case SPI_TRANSFER_TYPE_TXRX:
spi_init_rx_dma(&obj->spi);
spi_init_tx_dma(&obj->spi);
break;
case SPI_TRANSFER_TYPE_TX:
spi_init_tx_dma(&obj->spi);
break;
case SPI_TRANSFER_TYPE_RX:
spi_init_rx_dma(&obj->spi);
if(handle->Init.Direction == SPI_DIRECTION_2LINES) {
// For 2 line SPI, doing an Rx-only transfer still requires a second DMA channel to send the fill
// bytes.
spi_init_tx_dma(&obj->spi);
}
break;
default:
break;
}
useDMA = true;
}
#endif
DEBUG_PRINTF("SPI inst=0x%8X Start: type=%u, length=%u, DMA=%d\r\n", (int) handle->Instance, transfer_type, length, !!useDMA);
// Enable the interrupt. This might be needed even for DMA -- some HAL implementations (e.g. H7) have
// the DMA interrupt handler trigger the SPI interrupt.
IRQn_Type irq_n = spiobj->spiIRQ; IRQn_Type irq_n = spiobj->spiIRQ;
NVIC_DisableIRQ(irq_n);
NVIC_ClearPendingIRQ(irq_n); NVIC_ClearPendingIRQ(irq_n);
NVIC_SetPriority(irq_n, 1); NVIC_SetPriority(irq_n, 1);
NVIC_EnableIRQ(irq_n); NVIC_EnableIRQ(irq_n);
#if defined(STM32_SPI_CAPABILITY_DMA) && defined(__DCACHE_PRESENT)
if (useDMA && transfer_type != SPI_TRANSFER_TYPE_RX)
{
// For chips with a cache (e.g. Cortex-M7), we need to evict the Tx 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*)tx, length);
}
#endif
// flush FIFO // flush FIFO
#if defined(SPI_FLAG_FRLVL) #if defined(SPI_FLAG_FRLVL)
HAL_SPIEx_FlushRxFifo(handle); HAL_SPIEx_FlushRxFifo(handle);
@ -1400,21 +1613,52 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
#endif #endif
switch (transfer_type) { switch (transfer_type) {
case SPI_TRANSFER_TYPE_TXRX: case SPI_TRANSFER_TYPE_TXRX:
rc = HAL_SPI_TransmitReceive_IT(handle, (uint8_t *)tx, (uint8_t *)rx, words); if(useDMA) {
rc = HAL_SPI_TransmitReceive_DMA(handle, (uint8_t *)tx, (uint8_t *)rx, words);
}
else {
rc = HAL_SPI_TransmitReceive_IT(handle, (uint8_t *) tx, (uint8_t *) rx, words);
}
break; break;
case SPI_TRANSFER_TYPE_TX: case SPI_TRANSFER_TYPE_TX:
rc = HAL_SPI_Transmit_IT(handle, (uint8_t *)tx, words); if (useDMA) {
rc = HAL_SPI_Transmit_DMA(handle, (uint8_t *)tx, words);
}
else {
rc = HAL_SPI_Transmit_IT(handle, (uint8_t *) tx, words);
}
break; break;
case SPI_TRANSFER_TYPE_RX: case SPI_TRANSFER_TYPE_RX:
// the receive function also "transmits" the receive buffer so in order // the receive function also "transmits" the receive buffer so in order
// to guarantee that 0xff is on the line, we explicitly memset it here // to guarantee that 0xff is on the line, we explicitly memset it here
memset(rx, SPI_FILL_CHAR, length); memset(rx, SPI_FILL_CHAR, length);
rc = HAL_SPI_Receive_IT(handle, (uint8_t *)rx, words);
if (useDMA) {
#if defined(STM32_SPI_CAPABILITY_DMA) && defined(__DCACHE_PRESENT)
// For chips with a cache (e.g. Cortex-M7), we need to evict the Tx 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(rx, length);
#endif
rc = HAL_SPI_Receive_DMA(handle, (uint8_t *)rx, words);
}
else {
rc = HAL_SPI_Receive_IT(handle, (uint8_t *)rx, words);
}
break; break;
default: default:
length = 0; length = 0;
} }
#if defined(STM32_SPI_CAPABILITY_DMA) && defined(__DCACHE_PRESENT)
if (useDMA && transfer_type != SPI_TRANSFER_TYPE_TX)
{
// For chips with a cache (e.g. Cortex-M7), we need to invalidate the Rx data in cache.
// This ensures that the CPU will fetch the data from SRAM instead of using its cache.
SCB_InvalidateDCache_by_Addr(rx, length);
}
#endif
if (rc) { if (rc) {
#if defined(SPI_IP_VERSION_V2) #if defined(SPI_IP_VERSION_V2)
// enable SPI back in case of error // enable SPI back in case of error
@ -1430,15 +1674,11 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
} }
// asynchronous API // asynchronous API
// DMA support for SPI is currently not supported, hence asynchronous SPI does not support high speeds(MHZ range)
void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint) void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
{ {
struct spi_s *spiobj = SPI_S(obj); struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle); SPI_HandleTypeDef *handle = &(spiobj->handle);
// TODO: DMA usage is currently ignored
(void) hint;
// check which use-case we have // check which use-case we have
bool use_tx = (tx != NULL && tx_length > 0); bool use_tx = (tx != NULL && tx_length > 0);
bool use_rx = (rx != NULL && rx_length > 0); bool use_rx = (rx != NULL && rx_length > 0);
@ -1463,10 +1703,10 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
obj->spi.event = event; obj->spi.event = event;
// register the thunking handler // Register the callback.
IRQn_Type irq_n = spiobj->spiIRQ; // It's a function pointer, but it's passed as a uint32_t because of reasons.
NVIC_SetVector(irq_n, (uint32_t)handler); spiobj->driverCallback = (void (*)(void))handler;
DEBUG_PRINTF("SPI: Transfer: tx %u (%u), rx %u (%u), IRQ %u\n", use_tx, tx_length, use_rx, rx_length, irq_n); DEBUG_PRINTF("SPI: Transfer: tx %u (%u), rx %u (%u)\n", use_tx, tx_length, use_rx, rx_length);
// enable the right hal transfer // enable the right hal transfer
if (use_tx && use_rx) { if (use_tx && use_rx) {
@ -1477,22 +1717,19 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
obj->tx_buff.length = size; obj->tx_buff.length = size;
obj->rx_buff.length = size; obj->rx_buff.length = size;
} }
spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TXRX, tx, rx, size); spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TXRX, tx, rx, size, hint);
} else if (use_tx) { } else if (use_tx) {
spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TX, tx, NULL, tx_length); spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TX, tx, NULL, tx_length, hint);
} else if (use_rx) { } else if (use_rx) {
spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_RX, NULL, rx, rx_length); spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_RX, NULL, rx, rx_length, hint);
} }
} }
inline uint32_t spi_irq_handler_asynch(spi_t *obj) uint32_t spi_irq_handler_asynch(spi_t *obj)
{ {
int event = 0; int event = 0;
SPI_HandleTypeDef *handle = &(SPI_S(obj)->handle); SPI_HandleTypeDef *handle = &(SPI_S(obj)->handle);
// call the CubeF4 handler, this will update the handle
HAL_SPI_IRQHandler(handle);
if (handle->State == HAL_SPI_STATE_READY) { if (handle->State == HAL_SPI_STATE_READY) {
// When HAL SPI is back to READY state, check if there was an error // When HAL SPI is back to READY state, check if there was an error
int error = obj->spi.handle.ErrorCode; int error = obj->spi.handle.ErrorCode;
@ -1537,6 +1774,36 @@ inline uint32_t spi_irq_handler_asynch(spi_t *obj)
return (event & (obj->spi.event | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE)); return (event & (obj->spi.event | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE));
} }
// Callback from STM32 HAL when a bidirectional SPI transfer completes (interrupt based or DMA)
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
struct spi_s * spis = get_spis_pointer(hspi);
if(spis != NULL)
{
spis->driverCallback();
}
}
// Callback from STM32 HAL when a Rx-only SPI transfer completes (interrupt based or DMA)
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
struct spi_s * spis = get_spis_pointer(hspi);
if(spis != NULL)
{
spis->driverCallback();
}
}
// Callback from STM32 HAL when a Tx-only SPI transfer completes (interrupt based or DMA)
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
struct spi_s * spis = get_spis_pointer(hspi);
if(spis != NULL)
{
spis->driverCallback();
}
}
uint8_t spi_active(spi_t *obj) uint8_t spi_active(spi_t *obj)
{ {
struct spi_s *spiobj = SPI_S(obj); struct spi_s *spiobj = SPI_S(obj);
@ -1558,21 +1825,26 @@ void spi_abort_asynch(spi_t *obj)
struct spi_s *spiobj = SPI_S(obj); struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle); SPI_HandleTypeDef *handle = &(spiobj->handle);
// disable interrupt // disable interrupt if it was enabled
IRQn_Type irq_n = spiobj->spiIRQ; IRQn_Type irq_n = spiobj->spiIRQ;
NVIC_ClearPendingIRQ(irq_n); NVIC_ClearPendingIRQ(irq_n);
NVIC_DisableIRQ(irq_n); NVIC_DisableIRQ(irq_n);
#ifdef STM32_SPI_CAPABILITY_DMA
// Abort DMA transfers if DMA channels have been allocated
if(spiobj->txDMAInitialized) {
HAL_DMA_Abort_IT(spiobj->handle.hdmatx);
}
if(spiobj->rxDMAInitialized) {
HAL_DMA_Abort_IT(spiobj->handle.hdmarx);
}
#endif
// clean-up // clean-up
LL_SPI_Disable(SPI_INST(obj)); LL_SPI_Disable(SPI_INST(obj));
HAL_SPI_DeInit(handle); HAL_SPI_DeInit(handle);
HAL_SPI_Init(handle);
// cleanup input buffer init_spi(obj);
spi_flush_rx(obj);
// enable SPI back if it isn't 3-wire mode
if (handle->Init.Direction != SPI_DIRECTION_1LINE) {
LL_SPI_Enable(SPI_INST(obj));
}
} }
#endif //DEVICE_SPI_ASYNCH #endif //DEVICE_SPI_ASYNCH

View File

@ -0,0 +1,53 @@
/* mbed Microcontroller Library
* Copyright (c) 2016-2023 STMicroelectronics
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OS_STM_SPI_API_H
#define MBED_OS_STM_SPI_API_H
#include "spi_device.h"
#if STM32_SPI_CAPABILITY_DMA
#include "stm_dma_utils.h"
#endif
struct spi_s {
SPI_HandleTypeDef handle;
IRQn_Type spiIRQ;
SPIName spi;
PinName pin_miso;
PinName pin_mosi;
PinName pin_sclk;
PinName pin_ssel;
#if DEVICE_SPI_ASYNCH
uint32_t event;
uint8_t transfer_type;
// Callback function for when we get an interrupt on an async transfer.
// This will point, through a bit of indirection, to SPI::irq_handler_asynch()
// for the correct SPI instance.
void (*driverCallback)(void);
#endif
uint8_t spiIndex; // Index of the SPI peripheral, from 1-6
#if STM32_SPI_CAPABILITY_DMA
bool txDMAInitialized;
bool rxDMAInitialized;
#endif
};
#endif //MBED_OS_STM_SPI_API_H

View File

@ -3224,7 +3224,8 @@
"CRC", "CRC",
"TRNG", "TRNG",
"FLASH", "FLASH",
"MPU" "MPU",
"SPI_32BIT_WORDS"
] ]
}, },
"MCU_STM32H723xG": { "MCU_STM32H723xG": {
@ -4849,7 +4850,8 @@
"FLASH", "FLASH",
"MPU", "MPU",
"TRNG", "TRNG",
"SERIAL_ASYNCH" "SERIAL_ASYNCH",
"SPI_32BIT_WORDS"
] ]
}, },
"MCU_STM32U575xI": { "MCU_STM32U575xI": {

View File

@ -14,7 +14,7 @@ set(MBEDHTRUN_ARGS --skip-flashing @MBED_HTRUN_ARGUMENTS@) # filled in by config
# Print out command # Print out command
string(REPLACE ";" " " MBEDHTRUN_ARGS_FOR_DISPLAY "${MBEDHTRUN_ARGS}") string(REPLACE ";" " " MBEDHTRUN_ARGS_FOR_DISPLAY "${MBEDHTRUN_ARGS}")
message("Executing: mbedhtrun ${MBEDHTRUN_ARGS_FOR_DISPLAY}") message("Executing: @Python3_EXECUTABLE@ -m mbed_host_tests.mbedhtrun ${MBEDHTRUN_ARGS_FOR_DISPLAY}")
# Note: For this command, we need to survive mbedhtrun not being on the PATH, so we import the package and call the main function using "python -c" # Note: For this command, we need to survive mbedhtrun not being on the PATH, so we import the package and call the main function using "python -c"
execute_process( execute_process(