2021-01-07 07:28 AM
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:
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
Solved! Go to Solution.
2021-01-07 09:44 AM
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.
2021-01-07 09:44 AM
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.
2021-01-07 10:04 PM
Thank you for your response.
Regards
Jakob