【STM32F429-DISCOVERY学习笔记】STM32F429驱动SDRAM(IS42S16400J)详解

2024-02-05 07:48

本文主要是介绍【STM32F429-DISCOVERY学习笔记】STM32F429驱动SDRAM(IS42S16400J)详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 http://bbs.armfly.com/read.php?tid=1942


 驱动SDRAM的时序比较的麻烦一些,不像驱动SRAM,非常简单,网上搜索一下,估计有非常多的FPGA驱

动SDRAM的资料,而且是各种的给你讲时序问题,现在F429/439集成了控制 器以后就方便很多了,用户只需配
相应的寄存器即可,这里向大家推荐一篇文章,强烈的推荐, 不懂SDRAM为何物的,一定要看看。
《高手进阶,终极内存技术指南——完整/进阶版》 http://bbs.armfly.com/read.php?tid=1930 
1.  学习SDRAM驱动前的准备工作
    学习SDRAM前搞清楚两个问题,一个是SDRAM的基本原理,还有一个就是那几个关键的参数 ,参 数是F429
配置 SDRAM的关键,这几个参数大概知道是什么意思就行了,配置的时候,根据 SDRAM的手册配置 一下就OK
了。 在STM32F429/439的数据手册里关键参数说明,F429/439是把这几个关键的参数做到了一个 存器 里面
了,这些参数,手册上面有一些英文说明,但比较的笼统。

我推荐的那篇文章,建议大家一定要看,别的可以不看,这个必须得看,讲的实在太好了,我这里 把一些关键的
参数摘录出来:
tRCD:
       在发送列读写命令时必须要与行有效命令有一个间隔,这个间隔被定义为tRCD,即RAS to CAS 
Delay(RAS至CAS延迟),大家也可以理解为行选通周期,这应该是根据芯片存储阵列电子元件响
应时间(从一种状态到另一种状态变化的过程)所制定的延迟。tRCDSDRAM的一个重要时序参数
,可以通过主板BIOS经过北桥芯片进行调整,但不能超过厂商的预定范围。广义的tRCD以时钟周期
tCKClock Time)数为单位,比如tRCD=2,就代表延迟周期为两个时钟周期,具体到确切的时
,则要根据时钟频率而定,对于PC100SDRAMtRCD=2,代表20ns的延迟,对于PC133则为15ns
CL(CAS Latency):
        在选定列地址后,就已经确定了具体的存储单元,剩下的事情就是数据通过数据I/O通道(DQ)输
出到内存总线上了。但是在CAS发出之后,仍要经过一定的时间才能有数据输出,从CAS与读取命令发
出到第一笔数据输出的这段时间,被定义为CL(CAS Latency,CAS潜伏期)。由于CL只在读取时出现,
以CL又被称为读取潜伏期(RL,Read Latency)。CL的单位与tRCD一样,为时钟周期数,具体耗时
时钟频率决定。
       数据写入的操作也是在tRCD之后进行,但此时没有了CL(记住,CL只出现在读取操作中)。
tWR:
        数据并不是即时地写入存储电容,因为选通三极管(就如读取时一样)与电容的充电必须要有一段
时间,所以数据的真正写入需要一定的周期。为了保证数据的可靠写入,都会留出足够的写入/校正时间
tWRWriteRecovery Time),这个操作也被称作写回(Write Back)。
tRP:
        在发出预充电命令之后,要经过一段时间才能允许发送RAS行有效命令打开新的工作行,这个间隔被
称为tRP(Precharge command Period,预充电有效周期)。和tRCDCL一样,tRP的单位也是时钟周
期数,具体值视时钟频率而定。
我这里就先贴上这几个参数,其它的参数,大家可以查阅相关的资料。
2.  F429/439手册中对SDRAM的介绍
       如果你看了我在前面推荐的那个文章,现在看这个手册还是比较容易的。我这里就象征性的贴一下F429
439自带SDRAM控制器的特性和引脚,其它的大家自己看手册就行。



3.  F429/439驱动SDRAM详细过程
说明:以官方的Demonstration做例子


第一步:F429的时钟配置
        F429/439支持最高主频180Mhz,相比于407只提高了12M, 感觉劲还是不足,传说STM32F5系列将
做到250MHz,就相当的给力了。
F429配置过程和以前芯片的配置过程是一样的,我这里主要是想通过这个配置得到SDRAM的时钟频率, 先
说明一下这个开发板外接的是8MHz的晶振,通过锁相环得到180的主频。

#define PLL_SOURCE_HSE    // HSE (8MHz) used to clock the PLL, and the PLL is used as system clock source
/*  PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N  */
#if defined  (PLL_SOURCE_HSI)
#define PLL_M      16
#else
#define PLL_M      8
#endif
#define PLL_N      360
/* SYSCLK = PLL_VCO / PLL_P */  
#define PLL_P      2
/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
#define PLL_Q      7
由上面的公式得到 : SYSCLK = PLL_VCO / PLL_P =( (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N)/PLL_P  = 180
/* HCLK = SYSCLK / 1 = 180 */ RCC->CFGR |= RCC_CFGR_HPRE_DIV1;   
/* PCLK2 = HCLK / 2 = 90 */ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;  
/* PCLK1 = HCLK / 4 = 45 */ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
第二步:引脚配置
        驱动前要先搞清楚一个问题,驱动SDRAM的行选和列选的地址线是分时复用的,和SRAM不同
需要完整的地址线才可以访问各个地址空间,官方提供的原理图


关于这个芯片的特点:


标准的SDRAM一般都是4个BANK,这个芯片也不例外,芯片的总容量
1Mbitx 16-bit x 4-bank = 67,108,864 bits = 64-Mbit ,每个BANK的组成
4096rows x 256 columns x 16 bits, 这个比较重要,配置的时候要用到,也就是
12行8列。
第三步:FMC配置
这里FMC驱动SDRAM只支持两种频率,分别是
SDCLK period = 2 x HCLK periods
SDCLK period = 3 x HCLK periods
根据我们上面的配置,HCLK是180MHz,这里SDCLK就是2分频或者3分频,官方提供的
这个例子,在注释上面有误,他们是按照主频168MHz,2分频是SDCLK = 84MHz注释的,
不过不影响使用,只是注释上面是这样的。按照90MHz的话,每个时钟周期就是11.1ns
7个SDRAM关键参数的配置,下面一个一个的说。
1.  TMRD
/* TMRD: 2 Clock cycles */
FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2; 
这里为什么成2,查手册, 手册上提供的是三种速度等级时提供的参数, 我们这里是用
的90MHz,也取2个肯定是没问题的。


2. TXSR
/* TXSR: min=70ns (6x11.10ns) */
FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7;
开发板上面用的SDRAM速度等级的7,最高工作频率时143MHz


3. TRAS
/* TRAS: min=42ns (4x11.10ns) max=120k (ns) */
FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4;


4. TRC
/* TRC:  min=63 (6x11.10ns) */        
FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 7;    


5. TWR
/* TWR:  2 Clock cycles */
FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2;  

6. TRP
/* TRP:  15ns => 2x11.10ns */
FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2; 


7. TRCD                
/* TRCD: 15ns => 2x11.10ns */
FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2;


时序设置好以后就是SDRAM控制器的配置。

/* 支持两个SDRAM的BANK,这里使用的是bank2  */
  FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank2_SDRAM;
  /* 根据这个SDRAM的特性是12行,8列,在这里配置一下 */
  FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;
  FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b;
  /* 数据位宽是16 */
  FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH;
  /* 此芯片支持4个bank */
  FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
  /* 设置CAS的延迟是3 */
  FMC_SDRAMInitStructure.FMC_CASLatency = SDRAM_CAS_LATENCY; 
  FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable;
  /* 配置SDCLK的时钟频率 */
  FMC_SDRAMInitStructure.FMC_SDClockPeriod = SDCLOCK_PERIOD;  
  /* 禁止读取时的突发模式 */
  FMC_SDRAMInitStructure.FMC_ReadBurst = SDRAM_READBURST;
  /* 设置ReadPipe时的延迟  */
  FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_1;
  FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure;
第四步:SDRAM初始化

1.  使能时钟
  FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;  
  FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
  FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;  FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
  /* Wait until the SDRAM controller is ready */   

  while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
  {  }
  /* Send the command */  

  FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); 
2.  插入100ms的延迟

  __Delay(10);
3.  预充电配置  
  /* Configure a PALL (precharge all) command */   
  FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL;
  FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;  
  FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
  FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;  
  /* Wait until the SDRAM controller is ready */ 
  while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)  
  {
  }  
  /* Send the command */
  FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
4. 自动刷新配置
  /* Configure a Auto-Refresh command */   
  FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;
  FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;  
  FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 4;
  FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;  
  /* Wait until the SDRAM controller is ready */ 
  while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)  
  {
  }  
  /* Send the  first command */
  FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);  
  /* Wait until the SDRAM controller is ready */   
  while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
  {  }
  /* Send the second command */  
  FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
5. 配置外部模式寄存器  
  /* Program the external memory mode register */
  tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2          |                   
                   SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
                   SDRAM_MODEREG_CAS_LATENCY_3           |                   
                   SDRAM_MODEREG_OPERATING_MODE_STANDARD |
                   SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;  
  /* Configure a load Mode register command*/   
  FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode;
  FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;  
  FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
  FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;  
  /* Wait until the SDRAM controller is ready */ 
  while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)  
  {
  }  
  /* Send the command */
  FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
6. 刷新频率设置
  /* Set the refresh rate counter */  
  /* (7.81 us x Freq) - 20 */
  /* Set the device refresh counter */  
  FMC_SetRefreshCount(683);
  /* Wait until the SDRAM controller is ready */   
  while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
  {  }
关于刷新频率的的数值是这么得到的,这里得详细的说一下,目前公认的标准是,存储体中电容的数据有效保存期上限是
64ms(毫秒,1/1000秒),也就是说每一行刷新的循环周期是64ms。这样刷新速度就是:行数量/64ms。我们在看内
存规格时,经常会看到4096 Refresh Cycles/64ms或8192 RefreshCycles/64ms的标识,这里的4096与8192就代表这
个芯片中每个L-Bank的行数。刷新命令一次对一行有效,发送间隔也是随总行数而变化,4096行时为15.625μs(微秒,
1/1000毫秒),8192行时就为7.8125μs。        
       SDRAM的手册上说是4096 refresh cycles every 64 ms,这里就应该是15.525us,而注释上面是按8192行计算
,郁闷,有时间得研究研究。


到这里基本就设置完了,剩下就可以像使用SRAM一样,使用SDRAM了。


开发板上面用的SDRAM数据手册
 42-45S16400J.pdf (1136 K) 下载次数:35 


这篇关于【STM32F429-DISCOVERY学习笔记】STM32F429驱动SDRAM(IS42S16400J)详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/680223

相关文章

Go路由注册方法详解

《Go路由注册方法详解》Go语言中,http.NewServeMux()和http.HandleFunc()是两种不同的路由注册方式,前者创建独立的ServeMux实例,适合模块化和分层路由,灵活性高... 目录Go路由注册方法1. 路由注册的方式2. 路由器的独立性3. 灵活性4. 启动服务器的方式5.

Java中八大包装类举例详解(通俗易懂)

《Java中八大包装类举例详解(通俗易懂)》:本文主要介绍Java中的包装类,包括它们的作用、特点、用途以及如何进行装箱和拆箱,包装类还提供了许多实用方法,如转换、获取基本类型值、比较和类型检测,... 目录一、包装类(Wrapper Class)1、简要介绍2、包装类特点3、包装类用途二、装箱和拆箱1、装

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

Python中Markdown库的使用示例详解

《Python中Markdown库的使用示例详解》Markdown库是一个用于处理Markdown文本的Python工具,这篇文章主要为大家详细介绍了Markdown库的具体使用,感兴趣的... 目录一、背景二、什么是 Markdown 库三、如何安装这个库四、库函数使用方法1. markdown.mark

PLsql Oracle 下载安装图文过程详解

《PLsqlOracle下载安装图文过程详解》PL/SQLDeveloper是一款用于开发Oracle数据库的集成开发环境,可以通过官网下载安装配置,并通过配置tnsnames.ora文件及环境变... 目录一、PL/SQL Developer 简介二、PL/SQL Developer 安装及配置详解1.下

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

css渐变色背景|<gradient示例详解

《css渐变色背景|<gradient示例详解》CSS渐变是一种从一种颜色平滑过渡到另一种颜色的效果,可以作为元素的背景,它包括线性渐变、径向渐变和锥形渐变,本文介绍css渐变色背景|<gradien... 使用渐变色作为背景可以直接将渐China编程变色用作元素的背景,可以看做是一种特殊的背景图片。(是作为背

springboot日期格式化全局LocalDateTime详解

《springboot日期格式化全局LocalDateTime详解》文章主要分析了SpringBoot中ObjectMapper对象的序列化和反序列化过程,并具体探讨了日期格式化问题,通过分析Spri... 目录分析ObjectMapper与jsonSerializer结论自定义日期格式(全局)扩展利用配置

Java中基于注解的代码生成工具MapStruct映射使用详解

《Java中基于注解的代码生成工具MapStruct映射使用详解》MapStruct作为一个基于注解的代码生成工具,为我们提供了一种更加优雅、高效的解决方案,本文主要为大家介绍了它的具体使用,感兴趣... 目录介绍优缺点优点缺点核心注解及详细使用语法说明@Mapper@Mapping@Mappings@Co