cancel
Showing results for 
Search instead for 
Did you mean: 

SPI / DMA / D-Cache

jakob.brunhart
Associate III

Hello

I'm confused about SPI in combination with DMA and D-Cache.

I'm using the STM32H743ZI and KEIL uVision CMSIS Driver.

In my opinion, the CMSIS driver has a weak point. It only sends data by HAL_SPI_TransmitReceive_DMA() if length is a multiple of 32. Otherwise it sends data by HAL_SPI_TransmitReceive_IT(). All under the condition that the D-Cache is enabled.

This is the code snippet from the driver.

static int32_t SPI_Transfer (const void *data_out, void *data_in, uint32_t num, const SPI_RESOURCES *spi) 
{
 
...
 
  spi->xfer->dma_flag = 0U;
  if (spi->dma_use == SPI_DMA_USE_TX_RX) {
#if (__DCACHE_PRESENT == 1U)
    // Is DChache enabled
    if ((SCB->CCR & SCB_CCR_DC_Msk) != 0U) {
      if ((((uint32_t)data_out & 0x1FU) == 0) &&
          (((uint32_t)data_in  & 0x1FU) == 0) &&
            ((num & 0x1FU) == 0)) {
        // Data is 32Byte aligned and size is n *32 -> DMA can be used
        spi->xfer->dma_flag = 1U;
        SCB_CleanDCache_by_Addr ((uint32_t *)((uint32_t)data_out), (int32_t)(num  * spi->xfer->dataSize));
      }
    } else {
      spi->xfer->dma_flag = 1U;
    }
#else
    spi->xfer->dma_flag = 1U;
#endif
  }
 
#ifdef __SPI_DMA
  if (spi->xfer->dma_flag != 0U) {
    // DMA mode
    stat = HAL_SPI_TransmitReceive_DMA (spi->h, (uint8_t *)(uint32_t)data_out, (uint8_t *)(uint32_t)data_in, (uint16_t)num);
  } else
#endif
  {
    // Interrupt mode
    stat = HAL_SPI_TransmitReceive_IT (spi->h, (uint8_t *)(uint32_t)data_out, (uint8_t *)(uint32_t)data_in, (uint16_t)num);
  }
}

That is why I have also contacted the support of Keil. From my point of view it makes no sense to be able to send only a data quantity of a multiple of 32 via SPI.

But KEIL tells me for the repeated time that it is not possible to send data over SPI with DMA and D-Cache whose length is unequal a multiple of 32!

In my opinion I can do that in the following maner:

Define TX and RX Buffer:

  1. Size (size) is a multiple of 32.
  2. Alligned to 32 Byte address.
  3. linked to the corresponding DMA / RAM region.

Copy TX Data to TX Buffer. Number of Bytes (num) must be less or equal to the Buffer Size (size).

SCB_CleanDCache_by_Addr ((uint32_t *)((uint32_t)txBuffer), (int32_t)(size));

HAL_SPI_TransmitReceive_DMA( ...txBuffer, rxBuffer, num );

I have also tested and it seems to work.

Am I missing something? 

Thank you

Regards.

Jakob

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

You can send data that isn't aligned to cache boundaries. They may be trying to prevent you from causing issues with the cache where you need to clean one part of the page and invalidate the other, which of course is not possible.

If they let you do what you want, the call to SCB_CleanDCache_by_Addr would cause a problem in someone's program, eventually, and they would have to provide support for that case. Preventing that from happening seems like a fine decision. The HAL driver doesn't have such a restriction but requires the user to be aware of cache issues, which causes confusion regularly.

You can always write your own driver.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

2 REPLIES 2
TDK
Guru

You can send data that isn't aligned to cache boundaries. They may be trying to prevent you from causing issues with the cache where you need to clean one part of the page and invalidate the other, which of course is not possible.

If they let you do what you want, the call to SCB_CleanDCache_by_Addr would cause a problem in someone's program, eventually, and they would have to provide support for that case. Preventing that from happening seems like a fine decision. The HAL driver doesn't have such a restriction but requires the user to be aware of cache issues, which causes confusion regularly.

You can always write your own driver.

If you feel a post has answered your question, please click "Accept as Solution".
jakob.brunhart
Associate III

Thank you for your response.

Regards

Jakob