cancel
Showing results for 
Search instead for 
Did you mean: 

SPI DMA Circular Buffer weird bitflips

Framet
Associate III

Hello

Test Szenario:

  • Transfer uint64_t counter from STM to another MC called ALFA.
  • ALFA has a separate uint64_t counter.
  • Each transfer counts the counter up.
  • ALFA compares both counters and reports a missmatch

Setup:

  • ALFA -> SPI Master @ 10Mhz
  • STMG4 -> SPI Slave -> DMA
  • SPI Transation is 9 Bytes long, where the first byte is a placeholder byte (used by something else, but not important)
  • The STMG4 SPI DMA transaction is started when the chip select of ALFA goes back to high
    • we will miss the first transaction on purpose to ensure a clean start
    • Additional checks are done to keep the data synchronized between STMG4 and ALFA

Variables:

volatile uint32_t spiTransferState = SPI_TRANSFER_IDLE;

DMA Circulare Code:

[somewhere in main while loop]
volatile static uint64_t counter = 0;
if(spiTransferState == SPI_TRANSFER_COMPLETE){
	counter++;
	spiTxBuffer[0] = 8;
	memcpy(&spiTxBuffer[1],(uint8_t*)&counter,8);
 
	spiTransferState = SPI_TRANSFER_WAIT;
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
	spiTransferState = SPI_TRANSFER_COMPLETE;
}

DMA Normal Mode

Line 9 differs

[somewhere in main while loop]
volatile static uint64_t counter = 0;
if(spiTransferState == SPI_TRANSFER_COMPLETE){
	counter++;
	spiTxBuffer[0] = 8;
	memcpy(&spiTxBuffer[1],(uint8_t*)&counter,8);
 
	spiTransferState = SPI_TRANSFER_WAIT;
	HAL_SPI_TransmitReceive_DMA(&hspi1, (uint8_t*) spiTxBuffer, (uint8_t*) spiRxBuffer, SPI_BUFFER_SIZE);
}

When logging the receiving data in ciruclare mode:

b[0]: 8 b[1]: fe b[2]: ff b[3]: 0 b[4]: 0 b[5]: 0 b[6]: 0 b[7]: 0 b[8]: 0 
b[0]: 8 b[1]: ff b[2]: ff b[3]: 1 b[4]: 0 b[5]: 0 b[6]: 0 b[7]: 0 b[8]: 0 
alfa counter: 65535
received counter: 131071 //check b[3] flipped to early?
b[0]: 8 b[1]: 0 b[2]: 0 b[3]: 1 b[4]: 0 b[5]: 0 b[6]: 0 b[7]: 0 b[8]: 0 
b[0]: 8 b[1]: 1 b[2]: 0 b[3]: 1 b[4]: 0 b[5]: 0 b[6]: 0 b[7]: 0 b[8]: 0 

When running it without circular mode. this problem does not occure.

What did I wrong? What could cause this? Or probably what did I not understand when using ciruclar mode?

Best regards

Franco

1 ACCEPTED SOLUTION

Accepted Solutions

Part of the problem here is that you rely on prechewed Cube/HAL functions instead of writing your own, where you would develop an understanding of what's going on.

HAL_SPI_TxRxCpltCallback() is called when the receiver DMA throws the Transfer Complete interrupt, which is at the moment when the whole packet has been transferred. However, if the Tx DMA is circular, it has already transferred the first 3 bytes into the SPI Tx FIFO, with the *old* values, after that the increment happens, so the 4th byte is transmitted already after the increment.

You want to perform the increment in the Tx DMA Transfer Complete interrupt, if you can guarantee it will be completed before the first byte of it gets transferred into the FIFO. Alternatively, you can try to use the Double-Buffer DMA mode.

JW

View solution in original post

2 REPLIES 2

Part of the problem here is that you rely on prechewed Cube/HAL functions instead of writing your own, where you would develop an understanding of what's going on.

HAL_SPI_TxRxCpltCallback() is called when the receiver DMA throws the Transfer Complete interrupt, which is at the moment when the whole packet has been transferred. However, if the Tx DMA is circular, it has already transferred the first 3 bytes into the SPI Tx FIFO, with the *old* values, after that the increment happens, so the 4th byte is transmitted already after the increment.

You want to perform the increment in the Tx DMA Transfer Complete interrupt, if you can guarantee it will be completed before the first byte of it gets transferred into the FIFO. Alternatively, you can try to use the Double-Buffer DMA mode.

JW

Thank you for the quick response!

Your answer helped me solve the problem with my current szenario. It did show me that I have to change some concept in our main project, since we are not fast enaugh to load all the data in the interrupt itself.

Cheers!