SPI DMA Circular Buffer weird bitflips
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-12 2:16 AM
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
Solved! Go to Solution.
- Labels:
-
DMA
-
SPI
-
STM32G4 Series
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-12 4:03 AM
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-12 4:03 AM
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-12 4:39 AM
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!
