SPI / DMA / D-Cache
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:
- Size (size) is a multiple of 32.
- Alligned to 32 Byte address.
- 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
