rt-thread stm32h7 dma cache mpu 缓存一致性

  1. 本文以串口dma为例,发送和接收都设计到一致性问题
  2. mpu配置,只有mpu配置好后,才能使用缓存策略提升性能,特别是对外部sdram速度提升很高
int mpu_init(void)
{
    MPU_Region_InitTypeDef MPU_InitStruct;

    /* Disable the MPU */
    HAL_MPU_Disable();

    /* Configure the MPU attributes as WT for AXI SRAM */
    MPU_InitStruct.Enable            = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress       = 0x24000000;
    MPU_InitStruct.Size              = MPU_REGION_SIZE_512KB;
    MPU_InitStruct.AccessPermission  = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable      = MPU_ACCESS_NOT_BUFFERABLE;      // MPU_ACCESS_BUFFERABLE   MPU_ACCESS_NOT_BUFFERABLE
    MPU_InitStruct.IsCacheable       = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable       = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number            = MPU_REGION_NUMBER6;
    MPU_InitStruct.TypeExtField      = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable  = 0X00;
    MPU_InitStruct.DisableExec       = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);


//#undef BSP_USING_SDRAM
#ifdef BSP_USING_SDRAM
    /* Configure the MPU attributes as WT for SDRAM */
    MPU_InitStruct.Enable            = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress       = 0xD0000000;
    MPU_InitStruct.Size              = MPU_REGION_SIZE_64MB;
    MPU_InitStruct.AccessPermission  = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable      = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable       = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable       = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number            = MPU_REGION_NUMBER1;
    MPU_InitStruct.TypeExtField      = MPU_TEX_LEVEL1;
    MPU_InitStruct.SubRegionDisable  = 0x00;
    MPU_InitStruct.DisableExec       = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);
#endif

#define BSP_USING_ETH
#ifdef BSP_USING_ETH
    /* Configure the MPU attributes as Device not cacheable 
       for ETH DMA descriptors */
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress = 0x30040000;
    MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number = MPU_REGION_NUMBER2;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);
  
    /* Configure the MPU attributes as Cacheable write through 
       for LwIP RAM heap which contains the Tx buffers */
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress = 0x30044000;
    MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
    MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number = MPU_REGION_NUMBER3;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);
#endif

    /* Enable the MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

    /* Enable CACHE */
    SCB_EnableICache();
    SCB_EnableDCache();
    
    return RT_EOK;

}
  1. 串口接收,dma将数据更新到主存中,缓存中的数据不是最新的数据,读之前需要把数据从主存中读出来
/* 串口v1版本  文件名 serial.c   添加需要包含头文件 board.h    
   重点是SCB_InvalidateDCache/SCB_InvalidateDCache_by_Addr函数, 也可以放在别的位置,这里是我放的位置
*/
rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length){
	...
		/* 在这个地方让缓存中的数据无效    大概520行
		当有多块内存,比如有外部sdram等,它们配置为wb模式,要使用下面SCB_InvalidateDCache_by_Addr */
		// SCB_InvalidateDCache();	
		 SCB_InvalidateDCache_by_Addr(rx_fifo, serial->config.rx_bufsz);
        if (rx_fifo->get_index + recv_len < serial->config.bufsz)
            rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index, recv_len);
        else
        {
            rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index,
                    serial->config.bufsz - rx_fifo->get_index);
            rt_memcpy(data + serial->config.bufsz - rx_fifo->get_index, rx_fifo->buffer,
                    recv_len + rx_fifo->get_index - serial->config.bufsz);
        }
	 ...
}
/*-----------------------------------------------------------------------------------------------------------------------*/
/* 串口v2版本  文件名 serial_v2.c   添加需要包含头文件 board.h    
   重点是SCB_InvalidateDCache/SCB_InvalidateDCache_by_Addr函数, 也可以放在别的位置,这里是我放的位置
*/
static rt_size_t _serial_fifo_rx(struct rt_device        *dev,
                                        rt_off_t          pos,
                                        void             *buffer,
                                        rt_size_t         size)
                                        {
                                            /* This part of the code is open_flag as RT_SERIAL_RX_NON_BLOCKING */

    level = rt_hw_interrupt_disable();
    /* When open_flag is RT_SERIAL_RX_NON_BLOCKING,
     * the data is retrieved directly from the ringbuffer and returned */
     
     /* 在这个地方让缓存中的数据无效,当有多块内存,比如有外部sdram等,它们配置为wb模式,要使用下面SCB_InvalidateDCache_by_Addr */
	//SCB_InvalidateDCache();        
	SCB_InvalidateDCache_by_Addr(rx_fifo->buffer, serial->config.rx_bufsz);  // 425行左右
    recv_len = rt_ringbuffer_get(&(rx_fifo->rb), buffer, size);
}
  1. dma发送,无特殊要求,因为mpu中配置为透写了,个人理解,使用dma时,只能使用透写模式,否则缓存中有新数据,主存中也有新的数据,舍弃那组数据都不行
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值