cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L1 SPI DMA Receive half duplex (no HAL, only LL)

Denis Krasutski
Associate III

Hi All,

My environment: STM32L151CB, SPI2 Master, DMA1 Chan4(RX) and Chan5(TX)

I moved from HAL to LL (to save memory) and faced with the following issue:

When I configure SPI to receive data by DMA and setup only RX DMA channel SPI transaction doesn't start but if I setup RX+TX channels it's work but sometimes I lost one RX byte and DMA RX Complete never call!

//Doesnt' work
 
while (LL_SPI_IsActiveFlag_RXNE(SPI2)) {
        LL_SPI_ReceiveData8(SPI2);
}
 
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_4,
                           LL_SPI_DMA_GetRegAddr(SPI2),
                           (uint32_t)rx,
                           LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, size);
LL_SPI_EnableDMAReq_RX(SPI2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
//Works but sometimes I lost one RX byte and DMA Rx Complete doesn't call! DMA Ch5 CNT=0, DMA Ch4 CNT=1, start size 512 bytes
 
while (LL_SPI_IsActiveFlag_RXNE(SPI2)) {
        LL_SPI_ReceiveData8(SPI2);
}
 
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_4,
                           LL_SPI_DMA_GetRegAddr(SPI2),
                           (uint32_t)rx,
 
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, size);
LL_SPI_EnableDMAReq_RX(SPI2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
 
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_5,
                           (uint32_t)_spi_dummy_tx,
                           LL_SPI_DMA_GetRegAddr(SPI2),
                           LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_5));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_5, size);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_5);
LL_SPI_EnableDMAReq_TX(SPI2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_5);

From RM0038 Reference manual (DocID15965 Rev 15) page 769:

When the SPI is used only to transmit data, it is possible to enable only the SPI Tx DMA channel. In this case, the OVR flag is set because the data received are not read.

When the SPI is used only to receive data, it is possible to enable only the SPI Rx DMA channel.

How it explain? Should I use RXONLY bit to start receiving?

When I use RXONLY, I disabling this bit in RxComplete callback(max interrupt priority) but SPI still clocks and I lost the last byte(need it in next transaction). So is it OK for RXONLY mode or is it my mistake? Any advices!

When I used HAL, HAL_SPI_ReceivedDMA worked properly

BR, Dennis.

1 ACCEPTED SOLUTION

Accepted Solutions

> When I configure SPI to receive data by DMA and setup only RX DMA channel SPI transaction doesn't start

Yes - you need to Tx to generate clocks in master mode. Or alternatively, use RXONLY mode, which is tricky to use as it generates clocks undiscriminately, as you've discovered.

> but if I setup RX+TX channels it's work but sometimes I lost one RX byte and DMA RX Complete never call!

Find out, why. Loop back the data and observe, which one is missing. Use a LA to observe the clocks and data and count them. Check the status bits of SPI - don't you try to use an excessive baudrate which leads to DMA choking and ultimately then Rx overflow? Do you use something else on the same APB bus or in the same DMA, simultaneously to the SPI?

JW

PS. If you watch the SPI registers using debugger while trying the DMA, stop doing it. Reading out SPI_SR.RXNE by debugger clears the trigger to the DMA.

View solution in original post

4 REPLIES 4

> When I configure SPI to receive data by DMA and setup only RX DMA channel SPI transaction doesn't start

Yes - you need to Tx to generate clocks in master mode. Or alternatively, use RXONLY mode, which is tricky to use as it generates clocks undiscriminately, as you've discovered.

> but if I setup RX+TX channels it's work but sometimes I lost one RX byte and DMA RX Complete never call!

Find out, why. Loop back the data and observe, which one is missing. Use a LA to observe the clocks and data and count them. Check the status bits of SPI - don't you try to use an excessive baudrate which leads to DMA choking and ultimately then Rx overflow? Do you use something else on the same APB bus or in the same DMA, simultaneously to the SPI?

JW

PS. If you watch the SPI registers using debugger while trying the DMA, stop doing it. Reading out SPI_SR.RXNE by debugger clears the trigger to the DMA.

Thank you, JW. I was hoping it was my mistake

So, when I using TX+RX channels during receiving I'm losing one byte. It happens one at around 4 hours.

I am working with SD card and write audio stream 16bit@16KHz through FatFS from Chan.

After several hours my device hands: code wait for RX Completion but the last byte never received. CNT register for TX channel contains 0(it means all bytes sent, it is OK) but CNT for RX channel contains 1 and next transaction doesn't start because all TX data was sent. DMA transaction always is 512 bytes, small data frames I send by pulling.

Do you have any ideas on how it could happen?

As I've said above, check the status bits of SPI for RX overflow, when the problem happens. It may be a bus contention and/or DMA resources exhaustion.

JW