This post was last edited by DDZZ669 on 2020-10-4 17:28
1 SDRAM
RAM can be understood as memory, the space required by the program when running. GD32F450IK comes with 256K RAM. When a large memory is needed, it is necessary to expand the RAM. This development board is equipped with an MT48LC16M16A2P SDRAM.
1.1 Basic Principles of SDRAM Data Storage
The SDRAM model on the board is: MT48LC16M16A2P-6AIT, and its schematic diagram is as follows:
The function of each pin is shown in the following table:
SDRAM is divided into multiple areas called banks, which allow devices to access them in an interleaved manner to obtain greater concurrency and data transfer. Each bank can be considered as a matrix, where each address corresponds to the space of the memory storage width. The matrix consists of rows and columns, so the bank size of the memory can be considered as the number of rows and columns of the memory data width.
As shown in the figure below, for this storage array, we can regard it as a table. We only need to give the row address and column address to determine its unique location. This is the basic principle of SDRAM addressing. There are generally 4 such storage units (BANK0~BANK3) inside an SDRAM chip. Therefore, when addressing inside the SDRAM, first specify the BANK number and row address, and then specify the column address to find the target address.
When SDRAM is addressed:
1 First, the RAS signal is low, the row address is selected, and the address represented by the address lines A0~A12 will be transmitted and latched into the row address decoder as the row address.
2 At the same time, the BANK addresses represented by BS0 and BS1 on the BANK address lines will also be latched, and the corresponding BANK will be selected.
3 Then, the CAS signal is low, the column address is selected, and the address represented by the address lines A0~A12 will be transmitted and latched into the column address decoder as the column address.
In this way, one addressing is completed.
1.2 Analysis of Onboard SDRAM Models
Let's take a look at the meaning of the naming of the MT48LC16M16A2P-6AIT model. You can check its data sheet:
Here are some more tables:
The storage structure of MT48LC16M16A2P-6AIT is:
- Row address: 8192 (8K)
- Column address: 512
- Number of banks: 4
- Bit width: 16 bits
In this way, the capacity of the entire chip is 8192*512*4*16=32M bytes.
1.3 SDRAM Control Logic
A series of commands are required to control SDRAM, and various signal line state combinations produce different control commands.
Due to the volatile nature of data, SDRAM needs to be refreshed periodically. EXMC supports two refresh modes, self-refresh and auto-refresh. Self-refresh is used in the low-power mode when EXMC is suspended. The clock is provided by the internal count of SDRAM and refresh is performed internally. Auto-refresh is when EXMC periodically provides refresh commands, because SDRAM needs to transfer data at this time. The refresh interval is determined by the register EXMC_SDARI bit ARINTV, and the number of consecutive refreshes is determined by the register EXMC_SDCMD bit NARF.
DRAM cannot start reading and writing data immediately after power-on. It needs to be initialized step by step to precharge the storage matrix, refresh it, and set the mode register, etc.
SDRAM initialization process:
Power the SDRAM and enable the CLK clock. Note that after powering on, wait for at least 200us before sending other commands.
Send NOP (No Operation Command)
Send a precharge command to precharge all banks.
At least 8 self-refresh commands must be sent, and the interval between each self-refresh command is tRFC.
- Setting LOAD MODE REGISTER
Send the value of the mode register to configure the working parameters of the SDRAM. After the configuration is completed, you need to wait for tMRD (also called tRSC) for the configuration of the mode register to take effect before sending other commands.
After the previous operations, the initialization of SDRAM is completed. Next, you can send activation commands and read/write commands to read/write data.
2 EXMC
GD32's external memory controller EXMC is used to access various off-chip memories. By configuring registers, EXMC can convert the AMBA protocol into a dedicated off-chip memory communication protocol, including SRAM, ROM, NOR Flash, NAND Flash, PC Card and SDRAM. Users can also adjust related time parameters to improve communication efficiency. The EXMC module is divided into many sub-Banks, each Bank supports a specific memory type, and users can control the external memory by configuring the Bank's registers.
EXMC consists of 6 modules: AHB bus interface, EXMC configuration register, NOR/PSRAM controller, NAND/PC Card controller, SDRAM controller and external device interface. AHB clock HCLK is the reference clock.
EXMC divides the external memory into multiple banks, each bank occupies 256M bytes, of which Bank0 is divided into 4 regions, each region occupies 64M bytes. Bank1 and Bank2 are divided into 2 sections, namely attribute storage space and general storage space. Bank3 is divided into 3 sections, namely attribute storage space, general storage space and I/O storage space. Each bank and region has an independent chip select control signal and can be configured independently.
- Bank0 is used to access NOR and PSRAM devices.
- Bank1 and Bank2 are used to connect NAND Flash, and each Bank is connected to one NAND.
- Bank3 is used to connect PC card.
- SDRAM Device0 and SDRAM Device1 are used to connect SDRAM.
EXMC divides the SDRAM storage area into two blocks: device0 and device01. The SDRAM address mapping is as follows:
3 Program Analysis
Let's take a look at the SDRAM routine. First, the main function:
int main(void)
{
uint16_t i = 0;
/* LED initialize */
gd_eval_led_init(LED1);
gd_eval_led_init(LED3);
/* systick clock configure */
systick_config();
/* config the USART */
gd_eval_com_init(EVAL_COM1);
/* fill txbuffer */
fill_buffer(txbuffer, BUFFER_SIZE, 0x0000);
//===============SDRAM初始化===================
/* config the EXMC access mode */
exmc_synchronous_dynamic_ram_init(EXMC_SDRAM_DEVICE0);//SDRAM device0: 0x00000004U
printf("\r\nSDRAM initialized!");
delay_1ms(1000);
//===============写入SDRAM===================
printf("\r\nSDRAM write data...");
delay_1ms(1000);
/* write data to SDRAM */
sdram_writebuffer_8(EXMC_SDRAM_DEVICE0,txbuffer, WRITE_READ_ADDR, BUFFER_SIZE);
//===============读取SDRAM===================
printf("\r\nSDRAM read data...");
delay_1ms(1000);
/* read data from SDRAM */
sdram_readbuffer_8(EXMC_SDRAM_DEVICE0,rxbuffer, WRITE_READ_ADDR, BUFFER_SIZE);
//===============检查写入与读出的是否相同===================
printf("\r\nCheck the data!");
delay_1ms(1000);
/* compare two buffers */
for(i = 0;i < BUFFER_SIZE;i++)
{
if (rxbuffer[i] != txbuffer[i])
{
writereadstatus ++;
break;
}
}
if(writereadstatus)
{
printf("\r\nSDRAM test failed!");
/* failure, light on LED3 */
gd_eval_led_on(LED3);
}
else
{
printf("\r\nSDRAM test successed!");
delay_1ms(1000);
printf("\r\nThe data is:\r\n");
delay_1ms(1000);
for(i=0;i < BUFFER_SIZE;i++)
{
printf("%6x",rxbuffer[i]);
if(((i+1)%16) == 0)
{
printf("\r\n");
}
}
/* success, light on LED1 */
gd_eval_led_on(LED1);
}
while(1);
}
First, various peripherals and SDRAM are initialized, then specific data is written to SDRAM, the data is read out, and finally the written and read data are compared to see if they are the same.
Here is a look at the specific process of SDRAM initialization:
void exmc_synchronous_dynamic_ram_init(uint32_t sdram_device)
{
exmc_sdram_parameter_struct sdram_init_struct;
exmc_sdram_timing_parameter_struct sdram_timing_init_struct;
exmc_sdram_command_parameter_struct sdram_command_init_struct;
uint32_t command_content = 0, bank_select;
uint32_t timeout = SDRAM_TIMEOUT;
/* enable EXMC clock*/
rcu_periph_clock_enable(RCU_EXMC);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_GPIOF);
rcu_periph_clock_enable(RCU_GPIOG);
rcu_periph_clock_enable(RCU_GPIOH);
/* common GPIO configuration */
/* SDNE0(PC2),SDCKE0(PC5) pin configuration */
gpio_af_set(GPIOC, GPIO_AF_12, GPIO_PIN_2 | GPIO_PIN_5);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2 | GPIO_PIN_5);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2 | GPIO_PIN_5);
/* D2(PD0),D3(PD1),D13(PD8),D14(PD9),D15(PD10),D0(PD14),D1(PD15) pin configuration */
gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
/* NBL0(PE0),NBL1(PE1),D4(PE7),D5(PE8),D6(PE9),D7(PE10),D8(PE11),D9(PE12),D10(PE13),D11(PE14),D12(PE15) pin configuration */
gpio_af_set(GPIOE, GPIO_AF_12, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 |
GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 |
GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 |
GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
/* A0(PF0),A1(PF1),A2(PF2),A3(PF3),A4(PF4),A5(PF5),NRAS(PF11),A6(PF12),A7(PF13),A8(PF14),A9(PF15) pin configuration */
gpio_af_set(GPIOF, GPIO_AF_12, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
/* A10(PG0),A11(PG1),A12(PG2),A14(PG4),A15(PG5),SDCLK(PG8),NCAS(PG15) pin configuration */
gpio_af_set(GPIOG, GPIO_AF_12, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 |
GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 |
GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 |
GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15);
/* SDNWE(PH5) pin configuration */
gpio_af_set(GPIOH, GPIO_AF_12, GPIO_PIN_5);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_5);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
/* specify which SDRAM to read and write */
if(EXMC_SDRAM_DEVICE0 == sdram_device)
{
bank_select = EXMC_SDRAM_DEVICE0_SELECT;
}
else
{
bank_select = EXMC_SDRAM_DEVICE1_SELECT;
}
/* EXMC SDRAM device initialization sequence --------------------------------*/
//【1】配置SDRAM时间寄存器
/* Step 1 : configure SDRAM timing registers --------------------------------*/
/* LMRD: 2 clock cycles */
sdram_timing_init_struct.load_mode_register_delay = 2;
/* XSRD: min = 67ns */
sdram_timing_init_struct.exit_selfrefresh_delay = 7;
/* RASD: min=42ns , max=120k (ns) */
sdram_timing_init_struct.row_address_select_delay = 5;
/* ARFD: min=60ns */
sdram_timing_init_struct.auto_refresh_delay = 6;
/* WRD: min=1 Clock cycles +6ns */
sdram_timing_init_struct.write_recovery_delay = 2;
/* RPD: min=18ns */
sdram_timing_init_struct.row_precharge_delay = 2;
/* RCD: min=18ns */
sdram_timing_init_struct.row_to_column_delay = 2;
//【2】配置SDRAM控制寄存器
/* step 2 : configure SDRAM control registers ---------------------------------*/
sdram_init_struct.sdram_device = sdram_device;
sdram_init_struct.column_address_width = EXMC_SDRAM_COW_ADDRESS_9;
sdram_init_struct.row_address_width = EXMC_SDRAM_ROW_ADDRESS_13;
sdram_init_struct.data_width = EXMC_SDRAM_DATABUS_WIDTH_16B;
sdram_init_struct.internal_bank_number = EXMC_SDRAM_4_INTER_BANK;
sdram_init_struct.cas_latency = EXMC_CAS_LATENCY_3_SDCLK;
sdram_init_struct.write_protection = DISABLE;
sdram_init_struct.sdclock_config = EXMC_SDCLK_PERIODS_2_HCLK;
sdram_init_struct.brust_read_switch = ENABLE;
sdram_init_struct.pipeline_read_delay = EXMC_PIPELINE_DELAY_1_HCLK;
sdram_init_struct.timing = &sdram_timing_init_struct;
/* EXMC SDRAM bank initialization */
exmc_sdram_init(&sdram_init_struct);
//【3】配置CKE?
/* step 3 : configure CKE high command---------------------------------------*/
sdram_command_init_struct.command = EXMC_SDRAM_CLOCK_ENABLE;
sdram_command_init_struct.bank_select = bank_select;
sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_1_SDCLK;
sdram_command_init_struct.mode_register_content = 0;
/* wait until the SDRAM controller is ready */
while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
/* send the command */
exmc_sdram_command_config(&sdram_command_init_struct);
//【4】延时10ms
/* step 4 : insert 10ms delay----------------------------------------------*/
delay_1ms(10);
//【5】配置预充电
/* step 5 : configure precharge all command----------------------------------*/
sdram_command_init_struct.command = EXMC_SDRAM_PRECHARGE_ALL;
sdram_command_init_struct.bank_select = bank_select;
sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_1_SDCLK;
sdram_command_init_struct.mode_register_content = 0;
/* wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
/* send the command */
exmc_sdram_command_config(&sdram_command_init_struct);
//【6】配置自动刷新
/* step 6 : configure Auto-Refresh command-----------------------------------*/
sdram_command_init_struct.command = EXMC_SDRAM_AUTO_REFRESH;
sdram_command_init_struct.bank_select = bank_select;
sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_8_SDCLK;
sdram_command_init_struct.mode_register_content = 0;
/* wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
/* send the command */
exmc_sdram_command_config(&sdram_command_init_struct);
//【7】配置装载模式寄存器
/* step 7 : configure load mode register command-----------------------------*/
/* program mode register */
command_content = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
sdram_command_init_struct.command = EXMC_SDRAM_LOAD_MODE_REGISTER;
sdram_command_init_struct.bank_select = bank_select;
sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_1_SDCLK;
sdram_command_init_struct.mode_register_content = command_content;
/* wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
/* send the command */
exmc_sdram_command_config(&sdram_command_init_struct);
//【8】配置自动刷新频率
/* step 8 : set the auto-refresh rate counter--------------------------------*/
/* 64ms, 8192-cycle refresh, 64ms/8192=7.81us */
/* SDCLK_Freq = SYS_Freq/2 */
/* (7.81 us * SDCLK_Freq) - 20 */
exmc_sdram_refresh_count_set(761);
/* wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
}
4 Operation Effect
The operation effect is displayed through the serial port and LED, and the read and write operations are compared. If the data is consistent, LED1 is lit, otherwise LED3 is lit. At the same time, the serial port outputs the following information:
SDRAM initialized!
SDRAM write data...
SDRAM read data...
Check the data!
SDRAM test successed!
The data is:
0 1 2 3 4 5 6 7 8 9 a b c d e f
10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f
90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f
...略
This example program sometimes fails to run. The operation of SDRAM is a bit complicated, I haven't fully understood it yet, I will continue to study it when I have time.
|