feat: H7 SPI support (#5425)
This commit is contained in:
@@ -60,7 +60,11 @@ void stm32_spi_enable_clock(SPI_TypeDef *SPIx)
|
||||
#endif
|
||||
#if defined(SPI6)
|
||||
else if (SPIx == SPI6) {
|
||||
#if defined(LL_APB2_GRP1_PERIPH_SPI6)
|
||||
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI6);
|
||||
#elif defined(LL_APB4_GRP1_PERIPH_SPI6)
|
||||
LL_APB4_GRP1_EnableClock(LL_APB4_GRP1_PERIPH_SPI6);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -147,18 +151,47 @@ static void _config_dma_streams(const stm32_spi_t* spi)
|
||||
LL_DMA_InitTypeDef dmaInit;
|
||||
LL_DMA_StructInit(&dmaInit);
|
||||
|
||||
#if defined(STM32F2) || defined(STM32F4)
|
||||
dmaInit.Channel = spi->DMA_Channel;
|
||||
dmaInit.PeriphOrM2MSrcAddress = (uint32_t)&spi->SPIx->DR;
|
||||
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRegAddr(spi->SPIx);
|
||||
#endif
|
||||
|
||||
#if defined(STM32F2) || defined(STM32F4) || defined(STM32H7)
|
||||
dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||
dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH;
|
||||
dmaInit.FIFOMode = spi->DMA_FIFOMode;
|
||||
dmaInit.FIFOThreshold = spi->DMA_FIFOThreshold;
|
||||
dmaInit.MemoryOrM2MDstDataSize = spi->DMA_MemoryOrM2MDstDataSize;
|
||||
dmaInit.MemBurst = spi->DMA_MemBurst;
|
||||
#elif defined(STM32H7RS)
|
||||
dmaInit.Priority = LL_DMA_LOW_PRIORITY_HIGH_WEIGHT;
|
||||
#endif
|
||||
|
||||
#if defined(STM32H7)
|
||||
dmaInit.PeriphRequest = spi->rxDMA_PeriphRequest;
|
||||
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
|
||||
#elif defined(STM32H7RS)
|
||||
dmaInit.Request = spi->rxDMA_PeriphRequest;
|
||||
dmaInit.SrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
|
||||
dmaInit.SrcIncMode = LL_DMA_SRC_FIXED;
|
||||
dmaInit.DestIncMode = LL_DMA_DEST_INCREMENT;
|
||||
dmaInit.DestDataWidth = LL_DMA_DEST_DATAWIDTH_HALFWORD; // TODO
|
||||
#endif
|
||||
|
||||
dmaInit.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
|
||||
LL_DMA_Init(spi->DMA, spi->rxDMA_Stream, &dmaInit);
|
||||
|
||||
#if defined(STM32H7)
|
||||
dmaInit.PeriphRequest = spi->txDMA_PeriphRequest;
|
||||
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
|
||||
#elif defined(STM32H7RS)
|
||||
dmaInit.Request = spi->rxDMA_PeriphRequest;
|
||||
dmaInit.DestAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
|
||||
dmaInit.SrcIncMode = LL_DMA_SRC_INCREMENT;
|
||||
dmaInit.DestIncMode = LL_DMA_DEST_FIXED;
|
||||
dmaInit.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_HALFWORD; // TODO
|
||||
#endif
|
||||
|
||||
dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
||||
LL_DMA_Init(spi->DMA, spi->txDMA_Stream, &dmaInit);
|
||||
}
|
||||
@@ -212,10 +245,18 @@ void stm32_spi_set_max_baudrate(const stm32_spi_t* spi, uint32_t baudrate)
|
||||
uint8_t stm32_spi_transfer_byte(const stm32_spi_t* spi, uint8_t out)
|
||||
{
|
||||
auto* SPIx = spi->SPIx;
|
||||
#if defined(STM32H7) || defined(STM32H7RS)
|
||||
while (!LL_SPI_IsActiveFlag_TXP(SPIx));
|
||||
#else
|
||||
while (!LL_SPI_IsActiveFlag_TXE(SPIx));
|
||||
#endif
|
||||
LL_SPI_TransmitData8(SPIx, out);
|
||||
|
||||
#if defined(STM32H7) || defined(STM32H7RS)
|
||||
while (!LL_SPI_IsActiveFlag_RXP(SPIx));
|
||||
#else
|
||||
while (!LL_SPI_IsActiveFlag_RXNE(SPIx));
|
||||
#endif
|
||||
return LL_SPI_ReceiveData8(SPIx);
|
||||
}
|
||||
|
||||
@@ -242,10 +283,18 @@ uint16_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out,
|
||||
uint16_t stm32_spi_transfer_word(const stm32_spi_t* spi, uint16_t out)
|
||||
{
|
||||
auto* SPIx = spi->SPIx;
|
||||
#if defined(STM32H7) || defined(STM32H7RS)
|
||||
while (!LL_SPI_IsActiveFlag_TXP(SPIx));
|
||||
#else
|
||||
while (!LL_SPI_IsActiveFlag_TXE(SPIx));
|
||||
#endif
|
||||
LL_SPI_TransmitData16(SPIx, out);
|
||||
|
||||
while (!LL_SPI_IsActiveFlag_RXNE(SPIx));
|
||||
#if defined(STM32H7) || defined(STM32H7RS)
|
||||
while (!LL_SPI_IsActiveFlag_TXP(SPIx));
|
||||
#else
|
||||
while (!LL_SPI_IsActiveFlag_TXE(SPIx));
|
||||
#endif
|
||||
return LL_SPI_ReceiveData16(SPIx);
|
||||
}
|
||||
|
||||
@@ -253,13 +302,26 @@ uint16_t stm32_spi_transfer_word(const stm32_spi_t* spi, uint16_t out)
|
||||
static uint16_t _scratch_byte __DMA;
|
||||
static uint8_t _scratch_buffer[512] __DMA;
|
||||
|
||||
#if defined(STM32H7) || defined(STM32H7RS) || defined(STM32F4)
|
||||
extern uint32_t _sram;
|
||||
extern uint32_t _eram;
|
||||
#define _IS_DMA_BUFFER(addr) \
|
||||
((intptr_t)(addr) >= (intptr_t)&_sram && (intptr_t)(addr) <= (intptr_t)&_eram)
|
||||
#else
|
||||
#define _IS_DMA_BUFFER(addr) (true)
|
||||
#endif
|
||||
|
||||
#define _IS_ALIGNED(addr) (((intptr_t)(addr) & 3U) == 0U)
|
||||
|
||||
static void _dma_enable_stream(DMA_TypeDef* DMAx, uint32_t stream,
|
||||
const void* data, uint32_t length)
|
||||
{
|
||||
stm32_dma_check_tc_flag(DMAx, stream);
|
||||
#if !defined(STM32H7RS)
|
||||
LL_DMA_SetMemoryAddress(DMAx, stream, (uintptr_t)data);
|
||||
LL_DMA_SetDataLength(DMAx, stream, length);
|
||||
LL_DMA_EnableStream(DMAx, stream);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -271,7 +333,8 @@ uint16_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi,
|
||||
return stm32_spi_transfer_bytes(spi, nullptr, data, length);
|
||||
}
|
||||
|
||||
if (((uintptr_t)data < SRAM_BASE) || ((uintptr_t)data & 3)) {
|
||||
bool use_scratch_buffer = !_IS_DMA_BUFFER(data) || !_IS_ALIGNED(data);
|
||||
if (use_scratch_buffer) {
|
||||
_dma_enable_stream(spi->DMA, spi->rxDMA_Stream, _scratch_buffer, length);
|
||||
} else {
|
||||
_dma_enable_stream(spi->DMA, spi->rxDMA_Stream, data, length);
|
||||
@@ -279,23 +342,32 @@ uint16_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi,
|
||||
LL_SPI_EnableDMAReq_RX(spi->SPIx);
|
||||
|
||||
_scratch_byte = 0xFFFF;
|
||||
#if !defined(STM32H7RS)
|
||||
LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_NOINCREMENT);
|
||||
#endif
|
||||
_dma_enable_stream(spi->DMA, spi->txDMA_Stream, &_scratch_byte, length);
|
||||
LL_SPI_EnableDMAReq_TX(spi->SPIx);
|
||||
|
||||
// Wait for end of DMA transfer
|
||||
while(!stm32_dma_check_tc_flag(spi->DMA, spi->rxDMA_Stream));
|
||||
|
||||
// Disable SPI TX/RX DMA requests
|
||||
CLEAR_BIT(spi->SPIx->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
|
||||
|
||||
#if !defined(STM32H7) && !defined(STM32H7RS)
|
||||
// Wait for TXE=1
|
||||
while(!LL_SPI_IsActiveFlag_TXE(spi->SPIx));
|
||||
while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx));
|
||||
|
||||
// Wait for BSY=0
|
||||
while(LL_SPI_IsActiveFlag_BSY(spi->SPIx));
|
||||
#else
|
||||
// Wait for EOT=1
|
||||
while (!LL_SPI_IsActiveFlag_EOT(spi->SPIx));
|
||||
LL_SPI_ClearFlag_EOT(spi->SPIx);
|
||||
#endif
|
||||
|
||||
if (((uintptr_t)data < SRAM_BASE) || ((uintptr_t)data & 3)) {
|
||||
// Disable SPI TX/RX DMA requests
|
||||
LL_SPI_DisableDMAReq_TX(spi->SPIx);
|
||||
LL_SPI_DisableDMAReq_RX(spi->SPIx);
|
||||
|
||||
if (use_scratch_buffer) {
|
||||
memcpy(data, _scratch_buffer, length);
|
||||
}
|
||||
|
||||
@@ -313,21 +385,23 @@ uint16_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
|
||||
return stm32_spi_transfer_bytes(spi, data, nullptr, length);
|
||||
}
|
||||
|
||||
if (((uintptr_t)data < SRAM_BASE) || ((uintptr_t)data & 3)) {
|
||||
bool use_scratch_buffer = !_IS_DMA_BUFFER(data) || !_IS_ALIGNED(data);
|
||||
if (use_scratch_buffer) {
|
||||
memcpy(_scratch_buffer, data, length);
|
||||
data = _scratch_buffer;
|
||||
}
|
||||
|
||||
#if !defined(STM32H7RS)
|
||||
LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_INCREMENT);
|
||||
#endif
|
||||
|
||||
_dma_enable_stream(spi->DMA, spi->txDMA_Stream, data, length);
|
||||
LL_SPI_EnableDMAReq_TX(spi->SPIx);
|
||||
|
||||
// Wait for end of DMA transfer
|
||||
while (!stm32_dma_check_tc_flag(spi->DMA, spi->txDMA_Stream));
|
||||
|
||||
// Disable SPI TX DMA requests
|
||||
CLEAR_BIT(spi->SPIx->CR2, SPI_CR2_TXDMAEN);
|
||||
|
||||
#if !defined(STM32H7) && !defined(STM32H7RS)
|
||||
// Wait for TXE=1
|
||||
while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx));
|
||||
|
||||
@@ -338,6 +412,19 @@ uint16_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
|
||||
if (LL_SPI_IsActiveFlag_RXNE(spi->SPIx)) {
|
||||
(void)LL_SPI_ReceiveData8(spi->SPIx);
|
||||
}
|
||||
#else
|
||||
// Wait for EOT=1
|
||||
while (!LL_SPI_IsActiveFlag_EOT(spi->SPIx));
|
||||
LL_SPI_ClearFlag_EOT(spi->SPIx);
|
||||
|
||||
// Clear RX FIFO
|
||||
while (LL_SPI_IsActiveFlag_RXP(spi->SPIx)) {
|
||||
(void)LL_SPI_ReceiveData8(spi->SPIx);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Disable SPI TX DMA requests
|
||||
LL_SPI_DisableDMAReq_TX(spi->SPIx);
|
||||
|
||||
return length;
|
||||
#else
|
||||
|
||||
@@ -33,7 +33,12 @@ struct stm32_spi_t {
|
||||
uint32_t CS_Pin; // CS
|
||||
|
||||
DMA_TypeDef* DMA;
|
||||
#if defined(STM32H7) || defined(STM32H7RS)
|
||||
uint32_t txDMA_PeriphRequest;
|
||||
uint32_t rxDMA_PeriphRequest;
|
||||
#else
|
||||
uint32_t DMA_Channel;
|
||||
#endif
|
||||
uint32_t txDMA_Stream;
|
||||
uint32_t rxDMA_Stream;
|
||||
uint32_t DMA_FIFOMode;
|
||||
|
||||
Reference in New Issue
Block a user