HAL库记录-SDRAM的使用

news2025/2/9 3:25:42

正点原子--阿波罗开发板STM32F429IGT6

SDRAM硬件

 CLK           时钟信号,在该时钟的上升沿采集输入信号
CKE          时钟使能,禁止时钟时,SDRAM 会进入自刷新模式
CS#          片选信号,低电平有效
RAS#        行地址选通信号,低电平时,表示行地址
CAS#        列地址选通信号,低电平时,表示列地址
WE#         写使能信号,低电平有效
A0~A12     地址线(行/列)
BS0,BS1         BANK 地址线
DQ0~15            数据线
LDQM,UDQM   数据掩码,表示 DQ 的有效部分

W9825G6KH 同 STM32F429 的连接关系:


A[0:12]接 FMC_A[0:12]
BA[0:1]接 FMC_BA[0:1]
D[0:15]接 FMC_D[0:15]
CKE    接 FMC_SDCKE0
CLK     接 FMC_SDCLK
UDQM 接 FMC_NBL1
LDQM 接 FMC_NBL0
WE      接 FMC_SDNWE
CAS    接 FMC_SDNCAS
RAS    接 FMC_SDNRAS
CS      接 FMC_SDNE0

1.STM32CubeMX 的配置

 注意:正点原子 HAL库开发指南  Byte-enable 选择了disable,这个是不对,他自己写的驱动里有初始化PE0,PE1 ,  Byte-enable 只有选择了16bit-byte enable ,生成的代码才会初始PE0,PE1

 2.添加代码

/* USER CODE BEGIN 0 */
//SDRAM配置参数
#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)

static SDRAM_HandleTypeDef * psdram = &hsdram1;
//=============================================================
 uint8_t SDRAM_SendCmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint8_t regval);
 void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram);


//SDRAM 序列初始化
int SDRAM_AutoInit(void)
{
    SDRAM_Initialization_Sequence(psdram);//发送SDRAM初始化序列

	//刷新频率计数器(以SDCLK频率计数),计算方法:
	//COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
    //我们使用的SDRAM刷新周期为64ms,SDCLK=180/2=90Mhz,行数为8192(2^13).
	//所以,COUNT=64*1000*90/8192-20=683
	HAL_SDRAM_ProgramRefreshRate(psdram,683);//设置刷新频率
	return 0;
}

//=============================================================
//发送SDRAM初始化序列
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
    uint32_t temp=0;
                                                                                          //SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM
 SDRAM_SendCmd                       (0,FMC_SDRAM_CMD_CLK_ENABLE,1,0);                   //时钟配置使能
 for(volatile uint32_t i=0;i<0xFFFFFF;i++){}                                               //最少延时200us
 SDRAM_SendCmd                       (0,FMC_SDRAM_CMD_PALL,1,0);                         //对所有存储区预充电
 SDRAM_SendCmd                       (0,FMC_SDRAM_CMD_AUTOREFRESH_MODE,8,0);             //设置自刷新次数
                                                                                          //配置模式寄存器,SDRAM的bit0~bit2为指定突发访问的长度,
                                                                                          //bit3为指定突发访问的类型,bit4~bit6为CAS值,bit7和bit8为运行模式
                                                                                          //bit9为指定的写突发模式,bit10和bit11位保留位
 temp                                 =(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |  //设置突发长度:1(可以是1/2/4/8)
                                                 SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |  //设置突发类型:连续(可以是连续/交错)
                                                 SDRAM_MODEREG_CAS_LATENCY_3           |  //设置CAS值:3(可以是2/3)
                                                 SDRAM_MODEREG_OPERATING_MODE_STANDARD |  //设置操作模式:0,标准模式
                                       SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;              //设置突发写模式:1,单点访问
 SDRAM_SendCmd                       (0,FMC_SDRAM_CMD_LOAD_MODE,1,temp);                 //设置SDRAM的模式寄存器
}
/**
 * @brief :函数作用 : SDRAM配置
 * @note  :附加说明 :
 * @param :函数入口 : bankx: 0(向BANK5上面的SDRAM发送指令) 1(向BANK6上面的SDRAM发送指令)
 *                    cmd :指令(0,正常模式/1,时钟配置使能/2,预充电所有存储区/3,自动刷新/4,加载模式寄存器/5,自刷新/6,掉电)
 *                    refresh:自刷新次数
 *                    regval :模式寄存器的定义
 * @retval:函数返回 : 0,正常;1,失败.
 */
 uint8_t SDRAM_SendCmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint8_t regval)
 {
    uint32_t target_bank=0;
    FMC_SDRAM_CommandTypeDef Command;

    if  (bankx==0) target_bank          = FMC_SDRAM_CMD_TARGET_BANK1;
    else if(bankx==1) target_bank       = FMC_SDRAM_CMD_TARGET_BANK2;
         Command.CommandMode            = cmd;                         //命令
         Command.CommandTarget          = target_bank;                 //目标SDRAM存储区域
         Command.AutoRefreshNumber      = refresh;                     //自刷新次数
         Command.ModeRegisterDefinition = regval;                      //要写入模式寄存器的值
    if(HAL_SDRAM_SendCommand(psdram,&Command,0X1000)==HAL_OK) //向SDRAM发送命令
    {
        return 0;
    }
    else{
		//COM_Printf("SDRAM_SendCmd Err = %d\r\n",cmd);
		return 1;
	}
 }
/* USER CODE END 0 */

初始化完FMC后, 调用这个函数初始化SDRAM
int SDRAM_AutoInit(void); //SDRAM 序列初始化

3.测试代码

//uint16_t testsram[250000] __attribute__((at(0XC0000000)));//测试用数组  编译器V5 版本
uint16_t testsram[250000] __attribute__((section(".ARM.__at_0xC0000000")));  //编译器V6版本

//SDRAM内存测试
void fsmc_sdram_test(void)
{
	static volatile uint32_t i   =0;
	static volatile uint32_t temp=0;
	static volatile uint32_t sval=0;	//在地址0读到的数据
	i   =0;
	temp=0;	
	sval=0;	
  	COM_Printf("Ex Memory Test:    0KB \r\n");
	//每隔16K字节,写入一个数据,总共写入2048个数据,刚好是32M字节
	for(i=0;i<32*1024*1024;i+=16*1024)
	{
		*(volatile uint32_t*)(Bank5_SDRAM_ADDR+i)=temp;
		temp++;
	}
	
	//依次读出之前写入的数据,进行校验
 	for(i=0;i<32*1024*1024;i+=16*1024)
	{
  		temp=*(volatile uint32_t*)(Bank5_SDRAM_ADDR+i);
		if(i==0)sval=temp;
 		else if(temp<=sval)break;//后面读出的数据一定要比第一次读到的数据大.
		COM_Printf("SDRAM Capacity:%dKB\r\n",(uint16_t)(temp-sval+1)*16);//打印SDRAM容量			
 	}
}

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

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

相关文章

剑指offer57.和为s的两个数字

双指针i从左往右&#xff0c;j从右往左&#xff0c;如果大于目标值&#xff0c;j往左走否则i往右走&#xff0c;直到等于目标值 class Solution {public int[] twoSum(int[] nums, int target) {int[] res new int[2];int i 0; int j nums.length-1;int sum nums[i] nums…

docker指令

镜像命令 镜像命令 命令描述docker images php查看名字为php的镜像docker images查看所有镜像docker search搜索镜像docker pull 镜像名:tag 拉取镜像docker rmi php删除php镜像 (保存php镜像到目录) docker image save php > D:\phpstudy_pro\WWW\docker\php.tgz 或者 …

【利用AI让知识体系化】简要了解面向对象编程设计

文章目录 I. 面向对象编程简介面向对象编程的定义与发展历程面向对象编程的优点和特点面向对象和面向过程和面向函数式编程之间的对比 II. 面向对象编程的基本概念类和对象抽象和封装继承和多态封装、继承和多态之间的一些对比 III. 面向对象编程设计原则单一职责原则&#xff…

如何搭建高可用redis架构?

题记 Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库&#xff0c;并提供多种语言的 API。 如今&#xff0c;互联网业务的数据正以更快的速度在增长&#xff0c;数据类型越来越丰富&#xff0c;这对数据处理的速度和能力提…

chatgpt赋能python:Python怎么建网站的SEO

Python怎么建网站的SEO 介绍 Python是一种流行的编程语言&#xff0c;其灵活性和可靠性使其成为了许多网站开发人员的首选语言之一。Python可以用于构建各种类型的网站&#xff0c;包括电子商务和企业级应用程序等。但是&#xff0c;构建一个网站是不够的&#xff0c;您还需要…

力扣刷题记录--二叉树相关问题

目录 二叉树的前中后序遍历递归方法迭代方法&#xff08;未统一写法&#xff09;前序迭代中序迭代后序迭代 迭代方法&#xff08;统一模板&#xff09;二叉树遍历LeetCode 144. 二叉树的前序遍历LeetCode 145. 二叉树的后序遍历LeetCode 94. 二叉树的中序遍历 n叉树的遍历LeetC…

树莓派(raspbian2)上开发OpenCv_C++

树莓派[raspbian2]上开发OpenCv_C 背景故事一.首先就是搭建环境了1.该位置是环境下载地址2.远程连接3.安装OpenCV(如果使用的是上面的镜像,则不用安装) 二.代码示例1.打开摄像头2.采集图像 以上是2023-06-12的日志,接下来还有四天的实训!继续更新! 背景故事 最近刚好赶上学校的…

chatgpt赋能python:Python怎样进行快速复制?

Python怎样进行快速复制&#xff1f; 如果你经常使用Python编程&#xff0c;那么你了解到实现复制粘贴操作的重要性。可以通过快速复制代码片段&#xff0c;提高您的生产力和效率。在这篇文章中&#xff0c;我们将讨论一些Python中的技巧和工具&#xff0c;以便您进行快速复制…

《剑指 Offer--LeetCode 学习计划》-- 链表

剑指 Offer 06. 从尾到头打印链表&#xff08;Easy&#xff09; 题目描述 输入一个链表的头节点&#xff0c;从尾到头反过来返回每个节点的值&#xff08;用数组返回&#xff09;。限制&#xff1a;0 < 链表长度 < 10000。 举例说明 示例 1&#xff1a; 输入&#xf…

谈谈几个常见数据结构的原理

数组 数组是最常用的数据结构&#xff0c;创建数组必须要内存中一块 连续 的空间&#xff0c;并且数组中必须存放 相同 的数据类型。比如我们创建一个长度为10&#xff0c;数据类型为整型的数组&#xff0c;在内存中的地址是从1000开始&#xff0c;那么它在内存中的存储格式如…

【送书福利-第十期】清华社 IT BOOK 多得图书活动 ~!

大家好&#xff0c;我是洲洲&#xff0c;欢迎关注&#xff0c;一个爱听周杰伦的程序员。关注公众号【程序员洲洲】即可获得10G学习资料、面试笔记、大厂独家学习体系路线等…还可以加入技术交流群欢迎大家在CSDN后台私信我&#xff01; 本文目录 一、前言二、内容介绍三、抽奖方…

第一章JUC概述

文章目录 什么是JUC为什么学习好多线程很重要硬件来说软件来说存在的问题 Java多线程相关概念一把锁两个并三个程进程和程序的联系线程和进程的联系管程 用户线程和守护线程JAVA线程 什么是JUC 在 Java 5.0 提供了 java.util.concurrent &#xff08; 简称JUC &#xff09; 包…

Spring Cloud Alibaba - Sentinel源码分析

目录 一、Sentinel核心源码分析 1、Sentinel核心概念 1.1、Node之间的关系 2、Sentinel源码入口 2.1、SlotChain解析 2.2、NodeSelectorSlot解析 2.3、ClusterBuilderSlot解析 一、Sentinel核心源码分析 Sentinel是分布式系统的防御系统。以流量为切入点&#xff0c;通过…

001安装Jenkins

安装JenkinsJenkins 是一个开源自动化服务器http://www.jenkins.io/zh/doc/book/installing/#%E7%B3%BB%E7%BB%9F%E8%A6%81%E6%B1%82 docker docker run \-u root \--rm \-d \-p 8080:8080 \-p 50000:50000 \-v jenkins-data:/var/jenkins_home \-v /var/run/docker.sock:/va…

传感器融合概念及对比

1.多传感器融合的定义 传感器数据融合的定义可以概括为把分布在不同位置的多个同类或不同类传感器所提供的局部数据资源加以综合&#xff0c;采用计算机技术对其进行分析&#xff0c;消除多传感器信息之间可能存在的冗余和矛盾&#xff0c;加以互补&#xff0c;降低其不确实性…

记录好项目D2

记录好项目 你好呀&#xff0c;这里是我专门记录一下从某些地方收集起来的项目&#xff0c;对项目修改&#xff0c;进行添砖加瓦&#xff0c;变成自己的闪亮项目。修修补补也可以成为毕设哦 本次的项目是个旅游门户网站 技术栈&#xff1a;JSPjQueryAjaxechartsSpringSpring…

第四章LockSupport与线程中断

文章目录 线程中断机制面试题什么是中断机制?实现三种中断方式通过一个volatile变量实现通过AtomicBoolean&#xff08;原子布尔型&#xff09;通过Thread类自带的中断api方法实现 API源码分析当前线程的中断标识为true&#xff0c;是不是线程就立刻停止&#xff1f;后手案例-…

Vector-常用CAN工具 - Vector Hardware Manager

本文提供了有关 Vector 用于配置 Vector 接口的新工具Vector 硬件管理器(vHardwareManager) 的一些一般信息。 常见问题 1、什么是vHardwareManager&#xff1f; 2、哪些接口支持vHardwareManager&#xff1f; 3、什么时候需要vHardwareManager&#xff1f; 4、哪里可以下…

chatgpt赋能python:Python如何截图运行效果?

Python如何截图运行效果&#xff1f; 如果你是一位有10年python编程经验的工程师&#xff0c;那么你一定知道在编写程序时调试和调整非常重要。为了更好地调试程序&#xff0c;Python提供了许多进行程序运行效果截图的方法。本文将介绍几种常用的Python截图方法以及它们的优缺…

chatgpt赋能python:Python如何截图运行结果

Python如何截图运行结果 介绍 Python是一种高级编程语言&#xff0c;非常流行。它具有许多有用的功能和库&#xff0c;使其成为许多开发人员的首选编程语言之一。但是&#xff0c;当您运行Python程序并需要与他人共享结果时&#xff0c;您可能需要截图运行结果。在本文中&…