硬汉嵌入式论坛

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

[MPU] STM32H7的I2C DMA传输,打开MPU就数据不对,关闭MPU就数据是对的

[复制链接]

3

主题

14

回帖

23

积分

新手上路

积分
23
发表于 2021-9-7 09:34:04 | 显示全部楼层 |阅读模式
问题:
STM32H7的I2C DMA传输,打开MPU就数据不对,关闭MPU就数据是对的
DMA使用的是DMA1_Stream0

代码:

MPU设置

  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 = 0x30040000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
  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_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = 0x30044000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = 0x30000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  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);

I2C DMA传输测试代码
                                memset(&i2cWriteBuf, 8, sizeof(i2cWriteBuf));
                                memset(&i2cReadBuf, 0, sizeof(i2cWriteBuf));
       
                          //status = HAL_I2C_Mem_Write(&hi2c1, 0xA0, 0, I2C_MEMADD_SIZE_16BIT, i2cWriteBuf, I2C_BUF_LEN, 1000);
                                status = HAL_I2C_Mem_Write_DMA(&hi2c1, 0xA0, 0, I2C_MEMADD_SIZE_16BIT, i2cWriteBuf, I2C_BUF_LEN);
                          if (HAL_OK != status)
                          {
                                  printf("error\r\n");
                          }
                          
                          //HAL_Delay(100);
                          while (HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 32, 300) != HAL_OK);
                          
                          //status = HAL_I2C_Mem_Read(&hi2c1, 0xA1, 0, I2C_MEMADD_SIZE_16BIT, i2cReadBuf, I2C_BUF_LEN, 1000);
                          status = HAL_I2C_Mem_Read_DMA(&hi2c1, 0xA1, 0, I2C_MEMADD_SIZE_16BIT, i2cReadBuf, I2C_BUF_LEN);
                          if (HAL_OK != status)
                          {
                                  printf("error2\r\n");
                          }
                          
                          while (HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 32, 300) != HAL_OK);
                          //HAL_Delay(100);
                          
                                if (0 == memcmp(i2cReadBuf, i2cWriteBuf, sizeof(i2cReadBuf)))
                                {
                                        printf("data correct\r\n");
                                }
                                else
                                {
                                        printf("data error\r\n");
                                }
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-9-7 09:38:12 | 显示全部楼层
问题出现在哪里?MPU设置不对吗,我的想法是先不使用cache。区域0和区域1是LWIP使用的。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106833
QQ
发表于 2021-9-7 10:06:22 | 显示全部楼层
看下你的工程主RAM空间使用的那个,是512KB的AXI SRAM还是那个,将其关闭读写Cache。然后测试,应该就可以了。

回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-9-7 10:17:42 | 显示全部楼层
eric2013 发表于 2021-9-7 10:06
看下你的工程主RAM空间使用的那个,是512KB的AXI SRAM还是那个,将其关闭读写Cache。然后测试,应该就可以 ...

按照你说的改了一下,还是不行,KEIL配置仅使用AXI RAM

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 = 0x30040000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
  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_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = 0x30044000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = 0x30000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  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);
  
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER3;
  MPU_InitStruct.BaseAddress = 0x24000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_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_PRIVILEGED_DEFAULT);

}

参考硬汉的开发手册第25章内存基础,I2C DMA我选用的D2域 SRAM1,buffer的设定代码如下
#define I2C_BUF_LEN   (1024*2)
__attribute__((at(0x30000000))) uint8_t  i2cWriteBuf[I2C_BUF_LEN];
__attribute__((at(0x30008000))) uint8_t  i2cReadBuf[I2C_BUF_LEN];

KEIL配置:
只选择IRAM,0x24000000  0x80000。使用KEIL默认的SCT文件


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106833
QQ
发表于 2021-9-7 10:20:30 | 显示全部楼层
上传你的程序到百度云,我看下。
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-9-7 10:32:24 | 显示全部楼层
eric2013 发表于 2021-9-7 10:20
上传你的程序到百度云,我看下。

链接:https://pan.baidu.com/s/1y-1slOVLP6j5cNc9Fqx82A
提取码:abcd
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-9-7 11:24:06 | 显示全部楼层
eric2013 发表于 2021-9-7 10:20
上传你的程序到百度云,我看下。

我找到原因了。
__attribute__((at(0x30000000))) uint8_t  i2cWriteBuf[I2C_BUF_LEN];
__attribute__((at(0x30008000))) uint8_t  i2cReadBuf[I2C_BUF_LEN];

我的初衷是I2C写buff,位置是在D2域SDRAM1的前32K。I2C读buffer是在这之后的32K。也就是说这一块的MPU应该要设置为总共64K的内存需求才行。

  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = 0x30000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  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;
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-9-7 11:34:45 | 显示全部楼层
最近在使用STM32H7这颗芯片,这颗芯片的特殊之处在于,可能需要使用到CACHE,而使用CACHE必须配合MPU一起使用,而确保CACHE和SRAM之间的数据一致性是关键,尤其是在DMA的时候。
看了好几个开发板论坛和资料,相对来说,硬汉论坛和资料,这块写的是比较全面的,我也确实初步了解了一些概念。

在使用H7过程中遇到MPU/CACHE相关问题的话,可以参考如下资料
1、硬汉的论坛和开发手册相关章节
2、STM32H743CUBE例程,路径:STM32H743I-EVAL\Examples\Cortex\
也可以看LWIP、DMA、ADC相关例程,都会涉及到MPU的内容
3、ST的几个文档
PM0253,这个是CM7编程手册,详细讲解了M7 MPU相关的寄存器说明
AN4839,这个是cache的应用笔记,讲解了在开启cache之后,如何确保数据一致性
AN4838,这个是MPU的应用笔记,对于PM0253 MPU相关章节的更进一步描述

最后还有一个疑问,在H7 LWIP STM32CUBE官方参考例程,以太网DMA描述符、缓冲区,都是设置为不cache的。为什么不设置为cachable呢?是有什么特殊之处吗?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106833
QQ
发表于 2021-9-7 15:24:26 | 显示全部楼层
kevin_yf 发表于 2021-9-7 11:34
最近在使用STM32H7这颗芯片,这颗芯片的特殊之处在于,可能需要使用到CACHE,而使用CACHE必须配合MPU一起使 ...

描述符要配置为Strongely Order或者Device模式

而缓冲区随意设置Cache,你可以开启,开启的话,处理下底层的以太网数据首发即可,调用SCB Cache函数。

如果关闭了读Cache和写Cache,就不需要处理了。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-6 21:28 , Processed in 0.192602 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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