长草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了,敬请期待。
|