cancel
Showing results for 
Search instead for 
Did you mean: 

How do I use HAL_SPI_Receive_DMA in conjunction with a receive buffer on the stack and caching enabled?

arnold_w
Senior

I am working with the STM32F760I-EVAL board and caching (SCB_EnableICache() and SCB_EnableDCache() are called) and MPU (MPU_Config() is called) are enabled. I am using DMA with SPI and if I transmit data, HAL_SPI_Transmit_DMA, I need to call SCB_CleanDCache() to see any MOSI-data on the oscilloscope. What if want to receive data using HAL_SPI_TransmitReceive_DMA, what function do I need to call and at what point? I tried calling SCB_InvalidateDCache() when my receive is finished, but I then got stuck in an infinite loop inside SCB_InvalidateDCache():

  do {

   ways = (uint32_t)(CCSIDR_WAYS(ccsidr));

   do {

    SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |

           ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) );

    #if defined ( __CC_ARM )

     __schedule_barrier();

    #endif

   } while (ways--);

I'm aware that I could use fixed buffers allocated within TCMRAM to avoid the caching problems, but I would like to use buffers on the stack for the SPI and I don't see how I can make my stack buffers appear in TCMRAM. Can someone please help me?

1 ACCEPTED SOLUTION

Accepted Solutions

SCB_InvalidateDCache() has a lot of nasty side-effects, use the ByAddr variant and limit it's scope to the buffer in question. It works on 32-byte aligned addresses.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

4 REPLIES 4

SCB_InvalidateDCache() has a lot of nasty side-effects, use the ByAddr variant and limit it's scope to the buffer in question. It works on 32-byte aligned addresses.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
David Littell
Senior III

Make sure your receive buffer is aligned and sized to a 32-byte boundary and call SCB_InvalidateDCache_by_Addr() before accessing the receive buffer after the DMA completes.

arnold_w
Senior

Thanks, it works great with SCB_InvalidateDCache_by_Addr().

Just as a side note, strangely I had to call SCB_CleanDCache (line 2 below) before my call to HAL_SPI_Receive_DMA. If I remove line 2, then line 32 would be called forever as if someone had put an invisible while(TRUE)-loop around line 32!?!?! By the way, the code (you may have to click "Show More" to see it) is for the built-in STM bootloader SPI protocol.

static void SPI_BL_Rx(uint8_t *pRxData32bitAligned, uint16_t Size) {
    SCB_CleanDCache();
    setNssLow();
    SPI_DMA_InProgress = TRUE;
    HAL_SPI_Receive_DMA(hspi, pRxData32bitAligned, Size);
    while (SPI_DMA_InProgress) {}
    setNssHigh();
    SCB_InvalidateDCache_by_Addr((uint32_t*)pRxData32bitAligned, Size);
}
 
Bool_t BL_GetIDCmd(uint16_t* idCmd) {
    uint8_t cmdSeq[3];
    uint32_t rxNumberOfBytes32bitAligned = 0;
    uint8_t* rxNumberOfBytes = (uint8_t*)&rxNumberOfBytes32bitAligned;
    uint8_t ***** = 0x00;
    uint32_t rxBuffer32bitAligned = 0;
    uint8_t* rxBuffer = (uint8_t*)&rxBuffer32bitAligned;
 
    /* Send start of frame (0x5A) + Get ID command frame (0x02 0xFD) */
    cmdSeq[0] = BL_SPI_SOF;
    cmdSeq[1] = GET_ID_COMMAND;
    cmdSeq[2] = GET_ID_COMMAND ^ 0xFF;
    SPI_BL_Tx(cmdSeq, 0x3);
 
    /* Wait for ACK or NACK frame */
    if (waitForAck(DEFAULT_WAIT_FOR_ACK_TIMEOUT_MS) == FALSE) {
        return FALSE;
    }
 
    /* Receive data frame */
    SPI_BL_Tx(&*****, 0x1); /*!< Send ***** */
    SPI_BL_Rx(rxNumberOfBytes, 0x1);
    if (*rxNumberOfBytes > 2) {
        return FALSE;
    }
    SPI_BL_Rx(rxBuffer,(uint16_t) *rxNumberOfBytes + 0x1);
 
    /* received Byte #0 is ID MSB and received Byte #1 is ID LSB */
    *idCmd = (((uint16_t) rxBuffer[0]) << 8) | (rxBuffer[1]);
 
    /* Wait for ACK or NACK frame */
    return waitForAck(DEFAULT_WAIT_FOR_ACK_TIMEOUT_MS);
}

Amel NASRI
ST Employee

If this may bring some help: https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices. It concerns STM32H7, but should be valid for STM32F7 as well.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.