SPI RX buffer shifted
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-shift