硬汉嵌入式论坛

 找回密码
 立即注册
查看: 8631|回复: 22
收起左侧

[Cache] STM32H7使用函数SCB_InvalidateDCache_by_Addr,SCB_CleanDCache_by_Addr等函数注意事项

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
发表于 2018-11-3 02:08:00 | 显示全部楼层 |阅读模式
特别注意下面这三个函数的形参addr和dsize:

addr : 操作的地址一定要是32字节对齐的。

dsize :一定要是32字节的整数倍


  1. /**
  2.   \brief   D-Cache Invalidate by address
  3.   \details Invalidates D-Cache for the given address
  4.   \param[in]   addr    address (aligned to 32-byte boundary)
  5.   \param[in]   dsize   size of memory block (in number of bytes)
  6. */
  7. __STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
  8. {
  9.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
  10.      int32_t op_size = dsize;
  11.     uint32_t op_addr = (uint32_t)addr;
  12.      int32_t linesize = 32;                /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

  13.     __DSB();

  14.     while (op_size > 0) {
  15.       SCB->DCIMVAC = op_addr;
  16.       op_addr += (uint32_t)linesize;
  17.       op_size -=           linesize;
  18.     }

  19.     __DSB();
  20.     __ISB();
  21.   #endif
  22. }


  23. /**
  24.   \brief   D-Cache Clean by address
  25.   \details Cleans D-Cache for the given address
  26.   \param[in]   addr    address (aligned to 32-byte boundary)
  27.   \param[in]   dsize   size of memory block (in number of bytes)
  28. */
  29. __STATIC_INLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize)
  30. {
  31.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
  32.      int32_t op_size = dsize;
  33.     uint32_t op_addr = (uint32_t) addr;
  34.      int32_t linesize = 32;                /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

  35.     __DSB();

  36.     while (op_size > 0) {
  37.       SCB->DCCMVAC = op_addr;
  38.       op_addr += (uint32_t)linesize;
  39.       op_size -=           linesize;
  40.     }

  41.     __DSB();
  42.     __ISB();
  43.   #endif
  44. }


  45. /**
  46.   \brief   D-Cache Clean and Invalidate by address
  47.   \details Cleans and invalidates D_Cache for the given address
  48.   \param[in]   addr    address (aligned to 32-byte boundary)
  49.   \param[in]   dsize   size of memory block (in number of bytes)
  50. */
  51. __STATIC_INLINE void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
  52. {
  53.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
  54.      int32_t op_size = dsize;
  55.     uint32_t op_addr = (uint32_t) addr;
  56.      int32_t linesize = 32;                /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

  57.     __DSB();

  58.     while (op_size > 0) {
  59.       SCB->DCCIMVAC = op_addr;
  60.       op_addr += (uint32_t)linesize;
  61.       op_size -=           linesize;
  62.     }

  63.     __DSB();
  64.     __ISB();
  65.   #endif
  66. }
复制代码



评分

参与人数 1金币 +20 收起 理由
yunqi + 20 赞一个!

查看全部评分

回复

使用道具 举报

36

主题

2039

回帖

2147

积分

至尊会员

积分
2147
发表于 2018-11-3 09:45:00 | 显示全部楼层
dsize :一定要是32字节的整数倍


这条要求,貌似从来没有注意过,现在是不管什么大小都往里面填
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

32

主题

262

回帖

363

积分

高级会员

积分
363
发表于 2018-11-3 09:52:50 | 显示全部楼层
文档里写了cache是32字节对齐的,之前确实有时候用有时候没用,偶尔就会出点问题
回复

使用道具 举报

609

主题

3049

回帖

4896

积分

至尊会员

积分
4896
发表于 2018-11-3 11:10:32 | 显示全部楼层
研究越来越透彻了啊,之前只主要地址是 32对齐,数据大小还没有怎么注意过啊,看来以后也得多多注意才行
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2018-11-10 01:27:00 | 显示全部楼层
这个问题要特别引起注意。
回复

使用道具 举报

4

主题

42

回帖

54

积分

初级会员

积分
54
发表于 2020-9-3 14:32:19 | 显示全部楼层
Solution example 3: Use Cache maintenance functions
Transmitting data:
  1. #define TX_LENGTH  (16)
  2. uint8_t tx_buffer[TX_LENGTH];

  3. /* Write data */
  4. tx_buffer[0] = 0x0;
  5. tx_buffer[1] = 0x1;

  6. /* Clean D-cache */
  7. /* Make sure the address is 32-byte aligned and add 32-bytes to length, in case it overlaps cacheline */
  8. SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)tx_buffer) & ~(uint32_t)0x1F), TX_LENGTH+32);

  9. /* Start DMA transfer */
  10. HAL_UART_Transmit_DMA(&huart1, tx_buffer, TX_LENGTH);
复制代码
Receiving data:
  1. #define RX_LENGTH  (16)
  2. uint8_t rx_buffer[RX_LENGTH];

  3. /* Invalidate D-cache before reception */
  4. /* Make sure the address is 32-byte aligned and add 32-bytes to length, in case it overlaps cacheline */
  5. SCB_InvalidateDCache_by_Addr((uint32_t*)(((uint32_t)rx_buffer) & ~(uint32_t)0x1F), RX_LENGTH+32);

  6. /* Start DMA transfer */
  7. HAL_UART_Receive_DMA(&huart1, rx_buffer, RX_LENGTH);
  8. /* No access to rx_buffer should be made before DMA transfer is completed */
复制代码
Please note that in case of reception there can be problem if rx_buffer is not aligned to the size of cache-line (32-bytes), because during the invalidate operation another data sharing the same cache-line(s)  with rx_buffer can be lost.

参考文献:
https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2020-9-3 15:26:27 | 显示全部楼层
la9998372 发表于 2020-9-3 14:32
Solution example 3: Use Cache maintenance functionsTransmitting data:Receiving datalease note that ...

除了你帖的这个,还要注意H7的串口DMA有个硬件bug,务必要使用最新的HAL库
  1.     /* Work around for Errata 2.22: UART/USART- DMA transfer lock: DMA stream could be
  2.                                     lock when transfering data to/from USART/UART */
  3. #if (STM32H7_DEV_ID == 0x450UL)
  4.     if((DBGMCU->IDCODE & 0xFFFF0000U) >= 0x20000000U)
  5.     {
  6. #endif /* STM32H7_DEV_ID == 0x450UL */
  7.       if(IS_DMA_UART_USART_REQUEST(hdma->Init.Request) != 0U)
  8.       {
  9.         registerValue |= DMA_SxCR_TRBUFF;
  10.       }
  11. #if (STM32H7_DEV_ID == 0x450UL)
  12.     }
  13. #endif /* STM32H7_DEV_ID == 0x450UL */
复制代码


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2020-9-3 15:28:54 | 显示全部楼层
la9998372 发表于 2020-9-3 14:32
Solution example 3: Use Cache maintenance functionsTransmitting data:Receiving datalease note that ...

另外他这个接收数据回复有问题,应该是DMA接收后做无效化而不是DMA接收前作无效化。他们这个文章这部分有问题,应该给他们提出下。
回复

使用道具 举报

4

主题

42

回帖

54

积分

初级会员

积分
54
发表于 2020-9-6 21:34:02 | 显示全部楼层
eric2013 发表于 2020-9-3 15:28
另外他这个接收数据回复有问题,应该是DMA接收后做无效化而不是DMA接收前作无效化。他们这个文章这部分有 ...

是不是就是说,DMA接收完一帧数据之后,需要进行数据解析之前,进行Cache无效话处理?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2020-9-7 03:25:19 | 显示全部楼层
la9998372 发表于 2020-9-6 21:34
是不是就是说,DMA接收完一帧数据之后,需要进行数据解析之前,进行Cache无效话处理?

对,一般是这样的。
回复

使用道具 举报

1

主题

12

回帖

15

积分

新手上路

积分
15
发表于 2021-12-14 15:53:06 | 显示全部楼层
本帖最后由 zhoudn 于 2021-12-14 16:02 编辑

E:\123.pngV5.1.1版core_cm7.h文件好像已经对dsize做了字节对齐操作
123.png
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2021-12-14 16:19:23 | 显示全部楼层
zhoudn 发表于 2021-12-14 15:53
V5.1.1版core_cm7.h文件好像已经对dsize做了字节对齐操作

修改了好,更规范了。
回复

使用道具 举报

1

主题

12

回帖

15

积分

新手上路

积分
15
发表于 2021-12-16 11:39:04 | 显示全部楼层
eric2013 发表于 2021-12-14 16:19
修改了好,更规范了。

搞不清楚为啥既然采用do..while形式对dsize做了32字节对齐,但是op_addr地址32字节对齐却注释掉了?
回复

使用道具 举报

1

主题

12

回帖

15

积分

新手上路

积分
15
发表于 2021-12-16 11:54:16 | 显示全部楼层
eric2013 发表于 2021-12-14 16:19
修改了好,更规范了。

这句话是不是说SCB->DCCIMVAC寄存器仅31-5位是有效的,本身已经强制32位对齐了,那以后是不是可以直接传入地址和数据了,不需要再对地址和数据进行32位对齐了,我在编程手册上也没找到对DCCIMVAC寄存器的详细描述
1639626559(1).png
回复

使用道具 举报

5

主题

61

回帖

76

积分

初级会员

积分
76
发表于 2021-12-21 13:17:22 | 显示全部楼层
谁知道 这个 SCB_InvalidateDCache_by_Addr  和 SCB_CleanInvalidateDCache_by_Addr    这个两个的区别是什么
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2021-12-22 09:17:51 | 显示全部楼层
zhoudn 发表于 2021-12-16 11:54
这句话是不是说SCB->DCCIMVAC寄存器仅31-5位是有效的,本身已经强制32位对齐了,那以后是不是可以直接传 ...

他这个的设置来的,还不够全面,最好按照楼主位的再设置下。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2021-12-22 09:20:38 | 显示全部楼层
dghwjh 发表于 2021-12-21 13:17
谁知道 这个 SCB_InvalidateDCache_by_Addr  和 SCB_CleanInvalidateDCache_by_Addr    这个两个的区别是什 ...

SCB_CleanInvalidateDCache_by_Add比SCB_InvalidateDCache_by_Addr多了Clean操作,Clean操作的含义是将Cache里面的新内容刷到实际存储器中。
回复

使用道具 举报

9

主题

51

回帖

78

积分

初级会员

积分
78
发表于 2024-1-30 18:46:08 | 显示全部楼层
如果dsize没有32字节对齐,是不是会出现将变量前面或者后面的数据也刷掉,改变前后变量的值
回复

使用道具 举报

9

主题

51

回帖

78

积分

初级会员

积分
78
发表于 2024-1-30 18:46:53 | 显示全部楼层
addr:我看到STM32代码好像也是有自动向前对齐这个操作,哎。。。。
回复

使用道具 举报

9

主题

51

回帖

78

积分

初级会员

积分
78
发表于 2024-1-30 18:54:07 | 显示全部楼层
eric2013 发表于 2018-11-10 01:27
这个问题要特别引起注意。


1706611967469.png
我们HAL库版本不一样?实际使用发现这玩意有bug,感谢向前偏移会导致数据刷新错误
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2024-1-31 00:43:03 | 显示全部楼层
嵌入式菜鸟^_^ 发表于 2024-1-30 18:46
如果dsize没有32字节对齐,是不是会出现将变量前面或者后面的数据也刷掉,改变前后变量的值

如果不能保证整数倍和对齐,不要使用这个函数控制。
回复

使用道具 举报

9

主题

51

回帖

78

积分

初级会员

积分
78
发表于 2024-1-31 09:39:17 | 显示全部楼层
eric2013 发表于 2024-1-31 00:43
如果不能保证整数倍和对齐,不要使用这个函数控制。

求教一下哪使用什么函数比较好
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2024-1-31 10:23:34 | 显示全部楼层
嵌入式菜鸟^_^ 发表于 2024-1-31 09:39
求教一下哪使用什么函数比较好

函数SCB_InvalidateDCache或者SCB_CleanInvalidateDCache
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-29 23:23 , Processed in 0.395659 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表