发新帖本帖赏金 1.00元(功能说明)我要提问
返回列表
[STM32F7]

关于STM32F7开启L1-cache导致DMA数据不更新的问题

[复制链接]
7329|9
手机看帖
扫描二维码
随时随地手机跟帖
sonicll|  楼主 | 2017-10-16 15:16 | 显示全部楼层 |阅读模式
本帖最后由 sonicll 于 2017-10-17 14:39 编辑

今天发现了一个关于开启F7 L1-cache导致DMA数据不更新的问题,电路板使用的是正点原子的apollo开发板,核心板是STM32F767IGT6,程序代码非常简单,使用cubeMX生成代码,开启USART1,使能DMA收发,循环发送指定的字符串,代码如下:

char DataBuffer[64] = {"1234567\r\n"};

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* Enable I-Cache-------------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache-------------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
            
        sprintf(DataBuffer, "ABCDEFG\r\n");
            
        while(huart1.gState != HAL_UART_STATE_READY);        
        HAL_UART_Transmit_DMA(&huart1, (uint8_t *)DataBuffer, strlen(DataBuffer));         
         
        HAL_Delay(200);
         
  }
  /* USER CODE END 3 */

}


运行结果是USART1循环发送1234567,而不是ABCDEFG。仿真状态下单步调试,能看到DataBuffer里的数据是ABCDEFG,但是实际发送的却是初始值1234567。只要把前面开启D-cache的语句屏蔽掉,运行结果就能正常发送ABCDEFG。看起来似乎是D-cache缓存了DataBuffer的初始值,但是没有按照sprintf语句更新数据。请手头上有F7板子的朋友测试一下,看看是不是这样?如果测试结果确实是这样,应该怎么操作才能既开启cache,又能正常更新数据呢?

编译环境是MDK5.22,代码优化等级为0

刚才又测试了一下,似乎和内存地址有关系,如果程序默认内存地址设置为0x20020000开始,即运行于SRAM1,才会出现这种现象。如果默认内存地址为0x20000000开始,即运行于DTCM,结果是正常的,开启D-cache也不会有问题。这下晕了,求高手解答





aozima| | 2017-10-16 16:13 | 显示全部楼层
楼主检查一下默认的cache属性,如果是write-back,需要手动clean才能保证写入内存。

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
sonicll + 3 很给力!
aozima| | 2017-10-16 16:19 | 显示全部楼层
另外留意一下总线矩阵,DMA并不连接到DTCM上面,所以程序有数据在DTCM上面时,做DMA需要另外copy到与DMA相通的SRAM中去才行。

使用特权

评论回复

打赏榜单

feelhyq 打赏了 1.00 元 2017-10-16
理由:分析得到位

feelhyq| | 2017-10-16 16:43 | 显示全部楼层
本帖最后由 feelhyq 于 2017-10-16 17:11 编辑
aozima 发表于 2017-10-16 16:19
另外留意一下总线矩阵,DMA并不连接到DTCM上面,所以程序有数据在DTCM上面时,做DMA需要另外copy到与DMA相 ...

如果DMA不连接到DTCM,去做DMA操作,DMA的错误寄存器会有错误状态标志的。就像Memory to Memory  DMA1不行   DMA2行

使用特权

评论回复
aozima| | 2017-10-16 17:09 | 显示全部楼层
哈,还有打赏

这个打赏可以怎么用

使用特权

评论回复
sonicll|  楼主 | 2017-10-16 17:23 | 显示全部楼层
aozima 发表于 2017-10-16 16:13
楼主检查一下默认的cache属性,如果是write-back,需要手动clean才能保证写入内存。 ...

我试着在sprintf语句之前增加了一条
SCB_CleanDCache();
运行结果确实正常了

另外留意一下总线矩阵,DMA并不连接到DTCM上面,所以程序有数据在DTCM上面时,做DMA需要另外copy到与DMA相通的SRAM中去才行。
F7手册上的总线矩阵图,DTCM确实没有与DMA连接,但是ST官方HAL库里的例子,MDK的内存地址设置,是把DTCM和SRAM1、SRAM2合并在一起使用的,由于代码本身内存占用很低,实际使用的就是DTCM,而官方的UART DMA例子也没有做额外的数据copy操作,就是直接使用;我上面的例子,运行于DTCM也是正常的,运行于SRAM1反而有问题,还要手动clean D-cache,这样似乎与矩阵图矛盾...

使用特权

评论回复
aozima| | 2017-10-16 17:52 | 显示全部楼层
SCB_CleanDCache();
是刷新所有的cache,如果只需要刷新一部分数据的话,可以使用
SCB_CleanDCache_by_Addr
F7 的 cache_line 是 32字节。

进一下深入
用做DMA的buffer不光要满足DMA要求的4字节对齐
还需要满足cache line 的32字节对齐。
当有多个外设同时使用DMA时,刷新时不能全刷,只能刷需要的那一小块。
不然其它人的数据就不正确了。

使用DMA从外设读取数据时,对应的是
SCB_CleanDCache();
SCB_InvalidateDCache_by_Addr

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
sonicll + 3 很给力!
sonicll|  楼主 | 2017-10-16 17:56 | 显示全部楼层
aozima 发表于 2017-10-16 16:19
另外留意一下总线矩阵,DMA并不连接到DTCM上面,所以程序有数据在DTCM上面时,做DMA需要另外copy到与DMA相 ...

ST的英文论坛有一篇帖子,ST的工作人员说DTCM可以使用DMA
https://community.st.com/message/83334

然后ST有一份笔记AN4839,里面有一段关于SRAM1和cache数据一致性的使用指导:

The data coherency between the core and the DMA is ensured by:
1. Either making the SRAM1 buffers not cacheable
2. Or making the SRAM1 buffers cache enabled with write-back policy, with thecoherency ensured by software (clean or invalidate D-Cache)
3. Or modifying the SRAM1 region in the MPU attribute to a shared region.
4. Or making the SRAM1 buffers cache enabled with write-through policy.

这样看来,DMA如果使用了SRAM1,要么就不使用D-cache,要使用D-cache就要手动clean,或者设置为write-through

使用特权

评论回复
sonicll|  楼主 | 2017-10-17 14:35 | 显示全部楼层
这里还有一个帖子,使用SPI DMA的,也是DMA收发地址定位在DTCM里正常工作,DMA收发地址定位在SRAM里数据不更新。下面有人回复也是要手动操作cache或者不使用cache
https://community.st.com/message/89922

使用特权

评论回复
zchong| | 2018-4-5 22:04 | 显示全部楼层
F7和H7的DMA是连接到DTCM,F4的是不连接的

使用特权

评论回复
发新帖 本帖赏金 1.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

883

帖子

3

粉丝