023 - STM32学习笔记 - 扩展外部SDRAM(二) - 扩展外部SDRAM实验

023- STM32学习笔记 - 扩展外部SDRAM(一) - 扩展外部SDRAM实验

本节内容中要配置的引脚很多,如果你用的开发板跟我的不一样,请详细参照STM32规格书中说明对相关GPIO引脚进行配置。

先提前对本届内容的变成步骤进行总结如下:

  1. 初始化通讯使用的目标引脚及端口时钟;(再次强调,只要使用外设,一定要看时钟时候配置正确并开启!)
  2. 是能FMC外设时钟;(再再次强调,只要使用外设,一定要看时钟时候配置正确并开启!)
  3. 配置FMC SDRAM的时序和工作模式;
  4. 根据SDRAM的初始化流程编写初始化函数;
  5. 访问外部SDRAM存储器;
  6. 编写测试程序,校验读写的数据。

OK,参照如上步骤,实战之前先将我用的F429开发板中SDRAM部分贴出来。

023 - STM32学习笔记 - 扩展外部SDRAM(二) - 扩展外部SDRAM实验_第1张图片

一、相关GPIO宏定义

这次使用到的GPIO相当多,这里我们把FMC SDRAM相关的GPIO配置都宏定义到“bsp_sdram.h”中,相关的配置步骤参考之前的工程配置。这里我把我配置好的贴出来,如果我们使用的开发板不一致,请参考自己开发板的硬件原理图

/* A行列地址信号线 */
/* A0 PF0 */
#define FMC_A0_GPIO_PORT        GPIOF
#define FMC_A0_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A0_GPIO_PIN         GPIO_Pin_0
#define FMC_A0_PINSOURCE        GPIO_PinSource0
#define FMC_A0_AF               GPIO_AF_FMC

/* A1 PF1 */
#define FMC_A1_GPIO_PORT        GPIOF
#define FMC_A1_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A1_GPIO_PIN         GPIO_Pin_1
#define FMC_A1_PINSOURCE        GPIO_PinSource1
#define FMC_A1_AF               GPIO_AF_FMC

/* A2 PF2 */
#define FMC_A2_GPIO_PORT        GPIOF
#define FMC_A2_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A2_GPIO_PIN         GPIO_Pin_2
#define FMC_A2_PINSOURCE        GPIO_PinSource2
#define FMC_A2_AF               GPIO_AF_FMC

/* A3 PF3 */
#define FMC_A3_GPIO_PORT        GPIOF
#define FMC_A3_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A3_GPIO_PIN         GPIO_Pin_3
#define FMC_A3_PINSOURCE        GPIO_PinSource3
#define FMC_A3_AF               GPIO_AF_FMC

/* A4 PF4 */
#define FMC_A4_GPIO_PORT        GPIOF
#define FMC_A4_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A4_GPIO_PIN         GPIO_Pin_4
#define FMC_A4_PINSOURCE        GPIO_PinSource4
#define FMC_A4_AF               GPIO_AF_FMC

/* A5 PF5*/
#define FMC_A5_GPIO_PORT        GPIOF
#define FMC_A5_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A5_GPIO_PIN         GPIO_Pin_5
#define FMC_A5_PINSOURCE        GPIO_PinSource5
#define FMC_A5_AF               GPIO_AF_FMC

/* A6 PF12 */
#define FMC_A6_GPIO_PORT        GPIOF
#define FMC_A6_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A6_GPIO_PIN         GPIO_Pin_12
#define FMC_A6_PINSOURCE        GPIO_PinSource12
#define FMC_A6_AF               GPIO_AF_FMC

/* A7 PF13 */
#define FMC_A7_GPIO_PORT        GPIOF
#define FMC_A7_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A7_GPIO_PIN         GPIO_Pin_13
#define FMC_A7_PINSOURCE        GPIO_PinSource13
#define FMC_A7_AF               GPIO_AF_FMC

/* A8 PF14 */
#define FMC_A8_GPIO_PORT        GPIOF
#define FMC_A8_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A8_GPIO_PIN         GPIO_Pin_14
#define FMC_A8_PINSOURCE        GPIO_PinSource14
#define FMC_A8_AF               GPIO_AF_FMC

/* A9 PF15 */
#define FMC_A9_GPIO_PORT        GPIOF
#define FMC_A9_GPIO_CLK         RCC_AHB1Periph_GPIOF
#define FMC_A9_GPIO_PIN         GPIO_Pin_15
#define FMC_A9_PINSOURCE        GPIO_PinSource15
#define FMC_A9_AF               GPIO_AF_FMC

/* A10 PG0 */
#define FMC_A10_GPIO_PORT        GPIOG
#define FMC_A10_GPIO_CLK         RCC_AHB1Periph_GPIOG
#define FMC_A10_GPIO_PIN         GPIO_Pin_0
#define FMC_A10_PINSOURCE        GPIO_PinSource0
#define FMC_A10_AF               GPIO_AF_FMC

/* A11 PG1 */
#define FMC_A11_GPIO_PORT        GPIOG
#define FMC_A11_GPIO_CLK         RCC_AHB1Periph_GPIOG
#define FMC_A11_GPIO_PIN         GPIO_Pin_1
#define FMC_A11_PINSOURCE        GPIO_PinSource1
#define FMC_A11_AF               GPIO_AF_FMC

/*BA0 地址线 PG4*/
#define FMC_BA0_GPIO_PORT        GPIOG
#define FMC_BA0_GPIO_CLK         RCC_AHB1Periph_GPIOG
#define FMC_BA0_GPIO_PIN         GPIO_Pin_4
#define FMC_BA0_PINSOURCE        GPIO_PinSource4
#define FMC_BA0_AF               GPIO_AF_FMC

/*BA1 地址线 PG5 */
#define FMC_BA1_GPIO_PORT        GPIOG
#define FMC_BA1_GPIO_CLK         RCC_AHB1Periph_GPIOG
#define FMC_BA1_GPIO_PIN         GPIO_Pin_5
#define FMC_BA1_PINSOURCE        GPIO_PinSource5
#define FMC_BA1_AF               GPIO_AF_FMC

/*DQ 数据信号线*/
/*DQ0 数据线 PD14 */
#define FMC_D0_GPIO_PORT         GPIOD
#define FMC_D0_GPIO_CLK          RCC_AHB1Periph_GPIOD
#define FMC_D0_GPIO_PIN          GPIO_Pin_14
#define FMC_D0_PINSOURCE         GPIO_PinSource14
#define FMC_D0_AF                GPIO_AF_FMC

/*DQ1 数据线*/
#define FMC_D1_GPIO_PORT         GPIOD
#define FMC_D1_GPIO_CLK          RCC_AHB1Periph_GPIOD
#define FMC_D1_GPIO_PIN          GPIO_Pin_15
#define FMC_D1_PINSOURCE         GPIO_PinSource15
#define FMC_D1_AF                GPIO_AF_FMC

/*DQ2 数据线*/
#define FMC_D2_GPIO_PORT         GPIOD
#define FMC_D2_GPIO_CLK          RCC_AHB1Periph_GPIOD
#define FMC_D2_GPIO_PIN          GPIO_Pin_0
#define FMC_D2_PINSOURCE         GPIO_PinSource0
#define FMC_D2_AF                GPIO_AF_FMC

/*DQ3 数据线*/
#define FMC_D3_GPIO_PORT         GPIOD
#define FMC_D3_GPIO_CLK          RCC_AHB1Periph_GPIOD
#define FMC_D3_GPIO_PIN          GPIO_Pin_1
#define FMC_D3_PINSOURCE         GPIO_PinSource1
#define FMC_D3_AF                GPIO_AF_FMC

/*DQ4 数据线*/
#define FMC_D4_GPIO_PORT         GPIOE
#define FMC_D4_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D4_GPIO_PIN          GPIO_Pin_7
#define FMC_D4_PINSOURCE         GPIO_PinSource7
#define FMC_D4_AF                GPIO_AF_FMC

/*DQ5 数据线*/
#define FMC_D5_GPIO_PORT         GPIOE
#define FMC_D5_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D5_GPIO_PIN          GPIO_Pin_8
#define FMC_D5_PINSOURCE         GPIO_PinSource8
#define FMC_D5_AF                GPIO_AF_FMC

/*DQ6 数据线*/
#define FMC_D6_GPIO_PORT         GPIOE
#define FMC_D6_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D6_GPIO_PIN          GPIO_Pin_9
#define FMC_D6_PINSOURCE         GPIO_PinSource9
#define FMC_D6_AF                GPIO_AF_FMC

/*DQ7 数据线*/
#define FMC_D7_GPIO_PORT         GPIOE
#define FMC_D7_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D7_GPIO_PIN          GPIO_Pin_10
#define FMC_D7_PINSOURCE         GPIO_PinSource10
#define FMC_D7_AF                GPIO_AF_FMC

/*DQ8 数据线*/
#define FMC_D8_GPIO_PORT         GPIOE
#define FMC_D8_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D8_GPIO_PIN          GPIO_Pin_11
#define FMC_D8_PINSOURCE         GPIO_PinSource11
#define FMC_D8_AF                GPIO_AF_FMC

/*DQ9 数据线*/
#define FMC_D9_GPIO_PORT         GPIOE
#define FMC_D9_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D9_GPIO_PIN          GPIO_Pin_12
#define FMC_D9_PINSOURCE         GPIO_PinSource12
#define FMC_D9_AF                GPIO_AF_FMC

/*DQ10 数据线*/
#define FMC_D10_GPIO_PORT         GPIOE
#define FMC_D10_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D10_GPIO_PIN          GPIO_Pin_13
#define FMC_D10_PINSOURCE         GPIO_PinSource13
#define FMC_D10_AF                GPIO_AF_FMC

/*DQ11 数据线*/
#define FMC_D11_GPIO_PORT         GPIOE
#define FMC_D11_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D11_GPIO_PIN          GPIO_Pin_14
#define FMC_D11_PINSOURCE         GPIO_PinSource14
#define FMC_D11_AF                GPIO_AF_FMC

/*DQ12 数据线*/
#define FMC_D12_GPIO_PORT         GPIOE
#define FMC_D12_GPIO_CLK          RCC_AHB1Periph_GPIOE
#define FMC_D12_GPIO_PIN          GPIO_Pin_15
#define FMC_D12_PINSOURCE         GPIO_PinSource15
#define FMC_D12_AF                GPIO_AF_FMC

/*DQ13 数据线*/
#define FMC_D13_GPIO_PORT         GPIOD
#define FMC_D13_GPIO_CLK          RCC_AHB1Periph_GPIOD
#define FMC_D13_GPIO_PIN          GPIO_Pin_8
#define FMC_D13_PINSOURCE         GPIO_PinSource8
#define FMC_D13_AF                GPIO_AF_FMC

/*DQ14 数据线*/
#define FMC_D14_GPIO_PORT         GPIOD
#define FMC_D14_GPIO_CLK          RCC_AHB1Periph_GPIOD
#define FMC_D14_GPIO_PIN          GPIO_Pin_9
#define FMC_D14_PINSOURCE         GPIO_PinSource9
#define FMC_D14_AF                GPIO_AF_FMC

/*DQ15 数据线*/
#define FMC_D15_GPIO_PORT         GPIOD
#define FMC_D15_GPIO_CLK          RCC_AHB1Periph_GPIOD
#define FMC_D15_GPIO_PIN          GPIO_Pin_10
#define FMC_D15_PINSOURCE         GPIO_PinSource10
#define FMC_D15_AF                GPIO_AF_FMC

/*控制信号线*/
/*CS 片选*/
#define FMC_CS_GPIO_PORT          GPIOH
#define FMC_CS_GPIO_CLK           RCC_AHB1Periph_GPIOH
#define FMC_CS_GPIO_PIN           GPIO_Pin_6
#define FMC_CS_PINSOURCE          GPIO_PinSource6
#define FMC_CS_AF                 GPIO_AF_FMC

/*WE 写使能*/
#define FMC_WE_GPIO_PORT          GPIOC
#define FMC_WE_GPIO_CLK           RCC_AHB1Periph_GPIOC
#define FMC_WE_GPIO_PIN           GPIO_Pin_0
#define FMC_WE_PINSOURCE          GPIO_PinSource0
#define FMC_WE_AF                 GPIO_AF_FMC

/*RAS 行选通*/
#define FMC_RAS_GPIO_PORT         GPIOF
#define FMC_RAS_GPIO_CLK          RCC_AHB1Periph_GPIOF
#define FMC_RAS_GPIO_PIN          GPIO_Pin_11
#define FMC_RAS_PINSOURCE         GPIO_PinSource11
#define FMC_RAS_AF                GPIO_AF_FMC

/*CAS 列选通*/
#define FMC_CAS_GPIO_PORT         GPIOG
#define FMC_CAS_GPIO_CLK          RCC_AHB1Periph_GPIOG
#define FMC_CAS_GPIO_PIN          GPIO_Pin_15
#define FMC_CAS_PINSOURCE         GPIO_PinSource15
#define FMC_CAS_AF                GPIO_AF_FMC

/*CLK 同步时钟,存储区域 2*/
#define FMC_CLK_GPIO_PORT         GPIOG
#define FMC_CLK_GPIO_CLK          RCC_AHB1Periph_GPIOG
#define FMC_CLK_GPIO_PIN          GPIO_Pin_8
#define FMC_CLK_PINSOURCE         GPIO_PinSource8
#define FMC_CLK_AF                GPIO_AF_FMC

/*CKE 时钟使能,存储区域 2*/
#define FMC_CKE_GPIO_PORT         GPIOH
#define FMC_CKE_GPIO_CLK          RCC_AHB1Periph_GPIOH
#define FMC_CKE_GPIO_PIN          GPIO_Pin_7
#define FMC_CKE_PINSOURCE         GPIO_PinSource7
#define FMC_CKE_AF                GPIO_AF_FMC

/*DQM1 数据掩码*/
#define FMC_UDQM_GPIO_PORT        GPIOE
#define FMC_UDQM_GPIO_CLK         RCC_AHB1Periph_GPIOE
#define FMC_UDQM_GPIO_PIN         GPIO_Pin_1
#define FMC_UDQM_PINSOURCE        GPIO_PinSource1
#define FMC_UDQM_AF               GPIO_AF_FMC

/*DQM0 数据掩码*/
#define FMC_LDQM_GPIO_PORT        GPIOE
#define FMC_LDQM_GPIO_CLK         RCC_AHB1Periph_GPIOE
#define FMC_LDQM_GPIO_PIN         GPIO_Pin_0
#define FMC_LDQM_PINSOURCE        GPIO_PinSource0
#define FMC_LDQM_AF               GPIO_AF_FMC

这里需要注意的是,我们在原理图上可以看到,FMC_SDCKE和FMC_SDNE我们都选择的是1,那说明SDRAM在内存中的映射为FMC_Block2,起始地址为0xD000 0000,SDRAM的大小为8M,因此结束地址为0xD080 0000。

二、FMC及SDRAM配置

1、时钟周期配置

关于时钟周期配置,可以看一下SDRAM的数据手册,输入的时钟为HCLK(180MHz)的2分频为90MHz,因此一个时钟周期为1/90MHz≈11.11ns。

a、TMRD:数据手册中参数要求为2个周期;

b、TXSR:最小时间要求为70ns,计算得为约7个周期;

c、TRAS:要求最小时间42ns,最大100000ns,计算得为最小4个周期;

d、TRC:要求最小63ns,计算得最小为6个周期;

e、TWR:CAS Latency选择为2时,周期为2;

f、TRP:要求最小为15ns,计算得为2个周期;

g、TRCD:要求最小为15ns,计算得为2个周期;

/* SDCLK: 90 Mhz (HCLK/2 :180Mhz/2) 1 个时钟周期 Tsdclk =1/90MHz=1/90000000Hz=11.11ns*/
/* TMRD: 2个时钟周期 */
FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2;
/* TXSR: min=70ns (70/11.11=6.03个周期) 即为7个周期*/
FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7;
/* TRAS: min=42ns (42/11.11=3.7个周期) max=100k (ns)因此最小可配置为4个周期 */
FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4;
/* TRC: min=63ns (63/11.11=5.67个周期) 即为6个周期 */
FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 6;
/* TWR: 最小为2个周期 */
FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2;
/* TRP: 15ns (15/11.11=1.35个周期) 即为2个周期 */
FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2;
/* TRCD: 15ns (15/11.11=1.35个周期) 即为2个周期 */
FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2;
2、FMC控制配置
/* FMC SDRAM 控制配置 */
/* 选择存储区域为FMC_Bank2_SDRAM */
FMC_SDRAMInitStructure.FMC_Bank = FMC_BANK_SDRAM;
/* 行地址线宽度: [7:0]共8位 */
FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;
/* 列地址线宽度: [11:0]共12位 */
FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b;
/* 数据线宽度位16 */
FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH;
/* 设置SDRAM 内部bank数量为4 */
FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
/* CAS 潜伏期 */
FMC_SDRAMInitStructure.FMC_CASLatency = SDRAM_CAS_LATENCY;
/* 禁止写保护*/
FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable;
/* SDCLK 时钟分频因子, SDCLK = HCLK/SDCLOCK_PERIOD*/
FMC_SDRAMInitStructure.FMC_SDClockPeriod = SDCLOCK_PERIOD;
/* 突发读模式设置*/
FMC_SDRAMInitStructure.FMC_ReadBurst = SDRAM_READBURST;
/* 读延迟配置 */
FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_0;
/* SDRAM 时序参数 */
FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct =&FMC_SDRAMTimingInitStructure;
/* 调用初始化函数,向寄存器写入配置 */
FMC_SDRAMInit(&FMC_SDRAMInitStructure);
/* 执行FMC SDRAM的初始化流程*/
SDRAM_InitSequence();				//函数在下面实现
3、初始化SDRAM
static void SDRAM_InitSequence(void)
{
    FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure;
    uint32_t tmpr = 0;
    
    /* 配置命令:开启提供给 SDRAM 的时钟 */
    //下发使能 CLK 命令
    FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;
    //设置FMC内部存储区域2
    FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
    //设置FMC自动刷新次数,前面未下发自动刷新,此项任意值即可。
    FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 0;
    //此时不下发加载模式寄存器,配置为任意值即可
    FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
    /* 检查 SDRAM 标志,等待至 SDRAM 空闲 */
    while (FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET);
    /* 发送上述命令*/
    FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
    /*延时 */
    SDRAM_delay(10);
    /* 配置命令:对所有的 bank 预充电 */
    //发送对所有Bank预充电命令
    FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL;
    //设置FMC内部存储区域2
    FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
    //设置FMC自动刷新次数,前面未下发自动刷新,此项任意值即可。
    FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 0;
    //此时不下发加载模式寄存器,配置为任意值即可
    FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
    /* 检查 SDRAM 标志,等待至 SDRAM 空闲 */
    while (FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET);
    /* 发送上述命令*/
    FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
    /*延时 */
    SDRAM_delay(10);
    /* 配置命令:自动刷新 */
    //发送自动刷新命令
    FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;
    //设置FMC内部存储区域2
    FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
     //设置FMC自动刷新次数,这里设置为2次
    FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 2;
    //此时不下发加载模式寄存器,配置为任意值即可
    FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
    /* 检查 SDRAM 标志,等待至 SDRAM 空闲 */
    while (FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET);
    /* 发送自动刷新命令*/
    FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
    /*延时 */
    SDRAM_delay(10);
    /* 设置 sdram 加载模式寄存器配置 */
    tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_4           |   //突发长度设置为4
                     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL    |   //突发模式为顺序模式
                     SDRAM_MODEREG_CAS_LATENCY_2            |   //列选通延迟为2个周期
                     SDRAM_MODEREG_OPERATING_MODE_STANDARD  |   //工作模式为正常模式
                     SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED;  //
    
    /* 配置命令:设置 SDRAM 寄存器 */
    FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode;
    FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_COMMAND_TARGET_BANK;
    FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 0;
    FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;
    /* 检查 SDRAM 标志,等待至 SDRAM 空闲 */
    while (FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET);
    /* 发送上述命令*/
    FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
    /*延时 */
    SDRAM_delay(10);
    /* 设置刷新计数器 */
    /*刷新速率 = (COUNT + 1) x SDRAM 频率时钟COUNT =( SDRAM 刷新周期/行数) - 20*/
    /* 64ms/4096=15.62us (15.62 us x FSDCLK) - 20 =1386 */
    FMC_SetRefreshCount(1386);
    /* 发送上述命令*/
    while (FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET);
}

到这里,已经可以实现SDRAM的读写了,这里我们写个测试程序,来实验一下上面的劳动成果。

三、测试

前面我们将SDRAM映射到FMC_Block2上了,起始地址为0xD0000000,这里我们将要用到的几个参数都做宏定义

#define SDRAM_SIZE 0x800000  //400000*16bits = 0x800000  ,8M字节
/*SDRAM 的bank选择*/
#define FMC_BANK_SDRAM            FMC_Bank2_SDRAM  
#define FMC_COMMAND_TARGET_BANK   FMC_Command_Target_bank2

/* 这里将SDRAM挂载在FMC_Block2这里,起始地址为0xD000 0000 */   
#define SDRAM_BANK_ADDR     ((uint32_t)0xD0000000)
  
/* FMC SDRAM 数据宽度 */  
#define SDRAM_MEMORY_WIDTH    FMC_SDMemory_Width_16b 

/* FMC SDRAM CAS Latency */  
#define SDRAM_CAS_LATENCY   FMC_CAS_Latency_2  

/* FMC SDRAM SDCLK时钟分频因子 */  
#define SDCLOCK_PERIOD    FMC_SDClock_Period_2 

/* FMC SDRAM 突发读取特性 */  
#define SDRAM_READBURST    FMC_Read_Burst_Enable  

映射之后,向SDRAM中写入读取数据就可以用指针的方式进行操作,如下:

#include "stm32f4xx.h"
#include "bsp_led.h"
#include "bsp_usart_dma.h"
#include "bsp_sdram.h"
#include 
uint16_t read_data;
int main(void)
{
    DEBUG_USART1_Config();
    LED_Config();
    printf("\r\n这是测试扩展外部SDRAM的例程实验\r\n");
    /*初始化SDRAM模块*/
    SDRAM_Init();
	*(uint16_t*)(SDRAM_BANK_ADDR) = 0xFEFE;
    read_data = *( uint16_t*) SDRAM_BANK_ADDR;
    printf("\r\n读取到的数据为:0x%x\r\n",read_data);
    while(1)
    {
    }
}

这里需要注意,虽然我们通过指针将数据存放到SDRAM中了,但是实际在读取的时候,定义的变量read_data还是存放在sdram中,双击工程名,打开map文件,查看read_data会发现,系统分配的地址还是在内部SRAM中。

023 - STM32学习笔记 - 扩展外部SDRAM(二) - 扩展外部SDRAM实验_第2张图片

如果想将变量也定义到SDRAM中的话,需要进行强制指定将变量分配到SDRAM中,方法如下:

#include "stm32f4xx.h"
#include "bsp_led.h"
#include "bsp_usart_dma.h"
#include "bsp_sdram.h"
#include 
uint16_t read_data;
uint16_t read_data1 __attribute__((at(SDRAM_BANK_ADDR+0x124)));		/* 强制指定将read_data1定义到SDRAM中 */
int main(void)
{
    DEBUG_USART1_Config();
    LED_Config();
    printf("\r\n这是测试扩展外部SDRAM的例程实验\r\n");
    /*初始化SDRAM模块*/
    SDRAM_Init();
	*(uint16_t*)(SDRAM_BANK_ADDR) = 0xFEFE;
    read_data = *( uint16_t*) SDRAM_BANK_ADDR;
    printf("\r\n读取到的数据为:0x%x\r\n",read_data);
    *(uint16_t*)(SDRAM_BANK_ADDR+0x124) = 0xf9f9;		//这里也可以直接用read_data1来赋值
    printf("\r\n读取到的数据为:0x%x\r\n",read_data1);
    while(1)
    {
    }
}

再看map文件中,read_data1已经被定义到SDRAM中了。

023 - STM32学习笔记 - 扩展外部SDRAM(二) - 扩展外部SDRAM实验_第3张图片

注意,在map中要查询变量的地址时,一定要将变量定义为全局变量,否则在map中查不到,并且此时强制指定分配地址也会无效。

你可能感兴趣的:(stm32,stm32)