SPI DMA STM32H742VI with LL with Polling
Hello,
I have tried to implement a simple SPI driver.
Only with LL Lib. I would like to use DMA and I will do it without interrupts.
So it works now. But for me it is not clear how to poll if the transfer is finish in the right way.
So I use rx and tx dma therefore I taught the byte shifted in, guarantees the last shift out is done. That means i only wait for the rx dma stream to become ready.
So my dma transfer and init functions looks like that way
static void dma_init(void)
{
// dma init snippet
/* DMA controller clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
/* SPI3_TX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_STREAM_1, LL_DMAMUX1_REQ_SPI3_TX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_1, LL_DMA_PRIORITY_VERYHIGH);
LL_DMA_SetMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_BYTE);
LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_1);
/* SPI3_RX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_STREAM_0, LL_DMAMUX1_REQ_SPI3_RX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_0, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_0, LL_DMA_PRIORITY_VERYHIGH);
LL_DMA_SetMode(DMA1, LL_DMA_STREAM_0, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_0, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_0, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_0, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_0, LL_DMA_MDATAALIGN_BYTE);
LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_0);
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_0, 0);
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, 0);
/* SPI3 parameter configuration*/
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
SPI_InitStruct.BaudRate = PLATFORM_NETX_STM32H_SPI_CLOCK;
SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SPI_InitStruct.CRCPoly = 0x0;
LL_SPI_EnableGPIOControl(SPI3);
LL_SPI_SetStandard(SPI3, LL_SPI_PROTOCOL_MOTOROLA);
LL_SPI_Init(SPI3, &SPI_InitStruct);
LL_SPI_EnableDMAReq_RX(SPI3);
LL_SPI_EnableDMAReq_TX(SPI3);
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_0);
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_1);
/* LL_DMA_STREAM_0 => RX */
LL_DMA_ConfigAddresses(DMA1,
LL_DMA_STREAM_0,
(uint32_t) &(SPI3->RXDR),
(uint32_t) receiveBuffer,
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_0));
/* LL_DMA_STREAM_1 => TX */
LL_DMA_ConfigAddresses(DMA1,
LL_DMA_STREAM_1,
(uint32_t)transmitBuffer,
(uint32_t) &(SPI3->TXDR),
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_1));
/* clear flags */
LL_DMA_ClearFlag_TC0(DMA1);
LL_DMA_ClearFlag_TC1(DMA1);
LL_DMA_ClearFlag_HT0(DMA1);
LL_DMA_ClearFlag_HT1(DMA1);
LL_DMA_ClearFlag_TE0(DMA1);
LL_DMA_ClearFlag_TE1(DMA1);
/* Enable SPI1 */
LL_SPI_Enable(SPI3);
}
static void tranfsere_spi_dma(uint32_t ulLength)
{
// disable DMA streams
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_0);
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_1);
// disable spi needed on h7
LL_SPI_Disable(SPI3);
LL_DMA_ClearFlag_TC0(DMA1);
LL_DMA_ClearFlag_TC1(DMA1);
LL_DMA_ClearFlag_HT0(DMA1);
LL_DMA_ClearFlag_HT1(DMA1);
LL_DMA_ClearFlag_FE0(DMA1);
LL_DMA_ClearFlag_FE1(DMA1);
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_0, ulLength);
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, ulLength);
// Enable DMA Channels
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_0);
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_1);
// Enable SPI and start master transfer
LL_SPI_Enable(SPI3);
LL_SPI_StartMasterTransfer(SPI3);
while (!LL_DMA_IsActiveFlag_TC0(DMA1))
{
// todo error handling
}
}So is it enough to wait only for TC0 active ?
Is it better to use an Interrupt in relation to performance?
Do I need caching in any way? My buffers are on 0x24xxxxxx addresses.
By the way is there an example for H7 with DMA and LL ??
many thanks
cheers mathias