细说STM32F407单片机FSMC连接外部SRAM的方法及HAL驱动

目录

一、FSMC连接外部SRAM的原理

1、 FSMC控制区域的划分

2、SRAM芯片与MCU的连接

二、访问外部SRAM的HAL驱动程序

1、外部SRAM初始化与控制

2、外部SRAM读写函数

3、直接通过指针访问外部SRAM

4、DMA方式读写外部SRAM


        本文介绍STM32F407单片机FSMC连接外部SRAM及以轮询方式读写外部SRAM的方法。本文将继续使用旺宝红龙开发板STM32F407ZGT6 KIT V1.0。

        FSMC的Bank1除能连接TFT LC外,还可以用于连接外部的SRAM、NOR FLASH、PSRAM等存储器。STM32F407ZG有192KB的SRAM存储器,一般的应用程序足够用了,但是在使用GUI等需要大量内存的功能时,就需要扩展SRAM了。

一、FSMC连接外部SRAM的原理

1、 FSMC控制区域的划分

        FSMC控制器的存储区分为4个区(Bank),每个区256MB。其中,Bank1可以用于连接SRAM、NOR FLASH、PSRAM,还可以连接TFT LCD。Bank1的地址范围是0x60000000~0x6FFFFFFF。Bank1又分为4个子区,每个子区寻址空间是64MB,占用26位地址线。4个子区的地址范围分别如下。

  • Bank 1子区1:0x60000000~0x63FFFFFF。
  • Bank 1子区2:0x64000000~0x67FFFFFF。
  • Bank 1子区3:0x68000000~0x6BFFFFFF(开发板上用于外扩SRAM)。
  • Bank 1子区4:0x6C000000~0x6FFFFFFF(开发板上用于连接TFTLCD)。

        每个子区有一个专用的片选信号。本文将使用Bank 1子区3连接一个1MB的SRAM芯片,为系统扩展内存。

2、SRAM芯片与MCU的连接

        在开发板上有一个SRAM芯片IS61LV25616AL,这是一个16位宽256K容量(256K×16位,即512KB)的静态内存芯片。在开发板上它与MCU的连接电路如图所示。芯片几个主要管脚的功能,以及与MCU的连接原理如下。

  • A0至A18是19根地址线,连接FSMC的19根地址线,即FSMC_A0至FSMC_A18。
  • I/O0至I/O15是16位数据线,连接FSMC的FSMC_D0至FSMC_D15数据线。
  • CE是芯片的片选信号,连接MCU的FSMC_NE3(PG10引脚),也就是Bank 1子区3的片选信号。
  • OE是输出使能信号,连接MCU的FSMC_NOE(PD4引脚),是读数据时的使能信号。
  • WE是写使能信号,连接MCU的FSMC_NWE(PD5引脚),是写数据使能信号。
  • UB是高字节使能信号,连接MCU的FSMC_NBL1(PE1引脚)。
  • LB是低字节使能信号,连接MCU的FSMC_NBL0(PE0引脚)。

        通过UB和LB的控制可以只读取一个地址的高字节(I/O15~I/O8)或低字节(I/O7~I/O0)数据,或读取16位数据。IS61LV25616AL有19根地址线,能表示的地址范围是512K,偏移地址范围是0x00000~0x7FFFF。但是IS61LV25616AL的数据宽度是16位,实际存储容量是512KB,按字节寻址范围是512K,偏移地址范围是0x00000~0x3FFFF。因为Bank 1子区3的起始地址是0x68000000,所以IS61LV25616AL全部512KB的地址范围是0x68000000~0x6803FFFF。FSMC_NBL1和FSMC_NBL0控制高位字节和低位字节访问,实现全部512KB存储空间的访问。

二、访问外部SRAM的HAL驱动程序

1、外部SRAM初始化与控制

        访问外部SRAM的HAL驱动程序头文件是stm32f4xx_hal_sram.h,包括SRAM初始化函数、控制函数、读写函数和DMA方式读写函数等。SRAM初始化和控制的函数如表所示。

函数名

功能描述

HAL_SRAM_Init()

外部SRAM初始化函数,主要是FSMC访问接口的定义

HAL_SRAM_MspInit()

外部SRAM初始化MSP函数,需重新实现,主要是GPIO配
置和中断设置

HAL_SRAM_WriteOperation_Enable()

使能SRAM存储器的写操作

HAL SRAM_WriteOperation_Disable()

禁止SRAM存储器的写操作

HAL_SRAM_GetState()

返回SRAM存储器的当前状态,返回值是枚举类型HAL_
SRAM_StateTypeDef

        函数HAL_SRAM_Init()用于外部SRAM的初始化,其原型定义如下: 

HAL_StatusTypeDef HAL_SRAM_Init(SRAM_HandleTypeDef *hsram,FMC_NORSRAM_TimingTypeDef*Timing,FMC_NORSRAM_TimingTypeDef *ExtTiming);

        其中,参数hsram是SRAM_HandleTypeDef结构体类型指针,是FSMC子区对象的指针;Timing和ExtTiming是FSMC读写时序的对象指针。

        函数HAL_SRAM_Init()由CubeMX生成的FSMC外设初始化函数调用。初始化程序文件里会定义一个FSMC子区外设对象变量,例如,开发板上使用FSMC Bank 1的子区3访问外部SRAM,定义的FSMC子区外设对象变量如下:

SRAM_HandleTypeDef hsram3;	//访问外部SRAM的FSMC子区外设对象变量

        结构体SRAM_HandleTypeDef和FMC_NORSRAM_TimingTypeDef各成员变量的意义在CubeMX图形化设置和示例代码里解释。

        表格里的其他函数都是需要一个SRAM_HandleTypeDef类型指针作为函数参数,例如,使能SRAM写操作和禁止SRAM写操作的两个函数的原型定义如下:

HAL_StatusTypeDef HAL_SRAM_WriteOperation_Enable(SRAM_HandleTypeDef *hsram);
HAL_StatusTypeDef HAL_SRAM_WriteOperation_Disable(SRAM_HandleTypeDef *hsram);

2、外部SRAM读写函数

        文件stm32f4xx_hal_sram.h定义了几个读写外部SRAM数据的函数,如表所示。

函数名

功能描述

HAL_SRAM_Read_8b()

从指定地址读取指定长度的8位数据,存储到一个缓冲区

HAL_SRAM_Write_8b()

向指定地址写入一定长度的8位数据

HAL_SRAM_Read_16b()

从指定地址读取指定长度的16位数据,存储到一个缓冲区

HAL_SRAM_Write_16b()

向指定地址写入一定长度的16位数据

HAL_SRAM_Read_32b()

从指定地址读取指定长度的32位数据,存储到一个缓冲区

HAL_SRAM_Write_32b()

向指定地址写入一定长度的32位数据

        这些函数可用于读写8位、16位、32位的数据,这几个函数的输入参数形式是相似的。例如,向外部SRAM写入8位数据的函数HAL_SRAM_Write_8b()的原型定义如下:

HAL_StatusTypeDef HAL_SRAM_Write_8b(SRAM_HandleTypeDef *hsram,uint32_t *pAddress,uint8_t *pSrcBuffer,uint32_t BufferSize)

        其中,hsram是FSMC子区对象指针,pAddress是需要写入的SRAM目标地址指针,pSrcBuffer是源数据的缓冲区地址指针,BufferSize是源数据缓冲区长度(数据点个数)。开发板上使用FSMC的Bank 1子区3访问外部SRAM,Bank 1子区3的起始地址是0x68000000,那么向这个起始地址的外部SRAM写入一个字符串的示意代码如下:

uint32_t *pAddr=(uint32_t*)(0×68000000);//给指针赋值
uint8_t strIn[]="Moment in UPC";        //准备写入的字符串
uint16_t dataLen=sizeof(strIn);         //数据长度,包括最后的结束符'\O'
HAL_SRAM_Write_8b(&hsram3,pAddr,strIn,dataLen);

        其中,第一行语句定义一个指向uint32_t类型数据的指针pAddr,指针的地址就是0x68000000。函数HAL_SRAM_Write_8b()写入的数据是以字节为单位的,其内部会将指向uint32_t类型数据的指针转换为指向uint8_t类型数据的指针,函数HAL_SRAM_Write_8b()中的第一行代码如下:

__IO uint8_t*pSramAddress =(uint8_t*)pAddress;

        注意,因为STM32是32位处理器,所以指针总是32位的,因为指针保存的是地址数据。另两个写数据的函数的原型定义如下:

HAL_statusTypeDef HAL_SRAM_Write_16b(SRAM_HandleTypeDef *hsram,uint32_t *pAddress,
uint16_t*pSrcBuffer,uint32_t BufferSize)
HAL_statusTypeDef HAL_SRAM_Write_32b(SRAM HandleTypeDef *hsram,uint32_t *pAddress,
uint32_t *pSrcBuffer,uint32_t BufferSize)

        读取8位数据的函数HAL_SRAM_Read_8b()的原型定义如下:

HAL_StatusTypeDef HAL_SRAM_Read_8b(SRAM_HandleTypeDef *hsram,uint32_t *pAddress,uint8_t *pDstBuffer,uint32_t BufferSize);

        其中,pAddress是需要读取的SRAM目标地址指针,pDstBuffer是读出数据的缓冲区,BufferSize是缓冲区长度,即数据点个数。例如,从SRAM起始地址偏移1024字节处读取一个uint8_t类型数组数据的示意代码如下:

uint32_t *pAddr=(uint32_t*)(0x68000000+1024);uint8_t strOut[30]; //数据点个数
uint16_t dataLen=30;
HAL_SRAM_Read_8b(&hsram3,pAddr,strout,dataLen);                  //给指针赋值

        另两个读数据的函数的原型定义如下:

HAL_StatusTypeDef HAL_SRAM_Read_16b(SRAM_HandleTypeDef *hsram,uint32_t *pAddress,uint16_t *pDstBuffer,uint32_t BufferSize)
HAL_StatusTypeDef HAL_SRAM_Read_32b(SRAM_HandleTypeDef *hsram,uint32_t *pAddress,uint32_t *pDstBuffer,uint32_t BufferSize)

        这些读写函数中的参数BufferSize是缓冲区数据点个数,而不是字节数。传递给函数的SRAM目标地址指针都是uint32_t类型指针,函数内部会进行转换。SRAM目标地址指针应该注意数据对齐,不要使用奇数开始的地址。

3、直接通过指针访问外部SRAM

        用户还可以直接使用指针访问外部SRAM的数据,实际上,HAL提供的前述几个数据读写函数就是用指针实现数据访问的。例如,向SRAM一个目标地址写入一批uint16_t类型数据的示意代码如下。

uint16_t num=1000;
uint16_t *pAddr_16b=(uint16_t*)(0x68000000); //16位数据的指针for(uint16_t i=0;i<10;i++)	//连续写入10个16位整数
{num += 5;			//直接向指针所指的地址写入数据*pAddr_16b = num;	//++一次,地址加2,因为是16位数据pAddr_16b++;printf("num= %X\r\n",num);
}

        同样地,也可以通过指针读出数据,示意代码如下。

uint16_t num=0,data[10];
uint16_t *pAddr_16b = (uint16_t*)(0x68000000);	//指针赋值
for(uint16_t i=0;i<10;i++)	
{num=*pAddr_16b;		//直接从指针所指的地址读数data[i]=num;pAddr_16b++;		//++一次,地址加2,因为是16位数据
}

        直接使用指针访问外部SRAM的数据时,要注意指针指向数据的类型。比如,代码里是要访问16位数据,就要定义为uint16_t类型指针,如果要访问8位数据,就需要定义为uint8_t类型指针。

4、DMA方式读写外部SRAM

        外部SRAM还可以通过DMA方式读写,DMA2控制器具有存储器到存储器的DMA流。文件stm32f4xx_hal_sram.h定义了两个DMA方式读写数据的函数和相关的回调函数,如表所示:

函数名

功能

HAL_SRAM_Read_DMA()

以DMA方式从指定地址读取一定长度的32位数据

HAL_SRAM_Write_DMA()

以DMA方式向指定地址写入一定长度的32位数据

HAL_SRAM_DMA_XferCpltCallback()

DMA流传输完成事件中断的回调函数

HAL_SRAM_DMA_XferErrorCallback()

DMA流传输错误事件中断的回调函数

        一个FSMC子区只能关联一个DMA流,而且不区分发送和接收,所以这两个DMA读写函数在传输完成时的回调函数都是HAL_SRAM_DMA_XferCpltCallback(),需要用户在程序里添加代码进行DMA传输方向识别和控制

        函数HAL SRAM_Write_DMA()的原型定义如下:

HAL_StatusTypeDef HAL_SRAM_Write_DMA(SRAM_HandleTypeDef *hsram,uint32_t*pAddress,uint32_t *pSrcBuffer,uint32_t BufferSize)

        其中,hsram是FSMC子区对象指针,pAddress是SRAM目标地址指针,pSrcBuffer是源数据缓冲区指针,BufferSize是缓冲区长度,是数据点个数,而不是字节数。函数HAL_SRAM_Read_DMA()的原型定义如下:

HAL_StatusTypeDef HAL_SRAM_Read_DMA(SRAM_HandleTypeDef *hsram,uint32_t *pAddress,uint32_t *pDstBuffer,uint32_t BufferSize)

        这两个DMA方式读写函数只能读写uint32_t类型数据,参数BufferSize是缓冲区数据点个数,而不是字节数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/66403.shtml

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

相关文章

Gitee图形界面上传(详细步骤)

目录 1.软件安装 2.安装顺序 3.创建仓库 4.克隆远程仓库到本地电脑 提交代码的三板斧 1.软件安装 Git - Downloads (git-scm.com) Download – TortoiseGit – Windows Shell Interface to Git 2.安装顺序 1. 首先安装git-2.33.1-64-bit.exe&#xff0c;顺序不能搞错2. …

基于单片机洗衣机控制器的设计(论文+源码)

1需求分析 在智能洗衣机系统设计中&#xff0c;考虑到洗衣机在实际应用过程中&#xff0c;需要满足用户对于不同衣物清洁、消毒的应用要求&#xff0c;对设计功能进行分析&#xff0c;具体如下&#xff1a; 通过按键实现洗衣机不同工作模式的切换&#xff0c;包括标准模式&…

【学Rust开发CAD】2 创建第一个工作空间、项目及库

文章目录 一、 创建工作空间二、新建项目&#xff08;可执行文件&#xff09;三、 新建库&#xff08;库文件&#xff09;四、更新项目依赖五、编写代码七、总结 在 Rust 中&#xff0c;工作空间&#xff08;workspace&#xff09;允许你管理多个相关的包&#xff08;crate&…

STM32的LED点亮教程:使用HAL库与Proteus仿真

学习目标&#xff1a;掌握使用STM32 HAL库点亮LED灯&#xff0c;并通过Proteus进行仿真验证&#xff01; 建立HAL库标准工程 1.新建工程文件夹 新建工程文件夹建议路径尽量为中文。建立文件夹的目的为了更好分类去管理项目工程中需要的各类工程文件。 首先需要在某个位置建立工…

Unity Excel转Json编辑器工具

功能说明&#xff1a;根据 .xlsx 文件生成对应的 JSON 文件&#xff0c;并自动创建脚本 注意事项 Excel 读取依赖 本功能依赖 EPPlus 库&#xff0c;只能读取 .xlsx 文件。请确保将该脚本放置在 Assets 目录下的 Editor 文件夹中。同时&#xff0c;在 Editor 下再创建一个 Exc…

牛客网刷题 ——C语言初阶(6指针)——字符逆序

1. 题目描述&#xff1a;字符逆序 牛客网题目链接 将一个字符串str的内容颠倒过来&#xff0c;并输出。 输入描述: 输入一个字符串&#xff0c;可以有空格 输出描述: 输出逆序的字符串 示例1 输入 I am a student 输出 tneduts a ma I 2. 思路 首先字符串逆序&#xff0c;之…

【USRP】教程:在Macos M1(Apple芯片)上安装UHD驱动(最正确的安装方法)

Apple芯片 前言安装Homebrew安装uhd安装gnuradio使用b200mini安装好的路径下载固件后续启动频谱仪功能启动 gnu radio关于博主 前言 请参考本文进行安装&#xff0c;好多人买了Apple芯片的电脑&#xff0c;这种情况下&#xff0c;可以使用UHD吗&#xff1f;答案是肯定的&#…

141.《mac m系列芯片安装mongodb详细教程》

文章目录 下载从官网下载安装包 下载后双击解压出文件夹安装文件名修改为 mongodb配置data存放位置和日志log的存放位置启动方式一方式二方式二:输入mongo报错以及解决办法 本人电脑 m2 pro,属于 arm 架构 下载 官网地址: mongodb官网 怎么查看自己电脑应该下载哪个版本,输入…

Elasticsearch:基础概念

这里写目录标题 一、什么是Elasticsearch1、基础介绍2、什么是全文检索3、倒排索引4、索引&#xff08;1&#xff09;创建索引a 创建索引基本语法b 只定义索引名&#xff0c;setting、mapping取默认值c 创建一个名为student_index的索引&#xff0c;并设置一些自定义字段 &…

Dexcap复现代码数据预处理全流程(四)——demo_clipping_3d.py

此脚本的主要功能是可视化点云数据文件&#xff08;.pcd 文件&#xff09;&#xff0c;并通过键盘交互选择演示数据的起始帧和结束帧&#xff0c;生成片段标记文件 (clip_marks.json) 主要流程包括&#xff1a; 用户指定数据目录&#xff1a;检查目录是否存在并处理标记文件 -…

安装Cockpit服务,使用Web页面管理你的Linux服务器

说起管理 Linux 服务器&#xff0c;大家首先想到的使用 SecureCRT、Xshell、MobaXterm 等工具远程到服务器&#xff0c;然后使用命令行管理服务器。今天给大家介绍一个好玩的工具&#xff0c;名字叫Cockpit&#xff0c; Cockpit 是一个免费开源的基于 web 的 Linux 服务器管理…

[A-25]ARMv8/v9-GIC的系统架构(中断的硬件基础)

ver0.1 前言 我们在观看很多的影视剧过程中,尤其是军旅体裁类型的布景中,经常会看见高级干部的办公桌上都会有几部电话机。这样的电话可不能小看,重要的事情尤其是突发和紧急的情况都要通过这几部电话第一时间通知给决策者。这几部电话,必须举报几个特点:及时性好、稳定…

13-线段的转折点样式

13-线段的转折点样式_哔哩哔哩_bilibili13-线段的转折点样式是一次性学会 Canvas 动画绘图&#xff08;核心精讲50个案例&#xff09;2023最新教程的第14集视频&#xff0c;该合集共计53集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。https://www.bi…

计算机网络 (28)虚拟专用网VPN

前言 虚拟专用网络&#xff08;VPN&#xff09;是一种在公共网络上建立私有网络连接的技术&#xff0c;它允许远程用户通过加密通道访问内部网络资源&#xff0c;实现远程办公和安全通信。 一、基本概念 定义&#xff1a;VPN是一种通过公共网络&#xff08;如互联网&#xff09…

基于transformer的目标检测:DETR

目录 一、背景介绍 二、DETR的工作流程 三、DETR的架构 1. 损失函数 2. 网络框架讲解及举例 一、背景介绍 在深度学习和计算机视觉领域&#xff0c;目标检测一直是一个核心问题。传统方法依赖于复杂的流程和手工设计的组件&#xff0c;如非极大值抑制&#xff08;nms&…

Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)

Vue Amazing UI 一个 Vue 3 组件库 使用 TypeScript&#xff0c;都是单文件组件 (SFC)&#xff0c;支持 tree shaking 有点意思 English | 中文 Vue Amazing UI 是一个基于 Vue 3、TypeScript、Vite 等最新技术栈开发构建的现代化组件库&#xff0c;包含丰富的 UI 组件和常…

C语言----指针

目录 1.概念 2.格式 3.指针操作符 4.初始化 1. 将普通变量的地址赋值给指针变量 a. 将数组的首地址赋值给指针变量 b. 将指针变量里面保存的地址赋值给另一个指针变量 5.指针运算 5.1算术运算 5.2 关系运算 指针的大小 总结&#xff1a; 段错误 指针修饰 1. con…

Python应用——将Matplotlib图形嵌入Tkinter窗口

Python应用——将Matplotlib图形嵌入Tkinter窗口 目录 Python应用——将Matplotlib图形嵌入Tkinter窗口1 模块简介2 示例代码2.1 Matplotlib嵌入Tkinter2.2 Matplotlib嵌入Tkinter并显示工具栏 1 模块简介 Tkinter是Python的标准GUI&#xff08;图形用户界面&#xff09;库&…

【linux基础I/O(2)】理解文件系统|文件缓冲区|软硬链接|动静态库

目录 前言1. 理解C语言的缓冲区2. 对文件系统的初认识3. 理解软硬链接1. 软硬链接的特征2.软硬链接的作用 4. 理解动静态库5. 总结 前言 对于文件来讲,有打开的在内存中的文件,也有没有打开的在磁盘上文件,上一篇文章讲解的是前者,本篇文章将带大家了解后者! 本章重点: 本篇文…

什么是Redis的渐进式ReHash?

文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ Redis 的渐进式 rehash 是一…