【ART-Pi Review】Part 3: Onboard Storage - SDRAM
[Copy link]
This post was last edited by Digital Leaf on 2021-7-6 22:52
Although the main chip STM32H750XBH6 of ART-Pi has 1MB of internal SRAM, it still has a 32-Mbytes SDRAM chip W9825G6KH on board.
Or start from a blank project
Before opening any components, let's take a look at the resources of ART-Pi.
Obviously there is no 1MB size. Looking at the source file, you can find the defined size
Only 512KB of size is used
After opening the SDRAM component, check the resource status again
The board support package is more convenient for chip support packages or porting them yourself. Many components will generate corresponding initialization code after directly checking them.
After checking, a macro definition is actually added to rtconfig.h
#define BSP_USING_SDRAM
This macro then triggers a series of conditional compilations
In this driver file, you can see some code for initializing the SDRAM interface. For using the FMC interface to connect to SDRAM, a lot of low-level timing operations are omitted. You only need to give a few interface and timing parameters.
When you really connect to rtthread, you can use rt_memheap_init(struct rt_memheap *memheap, const char *name, void *start_addr, rt_uint32_t size); memory heap initialization function
#define SDRAM_BANK_ADDR ((uint32_t)0XC0000000)
#define SDRAM_SIZE ((uint32_t)0x2000000)
How does this address come from? Combined with the manual and ART-Pi's hardware circuit connection
The chip select signal enables the use of FMC SDNE0, selects BANK1, then the address will come out naturally
Finally, the SDRA test. The rtthread official document provides several test ideas, such as continuously applying for memory
for (i = 0; ; i++)
{
/* 每次分配 (1 << i) 大小字节数的内存空间 */
ptr = rt_malloc(1 << i);
/* 如果分配成功 */
if (ptr != RT_NULL)
{
rt_kprintf("get memory :%d byte\n", (1 << i));
/* 释放内存块 */
rt_free(ptr);
rt_kprintf("free memory :%d byte\n", (1 << i));
ptr = RT_NULL;
}
else
{
rt_kprintf("try to get %d byte memory failed!\n", (1 << i));
return;
}
}
For example, write data, read data, and then compare
for (i = 0; i < SDRAM_SIZE / data_width; i++)
{
*(__IO uint16_t *)(SDRAM_BANK_ADDR + i * data_width) = (uint16_t)0x5555;
}
time_cast = rt_tick_get() - start_time;
LOG_D("Write data success, total time: %d.%03dS.", time_cast / RT_TICK_PER_SECOND,
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
LOG_D("start Reading and verifying data, waiting....");
for (i = 0; i < SDRAM_SIZE / data_width; i++)
{
data = *(__IO uint16_t *)(SDRAM_BANK_ADDR + i * data_width);
if (data != 0x5555)
{
LOG_E("SDRAM test failed!");
break;
}
}
if (i >= SDRAM_SIZE / data_width)
{
LOG_D("SDRAM test success!");
}
The results can be seen through the finsh interface
Because the application was made in multiples, it stopped after reaching 16Mb.
The read and write tests were also verified. When doing the read and write tests, it was found that rtthread studio does not support the simple way in keil to directly define variables to the specified external address.
uint16_t testsram[250000] __attribute__((at(0XC0000000)));
The reason is that the GCC compiler is used, and the GCC compiler does not support the __attribute__ ((at(address))) instruction
But if you must use this definition method, there is a way. You need to modify the .lds file mentioned in the previous article, define the data segment in it, and then define the variable in the data segment, which is a bit similar to the operation of ccs.
|