2018-02-23 09:10 AM
Dear All,
I use SPI as a master with 2 lines full duplex with DMA on STM32F303RE with 8-bit data size.
Frames are made of variable number of Bytes. Normally SPI clocks out 3 Bytes of command on MOSI line + 4 Bytes of reception which contains the slave answer.
My TX buffer is something like this:
(CMD)(ADD_H)(ADD_L)(4 Bytes don't care)
My RX buffer will be:
(3 Bytes don't care, normally 0xFFFFFF)(0x21)(0x43)(0x65)(0x87)
The output on the oscilloscope is perfect, but after a 30 seconds of millions of good communication I find the Rx buffer shifted:
(0x43)(0x65)(0x87)(0xFFFFFF)(0x21) or
(0x65)(0x87)(0xFFFFFF)(0x21)(0x43) or(0x87)(0xFFFFFF)(0x21)(0x43)(0x65) or
The shifted conditions is kept for some second, then it change. If I let it go, it keep on shifting, till goes back in phase.
Here is the configuration of SPI:
SPI_I2S_DeInit(SPI2);
SPI2->CR1 = SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_Mode_Master | SPI_BaudRatePrescaler_64 | SPI_FirstBit_MSB | SPI_NSS_Soft | SPI_Direction_2Lines_FullDuplex;SPI2->CR2 = SPI_RxFIFOThreshold_QF | SPI_DataSize_8b | SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx;Here the configuration of the two DMA channels (channel 4 RX and channel 5 TX):
// DMA channel Rx of SPI Configuration
DMA_DeInit(DMA1_Channel4);DMA1_Channel4->CCR = DMA_DIR_PeripheralSRC | DMA_Mode_Normal | DMA_PeripheralInc_Disable | DMA_MemoryInc_Enable | DMA_PeripheralDataSize_Byte | DMA_MemoryDataSize_Byte | DMA_Priority_High | DMA_M2M_Disable;DMA1_Channel4->CNDTR = 0;DMA1_Channel4->CPAR = (uint32_t)&(SPI2->DR);DMA1_Channel4->CMAR = (uint32_t)&RxBuffer[0];// DMA channel Tx of SPI ConfigurationDMA_DeInit(DMA1_Channel5);DMA1_Channel5->CCR = DMA_DIR_PeripheralDST | DMA_Mode_Normal | DMA_PeripheralInc_Disable | DMA_MemoryInc_Enable | DMA_PeripheralDataSize_Byte | DMA_MemoryDataSize_Byte | DMA_Priority_Medium | DMA_M2M_Disable;DMA1_Channel5->CNDTR = 0;DMA1_Channel5->CPAR = (uint32_t)&(SPI2->DR);DMA1_Channel5->CMAR = (uint32_t)&TxBuffer[0];When I want to transmit and receive I created following function:
if((DMA1_Channel4->CNDTR != 0) || (DMA1_Channel5->CNDTR != 0))
return 0;if((SPI2->SR & (SPI_SR_FRLVL | SPI_SR_FTLVL | SPI_I2S_FLAG_RXNE | SPI_I2S_FLAG_BSY)) return 0;// Disable the SPI (trying to flush it)SPI2->CR1 &= ~SPI_CR1_SPE;// Disable the DMA channels to configure the CNDTRDMA1_Channel5->CCR &= ~DMA_CCR_EN;DMA1_Channel4->CCR &= ~DMA_CCR_EN;// Enable SPISPI2->CR1 |= SPI_CR1_SPE;// Configure odd transfersSPI2->CR2 &= ~SPI_LastDMATransfer_TxOddRxOdd;if((Tx_Size + Rx_Size) % 2) SPI2->CR2 |= SPI_LastDMATransfer_TxOddRxOdd;// NSS signal to 0ESC_CS_ON;// Number of Bytes to transmit and receiveDMA1_Channel4->CNDTR = Tx_Size + Rx_Size;DMA1_Channel5->CNDTR = Tx_Size + Rx_Size;// Enable receptionDMA1_Channel4->CCR |= DMA_CCR_EN;// Ebable transmissionDMA1_Channel5->CCR |= DMA_CCR_EN;Another function checks the transfers are completed and take the data from the buffer
if((DMA1->ISR & (DMA1_FLAG_TC4 | DMA1_FLAG_TC5)) != (DMA1_FLAG_TC4 | DMA1_FLAG_TC5))
return 0;if((DMA1_Channel4->CNDTR != 0) || (DMA1_Channel5->CNDTR != 0)) return 0;if(SPI2->SR & (SPI_SR_FRLVL | SPI_SR_FTLVL | SPI_I2S_FLAG_RXNE | SPI_I2S_FLAG_BSY)) return 0;SPI2->CR1 &= ~SPI_CR1_SPE;memcpy(value, (u8*)RxBuffer + Tx_Size, Rx_Size);return 1;My impression is that even though the SPI is disabled and enabled to try to flush it and even
though
I check that the RXFIFO is empty, there is something that remains there and corrupt the future transfers.
#dma #spi #spi-flushing #spi-shiftSolved! Go to Solution.
2019-05-01 04:54 AM
SPI works with DMA without a single byte shifting. Just needed to create the whole project in an orderly fashion. Set the clock first, make all free pins as analog, then save. After configure peripherals, enable DMA on SPI, turn on ISR for DMA and off for SPI.
2019-05-04 05:21 PM
Hello all, good news! It seems the SPI byte shifting problem has been solved. The SPI DMA HAL in Slave Mode has been working for one day flawlessly. No byte shifting at all.
What did I do?
I've created the whole project from the scratch by using CubeMX 5.1
After selecting the MCU from the list, CubeMX creates the project framework. Here are all the followed steps afterwards:
1) Go to project manager and define all the basic settings. Name for the project, application structure "Advanced", IDE, keep all default settings. Code Generator: copy only the necessary libraries, set all free pins as analog, keep all default settings.
2) Configure the clock and save the project.
3) Configure SPI (Master/Slave), activate DMA, turn on DMA interrupts, SPI interrupt off.
4) Save the project.
You need to move your custom files from the old project to the new one plus all the required configuration.
To make a test, the only method you need to call is:
HAL_SPI_TransmitReceive_DMA (in case of Full-Duplex)
This method makes all the necessary initialization inside.
Guessing about why is it now working, I believe that some resources need to be allocated first, maybe for the APB/AHB clocks, so the very first need to be the clock configuration.
After this I added the remaining peripherals I need for my project, and that is it.