打印
[STM32H7]

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

[复制链接]
634|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
长草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关键初始化代码如下:
 if (BSP_SDRAM_Init(0) != BSP_ERROR_NONE)
   printf("error init sdram");
  else
  sdram_test();
调用BSP_SDRAM_Init()函数就好啦。如果初始化成功,我们即可调用sdram_test(),具体解析看下文。另外我们还需要把SDRAM对应区间在MPU正确设置下:
  /* Configure the MPU attributes as WB for SDRAM */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress = SDRAM_ADDRESS;
  MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
  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_LEVEL0;
  MPU_InitStruct.SubRegionDisable = 0x00;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

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

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

static uint32_t DWT_get_count()
{
    return DWT->CYCCNT;
}

static uint32_t DWT_count_to_us(uint32_t delta_count)
{
    return delta_count/400;
}

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

void sdram_test(void)
{
        int i;
        uint32_t addr;
        uint32_t t1;
        static uint8_t testbuf[4096];
        void *p = (void *)SDRAM_ADDRESS;

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

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

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

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

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

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

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

        for (;;) {
                __WFI();
        }
}

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

icache关闭:


icache开启:


由此可得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 | 只看该作者
读为啥这么慢,写入这么快?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

125

帖子

0

粉丝