1. 问题

STM32H743开启D-cache以后,如果使用DMA会导致数据错乱。

2. 原因

DMA访问的是RAM, 实际的数据可能还在D-cache中,没有与RAM同步。

3. 解决方法

3.1 使用前同步

  • DMA发送前将cache中的数据写会RAM
SCB_CleanDCache_by_Addr()
  • DMA接收数据后,cache获取RMA的数据
SCB_InvalidateDCache_by_Addr()
  • 详情
//用于将 D-Cache 数据回写到 SRAM 里面
SCB_CleanDCache_by_Addr((uint32_t *)buf, len);

//用于重新从 SRAM 获取数据, 丢弃 D-Cache 当前数据,
SCB_InvalidateDCache_by_Addr((uint32_t *)buf, len);

//写回数据到 SRAM, 并重新获取 D-Cache数据
SCB_CleanInvalidateDCache_by_Addr((uint32_t *)buf, len);

3.2 MPU方式(推荐)

在这里插入图片描述

  • 通过MPU关闭一块SRAM的Cache功能

    • 例如:以0x30000000为首地址的128K(SRAM1)
    • 为什么不用0x24000000(AXI SRAM)这一块?因为这块ram的速度快,关闭Cache太浪费。
    • 在这里插入图片描述
  • DMA使用到的内存需要定义到关闭Cache的内存范围内

步骤

1. 开启MPU并设置
void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x30000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_HFNMI_PRIVDEF);

}
2. Keil工程设置Linker

在这里插入图片描述

3 STM32H743_DMA.sct
; STM32H743IITx
; Flash 2MB
; AXI SRAM(D1) 512KB
; SRAM1+SRAM2+SRAM3(D2) 288KB

LR_IROM1 0x08000000 0x00200000
{
    ER_IROM1 0x08000000 0x00200000
    {
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
    }

    ; 普通RW/ZI变量
    RW_RAM_D1 0x24000000 0x00080000
    {
        .ANY (+RW +ZI)
    }

    ; DMA专用区域
    RW_DMA 0x30000000 0x00048000
    {
        *(.dma_buffer)
    }
}
4. 使用
#define __DMA_RAM \
    __attribute__((section(".dma_buffer"))) \
    __attribute__((aligned(32)))

//注意,这里buf需要是全局变量或static变量
__DMA_RAM uint8_t buf[512] = {0};	//buf在0x30000000 sram段

3.3 D-Cache 的透写模式

  • 缺点: 会损失一些性能,因为每次都要从从Cache写会数据。
/**
* @brief 使能 STM32H7 的 L1-Cache, 同时开启 D cache 的强制透写
* @param 无
* @retval 无
*/
void sys_cache_enable(void)
{
	 SCB_EnableICache(); /* 使能 I-Cache,函数在 core_cm7.h 里面定义 */
	 SCB_EnableDCache(); /* 使能 D-Cache,函数在 core_cm7.h 里面定义 */
	 SCB->CACR |= 1 << 2; /* 强制 D-Cache 透写,如不开启透写,实际使用中可能遇到各种问题 */
}
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐