eric2013 发表于 2018-11-3 02:08:00

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

特别注意下面这三个函数的形参addr和dsize:

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

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

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

    __DSB();

    while (op_size > 0) {
      SCB->DCIMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=         linesize;
    }

    __DSB();
    __ISB();
#endif
}


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

    __DSB();

    while (op_size > 0) {
      SCB->DCCMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=         linesize;
    }

    __DSB();
    __ISB();
#endif
}


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

    __DSB();

    while (op_size > 0) {
      SCB->DCCIMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=         linesize;
    }

    __DSB();
    __ISB();
#endif
}



byccc 发表于 2018-11-3 09:45:00

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

这条要求,貌似从来没有注意过,现在是不管什么大小都往里面填

在水一方 发表于 2018-11-3 09:52:50

文档里写了cache是32字节对齐的,之前确实有时候用有时候没用{:18:},偶尔就会出点问题

hpdell 发表于 2018-11-3 11:10:32

研究越来越透彻了啊,之前只主要地址是 32对齐,数据大小还没有怎么注意过啊,看来以后也得多多注意才行

eric2013 发表于 2018-11-10 01:27:00

这个问题要特别引起注意。

la9998372 发表于 2020-9-3 14:32:19

Solution example 3: Use Cache maintenance functionsTransmitting data:#define TX_LENGTH(16)
uint8_t tx_buffer;

/* Write data */
tx_buffer = 0x0;
tx_buffer = 0x1;

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

/* Start DMA transfer */
HAL_UART_Transmit_DMA(&huart1, tx_buffer, TX_LENGTH);Receiving data:#define RX_LENGTH(16)
uint8_t rx_buffer;

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

/* Start DMA transfer */
HAL_UART_Receive_DMA(&huart1, rx_buffer, RX_LENGTH);
/* 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

eric2013 发表于 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库
    /* Work around for Errata 2.22: UART/USART- DMA transfer lock: DMA stream could be
                                    lock when transfering data to/from USART/UART */
#if (STM32H7_DEV_ID == 0x450UL)
    if((DBGMCU->IDCODE & 0xFFFF0000U) >= 0x20000000U)
    {
#endif /* STM32H7_DEV_ID == 0x450UL */
      if(IS_DMA_UART_USART_REQUEST(hdma->Init.Request) != 0U)
      {
      registerValue |= DMA_SxCR_TRBUFF;
      }
#if (STM32H7_DEV_ID == 0x450UL)
    }
#endif /* STM32H7_DEV_ID == 0x450UL */

eric2013 发表于 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接收前作无效化。他们这个文章这部分有问题,应该给他们提出下。

la9998372 发表于 2020-9-6 21:34:02

eric2013 发表于 2020-9-3 15:28
另外他这个接收数据回复有问题,应该是DMA接收后做无效化而不是DMA接收前作无效化。他们这个文章这部分有 ...

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

eric2013 发表于 2020-9-7 03:25:19

la9998372 发表于 2020-9-6 21:34
是不是就是说,DMA接收完一帧数据之后,需要进行数据解析之前,进行Cache无效话处理?

对,一般是这样的。

zhoudn 发表于 2021-12-14 15:53:06

本帖最后由 zhoudn 于 2021-12-14 16:02 编辑

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

eric2013 发表于 2021-12-14 16:19:23

zhoudn 发表于 2021-12-14 15:53
V5.1.1版core_cm7.h文件好像已经对dsize做了字节对齐操作

修改了好,更规范了。

zhoudn 发表于 2021-12-16 11:39:04

eric2013 发表于 2021-12-14 16:19
修改了好,更规范了。

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

zhoudn 发表于 2021-12-16 11:54:16

eric2013 发表于 2021-12-14 16:19
修改了好,更规范了。

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

dghwjh 发表于 2021-12-21 13:17:22

谁知道 这个 SCB_InvalidateDCache_by_Addr和 SCB_CleanInvalidateDCache_by_Addr    这个两个的区别是什么

eric2013 发表于 2021-12-22 09:17:51

zhoudn 发表于 2021-12-16 11:54
这句话是不是说SCB->DCCIMVAC寄存器仅31-5位是有效的,本身已经强制32位对齐了,那以后是不是可以直接传 ...

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

eric2013 发表于 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里面的新内容刷到实际存储器中。

嵌入式菜鸟^_^ 发表于 2024-1-30 18:46:08

如果dsize没有32字节对齐,是不是会出现将变量前面或者后面的数据也刷掉,改变前后变量的值

嵌入式菜鸟^_^ 发表于 2024-1-30 18:46:53

addr:我看到STM32代码好像也是有自动向前对齐这个操作,哎。。。。

嵌入式菜鸟^_^ 发表于 2024-1-30 18:54:07

eric2013 发表于 2018-11-10 01:27
这个问题要特别引起注意。



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

eric2013 发表于 2024-1-31 00:43:03

嵌入式菜鸟^_^ 发表于 2024-1-30 18:46
如果dsize没有32字节对齐,是不是会出现将变量前面或者后面的数据也刷掉,改变前后变量的值

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

嵌入式菜鸟^_^ 发表于 2024-1-31 09:39:17

eric2013 发表于 2024-1-31 00:43
如果不能保证整数倍和对齐,不要使用这个函数控制。

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

eric2013 发表于 2024-1-31 10:23:34

嵌入式菜鸟^_^ 发表于 2024-1-31 09:39
求教一下哪使用什么函数比较好

函数SCB_InvalidateDCache或者SCB_CleanInvalidateDCache
页: [1]
查看完整版本: STM32H7使用函数SCB_InvalidateDCache_by_Addr,SCB_CleanDCache_by_Addr等函数注意事项