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

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

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

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

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

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内部存储区域2FMC_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内部存储区域2FMC_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内部存储区域2FMC_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           |   //突发长度设置为4SDRAM_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中查不到,并且此时强制指定分配地址也会无效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/112159.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)

C# 在调用Cdll时&#xff0c;可能会出现 &#xff1a;试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)这个错误。 一般情况下是C#目标平台跟Cdll不兼容&#xff0c;64位跟32位兼容性问题&#xff0c; a.客户端调用Cdll报的错则&#xff0c; 1)允许的话把C#客户端…

C语言程序设计——小学生计算机辅助教学系统

题目&#xff1a;小学生计算机辅助教学系统 编写一个程序&#xff0c;帮助小学生学习乘法。然后判断学生输入的答案对错与否&#xff0c;按下列任务要求以循序渐进的方式分别编写对应的程序并调试。 任务1 程序首先随机产生两个1—10之间的正整数&#xff0c;在屏幕上打印出问题…

数据库——事务,事务隔离级别

文章目录 什么是事务?事务的特性(ACID)并发事务带来的问题事务隔离级别实际情况演示脏读(读未提交)避免脏读(读已提交)不可重复读可重复读防止幻读(可串行化) 什么是事务? 事务是逻辑上的一组操作&#xff0c;要么都执行&#xff0c;要么都不执行。 事务最经典也经常被拿出…

研磨设计模式day12命令模式

目录 定义 几个参数 场景描述 代码示例 参数化设置 命令模式的优点 本质 何时选用 定义 几个参数 Command&#xff1a;定义命令的接口。 ConcreteCommand:命令接口的实现对象。但不是真正实现&#xff0c;是通过接收者的功能来完成命令要执行的操作 Receiver&#x…

创建web应用程序,React和Vue怎么选?

React和Vue都是创建web应用程序的绝佳选择。React得到了科技巨头和庞大的开源社区的支持&#xff0c;代码库可以很大程度地扩展&#xff0c;允许你创建企业级web应用程序。React拥有大量合格甚至优秀的开发人员粉丝&#xff0c;可以解决你在开发阶段可能遇到的任何问题。 毫无疑…

视频汇聚/视频云存储/视频监控管理平台EasyCVR新增首次登录强制修改密码

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚平台既具…

机器学习:无监督学习

文章目录 线性学习方法聚类ClusteringKmeansHAC 分布表示降维PCAMatrix FactorizationManifold LearningLLELaplacian Eigenmapst-SEN 线性学习方法 聚类Clustering Kmeans 随机选取K个中心&#xff0c;然后计算每个点与中心的距离&#xff0c;找最近的&#xff0c;然后更新中…

感觉车载测试的这一波敏捷风快过去了

敏捷&#xff0c;算不得汽车行业的原生产物&#xff0c;几年前&#xff0c;耳边很少听到这个字眼&#xff0c;基本算是在近几年传统汽车行业开始衰落的大背景下&#xff0c;而后伴随着软件从互联网等行业传进来的。 这两年&#xff0c;大家开始把敏捷谈得风生水起&#xff0c;…

如何保证跨境传输的安全性?

随着互联网时代的到来&#xff0c;全球文件传输频率不断增加&#xff0c;市场经济的发展也对信息共享提出更高要求。传统电话交流已无法满足跨国企业的需求&#xff0c;企业内部诸如Web、电子邮件、企业资源计划&#xff08;ERP&#xff09;、网络电话&#xff08;VOIP&#xf…

面试了38位Java候选人之后,我总结出了他们关于面试中的16条通病

都说现在Java面试卷&#xff0c;前段时间项目招人的时候&#xff0c;我刚好就作为面试官面试了一些人 在整个面试的过程中&#xff0c;我就发现了一些关于面试的通病 所以呢&#xff0c;趁着这次金&#xff08;铜&#xff09;九银&#xff08;铁&#xff09;十的机会&#xf…

WebAssembly 在云原生中的实践指南

1 WebAssembly 介绍 WebAssembly&#xff08;Wasm&#xff09;是一种通用字节码技术&#xff0c;它可以将其他编程语言&#xff08;如 Go、Rust、C/C 等&#xff09;的程序代码编译为可在浏览器环境直接执行的字节码程序。 WebAssembly 的初衷之一是解决 JavaScript 的性能问…

4、Spring之Bean生命周期源码解析(创建)

Spring最重要的功能就是帮助程序员创建对象(也就是IOC),而启动Spring就是为创建Bean对象做准备,所以我们先明白Spring到底是怎么去创建Bean的,也就是先弄明白Bean的生命周期。 Bean的生命周期就是指:在Spring中,一个Bean是如何生成的,如何销毁的。 Bean生命周期流程图…

C语言练习题解析:挑战与突破,开启编程新篇章!(2)

&#x1f493;博客主页&#xff1a;江池俊的博客⏩收录专栏&#xff1a;C语言刷题专栏&#x1f449;专栏推荐&#xff1a;✅C语言初阶之路 ✅C语言进阶之路&#x1f4bb;代码仓库&#xff1a;江池俊的代码仓库&#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐ 文…

ssm端游游戏账号销售管理系统源码和论文

ssm端游游戏账号销售管理系统源码和论文069 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面…

电脑上的视频如何导入苹果手机?

AirDroid支持Windows、macOS、android、iOS相互传输文件、视频、图片等。 想要从电脑传输文件到iPhone也很简单&#xff0c;在电脑和iPhone都安装AirDroid&#xff0c;连接同一网络&#xff0c;然后登录同一个帐号就可以了。可绑定的iPhone数量不限&#xff0c;只要都登录同一…

测试理论与方法----软件测试工作流程第一个环节:提取测试需求

测试理论与方法 一、软件测试流程 1、软件测试定义 软件&#xff1a;程序数据文档&#xff1a;不仅仅包含应用程序&#xff0c;还应该包含和这个程序相关的数据&#xff0c;文档 软件测试&#xff1a;测试的对象&#xff1a;应用程序&#xff0c;数据&#xff0c;文档 软件…

学习pytorch7 神经网络的基本骨架--nn,module的使用

神经网络的基本骨架--nn,module的使用 官网Module介绍Python父类子类继承关系前向神经网络pycharm快捷键重写类方法codedebug B站小土堆视频学习笔记 官网Module介绍 https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module Python父类子类继承关系…

Unity 之利用 localEulerAngle与EulerAngle 控制物体旋转

文章目录 概念讲解localEulerAngle与EulerAngle的区别 概念讲解 欧拉角&#xff08;Euler Angles&#xff09;是一种常用于描述物体在三维空间中旋转的方法。它使用三个角度来表示旋转&#xff0c;分别绕物体的三个坐标轴&#xff08;通常是X、Y和Z轴&#xff09;进行旋转。这…

docker之 Consul(注册与发现)

目录 一、什么是服务注册与发现&#xff1f; 二、什么是consul 三、consul 部署 3.1建立Consul服务 3.1.1查看集群状态 3.1.2通过 http api 获取集群信息 3.2registrator服务器 3.2.1安装 Gliderlabs/Registrator 3.2.2测试服务发现功能是否正常 3.2.3验证 http 和 ng…

LeetCode第21~25题解

CONTENTS LeetCode 21. 合并两个有序链表&#xff08;简单&#xff09;LeetCode 22. 括号生成&#xff08;中等&#xff09;LeetCode 23. 合并K个升序链表&#xff08;困难&#xff09;LeetCode 24. 两两交换链表中的节点&#xff08;中等&#xff09;LeetCode 25. K 个一组翻转…