【普中STM32F1xx开发攻略--标准库版】-- 第 45 章 FSMC-外扩 SRAM 实验

发布时间:2026/6/9 9:44:37

【普中STM32F1xx开发攻略--标准库版】-- 第 45 章 FSMC-外扩 SRAM 实验 (1)实验平台普中STM32F103 朱雀、玄武开发板https://item.taobao.com/item.htm?id620302685024(2)资料下载 普中科技-各型号产品资料下载链接在前面的 FSMC-TFTLCD 实验章节中我们已经介绍过 FSMC 知道了通过它可以外扩存储器。 我们使用的 STM32F103ZET6 本身就有 64K 字节的 SRAM 对一般应用来说 已经足够使用 不过在一些对内存要求高的场合 STM32F1 自带的这些内存就不够用了 比如跑算法或者 GUI 等。 因此我们 STM32F1 开发板上集成了一颗 1M 字节容量的 SRAM 芯片 IS62WV51216 来满足大内存使用的需求。 这一章我们就来学习如何使用 FSMC45.1 IS62WV51216 介绍42.2 FSMC 配置步骤45.3 硬件设计45.4 软件设计45.4.1 外扩 SRAM 初始化函数45.4.2 外扩 SRAM 读写函数45.4.3 外扩 SRAM 容量测试函数45.4.4 主函数45.5 实验现象控制外扩 1MB 的 SRAMIS62WV51216 实现对IS62WV51216 的访问控制 并测试其容量。 本章要实现的功能是 测试外扩 SRAM IS62WV51216 的容量 并通过 KEY_UP 和 KEY1 键控制 SRAM 数据的读写 同时控制 DS0 指示灯闪烁 提示系统正常运行。 学习本章可以参考“FSMC-TFTLCD 实验” 章节内容 IS62WV51216 芯片介绍可以参考“\6--芯片资料\开发板芯片数据手册\IS62WV51216” 。 本章分为如下几部分内容45.1 IS62WV51216 介绍IS62WV51216 是 ISSIIntegrated Silicon Solution, Inc 公司生产的一颗 16 位宽 512K512*16 即 1M 字节 容量的 CMOS 静态内存芯片。 它拥有如下几个特点1) 高速访问。 具有 45ns/55ns 访问速度2) 低功耗。-36mW典型 操作功耗。-12uW典型 待机功耗。3) 兼容 TTL 电平接口。4) 全静态操作。 不需要刷新和时钟电路。5 三态输出。6) 字节控制功能。 支持高/低字节控制。IS62WV51216 的引脚如下图所示图中对应的引脚功能如下A0~18 为地址线 总共 19 根地址线可访问 2^19512K 空间1K1024 IO0~15 为数据线 总共 16 根数据线。 CS2 和 CS1 都是片选信号 不过 CS2 是高电平有效 CS1 是低电平有效 OE 是输出使能信号读信号 WE 为输入使能信号写信号 UB 和 LB 分别是高字节控制和低字节控制信号我们开发板已将 IS62WV51216 芯片连接在 STM32F1 的 FSMC 上 所以可以直接通过 FSMC 控制。 具体连接图在后面硬件设计部分介绍。 如果大家想要了解更多 IS62WV51216 芯片信息 可以参考“\6--芯片资料\开发板芯片数据手册\IS62WV51216” 。本章 我们使用 FSMC 的 Bank1 区域 3 来控制 IS62WV51216 关于 FSMC的详细介绍 我们在“FSMC-TFTLCD 显示实验” 已经介绍过 当时我们采用的是读写不同的时序来操作 TFTLCD 模块因为 TFTLCD 模块读的速度比写的速度慢很多 但是在本章 因为 IS62WV51216 的读写时间基本一致 所以 我们设置读写相同的时序来访问 FSMC。42.2 FSMC 配置步骤接下来我们介绍下如何使用库函数对 FSMC 的 Bank1 区域 3 进行配置。 这个也是在编写程序中必须要了解的。 FSMC 配置步骤在“FSMC-TFTLCD 显示实验” 章节已经详细讲解 这里我们简单提下 步骤如下 FSMC 相关库函数在stm32f10x_fsmc.c 和 stm32f10x_fsmc.h 文件中1 使能 FSMC 及端口时钟 并将对应 IO 配置为复用功能要使用 FSMC 必须使能其时钟 当然还需要使能 FSMC 对应引脚的端口时钟并将这些 IO 口配置为复用功能。使能 FSMC 及端口时钟函数为RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);//使能 FSMC 时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF|RCC_APB2Periph_GPIOG, ENABLE);同时配置对应的 IO 为复用功能 即初始化 GPIO。 如GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP;//复用输出2 初始化 FSMC 包括 FSMC 区域的选择、 读写时间设定等此部分包括设置区域 3 的存储器的工作模式、 位宽和读写时序等。 本章我们使用模式 A、 16 位宽 读写共用一个时序寄存器。 这个是通过调用函数FSMC_NORSRAMInit 来实现的 函数原型为void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct);3 使能 FSMC 的 Bank1 区域 3初始化 FSMC 后 接着就是使能 FSMC 本实验使用的是 FSMC 的 Bank1 区域 3控制 IS62WV51216 芯片 所以要使能 Bank1 区域 3。 函数为FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); // 使能 BANK3通过以上几个步骤 我们就完成了 FSMC 的 Bank1 区域 3 的配置 可以访问IS62WV51216 了 这里还需要注意 因为我们使用的是 Bank1 的区域 3 所以HADDR[27:26]10 故外部内存的首地址为 0X68000000。45.3 硬件设计本实验使用到硬件资源如下1 DS0 指示灯2 KEY_UP 和 KEY1 按键3 串口 14 TFTLCD 模块5 IS62WV51216DS0 指示灯、 KEY_UP 和 KEY1 按键、 串口 1、 TFTLCD 模块电路在前面章节都介绍过 这里就不多说 下面我们看下 IS62WV51216 与 STM32F1 的连接电路图如下图所示从电路图中可以看到 IS62WV51216 与 STM32F1 的连接关系是A0-A18 连接在 FSMC_A0-FSMC_A18 上IO0-IO15 连接在 FSMC_D0-FSMC_D15 上UB 和 LB 连接在 FSMC_NBL1 和 FSMC_NBL0 上OE 连接在 FSMC_NOE 上WE 连接在 FSMC_NWE 上CE 连接在 FSMC_NE3 上FSMC 具体对应的 IO 口 大家可以打开开发板原理图查看 这里就不截图。这里提醒下大家 A0-A18 与 FSMC_A0-FSMC_A18 的连接顺序可以打乱 因为地址是固定的 但是 IO0-IO15 和 FSMC_D0-FSMC_D15 的连接顺序不可打乱 否则读写数据将出错。DS0 指示灯用来提示系统运行状态 KEY_UP 和 KEY1 按键用来控制IS62WV51216 数据读写 TFTLCD 模块和串口 1 用来显示读写的内容。45.4 软件设计本章所要实现的功能是 测试外扩 SRAM IS62WV51216 的容量 并通过KEY_UP 和 KEY1 键控制 SRAM 数据的读写 同时控制 DS0 指示灯闪烁 提示系统正常运行。 本章实验我们使用的是 FSMC 的 Bank1 区域 3 来控制 IS62WV51216程序框架如下1 初始化外扩 SRAM初始化 FSMC 的 Bank1 区域 32 编写外扩 SRAM 的读写函数3 编写外扩 SRAM 容量测试函数4 编写主函数前面介绍 FSMC 配置步骤时 就已经讲解如何初始化 FSMC 的 Bank1 区域 3。下面我们打开“\4--实验程序\1--基础实验\37-FSMC-外扩 SRAM 实验” 工程 在APP 工程组中可以看到添加了 sram.c 文件里面包含了外扩 SRAM 的驱动程序 在 StdPeriph_Driver 工程组中添加了 stm32f10x_fsmc.c 库文件。 FSMC 操作的库函数都放在 stm32f10x_fsmc.c 和 stm32f10x_fsmc.h 文件中 所以使用到 FSMC就必须加入 stm32f10x_fsmc.c 文件 同时还要包含对应的头文件路径。这里我们分析几个重要函数 其他部分程序大家可以打开工程查看。45.4.1 外扩 SRAM 初始化函数通过前面的硬件电路介绍 我们知道外扩 SRAM 是直接连在 FSMC 上的 并且片选是通过 FSMC_NE3 控制 而且我们使用的是 FSMC 的 Bank1 区域 3 来控制外扩SRAM 因此要对 FSMC 的 Bank1 区域 3 初始化。 具体代码如下 在 FSMC_SRAM_Init()函数中 首先使能对应端口及 FSMC 时钟 并将对应的IO口复用映射为FSMC功能 然后初始化FSMC相关寄存器 最后使能FSMC的Bank1区域 3。 这一过程在前面步骤介绍中已经提了。45.4.2 外扩 SRAM 读写函数初始化后 我们就可以使用 FSMC 来控制外扩 SRAM 读写数据了 具体代码如下//在指定地址(WriteAddrBank1_SRAM3_ADDR)开始,连续写入n个字节. //pBuffer:字节指针 //WriteAddr:要写入的地址 //n:要写入的字节数 void FSMC_SRAM_WriteBuffer(u8* pBuffer,u32 WriteAddr,u32 n) { for(;n!0;n--) { *(u8*)(Bank1_SRAM3_ADDRWriteAddr)*pBuffer; WriteAddr; } } //在指定地址((WriteAddrBank1_SRAM3_ADDR))开始,连续读出n个字节. //pBuffer:字节指针 //ReadAddr:要读出的起始地址 //n:要写入的字节数 void FSMC_SRAM_ReadBuffer(u8* pBuffer,u32 ReadAddr,u32 n) { for(;n!0;n--) { *pBuffer*(u8*)(Bank1_SRAM3_ADDRReadAddr); ReadAddr; } }FSMC_SRAM_WriteBuffer 函数功能是在指定的地址处写入 n 个字节数据FSMC_SRAM_ReadBuffer 函数功能是从指定的地址处读取 n 个字节数据。 这两个函数内都使用了一个 Bank1_SRAM3_ADDR 这个是我们在 sram.h 开始处定义的Bank1 区域 3 的起始地址宏 地址为 0x68000000。这里需要注意的是 FSMC 当位宽为 16 位的时候 HADDR 右移一位同地址对齐 但是 ReadAddr 我们这里却没有加 2 而是加 1 是因为我们这里用的数据为宽是 8 位 通过 UB 和 LB 来控制高低字节位 所以地址在这里是可以只加 1 的。45.4.3 外扩 SRAM 容量测试函数编写好了外扩 SRAM 的读写函数后 接下来我们就可以测试其容量 具体代码如下//外部内存测试(最大支持 1M 字节内存测试) void ExSRAM_Cap_Test(u16 x,u16 y) { u8 writeData 0xf0, readData; u16 cap0; u32 addr; addr 1024; //从 1KB 位置开始算起 LCD_ShowString(x,y,239,y16,16,ExSRAM Cap: 0KB); while(1) { FSMC_SRAM_WriteBuffer(writeData, addr, 1); FSMC_SRAM_ReadBuffer(readData,addr,1); /* 查看读取到的数据是否跟写入数据一样 */ if(readData writeData) { cap; addr 1024; readData 0; if(addr 1024 * 1024) //SRAM 容量最大为 1MB { break; } } else { break; } } LCD_ShowxNum(x11*8,y,cap,4,16,0);//显示内存容量 printf(SRAM 容量为 %dKB\r\n,cap); }该函数功能很简单 就是判断对应地址写入和读取的数据是否一致 一致就表明 SRAM 正常 让 cap 加 1 直到 1MB 判断完成 此时 cap 值已自加了 1024 次每一次判断是经过 1KB。45.4.4 主函数编写好外扩 SRAM 初始化、 读写及容量测试函数后 接下来就可以编写主函数了 代码如下#include system.h #include SysTick.h #include led.h #include usart.h #include tftlcd.h #include key.h #include sram.h u8 text_buf[]www.prechin.net; #define TEXT_LEN sizeof(text_buf) //外部内存测试(最大支持1M字节内存测试) void ExSRAM_Cap_Test(u16 x,u16 y) { u8 writeData 0xf0, readData; u16 cap0; u32 addr; addr 1024; //从1KB位置开始算起 LCD_ShowString(x,y,239,y16,16,ExSRAM Cap: 0KB); while(1) { FSMC_SRAM_WriteBuffer(writeData, addr, 1); FSMC_SRAM_ReadBuffer(readData,addr,1); /* 查看读取到的数据是否跟写入数据一样 */ if(readData writeData) { cap; addr 1024; readData 0; if(addr 1024 * 1024) //SRAM容量最大为1MB { break; } } else { break; } } LCD_ShowxNum(x11*8,y,cap,4,16,0);//显示内存容量 printf(SRAM容量为%dKB\r\n,cap); } int main() { u8 i0; u8 key; u8 read_buf[TEXT_LEN]; SysTick_Init(72); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组 LED_Init(); USART1_Init(115200); TFTLCD_Init(); //LCD初始化 KEY_Init(); FSMC_SRAM_Init(); FRONT_COLORBLACK; LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,16,PRECHIN STM32F1); LCD_ShowString(10,30,tftlcd_data.width,tftlcd_data.height,16,www.prechin.net); LCD_ShowString(10,50,tftlcd_data.width,tftlcd_data.height,16,ExSRAM Test); LCD_ShowString(10,70,tftlcd_data.width,tftlcd_data.height,16,K_UP:Write KEY1:Read); FRONT_COLORRED; ExSRAM_Cap_Test(10,110); LCD_ShowString(10,130,tftlcd_data.width,tftlcd_data.height,16,Write:); LCD_ShowString(10,150,tftlcd_data.width,tftlcd_data.height,16,Read :); while(1) { keyKEY_Scan(0); if(keyKEY_UP_PRESS) { FSMC_SRAM_WriteBuffer(text_buf,0,TEXT_LEN); printf(写入的数据是%s\r\n,text_buf); LCD_ShowString(106*8,130,tftlcd_data.width,tftlcd_data.height,16,(u8 *)text_buf); } if(keyKEY1_PRESS) { FSMC_SRAM_ReadBuffer(read_buf,0,TEXT_LEN); printf(读取的数据是%s\r\n,read_buf); LCD_ShowString(106*8,150,tftlcd_data.width,tftlcd_data.height,16,read_buf); } i; if(i%200) { LED1!LED1; } delay_ms(10); } }主函数实现的功能很简单 首先调用之前编写好的硬件初始化函数 包括SysTick 系统时钟 中断分组 LED 初始化等。 然后调用我们前面编写的FSMC_SRAM_Init 函数初始化 FSMC 的 Bank1 区域 3 接着调用 ExSRAM_Cap_Test函数测试外扩 SRAM 的容量 将结果显示在 TFTLCD 上 同时通过串口 1 打印输出。最后进入 while 循环 检测 KEY_UP 和 KEY1 键是否按下 如果 KEY_UP 按下将text_buf 数组内容从 0 地址开始写入到外扩 SRAM 内 如果 KEY1 按下将从 0 地址开始处读取写入的数据 保存在 read_buf 内。 将写入和读取的数据显示在TFTLCD 模块上 并通过串口 1 打印输出。 同时 DS0 指示灯会间隔 200ms 闪烁提示系统正常运行。45.5 实验现象将工程程序编译后下载到开发板内 可以看到 DS0 指示灯不断闪烁 表示程序正常运行。 并且 TFTLCD 模块上会显示外扩 SRAM 的容量1024KB 通过 KEY_UP和 KEY1 键可以控制数据的读写 并在 TFTLCD 上显示。 实现现象如下图所示实验说明 保存在外扩 SDRAM 内的数据 在掉电后会丢失。

相关新闻