static void SDRAM_Config(void);
static void SDRAM_PinConfig(void);
void BoardSdram_Init(void)
{
SDRAM_PinConfig();
SDRAM_Config();
}
[重点是初始化配置] (# 初始化)
配置引脚
static void SDRAM_PinConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH | RCC_AHB1Periph_GPIOI, ENABLE);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_SDRAM); //DQM[0]
GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_SDRAM); //DQM[1]
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOE, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource8, GPIO_AF_SDRAM); //CLK
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOG, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_PinAFConfig(GPIOH, GPIO_PinSource2, GPIO_AF_SDRAM); //CKE
GPIO_PinAFConfig(GPIOH, GPIO_PinSource3, GPIO_AF_SDRAM); //CSN[0]
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
GPIO_Init(GPIOH, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOH, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource4, GPIO_AF_SDRAM); //BA0
GPIO_PinAFConfig(GPIOG, GPIO_PinSource5, GPIO_AF_SDRAM); //BA1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOG, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource11, GPIO_AF_SDRAM); //RAS_N
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOF, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource15, GPIO_AF_SDRAM); //CAS_N
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOG, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_PinAFConfig(GPIOH, GPIO_PinSource5, GPIO_AF_SDRAM); //WE_N
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOH, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOH, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource0, GPIO_AF_SDRAM); //A0
GPIO_PinAFConfig(GPIOF, GPIO_PinSource1, GPIO_AF_SDRAM); //A1
GPIO_PinAFConfig(GPIOF, GPIO_PinSource2, GPIO_AF_SDRAM); //A2
GPIO_PinAFConfig(GPIOI, GPIO_PinSource13, GPIO_AF_SDRAM); //A3
GPIO_PinAFConfig(GPIOI, GPIO_PinSource14, GPIO_AF_SDRAM); //A4
GPIO_PinAFConfig(GPIOI, GPIO_PinSource15, GPIO_AF_SDRAM); //A5
GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_SDRAM); //A6
GPIO_PinAFConfig(GPIOF, GPIO_PinSource13, GPIO_AF_SDRAM); //A7
GPIO_PinAFConfig(GPIOF, GPIO_PinSource14, GPIO_AF_SDRAM); //A8
GPIO_PinAFConfig(GPIOF, GPIO_PinSource15, GPIO_AF_SDRAM); //A9
GPIO_PinAFConfig(GPIOG, GPIO_PinSource0, GPIO_AF_SDRAM); //A10
GPIO_PinAFConfig(GPIOG, GPIO_PinSource1, GPIO_AF_SDRAM); //A11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOF, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOI, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOI, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOG, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_SDRAM); //D0
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_SDRAM); //D1
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_SDRAM); //D2
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_SDRAM); //D3
GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_SDRAM); //D4
GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_SDRAM); //D5
GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_SDRAM); //D6
GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_SDRAM); //D7
GPIO_PinAFConfig(GPIOI, GPIO_PinSource8, GPIO_AF_SDRAM); //D8
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDRAM); //D9
GPIO_PinAFConfig(GPIOG, GPIO_PinSource3, GPIO_AF_SDRAM); //D10
GPIO_PinAFConfig(GPIOI, GPIO_PinSource11, GPIO_AF_SDRAM); //D11
GPIO_PinAFConfig(GPIOI, GPIO_PinSource12, GPIO_AF_SDRAM); //D12
GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_SDRAM); //D13
GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_SDRAM); //D14
GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_SDRAM); //D15
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOD, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOE, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_Init(GPIOI, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOI, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOC, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_DriveStrengthConfig(GPIOG, GPIO_InitStructure.GPIO_Pin, GPIO_DriveStrength_High);
}
初始化
static void SDRAM_Config(void)
{
SDRAM_InitTypeDef SDRAM_InitStructure;
SDRAM_TimingTypeDef timing;
PeripheralEnable(PeripheralSDRAM, 1);
PeripheralEnable(PeripheralSYSCFG, 1);
SDRAM_CLKDivConfig(SDRAM_CLKDIV_Div2);
SDRAM_SampleDelayConfig(0x02);
SDRAM_DeInit();
SDRAM_InitStructure.MemoryDataWidth = SDRAM_MemoryDataWidth_16bit;
SDRAM_InitStructure.BankAddrBitsNumber = SDRAM_BankAddrBitsNumber_2bit;
SDRAM_InitStructure.ColumnBitsNumber = SDRAM_ColumnBitsNumber_8bit;
SDRAM_InitStructure.RowBitsNumber = SDRAM_RowBitsNumber_12bit;
SDRAM_InitStructure.PrechargeAlgorihm = SDRAM_PrechargeAlgorihm_Delayed;
SDRAM_InitStructure.FullRefreshBeforeSR = SDRAM_RefreshOneRowBeforeEnterSR;
SDRAM_InitStructure.FullRefreshAfterSR = SDRAM_RefreshOneRowAfterEnterSR;
SDRAM_InitStructure.ClkEdgeSel = SDRAM_ClkEdgeSelectRising;
SDRAM_InitStructure.ReadPipe = 2;
SDRAM_Init(&SDRAM_InitStructure);
timing.CASLatency = SDRAM_CASLatency_3CLK;
timing.RasMinDelay = 7; // t_ras 40ns
timing.RCDDelay = 2; // t_rcd 15ns
timing.RPDelay = 2; // t_rp 15ns
timing.WriteRecoveryTime = 1; // t_wr 10ns
timing.RCARTime = 7; // t_rc 55ns
timing.XSRDelay = 7; // t_xsr 57ns
timing.RCTime = 7; // t_rc 55ns
timing.InitDelay = 30000; // 200us
timing.InitRefNumber = 7;
/* Target SDK runs SYSCLK/APB at 300/75 MHz. Keep the vendor 2292-cycle
* refresh value; 2200 belongs to the separate 288/72 MHz project. */
timing.RefCycle = 2292;
SDRAM_TimingConfig(&timing);
SDRAM_SendCommand(SDRAM_CommandEnterInitialize);
while (SDRAM_GetCommandStatus(SDRAM_CommandStatus_Initialize) == SET);
}
-
SDRAM_InitStructure.MemoryDataWidth = SDRAM_MemoryDataWidth_16bit;
bank 数 = 2^2 = 4
-
SDRAM_InitStructure.BankAddrBitsNumber = SDRAM_BankAddrBitsNumber_2bit;
行数 = 2^12 = 4096
-
SDRAM_InitStructure.ColumnBitsNumber = SDRAM_ColumnBitsNumber_8bit;
列数 = 2^8 = 256
-
SDRAM_InitStructure.RowBitsNumber = SDRAM_RowBitsNumber_12bit;
每单元宽度 = 16 bit = 2 字节
4 × 4096 × 256 × 2 = 8,388,608 字节 = 8 MiB
一次写入的完整旅程
代码里写 *(volatile uint32_t *)0x60001234 = 0x12345678 时,发生这些事——没有一件需要软件介入:
① CPU 执行 STR 指令,地址 = 0x60001234
↓
② 地址译码器(组合逻辑)判断:落在 0x60000000-0x9FFFFFFF → 外部 RAM 区
↓
③ 总线矩阵把这个访问路由给 SDRAM 控制器
↓
④ SDRAM 控制器把地址拆解:
0x60001234 - 0x60000000 = 0x1234 偏移
→ bank 位 / row 位 / column 位
加上 CAS 延迟、RAS/CAS 时序
↓
⑤ 驱动物理引脚(地址线、数据线、RAS/CAS/WE)完成一次 SDRAM 突发写
②③④⑤ 全是硬件自动的,软件只提供⑤之前的那个地址。
LTDC、DMA、CPU —— 它们都是"总线主设备"
| 主设备 | 怎么发起访问 | 表现形式 |
|---|---|---|
| CPU | 执行 LDR/STR/LDM/STM | 代码里的指针读写、memset |
| LTDC | 自己按像素时钟递增地址 | 只要在 LTDC_LxCFBAR 寄存器写好起始地址 |
| DMA2_Stream7 | 自己按传输请求递增地址 | 只要在 DMA_Memory0BaseAddr 写好起始地址 |
LVGL双缓冲
lv_color_t *framebuffer0 = (lv_color_t *)(uintptr_t)0x60000000UL;
lv_color_t *framebuffer1 = (lv_color_t *)(uintptr_t)(0x60000000+320*240*4)UL;
0x60000000 的普通指针,没有任何特殊之处。
LTDC切换缓冲区首地址:
LTDC_Layer1->CFBAR = 0x60000000UL;
LTDC_ReloadConfig(LTDC_VBReload); //
注意点
SDRAM 里不能直接定义 C 全局变量。
static uint32_t buffer[240*240]; // ❌ 链接器会放进内部 RAM,不是 SDRAM
链接脚本 (mh2457.ld) 的 MEMORY 里只有 FLASH 和 RAM——根本没有 SDRAM 这一段,链接器不知道它存在。想用 SDRAM 只有一条路:
uint32_t *buffer = (uint32_t *)(uintptr_t)0x600F6000; // ✅ 手工地址