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