SRAM—> 内存
Flash–>硬盘
外置SRAM
可以存储1M数据
地址线:A0-A18;2^18次方;512K个数据块
每个数据块是2字节;
数据线:D0-D15
UB/LB 掩码;低电平有效
UB -》低电平-》数据高字节有效
LB-》低电平 -》数据低字节有效
OE: 读使能;低电平有效
WE:写使能,低电平有效
FSMC-- 扩展外部SRAM
用来管理拓展的存储器外设
驱动静态存储器,只能驱动SRAM,不能驱动SDRAM
驱动动态存储器的外设是FMC,STM32F407不支持,420支持
直接挂在到AHB总线上
STM32F407内存分布:
每一个Bank内部分为4块;这四块通过FSMC的片选区分;FSMC_NE1-4
硬件连接
代码
void MY_FSMC_INIT(void)
{
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStruct;// 初始化用到的结构体
FSMC_NORSRAMTimingInitTypeDef FSMC_NORSRAMTimingInitStruct; //时序结构体
//初始化FSMC相关GPIO
FSMC_GPIO_INIT();
//使能时钟
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);
//初始化时序结构体
FSMC_NORSRAMTimingInitStruct.FSMC_AccessMode = FSMC_AccessMode_A; //sram
FSMC_NORSRAMTimingInitStruct.FSMC_AddressSetupTime = 0; //地址保持时间 (0+1 CLK)
FSMC_NORSRAMTimingInitStruct.FSMC_DataSetupTime = 8; //数据保持时间 (8+1 CLK)
//以下时序配置跟异步SRAM无关
FSMC_NORSRAMTimingInitStruct.FSMC_AddressHoldTime = 0;
FSMC_NORSRAMTimingInitStruct.FSMC_BusTurnAroundDuration = 0;
FSMC_NORSRAMTimingInitStruct.FSMC_CLKDivision = 0;
FSMC_NORSRAMTimingInitStruct.FSMC_DataLatency = 0;
//其他参数与异步SRAM无关
//SRAM 总时间要求最小55ns, 数据保持时间最小25ns
// 一个clk 时间 1/168微妙 = 0.0059 = 6ns;一个clk约等于6ns
//读写都差不多
// 初始化FSMC结构体
FSMC_NORSRAMInitStruct.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable ;
FSMC_NORSRAMInitStruct.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; //异步等待
FSMC_NORSRAMInitStruct.FSMC_Bank = FSMC_Bank1_NORSRAM3;//bank
FSMC_NORSRAMInitStruct.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;//数据线和地址线是否复用
FSMC_NORSRAMInitStruct.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
FSMC_NORSRAMInitStruct.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//数据线宽度
FSMC_NORSRAMInitStruct.FSMC_MemoryType = FSMC_MemoryType_SRAM;//存储类型; SRAM
FSMC_NORSRAMInitStruct.FSMC_WriteOperation = FSMC_WriteOperation_Enable;//支持写
FSMC_NORSRAMInitStruct.FSMC_ReadWriteTimingStruct = &FSMC_NORSRAMTimingInitStruct;
FSMC_NORSRAMInitStruct.FSMC_WriteTimingStruct = &FSMC_NORSRAMTimingInitStruct;
//以下配置SRAM存储器没有用到
FSMC_NORSRAMInitStruct.FSMC_WaitSignal = FSMC_WaitSignal_Disable ;
FSMC_NORSRAMInitStruct.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState ;
FSMC_NORSRAMInitStruct.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low ;
FSMC_NORSRAMInitStruct.FSMC_WrapMode = FSMC_WrapMode_Disable ;
FSMC_NORSRAMInitStruct.FSMC_WriteBurst = FSMC_WriteBurst_Disable ;
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStruct);
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3,ENABLE);
}
static void FSMC_GPIO_INIT(void)
{
//1)配置GPIO和串口时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE, ENABLE);//通过AHB1总线使能GPIOF G D E组的时钟
//2) 配置GPIO为复用模式
GPIO_InitTypeDef Gpio_Value;
Gpio_Value.GPIO_Mode = GPIO_Mode_AF;//选择的是复用模式
Gpio_Value.GPIO_OType = GPIO_OType_PP;//选择推挽输出
Gpio_Value.GPIO_PuPd = GPIO_PuPd_UP;//选择下拉
Gpio_Value.GPIO_Speed = GPIO_Speed_100MHz;//选择100MHz
Gpio_Value.GPIO_Pin = GPIO_Pin_0
| GPIO_Pin_1
| GPIO_Pin_2
| GPIO_Pin_3
| GPIO_Pin_4
| GPIO_Pin_5
| GPIO_Pin_12
| GPIO_Pin_13
| GPIO_Pin_14
| GPIO_Pin_15;
GPIO_Init(GPIOF, &Gpio_Value);//按照上述配置初始化GPIOF组的管脚
Gpio_Value.GPIO_Pin = GPIO_Pin_0
| GPIO_Pin_1
| GPIO_Pin_2
| GPIO_Pin_3
| GPIO_Pin_4
| GPIO_Pin_5
| GPIO_Pin_10;
GPIO_Init(GPIOG, &Gpio_Value);//按照上述配置初始化GPIOG组的管脚
Gpio_Value.GPIO_Pin = GPIO_Pin_0
| GPIO_Pin_1
| GPIO_Pin_11
| GPIO_Pin_12
| GPIO_Pin_13
| GPIO_Pin_14
| GPIO_Pin_15
| GPIO_Pin_8
| GPIO_Pin_9
| GPIO_Pin_10
| GPIO_Pin_4
| GPIO_Pin_5;
GPIO_Init(GPIOD, &Gpio_Value);//按照上述配置初始化GPIOD组的管脚
Gpio_Value.GPIO_Pin = GPIO_Pin_0
| GPIO_Pin_1
| GPIO_Pin_11
| GPIO_Pin_12
| GPIO_Pin_13
| GPIO_Pin_14
| GPIO_Pin_15
| GPIO_Pin_8
| GPIO_Pin_9
| GPIO_Pin_10
| GPIO_Pin_7;
GPIO_Init(GPIOE, &Gpio_Value);//按照上述配置初始化GPIOE组的管脚
GPIO_PinAFConfig(GPIOF,GPIO_PinSource0,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource1,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource2,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource3,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource4,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource5,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource12,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource13,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource14,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource15,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource0,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource1,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource2,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource3,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource4,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource5,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource10,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource11,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource8,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource9,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource10,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource4,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource7,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource8,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource10,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource12,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource13,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource14,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource15,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource1,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource0,GPIO_AF_FSMC);
}
主函数
#define INER_SRAM_ADDR 0x20001000
#define SRAM_BASE_ADDR 0x68000000
int main(void)
{
my_usart_init();
MY_FSMC_INIT();
printf("\n\n Begin 内部数据 \n\n");
volatile uint8_t *p = (uint8_t *)INER_SRAM_ADDR;
*p = 0x77;
printf("write 0x77\n");
printf("read is 0x%x\n",*p);
printf("\n\n Begin SRAM \n\n");
p = (uint8_t *)SRAM_BASE_ADDR;
*p = 0x77;
printf("write 0x77\n");
printf("addr : 0x%p read is 0x%x\n",p,*p);
while(1)
{
}
//return 0;
}
attribute 关键字
在Keil中使用此关键字指定变量存储地址
volatile uint8_t testvalue __attribute((at(0x6C000050)));
volatile double testvalue_double __attribute((at(0x6C000080)));
//变量类型 变量名 __attribute((at(指定的变量地址)));
//当地址为外部SRAM空间时
//1.必须为全局变量
//2.变量定义的初始值无效
//3.必须放在FSMC初始化之后才使用