STM32H723 SPI DMA Low Level Drivers - sends only one frame
Hi Folks,
I have a problem with STM32H723 SPI with DMA and Low Level drivers.
The issue is: it sends only one Frame, after that the DMA transfer sends constant Transfer-Error Interrupts.
The SPI should be triggered every 100 ms and should send a frame of 10 bytes. I got it running using HAL, so the Hardware is OK (i was able to Rx/Tx data), but I can not get it running with Low Level Drivers. My guess is: i forgot something in the SPI / DMA Interrupt handlers. It's working when the programm is (re-)started, but after the first frame the DMA remains blocked/locked and triggers a "transfer error" uppon the next request.
Hardware Setup
SPI: Full Duplex Master, 8 Bit, Motorola, MSB First, NSS Output Hardware, Fifo Threshold 1 Data
DMA: one channel for Rx and Tx each, normal mode, data width = 1 byte and memory increment.
Basic initialisation and Code generation is done by Cube MX
Code
Basic init, called once to configure the DMA
void myDMA_init(void) {
// DMA Basic Configuriation
LL_DMA_ConfigAddresses( DMA1, LL_DMA_STREAM_2,
LL_SPI_DMA_GetRxRegAddr(SPI2),
(uint32_t)RxBuffer,
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_2));
LL_DMA_ConfigAddresses(DMA1, LL_DMA_STREAM_3,
(uint32_t)TxBuffer,
LL_SPI_DMA_GetTxRegAddr(SPI2),
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_3));
}Send function: called periodically in the main loop
void SendData(void) {
// configure RX DMA
uint32_t rxAddr = (uint32_t)RxBuffer;
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_2, rxAddr);
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_2, DataSize);
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_2);
LL_SPI_EnableDMAReq_RX(SPI2);
// configure TX DMA
uint32_t txAddr = (uint32_t)TxBuffer;
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_3, txAddr);
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_3, DataSize);
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_3);
LL_SPI_SetTransferSize(SPI2, DataSize);
LL_SPI_EnableDMAReq_TX(SPI2);
// enable Transfer Complete and Transfer Error IT for RxDMA Stream
LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_2);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_STREAM_2);
// enable and start SPI Master Transfer
LL_SPI_Enable(SPI2);
LL_SPI_StartMasterTransfer(SPI2);
}Note: DataSize = 10, uint8_t TxBuffer[10] and uint8_t RxBuffer[10] are global variables. TxBuffer is filled before send, RxBuffer is cleared before send. The SendData function works once. I can see the transmission on the Scope.
Furthermore I have 3 Interrupt Handlers:
Handler for DMA1 Stream 2 (Rx DMA)
void DMA1S2_IRQHandler(void) {
// clear Transfer Complete and Transfer Error IRQ-Flag
if(LL_DMA_IsActiveFlag_TC2(DMA1)) LL_DMA_ClearFlag_TC2(DMA1);
if(LL_DMA_IsActiveFlag_TE2(DMA1)) LL_DMA_ClearFlag_TE2(DMA1);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_STREAM_2);
LL_DMA_DisableIT_TE(DMA1, LL_DMA_STREAM_2);
// enable SPI End of Transfer Interrupt
LL_SPI_EnableIT_EOT(SPI2);
}Handler for DMA1 Stream 3 (Tx DMA)
void DMA1S3_IRQHandler(void) {
// clear Transfer Complete and Transfer Error IRQ-Flag
if(LL_DMA_IsActiveFlag_TC3(DMA1)) LL_DMA_ClearFlag_TC3(DMA1);
if(LL_DMA_IsActiveFlag_TE3(DMA1)) LL_DMA_ClearFlag_TE3(DMA1);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_STREAM_2);
LL_DMA_DisableIT_TE(DMA1, LL_DMA_STREAM_2);
}and the Handler for the SPI Interrupt(s):
void SPI2_myIRQHandler(void) {
// clear the End of Transfer Interrupt Flag
LL_SPI_ClearFlag_EOT(SPI2);
LL_SPI_DisableIT_EOT(SPI2);
// Disable SPI2
LL_SPI_Disable(SPI2);
// Disable DMA1 Stream 2 and DMA Request
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);
LL_SPI_DisableDMAReq_RX(SPI2);
// Disable DMA1 Stream 3 and DMA Request
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);
LL_SPI_DisableDMAReq_TX(SPI2);
}Behaviour:
on the first run, the DMA Rx Interrupt calls the Interrupt handler, the Transfer complete Flag is Set, but no transfer error. At the end of the Handler the SPI End of Transfer Interrupt is enabled, which is called without almost any delay. On the second and all following runs the Rx DMA Interrupt handler is called with TE and TC flags enabled. The SPI EoT Interrupt is never triggered again. In the Scope I can see that one frame has been sent out, but that's it.
The Question: has anyone an idea, why the DMA aborts immediately with an Transfer Error after the first run? Thanks!
