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.mzph.cn/news/60272.shtml

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

相关文章

supervisorctl(-jar)启动配置设置NACOS不同命名空间

背景 由于需要在上海服务器上面配置B测试环境&#xff0c;原本上面已有A测试环境&#xff0c;固需要将两套权限系统分开 可以使用不同的命名空间来隔离启动服务 注&#xff1a;本文章均不涉及公司机密 1、新建命名空间 命名空间默认会有一个public&#xff0c;并且不能删除&a…

【QT】信号和槽(15)

前面的内容说了很多不同的控件如何使用&#xff0c;今天来看下QT的核心&#xff0c;信号与槽&#xff08;Signals and slots&#xff09;&#xff01; 简单理解一下&#xff0c;就是我们的信号与槽连接上了之后&#xff0c;发射一个信号给到槽&#xff0c;槽函数接收到了这个信…

数据库(一) 基础知识

概述 数据库是按照数据结构来组织,存储和管理数据的仓库 数据模型 数据库系统的核心和基础是数据模型&#xff0c;数据模型是严格定义的一组概念的集合。因此数据模型一般由数据结构、数据操作和完整性约束三部分组成。数据模型主要分为三种:层次模型&#xff0c;网状模型和关…

docker linux(centos 7) 安装

这是个目录 1:安装1:手动安装(适用于centos7)之一2:手动安装(适用于centos7)之二3&#xff1a;一键安装docker4:二进制安装1&#xff1a;下载二进制包2&#xff1a;解压3&#xff1a;移动文件4&#xff1a;后台运行docker5&#xff1a;测试 dicker命令表999&#xff1a;遇到的问…

java解析html

目录 场景描述一.引入依赖二.调用接口响应回来的html三.测试代码 场景描述 我调用外部接口&#xff0c;但是返回来的数据是html的格式&#xff0c;所以我就需要进行处理来获得我想要的数据。我使用的是jsoup。 一.引入依赖 <dependency><groupId>org.jsoup</gr…

Go 使用 Gorm 将操作信息集成到链路跟踪 Jaeger,进行增删改查使用举例,并做可视化UI界面展示(附源码)

Go 使用 Gorm 将操作信息集成到链路跟踪 Jaeger,进行增删改查使用举例(附源码)。 为了增强程序的可观测性,方便问题定位,在发起数据库操作请求时我们也可以调用代码统一集成链路跟踪的能力,Jaeger 是当今比较流行的选择。使用 Gorm 来将操作信息集成到 Jaeger 中。 全面…

C++笔记之临时变量与临时对象与匿名对象

C笔记之临时变量与临时对象与匿名对象 code review! 文章目录 C笔记之临时变量与临时对象与匿名对象1.C中的临时变量指的是什么&#xff1f;2.C中的临时对象指的是什么&#xff1f;3.C中临时对象的作用是什么&#xff1f;什么时候要用到临时对象?4.给我列举具体的例子说明临…

回归预测 | MATLAB实现CSO-ELM布谷鸟算法优化极限学习机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现CSO-ELM布谷鸟算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现CSO-ELM布谷鸟算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本介…

html中如何用vue语法,并使用UI组件库 ,html中引入vue+ant-design-vue或者vue+element-plus

html中如何用vue语法&#xff0c;并使用UI组件库 前言 先说一下本次应用的场景&#xff0c;本次项目中&#xff0c;需要引入github中别人写好的插件&#xff0c;插件比较大&#xff0c;没有方法直接在自己项目中&#xff0c;把别人的项目打包合并生成html&#xff08;类似于前…

Muscles|Tissue —— 介绍

BETA —— 此功能仍然在开发测试中&#xff0c;相关文档很少或没有&#xff0c;使用时需注意&#xff1b; 可使用Vellum-based Muscles & Tissue系统&#xff0c;模拟角色的肌肉、组织、及皮肤&#xff1b;可轻易导入模型和动画&#xff0c;并快速配置解算模拟&#xff1b;…

提高企业会计效率,选择Manager for Mac(企业会计软件)

作为一家企业&#xff0c;良好的财务管理是保持业务运转的关键。而选择一款适合自己企业的会计软件&#xff0c;能够帮助提高会计效率、减少错误和节约时间。在众多的选择中&#xff0c;Manager for Mac(企业会计软件)是一款值得考虑的优秀软件。 首先&#xff0c;Manager for…

Java流式编程详细介绍

文章目录 1. 流式编程介绍2. 过滤2.1 filter2.2 distinct2.3 limit2.4 sorted2.5 skip 3. 映射3.1 map3.2 flatmap 4 查找4.1 allMatch4.2 anyMatch4.3 noneMatch4.4 findFirst4.5 findAny 5. 归约6. 收集6.1 counting6.2 maxBy,minBy6.3 summingInt、summingLong、summingDoub…

【jvm】运行时数据区

目录 一、运行时数据区一、作用二、说明三、线程共用与私有区域 一、运行时数据区 一、作用 1.内存是非常重要的系统资源&#xff0c;是硬盘和CPU 的中间仓库及桥梁&#xff0c;承载着操作系统和应用程序的实时运行。JVM内存布局规定了Java在运行过程中内存申请、分配、管理的策…

分布式集群——搭建Hadoop环境以及相关的Hadoop介绍

系列文章目录 分布式集群——jdk配置与zookeeper环境搭建 分布式集群——搭建Hadoop环境以及相关的Hadoop介绍 文章目录 前言 一 hadoop的相关概念 1.1 Hadoop概念 补充&#xff1a;块的存储 1.2 HDFS是什么 1.3 三种节点的功能 I、NameNode节点 II、fsimage与edits…

Kubernetes(K8s 1.28.x)部署---超详细

目录 一、基础环境配置&#xff08;所有主机均要配置&#xff09; 1、配置IP地址和主机名、hosts解析 2、关闭防火墙、禁用SELinux 3、安装常用软件 4、配置时间同步 5、禁用Swap分区 6、修改linux的内核参数 7、配置ipvs功能 二、容器环境操作 1、定制软件源 2、安…

色温曲线坐标轴的选取:G/R、G/B还是R/G、B/G ?

海思色温曲线坐标 Mstar色温曲线坐标 高通色温曲线坐标 联咏色温曲线坐标 查看各家白平衡调试界面&#xff0c;比如海思、Mstart、高通等调试资料&#xff0c;白平衡模块都是以R/G B/G作为坐标系的两个坐标轴&#xff0c;也有方案是以G/R G/B作为坐标系的两个坐标轴。 以G/R G…

Fooocus启动时modules报错的解决方法

原理&#xff1a;是由于其他程序的安装导致modules的版本不对&#xff0c;先卸载现有版本&#xff0c;再运行run.bat让其自动安装响应的modules版本。 1、cmd运行windows dos终端。 2、将Fooocus_win64_1-1-1035文件夹备份&#xff0c;rename为Fooocus_win64_1-1-1035backup文…

【Kafka】Kafka Stream简单使用

一、实时流式计算 1. 概念 一般流式计算会与批量计算相比较。在流式计算模型中&#xff0c;输入是持续的&#xff0c;可以认为在时间上是无界的&#xff0c;也就意味着&#xff0c;永远拿不到全量数据去做计算。同时&#xff0c;计算结果是持续输出的&#xff0c;也即计算结果…

向函数传递参数(传地址)

过往课程 向函数传递参数&#xff08;传值、传引用、传const引用&#xff09; 传地址 向函数传地址&#xff0c;是指将变量的地址传递给函数。 函数通过声明参数为地址变量来接收一个变量的地址。 示例如下&#xff1a; #include <iostream> using namespace std;v…

Mybatis 日志(JDK Log)

上一篇我们介绍了Mybatis中的参数&#xff0c;本篇我们使用JDK Log打印一下Mybatis运行时的日志&#xff0c;看一下Mybatis执行的过程。 这里我选取上一篇的示例进行JDK Log的集成&#xff0c;这里如果您想对上一篇进行详细了解&#xff0c;可以参考&#xff1a; Mybatis参数…