ST意法半导体
直播中

萧蔼晨

7年用户 989经验值
私信 关注
[问答]

使用STM32H743ZI和KEIL uVision CMSIS驱动程序,SPI/DMA/D-缓存问题求解

你好
我对 SPI 与 DMA 和 D-Cache 的结合感到困惑。
我正在使用 STM32H743ZI 和 KEIL uVision CMSIS 驱动程序。
在我看来,CMSIS 驱动程序有一个弱点。如果长度是 32 的倍数,它仅通过 HAL_SPI_TransmitReceive_DMA() 发送数据。否则它通过 HAL_SPI_TransmitReceive_IT() 发送数据。都是在D-Cache开启的情况下。
这是来自驱动程序的代码片段。
  • 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);
  •   }
  • }
这就是为什么我也联系了 Keil 的支持。在我看来,通过 SPI 只能发送 32 的倍数的数据量是没有意义的。
但是KEIL反复告诉我不能用DMA和D-Cache通过SPI发送长度不等于32的倍数的数据!
在我看来,我可以通过以下方式做到这一点:
定义 TX 和 RX 缓冲区:
  • 尺寸(size)是32的倍数。
  • 分配给 32 字节地址。
  • 链接到相应的 DMA/RAM 区域。
将 TX 数据复制到 TX 缓冲区。字节数 ( num ) 必须小于或等于缓冲区大小 ( size )。
SCB_CleanDCache_by_Addr ((uint32_t *)((uint32_t)txBuffer), (int32_t)(大小));
HAL_SPI_TransmitReceive_DMA( ...txBuffer, rxBuffer, num );
我也测试过,它似乎有效。
我错过了什么吗?








回帖(1)

李斌

2023-1-10 14:15:03
您可以发送未与缓存边界对齐的数据。他们可能试图阻止您在需要清理页面的一部分并使另一部分无效的情况下导致缓存出现问题,这当然是不可能的。
如果他们让你做你想做的事,那么调用 SCB_CleanDCache_by_Addr 最终会导致某人的程序出现问题,他们将不得不为这种情况提供支持。防止这种情况发生似乎是一个不错的决定。HAL 驱动程序没有这样的限制,但需要用户注意缓存问题,这经常会导致混淆。
您始终可以编写自己的驱动程序。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分