野火视频教程:https://www.bilibili.com/video/BV1yW411Y7Gw?p=69
FSMC初始化结构体
时序结构体
typedef struct{uint32_t FSMC_AddressSetupTime; // 地址建立时间,0-0xF个HCLK周期uint32_t FSMC_AddressHoldTime; // 地址保持时间,0-0xF个HCLK周期uint32_t FSMC_DataSetupTime; // 地址建立时间,0-0xF个HCLK周期uint32_t FSMC_BusTurnAroundDuration; // 总线转换周期,0-0xF个HCLK周期,在NOR FLASHuint32_t FSMC_CLKDivision; // 时钟分频因子,1-0xF,若控制异步存储器,本参数无效uint32_t FSMC_DataLatency; // 数据延迟时间,若控制异步存储器,本参数无效uint32_t FSMC_AccessMode; // 设置访问模式}FSMC_NORSRAMTimingInitTypeDef;
- FSMC_AddressSetupTime:本成员设置地址建立时间,它可以被设置为0-0xF个HCLK周期数,按STM32标准库的默认配置,HCLK的时钟频率为72MHz,即一个HCLK周期为1/72us。
- FSMC_AddressHoldTime:本成员设置地址保持时间,它可以被设置为0-0xF个HCLK周期数。
- FSMC_DataSetupTime:本成员设置数据建立时间,它可以被设置为0-0xF个HCLK周期数。
- FSMC_BusTurnAroundDuration:本成员设置总线转换周期,在NOR FLASH存储器中,地址线与数据线可以分时复用,总线转换周期就是指总线在这两种状态间切换需要的延时,防止冲突。控制其他存储器时这个参数无效,配置为0即可。
- FSMC_CLKDivision:本成员用于设置时钟分频,它可以HCLK时钟作为输入,经过FSMC_CLKDivision分频后输出到FSMC_CLK引脚作为通讯使用的同步时钟。控制其他异步通讯的存储器时这个参数无效,配置为0即可。
- FSMC_DataLatency:本成员设置数据保持时间,它表示在读取第一个数据之前要等待的周期数,该周期指同步时钟的周期,本参数仅用于同步NOR FLASH类的存储器,控制其他类型的存储器时,本参数无效。
- FSMC_AccessMode:本成员设置存储器访问模式,不同的模式下FSMC访问存储器地址时引脚输出的时序不一样,可选FSMC_AccessMode_A/B/C/D模式,一般来说控制SRAM时使用A模式。
这个FSMC_NORSRAMTimingInitTypeDef时序结构体配置的延时参数,将作为下一节的FSMC SRAM初始化结构体的一个成员。
FSMC的SRAM初始化结构体
typedef struct{uint32_t FSMC_Bank; /*设置要控制的 Bank 区域 */uint32_t FSMC_DataAddressMux; /*设置地址总线与数据总线是否复用 */uint32_t FSMC_MemoryType; /*设置存储器的类型 */uint32_t FSMC_MemoryDataWidth; /*设置存储器的数据宽度*/uint32_t FSMC_BurstAccessMode; /*设置是否支持突发访问模式,只支持同步类型的存储器 */uint32_t FSMC_AsynchronousWait; /*设置是否使能在同步传输时的等待信号, */uint32_t FSMC_WaitSignalPolarity; /*设置等待信号的极性*/uint32_t FSMC_WrapMode; /*设置是否支持对齐的突发模式 */uint32_t FSMC_WaitSignalActive; /*配置等待信号在等待前有效还是等待期间有效 */uint32_t FSMC_WriteOperation; // 设置是否写使能uint32_t FSMC_WaitSignal; // 设置是否使能等待状态插入uint32_t FSMC_ExtendedMode; // 设置是否使能扩展模式uint32_t FSMC_WriteBurst; // 设置是否使能写突发操作// 当不使用扩展模式时,本参数用于配置读写时序,否则用于配置读时序FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct;// 当使用扩展模式时,本参数用于配置写时序FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;}FSMC_NORSRAMInitTypeDef;
这个结构体,除最后两个成员是上一小节讲解的时序配置外,其它结构体成员的配置都对应到 FSMC_BCR 中的寄存器位。各个成员意义介绍如下,括号中的是 STM32 标准库
定义的宏:
FSMC_Bank:本成员用于选择 FSMC 映射的存储区域, 它的可选参数以及相应的内核地址映射范围 | 可以输入的宏 | 对应的地址区域 | | —- | —- | | FSMC_Bank1_NORSRAM1 | 0x60000000-0x63FFFFFF | | FSMC_Bank1_NORSRAM2 | 0x64000000-0x67FFFFFF | | FSMC_Bank1_NORSRAM3 | 0x68000000-0x6BFFFFFF | | FSMC_Bank1_NORSRAM4 | 0x6C000000-0x6FFFFFFF |
FSMC_DataAddressMux:本成员用于设置地址总线与数据总线是否复用(FSMC_DataAddressMux_Enable/Disable),在控制 NOR FLASH 时,可以地址总线与数据总线可以分时复用,以减少使用 STM32 信号线的数量。
- FSMC_MemoryType:本成员用于设置要控制的存储器类型,它支持控制的存储器类型为 SRAM、PSRAM以及 NOR FLASH(FSMC_MemoryType_SRAM/PSRAM/NOR)。
- FSMC_MemoryDataWidth:本成员用于设置要控制的存储器的数据宽度,可选择设置成 8 或 16 位(FSMC_MemoryDataWidth_8b /16b)。
- FSMC_BurstAccessMode:本成员用于设置是否使用突发访问模式(FSMC_BurstAccessMode_Enable/Disable),突发访问模式是指发送一个地址后连续访问多个数据,非突发模式下每访问一个数据都需要输入一个地址,仅在控制同步类型的存储器时才能使用突发模式。
- FSMC_AsynchronousWait:本成员用于设置是否使能在同步传输时使用的等待信号(FSMC_AsynchronousWait_Enable/Disable),在控制同步类型的 NOR 或 PSRAM 时,存储器可以使用 FSMC_NWAIT 引脚通知 STM32 需要等待。
- FSMC_WaitSignalPolarity:本成员用于设置等待信号的有效极性,即要求等待时,使用高电平还是低电平(FSMC_WaitSignalPolarity_High/Low)。
- FSMC_WrapMode:本成员用于设置是否支持把非对齐的AHB 突发操作分割成 2 次线性操作(FSMC_WrapMode_Enable/Disable),该配置仅在突发模式下有效。
- FSMC_WaitSignalActive:本成员用于配置在突发传输模式时,决定存储器是在等待状态之前的一个数据周期有效还是在等待状态期间有效(FSMC_WaitSignalActive_BeforeWaitState/DuringWaitState)。
- FSMC_WriteOperation:这个成员用于设置是否写使能(FSMCWriteOperation Enable /Disable),禁止写使能的话 FSMC 只能从存储器中读取数据,不能写入。
- FSMC_WaitSignal:本成员用于设置当存储器处于突发传输模式时,是否允许通过 NWAIT 信号插入等待
状态(FSMC_WaitSignal_Enable/Disable)。 - FSMC_ExtendedMode:本成员用于设置是否使用扩展模式(FSMC_ExtendedMode_Enable/Disable),在非扩展模式下,对存储器读写的时序都只使用 FSMC_BCR 寄存器中的配置,即下面的FSMC_ReadWriteTimingStruct 结构体成员;在扩展模式下,对存储器的读写时序可以分开配置,读时序使用 FSMC_BCR 寄存器,写时序使用FSMC_BWTR 寄存器的配置,即下面的 FSMC_WriteTimingStruct 结构体。
- FSMC_ReadWriteTimingStruct:本成员是一个指针,赋值时使用上一小节中讲解的时序结构体FSMC_NORSRAMInitTypeDef 设置,当不使用扩展模式时,读写时序都使用本成员的参数配置。
- FSMC_WriteTimingStruct:同样地,本成员也是一个时序结构体的指针,只有当使用扩展模式时,本配置才有效,它是写操作使用的时序。
对本结构体赋值完成后,调用 FSMC_NORSRAMInit 库函数即可把配置参数写入到FSMC_BCR 及 FSMC_BTR/BWTR 寄存器中。
读写时序要求
- 读
ADDSET+1+DATAST+1 > 55ns
DATAS+1 > 40ns
ADDSET+1 > 0ns
- 写
ADDSET+1+DATAST+1 +2HCLK > 55ns
DATAS+1 > 22ns
ADDSET+1 > 0ns
FSMC—外部SRAM实例
bsp_sram.h
#ifndef __BSP_SRAM_H#define __BSP_SRAM_H#include "stm32f10x.h"#include "./usart/bsp_usart.h"//使用NOR/SRAM的 Bank1.sector3,地址位HADDR[27,26]=10//对IS61LV25616/IS62WV25616,地址线范围为A0~A17//对IS61LV51216/IS62WV51216,地址线范围为A0~A18#define Bank1_SRAM3_ADDR ((uint32_t)(0x68000000))#define IS62WV51216_SIZE 0x100000 //512*16/2bits = 0x100000 ,1M字节/*A地址信号线*/#define FSMC_A0_GPIO_PORT GPIOF#define FSMC_A0_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A0_GPIO_PIN GPIO_Pin_0#define FSMC_A1_GPIO_PORT GPIOF#define FSMC_A1_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A1_GPIO_PIN GPIO_Pin_1#define FSMC_A2_GPIO_PORT GPIOF#define FSMC_A2_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A2_GPIO_PIN GPIO_Pin_2#define FSMC_A3_GPIO_PORT GPIOF#define FSMC_A3_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A3_GPIO_PIN GPIO_Pin_3#define FSMC_A4_GPIO_PORT GPIOF#define FSMC_A4_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A4_GPIO_PIN GPIO_Pin_4#define FSMC_A5_GPIO_PORT GPIOF#define FSMC_A5_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A5_GPIO_PIN GPIO_Pin_5#define FSMC_A6_GPIO_PORT GPIOF#define FSMC_A6_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A6_GPIO_PIN GPIO_Pin_12#define FSMC_A7_GPIO_PORT GPIOF#define FSMC_A7_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A7_GPIO_PIN GPIO_Pin_13#define FSMC_A8_GPIO_PORT GPIOF#define FSMC_A8_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A8_GPIO_PIN GPIO_Pin_14#define FSMC_A9_GPIO_PORT GPIOF#define FSMC_A9_GPIO_CLK RCC_APB2Periph_GPIOF#define FSMC_A9_GPIO_PIN GPIO_Pin_15#define FSMC_A10_GPIO_PORT GPIOG#define FSMC_A10_GPIO_CLK RCC_APB2Periph_GPIOG#define FSMC_A10_GPIO_PIN GPIO_Pin_0#define FSMC_A11_GPIO_PORT GPIOG#define FSMC_A11_GPIO_CLK RCC_APB2Periph_GPIOG#define FSMC_A11_GPIO_PIN GPIO_Pin_1#define FSMC_A12_GPIO_PORT GPIOG#define FSMC_A12_GPIO_CLK RCC_APB2Periph_GPIOG#define FSMC_A12_GPIO_PIN GPIO_Pin_2#define FSMC_A13_GPIO_PORT GPIOG#define FSMC_A13_GPIO_CLK RCC_APB2Periph_GPIOG#define FSMC_A13_GPIO_PIN GPIO_Pin_3#define FSMC_A14_GPIO_PORT GPIOG#define FSMC_A14_GPIO_CLK RCC_APB2Periph_GPIOG#define FSMC_A14_GPIO_PIN GPIO_Pin_4#define FSMC_A15_GPIO_PORT GPIOG#define FSMC_A15_GPIO_CLK RCC_APB2Periph_GPIOG#define FSMC_A15_GPIO_PIN GPIO_Pin_5#define FSMC_A16_GPIO_PORT GPIOD#define FSMC_A16_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_A16_GPIO_PIN GPIO_Pin_11#define FSMC_A17_GPIO_PORT GPIOD#define FSMC_A17_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_A17_GPIO_PIN GPIO_Pin_12#define FSMC_A18_GPIO_PORT GPIOD#define FSMC_A18_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_A18_GPIO_PIN GPIO_Pin_13/*D 数据信号线*/#define FSMC_D0_GPIO_PORT GPIOD#define FSMC_D0_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_D0_GPIO_PIN GPIO_Pin_14#define FSMC_D1_GPIO_PORT GPIOD#define FSMC_D1_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_D1_GPIO_PIN GPIO_Pin_15#define FSMC_D2_GPIO_PORT GPIOD#define FSMC_D2_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_D2_GPIO_PIN GPIO_Pin_0#define FSMC_D3_GPIO_PORT GPIOD#define FSMC_D3_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_D3_GPIO_PIN GPIO_Pin_1#define FSMC_D4_GPIO_PORT GPIOE#define FSMC_D4_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D4_GPIO_PIN GPIO_Pin_7#define FSMC_D5_GPIO_PORT GPIOE#define FSMC_D5_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D5_GPIO_PIN GPIO_Pin_8#define FSMC_D6_GPIO_PORT GPIOE#define FSMC_D6_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D6_GPIO_PIN GPIO_Pin_9#define FSMC_D7_GPIO_PORT GPIOE#define FSMC_D7_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D7_GPIO_PIN GPIO_Pin_10#define FSMC_D8_GPIO_PORT GPIOE#define FSMC_D8_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D8_GPIO_PIN GPIO_Pin_11#define FSMC_D9_GPIO_PORT GPIOE#define FSMC_D9_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D9_GPIO_PIN GPIO_Pin_12#define FSMC_D10_GPIO_PORT GPIOE#define FSMC_D10_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D10_GPIO_PIN GPIO_Pin_13#define FSMC_D11_GPIO_PORT GPIOE#define FSMC_D11_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D11_GPIO_PIN GPIO_Pin_14#define FSMC_D12_GPIO_PORT GPIOE#define FSMC_D12_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_D12_GPIO_PIN GPIO_Pin_15#define FSMC_D13_GPIO_PORT GPIOD#define FSMC_D13_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_D13_GPIO_PIN GPIO_Pin_8#define FSMC_D14_GPIO_PORT GPIOD#define FSMC_D14_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_D14_GPIO_PIN GPIO_Pin_9#define FSMC_D15_GPIO_PORT GPIOD#define FSMC_D15_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_D15_GPIO_PIN GPIO_Pin_10/*控制信号线*//*CS片选*//*NE3 ,对应的基地址0x68000000*/#define FSMC_CS_GPIO_PORT GPIOG#define FSMC_CS_GPIO_CLK RCC_APB2Periph_GPIOG#define FSMC_CS_GPIO_PIN GPIO_Pin_10/*WE写使能*/#define FSMC_WE_GPIO_PORT GPIOD#define FSMC_WE_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_WE_GPIO_PIN GPIO_Pin_5/*OE读使能*/#define FSMC_OE_GPIO_PORT GPIOD#define FSMC_OE_GPIO_CLK RCC_APB2Periph_GPIOD#define FSMC_OE_GPIO_PIN GPIO_Pin_4/*UB数据掩码*/#define FSMC_UDQM_GPIO_PORT GPIOE#define FSMC_UDQM_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_UDQM_GPIO_PIN GPIO_Pin_1/*LB数据掩码*/#define FSMC_LDQM_GPIO_PORT GPIOE#define FSMC_LDQM_GPIO_CLK RCC_APB2Periph_GPIOE#define FSMC_LDQM_GPIO_PIN GPIO_Pin_0/*信息输出*/#define SRAM_DEBUG_ON 1#define SRAM_INFO(fmt,arg...) printf("<<-SRAM-INFO->> "fmt"\n",##arg)#define SRAM_ERROR(fmt,arg...) printf("<<-SRAM-ERROR->> "fmt"\n",##arg)#define SRAM_DEBUG(fmt,arg...) do{\if(SRAM_DEBUG_ON)\printf("<<-SRAM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\}while(0)void FSMC_SRAM_Init(void);void FSMC_SRAM_WriteBuffer(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t NumHalfwordToWrite);void FSMC_SRAM_ReadBuffer(uint8_t* pBuffer,uint32_t ReadAddr,uint32_t NumHalfwordToRead);uint8_t SRAM_Test(void);#endif // BSP_SRAM
bsp_sram.c
/********************************************************************************* @file bsp_sram.c* @author fire* @version V1.0* @date 2015-xx-xx* @brief sram应用函数接口******************************************************************************* @attention** 实验平台:野火 F103-霸道 STM32 开发板* 论坛 :http://www.firebbs.cn* 淘宝 :https://fire-stm32.taobao.com********************************************************************************/#include "./sram/bsp_sram.h"/*** @brief 初始化控制SRAM的IO* @param 无* @retval 无*/static void SRAM_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;/* 使能SRAM相关的GPIO时钟 *//*地址信号线*/RCC_APB2PeriphClockCmd(FSMC_A0_GPIO_CLK | FSMC_A1_GPIO_CLK | FSMC_A2_GPIO_CLK |FSMC_A3_GPIO_CLK | FSMC_A4_GPIO_CLK | FSMC_A5_GPIO_CLK |FSMC_A6_GPIO_CLK | FSMC_A7_GPIO_CLK | FSMC_A8_GPIO_CLK |FSMC_A9_GPIO_CLK | FSMC_A10_GPIO_CLK| FSMC_A11_GPIO_CLK|FSMC_A12_GPIO_CLK| FSMC_A13_GPIO_CLK|FSMC_A14_GPIO_CLK|FSMC_A15_GPIO_CLK|FSMC_A16_GPIO_CLK|FSMC_A17_GPIO_CLK|FSMC_A18_GPIO_CLK|/*数据信号线*/FSMC_D0_GPIO_CLK | FSMC_D1_GPIO_CLK | FSMC_D2_GPIO_CLK |FSMC_D3_GPIO_CLK | FSMC_D4_GPIO_CLK | FSMC_D5_GPIO_CLK |FSMC_D6_GPIO_CLK | FSMC_D7_GPIO_CLK | FSMC_D8_GPIO_CLK |FSMC_D9_GPIO_CLK | FSMC_D10_GPIO_CLK| FSMC_D11_GPIO_CLK|FSMC_D12_GPIO_CLK| FSMC_D13_GPIO_CLK| FSMC_D14_GPIO_CLK|FSMC_D15_GPIO_CLK|/*控制信号线*/FSMC_CS_GPIO_CLK | FSMC_WE_GPIO_CLK | FSMC_OE_GPIO_CLK |FSMC_UDQM_GPIO_CLK|FSMC_LDQM_GPIO_CLK, ENABLE);/*-- GPIO 配置 -----------------------------------------------------*//* 通用 GPIO 配置 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //配置为复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*A地址信号线 针对引脚配置*/GPIO_InitStructure.GPIO_Pin = FSMC_A0_GPIO_PIN;GPIO_Init(FSMC_A0_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A1_GPIO_PIN;GPIO_Init(FSMC_A1_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A2_GPIO_PIN;GPIO_Init(FSMC_A2_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A3_GPIO_PIN;GPIO_Init(FSMC_A3_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A4_GPIO_PIN;GPIO_Init(FSMC_A4_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A5_GPIO_PIN;GPIO_Init(FSMC_A5_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A6_GPIO_PIN;GPIO_Init(FSMC_A6_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A7_GPIO_PIN;GPIO_Init(FSMC_A7_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A8_GPIO_PIN;GPIO_Init(FSMC_A8_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A9_GPIO_PIN;GPIO_Init(FSMC_A9_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A10_GPIO_PIN;GPIO_Init(FSMC_A10_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A11_GPIO_PIN;GPIO_Init(FSMC_A11_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A12_GPIO_PIN;GPIO_Init(FSMC_A12_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A13_GPIO_PIN;GPIO_Init(FSMC_A13_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A14_GPIO_PIN;GPIO_Init(FSMC_A14_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A15_GPIO_PIN;GPIO_Init(FSMC_A15_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A16_GPIO_PIN;GPIO_Init(FSMC_A16_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A17_GPIO_PIN;GPIO_Init(FSMC_A17_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_A18_GPIO_PIN;GPIO_Init(FSMC_A18_GPIO_PORT, &GPIO_InitStructure);/*DQ数据信号线 针对引脚配置*/GPIO_InitStructure.GPIO_Pin = FSMC_D0_GPIO_PIN;GPIO_Init(FSMC_D0_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D1_GPIO_PIN;GPIO_Init(FSMC_D1_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D2_GPIO_PIN;GPIO_Init(FSMC_D2_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D3_GPIO_PIN;GPIO_Init(FSMC_D3_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D4_GPIO_PIN;GPIO_Init(FSMC_D4_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D5_GPIO_PIN;GPIO_Init(FSMC_D5_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D6_GPIO_PIN;GPIO_Init(FSMC_D6_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D7_GPIO_PIN;GPIO_Init(FSMC_D7_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D8_GPIO_PIN;GPIO_Init(FSMC_D8_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D9_GPIO_PIN;GPIO_Init(FSMC_D9_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D10_GPIO_PIN;GPIO_Init(FSMC_D10_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D11_GPIO_PIN;GPIO_Init(FSMC_D11_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D12_GPIO_PIN;GPIO_Init(FSMC_D12_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D13_GPIO_PIN;GPIO_Init(FSMC_D13_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D14_GPIO_PIN;GPIO_Init(FSMC_D14_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_D15_GPIO_PIN;GPIO_Init(FSMC_D15_GPIO_PORT, &GPIO_InitStructure);/*控制信号线*/GPIO_InitStructure.GPIO_Pin = FSMC_CS_GPIO_PIN;GPIO_Init(FSMC_CS_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_WE_GPIO_PIN;GPIO_Init(FSMC_WE_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_OE_GPIO_PIN;GPIO_Init(FSMC_OE_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_UDQM_GPIO_PIN;GPIO_Init(FSMC_UDQM_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = FSMC_LDQM_GPIO_PIN;GPIO_Init(FSMC_LDQM_GPIO_PORT, &GPIO_InitStructure);}//写时序的要求//1. ADDSET+1+DATAST+1 >55ns//2. DATAST+1 > 40ns//3. ADDSET+1 > 0ns//读时序的要求//1. ADDSET+1+DATAST+1 +2 >55ns//2. DATAST+1 > 25ns//3. ADDSET+1 > 0ns//1 个HCLK时钟周期://T = 1/72MHz = 1.38*10^-8 s = 13.8 ns//读时序的要求//ADDSET = 0//DATAST =1 (经测试,DATAST配置成1是不能正常工作的)//1. ADDSET+1+DATAST+1 +2 >55ns ------- 0+1+1+1+2 = 69 ns > 55ns//2. DATAST+1 > 25ns ------ 1+1 = 27.6 >25 ns//3. ADDSET+1 > 0ns ------ 0+1 = 13.8ns >0 ns//写时序的要求//ADDSET = 0//DATAST = 2//1. ADDSET+1+DATAST+1 >55ns ------ 0+1+2+1 =55.2 >55ns//2. DATAST+1 > 40ns ------ 2+1 = 41.4 >40 ns//3. ADDSET+1 > 0ns ------ 0+1 = 13.8ns >0 ns/*** @brief 初始化FSMC外设* @param None.* @retval None.*/void FSMC_SRAM_Init(void){FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;FSMC_NORSRAMTimingInitTypeDef readWriteTiming;/*初始化SRAM相关的GPIO*/SRAM_GPIO_Config();/*使能FSMC外设时钟*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE);//地址建立时间(ADDSET)为1个HCLK 1/72M=14nsreadWriteTiming.FSMC_AddressSetupTime = 0x00;//地址保持时间(ADDHLD)模式A未用到readWriteTiming.FSMC_AddressHoldTime = 0x00;//数据保持时间(DATAST)+ 1个HCLK = 3/72M=42ns(对EM的SRAM芯片)readWriteTiming.FSMC_DataSetupTime = 0x02; // 2是经验值,理论值为1//设置总线转换周期,仅用于复用模式的NOR操作readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;//设置时钟分频,仅用于同步类型的存储器readWriteTiming.FSMC_CLKDivision = 0x00;//数据保持时间,仅用于同步型的NORreadWriteTiming.FSMC_DataLatency = 0x00;//选择匹配SRAM的模式readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;// 选择FSMC映射的存储区域: Bank1 sram3FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;//设置地址总线与数据总线是否复用,仅用于NORFSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;//设置要控制的存储器类型:SRAM类型FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_SRAM;//存储器数据宽度:16位FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//设置是否使用突发访问模式,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;//设置是否使能等待信号,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;//设置等待信号的有效极性,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;//设置是否支持把非对齐的突发操作,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;//设置等待信号插入的时间,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;//存储器写使能FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;//不使用等待信号FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;// 不使用扩展模式,读写使用相同的时序FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;//突发写操作FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;//读写时序配置FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;//读写同样时序,使用扩展模式时这个配置才有效FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming;FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); //初始化FSMC配置FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); // 使能BANK}/*** @brief 以“字”为单位向sdram写入数据* @param pBuffer: 指向数据的指针* @param uwWriteAddress: 要写入的SRAM内部地址* @param uwBufferSize: 要写入数据大小* @retval None.*/void SRAM_WriteBuffer(uint32_t* pBuffer, uint32_t uwWriteAddress, uint32_t uwBufferSize){__IO uint32_t write_pointer = (uint32_t)uwWriteAddress;/* 循环写入数据 */for (; uwBufferSize != 0; uwBufferSize--){/* 发送数据到SRAM */*(uint32_t *) (Bank1_SRAM3_ADDR + write_pointer) = *pBuffer++;/* 地址自增*/write_pointer += 4;}}/*** @brief 从SRAM中读取数据* @param pBuffer: 指向存储数据的buffer* @param ReadAddress: 要读取数据的地十* @param uwBufferSize: 要读取的数据大小* @retval None.*/void SRAM_ReadBuffer(uint32_t* pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize){__IO uint32_t write_pointer = (uint32_t)uwReadAddress;/*读取数据 */for(; uwBufferSize != 0x00; uwBufferSize--){*pBuffer++ = *(__IO uint32_t *)(Bank1_SRAM3_ADDR + write_pointer );/* 地址自增*/write_pointer += 4;}}/*** @brief 测试SRAM是否正常* @param None* @retval 正常返回1,异常返回0*/uint8_t SRAM_Test(void){/*写入数据计数器*/uint32_t counter=0;/* 8位的数据 */uint8_t ubWritedata_8b = 0, ubReaddata_8b = 0;/* 16位的数据 */uint16_t uhWritedata_16b = 0, uhReaddata_16b = 0;SRAM_INFO("正在检测SRAM,以8位、16位的方式读写sram...");/*按8位格式读写数据,并校验*//* 把SRAM数据全部重置为0 ,IS62WV51216_SIZE是以8位为单位的 */for (counter = 0x00; counter < IS62WV51216_SIZE; counter++){*(__IO uint8_t*) (Bank1_SRAM3_ADDR + counter) = (uint8_t)0x0;}/* 向整个SRAM写入数据 8位 */for (counter = 0; counter < IS62WV51216_SIZE; counter++){*(__IO uint8_t*) (Bank1_SRAM3_ADDR + counter) = (uint8_t)(ubWritedata_8b + counter);}/* 读取 SRAM 数据并检测*/for(counter = 0; counter<IS62WV51216_SIZE;counter++ ){ubReaddata_8b = *(__IO uint8_t*)(Bank1_SRAM3_ADDR + counter); //从该地址读出数据if(ubReaddata_8b != (uint8_t)(ubWritedata_8b + counter)) //检测数据,若不相等,跳出函数,返回检测失败结果。{SRAM_ERROR("8位数据读写错误!");return 0;}}/*按16位格式读写数据,并检测*//* 把SRAM数据全部重置为0 */for (counter = 0x00; counter < IS62WV51216_SIZE/2; counter++){*(__IO uint16_t*) (Bank1_SRAM3_ADDR + 2*counter) = (uint16_t)0x00;}/* 向整个SRAM写入数据 16位 */for (counter = 0; counter < IS62WV51216_SIZE/2; counter++){*(__IO uint16_t*) (Bank1_SRAM3_ADDR + 2*counter) = (uint16_t)(uhWritedata_16b + counter);}/* 读取 SRAM 数据并检测*/for(counter = 0; counter<IS62WV51216_SIZE/2;counter++ ){uhReaddata_16b = *(__IO uint16_t*)(Bank1_SRAM3_ADDR + 2*counter); //从该地址读出数据if(uhReaddata_16b != (uint16_t)(uhWritedata_16b + counter)) //检测数据,若不相等,跳出函数,返回检测失败结果。{SRAM_ERROR("16位数据读写错误!");return 0;}}SRAM_INFO("SRAM读写测试正常!");/*检测正常,return 1 */return 1;}/*********************************************END OF FILE**********************/
main.c
/********************************************************************************* @file FSMC—外部SRAM* @author fire* @version V1.0* @date 2015-xx-xx* @brief sram应用例程******************************************************************************* @attention** 实验平台:野火 F103-霸道 STM32 开发板* 论坛 :http://www.firebbs.cn* 淘宝 :https://fire-stm32.taobao.com********************************************************************************/#include "stm32f10x.h"#include "./usart/bsp_usart.h"#include "./led/bsp_led.h"#include "./sram/bsp_sram.h"/*绝对定位方式访问SRAM,这种方式必须定义成全局变量*/uint8_t testValue __attribute__((at(Bank1_SRAM3_ADDR)));/*** @brief 主函数* @param 无* @retval 无*/int main(void){LED_GPIO_Config();//串口初始化USART_Config();//初始化外部SRAMFSMC_SRAM_Init();printf ( "\r\n野火外部 SRAM 测试\r\n" );/*蓝灯亮,表示正在读写SRAM测试*/LED_BLUE;/*对SRAM进行读写测试,检测SRAM是否正常*/if(SRAM_Test()==1){//测试正常 绿灯亮LED_GREEN;}else{//测试失败 红灯亮LED_RED;}/*指针方式访问SRAM*/{uint32_t temp;printf("\r\n指针方式访问SRAM\r\n");/*向SRAM写入8位数据*/*( uint8_t*) (Bank1_SRAM3_ADDR ) = (uint8_t)0xAA;printf("\r\n指针访问SRAM,写入数据0xAA \r\n");/*从SRAM读取数据*/temp = *( uint8_t*) (Bank1_SRAM3_ADDR );printf("读取数据:0x%X \r\n",temp);/*写/读 16位数据*/*( uint16_t*) (Bank1_SRAM3_ADDR+10 ) = (uint16_t)0xBBBB;printf("指针访问SRAM,写入数据0xBBBB \r\n");temp = *( uint16_t*) (Bank1_SRAM3_ADDR+10 );printf("读取数据:0x%X \r\n",temp);/*写/读 32位数据*/*( uint32_t*) (Bank1_SRAM3_ADDR+20 ) = (uint32_t)0xCCCCCCCC;printf("指针访问SRAM,写入数据0xCCCCCCCC \r\n");temp = *( uint32_t*) (Bank1_SRAM3_ADDR+20 );printf("读取数据:0x%X \r\n",temp);}/*绝对定位方式访问SRAM,这种方式必须定义成全局变量*/{testValue = 0xDD;printf("\r\n绝对定位访问SRAM,写入数据0xDD,读出数据0x%X,变量地址为%X\r\n",testValue,(uint32_t )&testValue);}}/*********************************************END OF FILE**********************/
可执行程序:FSMC—外部SRAM.zip
FSMC—外部SRAM(内存管理)
bsp_malloc.h
#ifndef __BSP_MALLOC_H#define __BSP_MALLOC_H#include "stm32f10x.h"#ifndef NULL#define NULL 0#endif//定义两个内存池#define SRAMIN 0 //内部内存池#define SRAMEX 1 //外部内存池#define SRAMBANK 2 //定义支持的SRAM块数.//mem1内存参数设定.mem1完全处于内部SRAM里面.#define MEM1_BLOCK_SIZE 32 //内存块大小为32字节#define MEM1_MAX_SIZE 40*1024 //最大管理内存 40K#define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //内存表大小//mem2内存参数设定.mem2的内存池处于外部SRAM里面#define MEM2_BLOCK_SIZE 32 //内存块大小为32字节#define MEM2_MAX_SIZE 960 *1024 //最大管理内存960K#define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //内存表大小//内存管理控制器struct _m_mallco_dev{void ( * init ) ( uint8_t ); //初始化uint8_t ( * perused ) ( uint8_t ); //内存使用率uint8_t * membase [ SRAMBANK ]; //内存池 管理SRAMBANK个区域的内存uint16_t * memmap [ SRAMBANK ]; //内存管理状态表uint8_t memrdy [ SRAMBANK ]; //内存管理是否就绪};extern struct _m_mallco_dev mallco_dev; //在mallco.c里面定义void mymemset(void *s,uint8_t c,uint32_t count); //设置内存void mymemcpy(void *des,void *src,uint32_t n); //复制内存void my_mem_init(uint8_t memx); //内存管理初始化函数(外/内部调用)uint32_t my_mem_malloc(uint8_t memx,uint32_t size); //内存分配(内部调用)uint8_t my_mem_free(uint8_t memx,uint32_t offset); //内存释放(内部调用)uint8_t my_mem_perused(uint8_t memx); //获得内存使用率(外/内部调用)//用户调用函数void myfree(uint8_t memx,void *ptr); //内存释放(外部调用)void *mymalloc(uint8_t memx,uint32_t size); //内存分配(外部调用)void *myrealloc(uint8_t memx,void *ptr,uint32_t size); //重新分配内存(外部调用)#endif // __BSP_MALLOC_H
bsp_malloc.c
#include "bsp_malloc.h"//内存池(32字节对齐)__align(32) uint8_t mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池__align(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); //外部SRAM内存池//内存管理表uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; //内部SRAM内存池MAPuint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE))); //外部SRAM内存池MAP//内存管理参数const uint32_t memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE}; //内存表大小const uint32_t memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE}; //内存分块大小const uint32_t memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE}; //内存总大小//内存管理控制器struct _m_mallco_dev mallco_dev={my_mem_init, //内存初始化my_mem_perused, //内存使用率mem1base,mem2base, //内存池mem1mapbase,mem2mapbase, //内存管理状态表0,0, //内存管理未就绪};//复制内存//*des:目的地址//*src:源地址//n:需要复制的内存长度(字节为单位)void mymemcpy(void *des,void *src,uint32_t n){uint8_t *xdes=des;uint8_t *xsrc=src;while(n--)*xdes++=*xsrc++;}//设置内存//*s:内存首地址//c :要设置的值//count:需要设置的内存大小(字节为单位)void mymemset(void *s,uint8_t c,uint32_t count){uint8_t *xs = s;while(count--)*xs++=c;}//内存管理初始化//memx:所属内存块void my_mem_init(uint8_t memx){mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零mymemset(mallco_dev.membase[memx], 0,memsize[memx]); //内存池所有数据清零mallco_dev.memrdy[memx]=1; //内存管理初始化OK}//获取内存使用率//memx:所属内存块//返回值:使用率(0~100)uint8_t my_mem_perused(uint8_t memx){uint32_t used=0;uint32_t i;for(i=0;i<memtblsize[memx];i++){if(mallco_dev.memmap[memx][i])used++;}return (used*100)/(memtblsize[memx]);}//内存分配(内部调用)//memx:所属内存块//size:要分配的内存大小(字节)//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址uint32_t my_mem_malloc(uint8_t memx,uint32_t size){signed long offset=0;uint32_t nmemb; //需要的内存块数uint32_t cmemb=0;//连续空内存块数uint32_t i;if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先执行初始化if(size==0)return 0XFFFFFFFF;//不需要分配nmemb=size/memblksize[memx]; //获取需要分配的连续内存块数if(size%memblksize[memx])nmemb++;for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区{if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加else cmemb=0; //连续内存块清零if(cmemb==nmemb) //找到了连续nmemb个空内存块{for(i=0;i<nmemb;i++) //标注内存块非空{mallco_dev.memmap[memx][offset+i]=nmemb;}return (offset*memblksize[memx]);//返回偏移地址}}return 0XFFFFFFFF;//未找到符合分配条件的内存块}//释放内存(内部调用)//memx:所属内存块//offset:内存地址偏移//返回值:0,释放成功;1,释放失败;uint8_t my_mem_free(uint8_t memx,uint32_t offset){int i;if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化{mallco_dev.init(memx);return 1;//未初始化}if(offset<memsize[memx])//偏移在内存池内.{int index=offset/memblksize[memx]; //偏移所在内存块号码int nmemb=mallco_dev.memmap[memx][index]; //内存块数量for(i=0;i<nmemb;i++) //内存块清零{mallco_dev.memmap[memx][index+i]=0;}return 0;}elsereturn 2;//偏移超区了.}//释放内存(外部调用)//memx:所属内存块//ptr:内存首地址void myfree(uint8_t memx,void *ptr){uint32_t offset;if(ptr==NULL)return;//地址为0.offset=(uint32_t)ptr-(uint32_t)mallco_dev.membase[memx];my_mem_free(memx,offset); //释放内存}//分配内存(外部调用)//memx:所属内存块//size:内存大小(字节)//返回值:分配到的内存首地址.void *mymalloc(uint8_t memx,uint32_t size){uint32_t offset;offset=my_mem_malloc(memx,size);if(offset==0XFFFFFFFF)return NULL;else return (void*)((uint32_t)mallco_dev.membase[memx]+offset);}//重新分配内存(外部调用)//memx:所属内存块//*ptr:旧内存首地址//size:要分配的内存大小(字节)//返回值:新分配到的内存首地址.void *myrealloc(uint8_t memx,void *ptr,uint32_t size){uint32_t offset;offset=my_mem_malloc(memx,size);if(offset==0XFFFFFFFF)return NULL;else{ //拷贝旧内存内容到新内存mymemcpy((void*)((uint32_t)mallco_dev.membase[memx]+offset),ptr,size);//释放旧内存myfree(memx,ptr);//返回新内存首地址return (void*)((uint32_t)mallco_dev.membase[memx]+offset);}}
main.c
/********************************************************************************* @file FSMC—外部SRAM(内存管理)* @author fire* @version V1.0* @date 2015-xx-xx* @brief sram应用例程******************************************************************************* @attention** 实验平台:野火 F103-霸道 STM32 开发板* 论坛 :http://www.firebbs.cn* 淘宝 :https://fire-stm32.taobao.com********************************************************************************/#include "stm32f10x.h"#include "./usart/bsp_usart.h"#include "./led/bsp_led.h"#include "./sram/bsp_sram.h"#include "bsp_malloc.h"int main(void){u8 *p=0;u8 sramx=0; //默认为内部sramUSART_Config(); //串口初始化为115200FSMC_SRAM_Init(); //初始化外部SRAMmy_mem_init(SRAMIN); //初始化内部内存池my_mem_init(SRAMEX); //初始化外部内存池printf ( "\r\n野火内存管理\r\n" );printf ( "\r\n分配内存\r\n" );p = mymalloc ( sramx, 1024 *2 );//申请2K字节sprintf((char*)p,"Memory Malloc");//使用申请空间存储内容printf ( "SRAMIN USED:%d%%\r\n", my_mem_perused(SRAMIN) );//显示内部内存使用率printf ( "SRAMEX USED:%d%%\r\n", my_mem_perused(SRAMEX) );//显示外部内存使用率myfree(sramx,p); //释放内存p=0; //指向空地址printf ( "\r\n释放内存\r\n" );printf ( "SRAMIN USED:%d%%\r\n", my_mem_perused(SRAMIN) );//显示内部内存使用率printf ( "SRAMEX USED:%d%%\r\n", my_mem_perused(SRAMEX) );//显示外部内存使用率while(1);}/*********************************************END OF FILE**********************/
可执行程序:FSMC—外部SRAM(内存管理).zip
