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

(1)实验平台:

普中STM32F103 朱雀、玄武开发板https://item.taobao.com/item.htm?id=620302685024(2)资料下载 :普中科技-各型号产品资料下载链接


在前面的 FSMC-TFTLCD 实验章节中我们已经介绍过 FSMC, 知道了通过它可以外扩存储器。 我们使用的 STM32F103ZET6 本身就有 64K 字节的 SRAM, 对一般应用来说, 已经足够使用, 不过在一些对内存要求高的场合, STM32F1 自带的这些内存就不够用了, 比如跑算法或者 GUI 等。 因此我们 STM32F1 开发板上集成了一颗 1M 字节容量的 SRAM 芯片: IS62WV51216, 来满足大内存使用的需求。 这一章我们就来学习如何使用 FSMC

[45.1 IS62WV51216 介绍](#45.1 IS62WV51216 介绍)

[42.2 FSMC 配置步骤](#42.2 FSMC 配置步骤)

[45.3 硬件设计](#45.3 硬件设计)

[45.4 软件设计](#45.4 软件设计)

[45.4.1 外扩 SRAM 初始化函数](#45.4.1 外扩 SRAM 初始化函数)

[45.4.2 外扩 SRAM 读写函数](#45.4.2 外扩 SRAM 读写函数)

[45.4.3 外扩 SRAM 容量测试函数](#45.4.3 外扩 SRAM 容量测试函数)

[45.4.4 主函数](#45.4.4 主函数)

[45.5 实验现象](#45.5 实验现象)


控制外扩 1MB 的 SRAM(IS62WV51216) , 实现对IS62WV51216 的访问控制, 并测试其容量。 本章要实现的功能是: 测试外扩 SRAM (IS62WV51216) 的容量, 并通过 KEY_UP 和 KEY1 键控制 SRAM 数据的读写, 同时控制 DS0 指示灯闪烁, 提示系统正常运行。 学习本章可以参考"FSMC-TFTLCD 实验" 章节内容, IS62WV51216 芯片介绍可以参考"\6--芯片资料\开发板芯片数据手册\IS62WV51216" 。 本章分为如下几部分内容:

45.1 IS62WV51216 介绍

IS62WV51216 是 ISSI(Integrated Silicon Solution, Inc) 公司生产的一颗 16 位宽 512K(512*16, 即 1M 字节) 容量的 CMOS 静态内存芯片。 它拥有如下几个特点:

  1. 高速访问。 具有 45ns/55ns 访问速度

  2. 低功耗。

-36mW(典型) 操作功耗。

-12uW(典型) 待机功耗。

  1. 兼容 TTL 电平接口。

  2. 全静态操作。 不需要刷新和时钟电路。

5) 三态输出。

  1. 字节控制功能。 支持高/低字节控制。

IS62WV51216 的引脚如下图所示:

图中对应的引脚功能如下:

A0~18 为地址线, 总共 19 根地址线(可访问 2^19=512K 空间(1K=1024) ); 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 及端口时钟函数为:

cpp 复制代码
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);//使能 FSMC 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF|RCC_APB2Periph_GPIOG, ENABLE);

同时配置对应的 IO 为复用功能, 即初始化 GPIO。 如:

cpp 复制代码
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用输出

(2) 初始化 FSMC, 包括 FSMC 区域的选择、 读写时间设定等

此部分包括设置区域 3 的存储器的工作模式、 位宽和读写时序等。 本章我们使用模式 A、 16 位宽, 读写共用一个时序寄存器。 这个是通过调用函数FSMC_NORSRAMInit 来实现的, 函数原型为:

cpp 复制代码
void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct);

(3) 使能 FSMC 的 Bank1 区域 3

初始化 FSMC 后, 接着就是使能 FSMC, 本实验使用的是 FSMC 的 Bank1 区域 3控制 IS62WV51216 芯片, 所以要使能 Bank1 区域 3。 函数为:

cpp 复制代码
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); // 使能 BANK3

通过以上几个步骤, 我们就完成了 FSMC 的 Bank1 区域 3 的配置, 可以访问IS62WV51216 了, 这里还需要注意, 因为我们使用的是 Bank1 的区域 3, 所以HADDR27:26=10, 故外部内存的首地址为 0X68000000。

45.3 硬件设计

本实验使用到硬件资源如下:

(1) DS0 指示灯

(2) KEY_UP 和 KEY1 按键

(3) 串口 1

(4) TFTLCD 模块

(5) IS62WV51216

DS0 指示灯、 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 区域 3)

(2) 编写外扩 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 读写数据了, 具体代码如下

cpp 复制代码
//在指定地址(WriteAddr+Bank1_SRAM3_ADDR)开始,连续写入n个字节.
//pBuffer:字节指针
//WriteAddr:要写入的地址
//n:要写入的字节数
void FSMC_SRAM_WriteBuffer(u8* pBuffer,u32 WriteAddr,u32 n)
{
	for(;n!=0;n--)  
	{										    
		*(u8*)(Bank1_SRAM3_ADDR+WriteAddr)=*pBuffer++;	 		
		WriteAddr++;
	}   
}		

//在指定地址((WriteAddr+Bank1_SRAM3_ADDR))开始,连续读出n个字节.
//pBuffer:字节指针
//ReadAddr:要读出的起始地址
//n:要写入的字节数
void FSMC_SRAM_ReadBuffer(u8* pBuffer,u32 ReadAddr,u32 n)
{
	for(;n!=0;n--)  
	{											    
		*pBuffer++=*(u8*)(Bank1_SRAM3_ADDR+ReadAddr);    
		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 的读写函数后, 接下来我们就可以测试其容量, 具体代码如下:

cpp 复制代码
//外部内存测试(最大支持 1M 字节内存测试)
void ExSRAM_Cap_Test(u16 x,u16 y)
{
    u8 writeData = 0xf0, readData;
    u16 cap=0;
    u32 addr;

    addr = 1024; //从 1KB 位置开始算起

    LCD_ShowString(x,y,239,y+16,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(x+11*8,y,cap,4,16,0);//显示内存容量
    printf("SRAM 容量为: %dKB\r\n",cap);
}

该函数功能很简单, 就是判断对应地址写入和读取的数据是否一致, 一致就表明 SRAM 正常, 让 cap 加 1, 直到 1MB 判断完成, 此时 cap 值已自加了 1024 次,每一次判断是经过 1KB。

45.4.4 主函数

编写好外扩 SRAM 初始化、 读写及容量测试函数后, 接下来就可以编写主函数了, 代码如下:

cpp 复制代码
#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 cap=0;
    u32 addr;
	
	addr = 1024; //从1KB位置开始算起
	
	LCD_ShowString(x,y,239,y+16,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(x+11*8,y,cap,4,16,0);//显示内存容量 
	printf("SRAM容量为:%dKB\r\n",cap);
}

int main()
{
	u8 i=0;
	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_COLOR=BLACK;
	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_COLOR=RED;
	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)
	{
		key=KEY_Scan(0);
		if(key==KEY_UP_PRESS)
		{
			FSMC_SRAM_WriteBuffer(text_buf,0,TEXT_LEN);
			printf("写入的数据是:%s\r\n",text_buf);
			LCD_ShowString(10+6*8,130,tftlcd_data.width,tftlcd_data.height,16,(u8 *)text_buf);
		}
		if(key==KEY1_PRESS)
		{
			FSMC_SRAM_ReadBuffer(read_buf,0,TEXT_LEN);
			printf("读取的数据是:%s\r\n",read_buf);
			LCD_ShowString(10+6*8,150,tftlcd_data.width,tftlcd_data.height,16,read_buf);
		}
		
		i++;
		if(i%20==0)
		{
			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 内的数据, 在掉电后会丢失。

相关推荐
xiaoyuchidayuma3 小时前
永磁同步发电机的线电压和直流母线电压的关系
嵌入式硬件
潜创微科技3 小时前
4K60 over IP 方案简介
网络·嵌入式硬件·网络协议·tcp/ip·音视频
rit84324994 小时前
基于C#的USB HID设备读取测试软件
嵌入式硬件
三佛科技-187366133974 小时前
FT32F103C8AT7兼容GD32F103C8T632 位通用微控制器MCU,替代性分析
单片机·嵌入式硬件
iCxhust4 小时前
8086汇编 word ptr
汇编·单片机·嵌入式硬件·微机原理·8088单板机
嵌入式ZYXC5 小时前
第3篇:《面试题:I2C为什么要加上拉电阻?阻值怎么选?》
stm32·单片机·嵌入式硬件·面试·职场和发展
leo__5205 小时前
C# 虚拟键盘(软键盘)实现
单片机·c#·计算机外设
你疯了抱抱我6 小时前
【STM32】使用 STM32CubeMX 生成项目,LED测试;上位机:STM32F411CEU6
stm32·单片机·嵌入式硬件