023- STM32学习笔记 - 扩展外部SDRAM(一) - 扩展外部SDRAM实验
本节内容中要配置的引脚很多,如果你用的开发板跟我的不一样,请详细参照STM32规格书中说明对相关GPIO引脚进行配置。
先提前对本届内容的变成步骤进行总结如下:
- 初始化通讯使用的目标引脚及端口时钟;(再次强调,只要使用外设,一定要看时钟时候配置正确并开启!)
- 是能FMC外设时钟;(再再次强调,只要使用外设,一定要看时钟时候配置正确并开启!)
- 配置FMC SDRAM的时序和工作模式;
- 根据SDRAM的初始化流程编写初始化函数;
- 访问外部SDRAM存储器;
- 编写测试程序,校验读写的数据。
OK,参照如上步骤,实战之前先将我用的F429开发板中SDRAM部分贴出来。
一、相关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 <stdio.h>
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中。
如果想将变量也定义到SDRAM中的话,需要进行强制指定将变量分配到SDRAM中,方法如下:
#include "stm32f4xx.h"
#include "bsp_led.h"
#include "bsp_usart_dma.h"
#include "bsp_sdram.h"
#include <stdio.h>
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中了。
注意,在map中要查询变量的地址时,一定要将变量定义为全局变量,否则在map中查不到,并且此时强制指定分配地址也会无效。