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;   // ✅ 手工地址