20.2 FMC驱动SDRAM的时序初始化实现及内存测试
继续上一篇的话题,写到SDRAM通过CubeMx配置后,在工程代码编写时直接引用的是我事先写好的时序初始化、内存测试文件,而未对其进行详细的解释,所以本篇文章就来娓娓道来。不多说,开始吧
SDRAM的初始化流程简述
SDRAM初始化流程
SDRAM的初始化流程基本都是一样的
SDRAM并不是一上电就可以直接读写数据的,而是需要一系列的步骤进行初始化,对存储矩阵进行预充电、刷新并设置模式寄存器,详细见下图:
(1)、SDRAM上电并提供稳定的时钟信号,至少等待100us
(2)、发送空操作命令(NOP)
(3)、发送于预充电命令(PRECHANGE),控制所有Bank进行预充电,并等待TRP时间
(4)、发送至少2个自动刷新命令(AUTO REFRESH),每个命令后需等待TRFC时间;TRFC表示自动刷新时间;
(5)、发送加载模式寄存器命令(LOAD MODE REGISTER),配置SDRAM的工作参数,并等待TMRD时间,TMRD表示加载模式寄存器与行或刷新命令之间的延迟时间;
(6)、初始化流程完毕,可以开始读写数据
接下来我们就应该在FMC对SDRAM参数初始化完毕后进行SDRAM流程时序初始化
SDRAM初始化流程代码实现
首先来看下整体流程:
首先MX_FMC_Init()函数内调用HAL_SDRAM_Init()对SDRAM基本参数及时序参数进行初始化,然后才调用编写好的sdram_driver文件内的流程初始化函数void sdram_InitialTimingSequence(SDRAM_HandleTypeDef *hsdram);
此代码是fmc.c文件的函数
/* FMC initialization function */
void MX_FMC_Init(void)
{/* USER CODE BEGIN FMC_Init 0 *//* USER CODE END FMC_Init 0 */FMC_SDRAM_TimingTypeDef SdramTiming = {0};/* USER CODE BEGIN FMC_Init 1 *//* USER CODE END FMC_Init 1 *//** Perform the SDRAM1 memory initialization sequence*/hsdram1.Instance = FMC_SDRAM_DEVICE;/* hsdram1.Init */hsdram1.Init.SDBank = FMC_SDRAM_BANK1;hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;/* SdramTiming */SdramTiming.LoadToActiveDelay = 2;SdramTiming.ExitSelfRefreshDelay = 8;SdramTiming.SelfRefreshTime = 5;SdramTiming.RowCycleDelay = 6;SdramTiming.WriteRecoveryTime = 4;SdramTiming.RPDelay = 2;SdramTiming.RCDDelay = 2;if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK){Error_Handler( );}/* USER CODE BEGIN FMC_Init 2 */sdram_InitialTimingSequence(&hsdram1);//SDRAM时序初始化/* USER CODE END FMC_Init 2 */
}
本片主要的SDRAM时序初始化函数就是sdram_InitialTimingSequence(&hsdram1)这个了,函数内部代码也是按照上面讲解的顺序进行一一对应:时钟使能->延时100us->对所有的Banks预充电->自刷新->编程sdram的加载模式寄存器
最后配置stm32 FMC的sdram控制器的自动刷新周期
函数内部使用了HAL带的SDRAM发送命令函数和编程自刷新周期函数
/****************************************************
@function:初始化SDRAM时序
@param:hsdram--sdram句柄
@return:void
@note:
****************************************************/
void sdram_InitialTimingSequence(SDRAM_HandleTypeDef *hsdram)
{FMC_SDRAM_CommandTypeDef Command;//时钟使能Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;Command.AutoRefreshNumber = 1;Command.ModeRegisterDefinition = 0;HAL_SDRAM_SendCommand(hsdram,&Command,0xFFFF);//延时至少200usHAL_Delay(1);//对所有的Banks预充电Command.CommandMode = FMC_SDRAM_CMD_PALL;Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;Command.AutoRefreshNumber = 1;Command.ModeRegisterDefinition = 0;HAL_SDRAM_SendCommand(hsdram,&Command,0xFFFF);//插入8个自动刷新周期Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;Command.AutoRefreshNumber = 8;Command.ModeRegisterDefinition = 0;HAL_SDRAM_SendCommand(hsdram,&Command,0xFFFF);//编程sdram的加载模式寄存器Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;Command.AutoRefreshNumber = 1;Command.ModeRegisterDefinition = 0x230;HAL_SDRAM_SendCommand(hsdram,&Command,0xFFFF);//配置stm32 FMC的sdram控制器的自动刷新周期//Refresh rate = (SDRAM refresh rate * SDRAM clock frequency) - 20//SDRAM refresh rate = SDRAM refresh period / Number of rows//SDRAM refresh rate = 64ms / 8196(rows) = 7.81us//Refresh rate = 7.81us * 100Mhz - 20 = 761HAL_SDRAM_ProgramRefreshRate(hsdram,761);
}
SDRAM发送命令函数HAL_SDRAM_SendCommand()
函数原型如下:
/*** @brief Sends Command to the SDRAM bank.* @param hsdram pointer to a SDRAM_HandleTypeDef structure that contains* the configuration information for SDRAM module.* @param Command SDRAM command structure* @param Timeout Timeout duration* @retval HAL status*/
HAL_StatusTypeDef HAL_SDRAM_SendCommand(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command,uint32_t Timeout)
FMC_SDRAM_CommandTypeDef 结构体:
/*** @brief SDRAM command parameters structure definition*/
typedef struct
{uint32_t CommandMode; /*!< Defines the command issued to the SDRAM device.This parameter can be a value of @ref FMC_SDRAM_Command_Mode. */uint32_t CommandTarget; /*!< Defines which device (1 or 2) the command will be issued to.This parameter can be a value of @ref FMC_SDRAM_Command_Target. */uint32_t AutoRefreshNumber; /*!< Defines the number of consecutive auto refresh command issuedin auto refresh mode.This parameter can be a value between Min_Data = 1 and Max_Data = 15 */uint32_t ModeRegisterDefinition; /*!< Defines the SDRAM Mode register content */
} FMC_SDRAM_CommandTypeDef;
CommandMode参数是待发送的命令
CommandTarget参数是目标存储器区域;发送给FMC控制下的SDRAM1还是SDRAM2
AutoRefreshNumber参数是自动刷新数;若发送的是自动刷新命令,此处为发送的刷新次数,其它命令时无效
ModeRegisterDefinition参数;若发送的是加载模式寄存器命令,此处为要写入 SDRAM 模式寄存器的参数;当向 SDRAM 发送加载模式寄存器命令时,这个结构体成员的值将通过地址线发送到SDRAM 的模式寄存器中,这个成员值长度为 13 位,各个位一一对应 SDRAM 的模式寄存器。
初始化到这一步SDRAM还差自动刷新配置啦
配置stm32 FMC的sdram控制器的自动刷新周期
SDRAM为什么需要这个自动刷新呢,因为SDRAM内部是一个个的电容,电容电压会随时间进行放电过程,所以原本为1的数据对应电容,在很久不操作就会变成电量0;所以需要间隔一定时间进行及时充电刷新,这个间隔就是自动刷新周期。
可以看到使用的这个W9825G6KH刷新周期要求是64毫秒
看看HAL库刷新周期配置函数:
/*** @brief Programs the SDRAM Memory Refresh rate.* @param hsdram pointer to a SDRAM_HandleTypeDef structure that contains* the configuration information for SDRAM module.* @param RefreshRate The SDRAM refresh rate value* @retval HAL status*/
HAL_StatusTypeDef HAL_SDRAM_ProgramRefreshRate(SDRAM_HandleTypeDef *hsdram, uint32_t RefreshRate)
RefreshRate SDRAM刷新率
那这个参数如何配置呢,可以在参考手册中看这个刷新速率的解释
SDRAM时钟频率在上一篇文档中,工程配置的是FMC 200MHz / SDRAM二分频 = 100MHz
那么SDRAM的行数是多少呢,可以看下芯片数据手册寻找
可以看到行数等于8192行,我的工程代码里面用的是8196行,直接沿用的数据手册,只不过芯片数据手册这个才是最正确的哈,也不修改了喔
此处函数的参数RefreshRate 就是上面看到的COUNT参数喔
刷新速率 = 64ms / 8192行 = 7.812us
RefreshRate = 7.812us * 100MHz - 20 = 761
所以这样配置后SDRAM就会间隔自动刷新了,这之后就可以正常访问SDRAM数据了
SDRAM的内存测试
这部分就不过多说了,只需要申请指定SDRAM1开始的内存地址,32M大小的数组即可
然后进行数据写入、读取对比,若写入数据和读取数据不等,则SDRAM内存数据错误,此时应检查配置参数是否正常,然后进行降低SDRAM频率,直到可以正确读写数据为止。
读写数据测试函数如下所示
/****************************************************
@function:SDRAM内存简单测试
@param:void
@return:void
@note:
****************************************************/
uint32_t pbuffer[(32*1024*1024)/4] __attribute__((at(0xC0000000)));//0xC0000000是SDRAM1的起始地址
void sdram_test(void)
{uint32_t i = 0,err = 0;while(1){for(i=0;i < (32*1024*1024)/4;i++){pbuffer[i] = i;}err = 0;for(i=0;i < (32*1024*1024)/4;i++){if(pbuffer[i] != i)err++;else if(i < 10)printf("pbuffer[%d]=%d\n",i,pbuffer[i]);}if(err){printf("err:%d\n",err);while(1)HAL_Delay(25);}}
}
相关文章:

20.2 FMC驱动SDRAM的时序初始化实现及内存测试
继续上一篇的话题,写到SDRAM通过CubeMx配置后,在工程代码编写时直接引用的是我事先写好的时序初始化、内存测试文件,而未对其进行详细的解释,所以本篇文章就来娓娓道来。不多说,开始吧 SDRAM的初始化流程简述 SDRAM初…...

联想电脑一键重装系统Win10操作方法
很多用户都会利用重装系统的方法,来解决系统崩溃、病毒感染等问题。但是,很多新手用户不知道联想电脑Win10系统重装的详细方法步骤,下面小编给大家详细介绍关于联想电脑Win10系统重装的操作方法,帮助大家轻松快速地完成系统的重装…...

Mysql数据库 1.概述
Mysql内容概述 1. Mysql概述 数据库相关概念: 名称 全称 简称 数据库 存储数据的仓库,数据是有组织的进行存储 …...

Qt编程,文件操作、UDP通信
目录 1、文件类 QFile 2、 UPD/TCP网络编程 1、##UDP客户端 2、##UDP服务器端 1、文件类 QFile QFile file(filename); file.exists() file.setFileName(filename1); file.fileName() file.bytesAvailable() file.size() file.copy("2.txt") file1.errorString(…...

Docker 的数据管理和Dockerfile镜像的创建
目录 Docker 的数据管理 管理 Docker 容器中数据的方式 端口映射 容器互联(使用centos镜像) Docker 镜像的创建 Dockerfile 操作常用的指令 编写 Dockerfile 时格式 Dockerfile 案例 Docker 的数据管理 管理 Docker 容器中数据的方式 管理 Doc…...

[python] 利用 Pydoc 快速生成整个 Python 项目的文档
如何写注释 class MyClass:"""This is a simple example class.Attributes:param1 (int): The first parameter.param2 (str): The second parameter."""def __init__(self, param1, param2):"""The constructor for MyClass.:p…...

Maven 配置指南
目录 一、配置本地存储库 二、配置并行Artifact 解析 三、安全和部署设置 四、将镜像用于存储库 五、Profiles 六、可选配置 七、Settings 八、安全性 九、工具链 Maven配置发生在3个级别: 项目-大多数静态配置发生在pom.xml中安装-这是为Maven安装添加的…...

第十八章 类和对象——多态
一、多态的基本概念 多态是C面向对象三大特性之一 多态分为两类 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名 动态多态: 派生类和虚函数实现运行时多态 静态多态和动态多态区别: 静态多态的函数地址早绑定 - 编译阶段确定函数地址 动…...

京东数据平台:2023年服饰行业销售数据分析
最近看到有些消费机构分析,不少知名的运动品牌都把“主战场”放到了冲锋衣,那么羽绒服市场就比较危险了。但其实羽绒服市场也有机会点可寻。 先来说冲锋衣。的确,从今年的销售数据以及增长情况,冲锋衣的确会是今年冬天的大热门品…...

Nginx proxy_set_header参数设置
一、不设置 proxy_set_header Host 不设置 proxy_set_header Host 时,浏览器直接访问 nginx,获取到的 Host 是 proxy_pass 后面的值,即 $proxy_host 的值,参考Module ngx_http_proxy_module 1 2 3 4 5 6 7 8 # cat ngx_header.c…...

如何用 ChatGPT 的 Advanced Data Analysis 帮你采集数据?
(注:本文为小报童精选文章,已订阅小报童或加入知识星球「玉树芝兰」用户请勿重复付费) 想采集网页数据却不会写 Python 爬虫?不会就不会吧,ChatGPT 会就可以了 😂 问题描述 朋友最近遇到了一点儿…...

Linux运行环境搭建系列-Flink安装
Flink安装 ## 下载 https://archive.apache.org/dist/flink/flink-1.16.2 ## 解压 tar -zxvf flink-1.16.2-bin-scala_2.12.tgz && rm -rf flink-1.16.2-bin-scala_2.12.tgz ## 启动 cd flink-1.16.2/bin ## 修改/etc/hosts文件,把第一行的127.0.0.1改成自…...

求最大bit数(java)
题目描述 求一个int类型数字对应的二进制数字中1的最大连续数 例如3的二进制为00000011,最大连续2个1 数据范围:数据组数:11t15,11n1500000进阶: 时间复杂度: O(logn),空间复杂度: O(1) 输入: 200 输出 2 说明 200的二进制表示是11001000&am…...

【Java 进阶篇】JavaScript 与 HTML 的结合方式
JavaScript是一种广泛应用于Web开发中的脚本语言,它与HTML(Hypertext Markup Language)结合使用,使开发人员能够创建交互式和动态的网页。在这篇博客中,我们将深入探讨JavaScript与HTML的结合方式,包括如何…...

华为云云耀云服务器L实例评测 | 实例评测使用之硬件参数评测:华为云云耀云服务器下的 Linux 磁盘目录分析神器 ncdu
华为云云耀云服务器L实例评测 | 实例评测使用之硬件参数评测:华为云云耀云服务器下的 Linux 磁盘目录分析神器 ncdu 介绍华为云云耀云服务器 华为云云耀云服务器 (目前已经全新升级为 华为云云耀云服务器L实例) 华为云云耀云服务器…...

Linux大老都是怎么记住这么多命令的?
今天给大家带来的是面试/实际工作中经常用到的Linux相关操作命令: 一. vi/vim编辑器 ---->文本编辑器 作用:创建文件,编辑文件,查看文件 格式:vi/vim 文件的名字 解析:如果该文件不存在,vi就会创建该…...

LoRa技术未来发展前景:物联网和边缘计算的引领者
随着物联网和边缘计算的快速发展,低功耗广域网(LoRa)技术在连接远距离设备、实现长距离通信和满足低功耗需求方面崭露头角。本文将分析LoRa技术在未来的发展前景,尤其是在物联网和边缘计算领域的潜在影响。 LoRa技术的核心优势 1…...

出现 PowerShell终端执行conda activate无效 解决方法
目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 在cmd命令行中执行conda activate 可以成功,但是回pycharm的PowerShell终端执行该命令,一直无效 具体过程如下: PS E:\pythonProject\SteganoGAN-master> conda activate py37 PS E:\pythonProject\SteganoGAN-mas…...

Python实现某音短视频JS XB逆向解析
哈喽兄弟们,今天来实现一下某音短视频的JS逆向解析。 知识点 动态数据抓包在这里插入代码片 requests发送请求 X-Bogus 参数逆向环境模块 python 3.8 运行代码 pycharm 2022.3 辅助敲代码 requests pip install request…...

SecureCRT 自动测试脚本的使用方法
脚本示例(get_batteryifo_interval_2s.vbs): Sub Main Do While(1)crt.Screen.Send "pm_client batteryinfo" & chr(13)crt.Sleep 2000 Loop End Sub 1. 解压 SecureCRT 压缩包(网上下载);…...

常用图像标注工具
1. LabelImg 1)LabelImg 是一款开源的图像标注工具,标签可用于分类和目标检测,它是用 Python 编写的,并使用Qt作为其图形界面,简单好用。注释以 PASCAL VOC 格式保存为 XML 文件,这是 ImageNet 使用的格式。…...

hadoop namenode -format报错显示:命令未找到
这个bug很搞笑,我做分布式搭建时,slaver1和slaver2都可以hadoop name -format,就是master不可以,配置都是一样的,这个第一时间也是想到了环境配置问题 打开环境配置文件编辑 sudo vim ~/.bashrc 添加以下代码&#…...

prostate数据集下载
1. prostatex 下载地址:https://wiki.cancerimagingarchive.net/pages/viewpage.action?pageId23691656 比赛:https://prostatex.grand-challenge.org/ 这个下载的是一个tcia文件,参考这篇文章打开该文件 2. promise12 地址:…...

比较和同步数据库架构和数据:MssqlMerge Pro Crack
比较和同步数据库架构和数据 适用于Oracle、MySQL 和 MariaDB、SQL Server、PostgreSQL、SQLite、MS Access和跨 DBMS 场景 业界领先的文本比较工具中常用的两面板 UI 快速过滤器显示所有/新/更改/新更改 合并两个方向的更改 轻量级:跨 DBMS 工具小于 20 MB…...

R语言——赋值(= ,<- ,<<-)
R语言 R语言——赋值( ,<- ,<<-) 文章目录 R语言一、 与 <- 的区别二、 <<- ,向上一环境层写入变量 R语言中" <- " 与 " " 都可以用来赋值,但R中建议使用" <- “…...

图形界面四则运算计算器(Python+PyQt5)
(1) 导入所需的库和模块。 (2) 创建一个名为Calculator的类,继承自QMainWindow。 (3) 在Calculator类的__init__方法中,调用initUI方法初始化界面。 (4) 在initUI方法中,设置窗口标题和大小,创建显示结果的文本框,并调…...

SQL Server 创建表
切换数据库,判断是否存在 --切换数据库 use DBTEST--判断表是否存在 --创建的所有表都可以在sys.boject中找到,所以这里在sys.objects中查找是否有名字为department的表并且type为U 即用户生成的表 if exists(select * from sys.objects where namedepa…...

JS数组或数组对象去重常用方法
数组去重有许多种方法,下面列举几种常见方法 数组去重数组对象去重 数组去重 使用 Set:将数组转化为 Set 对象,去重后再转化回数组,Set 会自动去重 const arr [1, 2, 3, 2, 1, 4] const newArr [...new Set(arr)] console.log…...

allure测试报告生成逻辑--解决在Jenkins里打开allure报告页面后空白显示无数据问题(以window环境为例)
前言 相信大家在用Jenkins持续集成+ant自动构建+jmeter接口测试+pytest代码.xml文件转化+allure测试报告为一体的接口自动化测试构建过程中,都会遇到Jenkins里打开allure报告页面后空白显示无数据问题这一现象级问题,今天Darren洋就给大家分享一下如何讲讲allure测试报告生成…...

基于JAYA优化的BP神经网络(分类应用) - 附代码
基于JAYA优化的BP神经网络(分类应用) - 附代码 文章目录 基于JAYA优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.JAYA优化BP神经网络3.1 BP神经网络参数设置3.2 JAYA算法应用 4.测试结果:5.M…...