[STM32H7] 【STM32H745I-DISCO试用】sdram测试与性能数据

[复制链接]
 楼主| xhackerustc 发表于 2025-2-15 18:14 | 显示全部楼层 |阅读模式
<
长草ST家的H7系开发板很久了,可惜以前H7系的试用没选上,这次终于中了。笔者一直很喜欢linux,开发都在linux下做;任何一块开发板如果资源够跑linux也会跑一把,可参考笔者以前文章:https://bbs.21ic.com/icview-3408348-1-1.html。这块板子拿到手我就想跑linux试试,第一个拦路虎就是sdram要初始化起来,并且能过读写测试,顺便把性能数据也测量一下。让我们开始搞sdram之旅吧。

下载STM32Cube_FW_H7这些都简单,这里略过不提。STM32Cube_FW_H7中其实有STM32H745I-DISCO板级BSP,咱们可以直接用的。其中SDRAM关键初始化代码如下:
  1. if (BSP_SDRAM_Init(0) != BSP_ERROR_NONE)
  2.    printf("error init sdram");
  3.   else
  4.   sdram_test();
调用BSP_SDRAM_Init()函数就好啦。如果初始化成功,我们即可调用sdram_test(),具体解析看下文。另外我们还需要把SDRAM对应区间在MPU正确设置下:
  1.   /* Configure the MPU attributes as WB for SDRAM */
  2.   MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  3.   MPU_InitStruct.BaseAddress = SDRAM_ADDRESS;
  4.   MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
  5.   MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  6.   MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
  7.   MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  8.   MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  9.   MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  10.   MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  11.   MPU_InitStruct.SubRegionDisable = 0x00;
  12.   MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  13.   HAL_MPU_ConfigRegion(&MPU_InitStruct);
注:为跑linux笔者未像示例代码一样把对应MPU属性配置成WT属性,而是把MPU属性设置成WriteBack了。

笔者未用STM32Cube_FW_H7的SDRAM测试样例代码,而是自己写了一个sdram_test()函数,也正是自己写的这份代码发现了这块板子一个问题--只能访问SDRAM的前面8MB部分,访问SDRAM后8MB部分系统就挂了。不知道是笔者代码写错了还是共性。其代码如下:
  1. static void DWT_init()
  2. {
  3.     CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
  4.     DWT->CTRL = 0;
  5.     DWT->CYCCNT = 0;
  6.     DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
  7. }

  8. static uint32_t DWT_get_count()
  9. {
  10.     return DWT->CYCCNT;
  11. }

  12. static uint32_t DWT_count_to_us(uint32_t delta_count)
  13. {
  14.     return delta_count/400;
  15. }

  16. #define SDRAM_ADDRESS   (0xD0000000U)
  17. #define SDRAM_SIZE (8*1024*1024)  // 注这里8改成16就会复现笔者说的问题

  18. void sdram_test(void)
  19. {
  20.         int i;
  21.         uint32_t addr;
  22.         uint32_t t1;
  23.         static uint8_t testbuf[4096];
  24.         void *p = (void *)SDRAM_ADDRESS;

  25.         printf("Writing SDRAM...\n");
  26.         for (addr = 0; addr < SDRAM_SIZE; ++addr) {
  27.                 uint8_t data = addr & 0xff;
  28.                 *(uint8_t *)(p + addr) = data;
  29.         }

  30.         printf("Reading SDRAM...\n");
  31.         for (addr = 0; addr < SDRAM_SIZE; ++addr) {
  32.                 uint8_t data, expected;

  33.                 expected = addr & 0xff;
  34.                 data = *(uint8_t *)(p + addr);
  35.                 if (data != expected)
  36.                         printf("SDRAM 8bit read failed at %lx (%x != %x)\n", addr, data, expected);
  37.         }
  38.         printf("SDRAM 8bit read pass.\n");

  39.         for (addr = 0; addr < SDRAM_SIZE; addr += 2) {
  40.                 uint16_t data, expected;
  41.                 expected = (((addr + 1) & 0xff) << 8) |
  42.                            (addr & 0xff);
  43.                 data = *(uint16_t *)(p + addr);
  44.                 if (data != expected)
  45.                         printf("SDRAM 16bit read failed at %lx (%x != %x)\n", addr, data,
  46. expected);
  47.         }
  48.         printf("SDRAM 16bit read pass.\n");

  49.         for (addr = 0; addr < SDRAM_SIZE; addr += 4) {
  50.                 uint32_t data, expected;
  51.                 expected = (((addr + 3) & 0xff) << 24) |
  52.                            (((addr + 2) & 0xff) << 16) |
  53.                            (((addr + 1) & 0xff) << 8) |
  54.                            (addr & 0xff);
  55.                 data = *(uint32_t *)(p + addr);
  56.                 if (data != expected)
  57.                         printf("SDRAM 32bit read failed at %lx (%lx != %lx)\n", addr, data, expected);
  58.         }
  59.         printf("SDRAM 32bit read pass.\n");

  60.         memset(testbuf, 0x5a, sizeof(testbuf));
  61.         DWT_init();
  62.         t1 = DWT_get_count();
  63.         for (i = 0; i < 10000; ++i) {
  64.                 memcpy(p, testbuf, 4096);
  65.         }
  66.         t1 = DWT_get_count() - t1;
  67.         t1 = DWT_count_to_us(t1);
  68.         t1 /= 1000;
  69.         printf("SDRAM write speed: %ld KB/s.\n", 4 * 10000 * 1000 / t1);

  70.         t1 = DWT_get_count();
  71.         for (i = 0; i < 10000; ++i) {
  72.                 memcpy(testbuf, p, 4096);
  73.         }
  74.         t1 = DWT_get_count() - t1;
  75.         t1 = DWT_count_to_us(t1);
  76.         t1 /= 1000;
  77.         printf("SDRAM read speed: %ld KB/s.\n", 4 * 10000 * 1000 / t1);

  78.         for (;;) {
  79.                 __WFI();
  80.         }
  81. }

为测试sdram自身速度,最好把dcache关闭,否则如果buffer太小就是测试cache的速度了。icache可以
开启。咱们分别测试下icache未开启和icache开启的情形。

icache关闭:
1.jpg

icache开启:
2.jpg

由此可得SDRAM写速度大概为189MB/s,读速度大概为53MB/s,读远比写慢。开启icache后sdram读写速度稍微提升些但不大,这也容易理解,cpu执行指令快了。

至此sdram测试完毕,可以愉快玩linux了,敬请期待。

 楼主| xhackerustc 发表于 2025-2-15 18:16 | 显示全部楼层
#define SDRAM_SIZE (8*1024*1024)

这里8改成16就会复现笔者说的问题:只能访问SDRAM前8MB,访问后8MB时系统就挂了
WoodData 发表于 2025-2-20 12:03 | 显示全部楼层
读为啥这么慢,写入这么快?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

42

主题

165

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部