完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
在看下面教程之前,如果你之前没有使用过SDRAM,建议先看以下文档,以对SDRAM的原理和控制有一定的了解。
高手进阶,终极内存技术指南——完整.doc 一、SDRAM简介 SDRAM(Synchronous Dynamic Random Access Memory)同步动态随机存取存储器 ·同步是指存储器工作需要同步时钟,内部命令的发送与数据传输都以它为基准 ·动态是指存储阵列需要不断的刷新来保证数据不丢失 ·随机存取是指存储器的内容可以以任意顺序访问,而不管前一次访问的是哪一个位置 开发板使用的SDRAM型号是IC42S16400J-7TL或IS42S16400J-7TL(两个型号仅产地不同,性能相同),它是一颗8M字节(1 Meg Bits × 16Bits × 4 Banks = 67108864 bits = 64-Mbit)内存芯片。 顺便说下:“-7TL”中,7表示速度等级,T表示封装 TSOPII,L表示无铅(符合RoHS标准),属于商用系列,工作温度:0℃ ~ 70℃。如下为芯片数据手册: |
|
相关推荐
|
|
SDRAM的内部是一个存储阵列,阵列就如同表格一样,先指定一个行(Row),再指定一个列(Column),我们就可以准确地找到所需要的单元格,这就是内存芯片寻址的基本原理。对于内存,这个单元格可称为存储单元,那么这个表格就是逻辑Bank(Logical Bank,下文简称L-Bank)。SDRAM内部分割成多个L-Bank。IC42S16400J分为四个Bank。 |
|
|
|
|
|
上图是SDRAM内部结构图,引脚(Pin)所对应的功能简单翻译如下: A0~A11:时分复用地址总线(发送地址时,先行后列,12行,8列) DQ0~DQ15:双向数据总线 BA0/BA1:Bank地址(两条总线,可以选通4个Bank) CS#:片选信号(低电平有效) WE#:写使能信号(低电平有效) RAS#:行地址信号(低电平有效) CAS#:列地址信号(低电平有效) CLK:同步时钟 CKE:时钟使能信号 UDQM/LDQM:数据掩码 VDD/VDDQ:工作电压/DQ电压 GND/GNDQ:相应电压接地 |
|
|
|
|
|
SDRAM与Open746I-C开发板连接如下图:
对于SDRAM来说,有三个参数对其性能影响至关重要,它们是tRCD、CL和tRP,对于这三个参数的详细描述可以查看“高手进阶,终极内存技术指南——完整.doc”。 |
|
|
|
|
|
下面是对三个参数的一些简要摘录(顺便加多了一个tWR):
tRCD: 在发送列读写命令时必须要与行有效命令有一个间隔,这个间隔被定义为tRCD,即RAS to CAS Delay(RAS至CAS延迟),可以理解为行选通周期,这应该是根据芯片存储阵列电子元件响 应时间(从一种状态到另一种状态变化的过程)所制定的延迟。广义的tRCD以时钟周期(tCK,Clock Time)数为单位,比如tRCD=2,就代表延迟周期为两个时钟周期,具体到确切的时间,则要根据时钟频率而定,对于IS42S16400J-7TL,tRCD为15ns。 CL(CAS Latency):在选定列地址后,就已经确定了具体的存储单元,剩下的事情就是数据通过数据I/O通道(DQ)输出到内存总线上了。但是在CAS发出之后,仍要经过一定的时间才能有数据输出,从CAS与读取命令发出到第一笔数据输出的这段时间,被定义为CL(CAS Latency,CAS潜伏期)。由于CL只在读取时出现,所以CL又被称为读取潜伏期(RL,Read Latency)。CL的单位与tRCD一样,为时钟周期数,具体耗时由时钟频率决定。 数据写入的操作也是在tRCD之后进行,但此时没有了CL(CL只出现在读取操作中)。对于IS42S16400J-7TL,CL可取2或3个周期。 tRP:在发出预充电命令之后,要经过一段时间才能允许发送RAS行有效命令打开新的工作行,这个间隔被称为tRP(Precharge command Period,预充电有效周期)。和tRCD、CL一样,tRP的单位也是时钟周期数,具体值视时钟频率而定。对于IS42S16400J-7TL,tRP为15ns。 tWR:数据并不是即时地写入存储电容,因为选通三极管(就如读取时一样)与电容的充电必须要有一段时间,所以数据的真正写入需要一定的周期。为了保证数据的可靠写入,都会留出足够的写入/校正时间(tWR,WriteRecovery Time),这个操作也被称作写回(Write Back)。对于IS42S16400J-7TL,tWR为2个周期。 |
|
|
|
|
|
操作SDRAM,需要先知道它的地址映射区域。从下图可知,SDRAM在STM32内部是连续的地址空间,我们使用的是区域2,所以地址应该在0xD0000000 ~ 0xDFFFFFFF之间。
由于我们的SDRAM是4Bank,12行,8列,由下图知,对于32位的地址空间,其23~31位的地址是固定了。为0xD0000000。0~22位的地址是实际的SDRAM可变地址,即地址映射为:0xD0000000 ~ 0xD07FFFFF 控制SDRAM涉及到以下几个寄存器,之后在对SDRAM配置时,使用到的位会有简单的介绍,详细描述请查看数据手册。 SDRAM控制寄存器1,2(FMC_SDCR1,FMC_SDCR2) SDRAM时序寄存器1,2(FMC_SDTR1,FMC_SDTR2) SDRAM命令模式寄存器(FMC_SDCMR) SDRAM刷新定时器寄存器(FMC_SDRTR) |
|
|
|
|
|
总的SDRAM初始化步骤如下,读者可以在对SDRAM配置完成后,返回对照下面的步骤在看一下相应的代码,相信会有一定的收获。
前面对SDRAM和STM32的SDRAM控制器有了一些简单的介绍,对于使用cube库的用户来说,基本是足够使用了。由于有SDRAM控制器,我们只需要简单的对控制器相应位进行配置后,就可以像操作内部的SRAM一样去操作SDRAM。 |
|
|
|
|
|
四、stm32CubeMX配置与说明
复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置,选择SDRAM 1,配置为4 banks,地址线12 bits,数据线 16 bits。 FMC之SDRAM引脚映射配置如下(注意PH5是FMC_SDNWE): |
|
|
|
|
|
下面详细说明,各个选项的配置:
1.Bank 由硬件连接决定需要选择SDRAM bank 22.Column bit number表示列数,8位 3.Row bit number表示行数,12位 4.CAS latency表示CAS潜伏期,即上面说的CL,该配置需要与之后的SDRAM模式寄存器的配置相同,这里先配置为2 memory clock cycles(对于SDRAM时钟超过133MHz的,则需要配置为3 memory clock cycles) 5.Write protection 表示写保护,一般配置为Disabled 6.SDRAM common clock为SDRAM 时钟配置,可选HCLK的2分频3分频不使能SDCLK时钟 [size=13.6364px]前面主频配置为216MHz,SDRAM common clock设置为2分频,那SDCLK时钟为108MHz,每个时钟周期为9.25ns [size=13.6364px] 7.SDRAM common burst read 表示突发读,这里选择使能8.SDRAM common read pipe delay 表示CAS潜伏期后延迟多少个时钟在进行读数据,这里选择0 HCLK clock cycle 前面这8项主要是对SDRAM控制寄存器1,2(FMC_SDCR1,FMC_SDCR2)相关位进行的配置 接下来的7项是对SDRAM时序寄存器1,2(FMC_SDTR1,FMC_SDTR2)相关位的配置 [size=13.6364px] 9.Load mode register to active delay : 加载模式寄存器命令和激活或刷新命令之间的延迟,按存储器时钟周期计 [size=13.6364px]10.Exit self-refresh delay : 从发出自刷新命令到发出激活命令之间的延迟,按存储器时钟周期数计 [size=13.6364px]查数据手册知道其最小值为70ns,由于我们每个时钟周期为9.25ns,所以设为8 (70÷9.25,向上取整) [size=13.6364px] 11.Self refresh time : 最短的自刷新周期,按存储器时钟周期数计 [size=13.6364px]查数据手册知道其最小值为42ns,最大值为100000ns,由于我们每个时钟周期为9.25ns,所以设为5 (40÷9.25,向上取整) |
|
|
|
|
|
[size=13.6364px]12.SDRAM common row cycle delay : 刷新命令和激活命令之间的延迟,以及两个相邻刷新命令之间的延迟, 以存储器时钟周期
数表示[size=13.6364px]查数据手册知道其最小值为63ns,由于我们每个时钟周期为9.25ns,所以设为7 (63÷9.25,向上取整) [size=13.6364px] [size=13.6364px] 13.Write recovery time : 写命令和预充电命令之间的延迟,按存储器时钟周期数计 [size=13.6364px] 14.SDRAM common row precharge delay : 预充电命令与其它命令之间的延迟,按存储器时钟周期数计 查数据手册知道其最小值为15ns,由于我们每个时钟周期为9.25ns,所以设为2 (15÷9.25,向上取整) [size=13.6364px] 15.Row to column delay : 激活命令与读/写命令之间的延迟,按存储器时钟周期数计 [size=13.6364px]查数据手册知道其最小值为15ns,由于我们每个时钟周期为9.25ns,所以这里本应该设为2 (15÷9.25,向上取整) 但要注意,时序必须满足以下式子: TWR ≥ TRAS - TRCD TWR ≥ TRC - TRCD - TRP 其中:TWR = Write recovery time = 2 [size=13.6364px]TRAS = Self refresh time = 5 [size=13.6364px]TRC = SDRAM common row cycle delay = 7 [size=13.6364px]TRP = SDRAM common row precharge delay = 2 [size=13.6364px]TRCD = Row to column delay [size=13.6364px]所以这里Row to column delay应该取3 [size=13.6364px] 生成报告以及代码,编译程序。在fmc.c文件中可以看到初始化函数。在stm32f7xx_hal_sdram.h头文件中可以看到sdram的操作函数。 |
|
|
|
|
|
五、应用程序编写
下载这个应用文件解压并添加到工程中: stm32746g_sdram.zip 在main.c中包含头文件"stm32746g_sdram.h" 1 /* USER CODE BEGIN Includes */ 2 #include "stm32746g_sdram.h" 3 /* USER CODE END Includes */ 添加变量,aRxBuffer,aTxbuffer为读写缓存,我uwWriteReadStatus存储读写状态。 01 /* USER CODE BEGIN PFP */ 02 /* Private function prototypes -----------------------------------------------*/ 03 #define BUFFER_SIZE ((uint32_t)0x0100) 04 #define WRITE_READ_ADDR ((uint32_t)0x0800) 05 /* Read/Write Buffers */ 06 uint32_t aTxBuffer[BUFFER_SIZE]; 07 uint32_t aRxBuffer[BUFFER_SIZE]; 08 /* Status variables */ 09 __IO uint32_t uwWriteReadStatus = 0; 10 int i; 11 /* USER CODE END PFP */ 在main函数中添加以下测试代码: 01 /* USER CODE BEGIN 2 */ 02 BSP_SDRAM_Initialization_sequence(&hsdram1, REFRESH_COUNT); 03 /*##-2- SDRAM memory read/write access #####################################*/ 04 /* Fill the buffer to write */ 05 for(i=0; i { 07 aTxBuffer[i]=0xC178A562+i; /* TxBuffer init */ 08 } 09 10 /* Write data to the SDRAM memory */ 11 BSP_SDRAM_WriteData(&hsdram1, SDRAM_DEVICE_ADDR+WRITE_READ_ADDR,aTxBuffer, BUFFER_SIZE); 12 printf("rn/* Write data to the SDRAM memory */rnrn"); 13 for(i=0;i< BUFFER_SIZE;i++) 14 { 15 printf("%02X:0x%08X ",i,aTxBuffer[i]); 16 } 17 printf("rn"); 18 19 /* Read back data from the SDRAM memory */ 20 BSP_SDRAM_ReadData(&hsdram1, SDRAM_DEVICE_ADDR+WRITE_READ_ADDR, aRxBuffer, BUFFER_SIZE); 21 printf("rn/* Read back data from the SDRAM memory */rnrn"); 22 for(i=0;i< BUFFER_SIZE;i++) 23 { 24 printf("%02X:0x%08X ",i,aRxBuffer[i]); 25 } 26 printf("rn"); 27 28 /*##-3- Checking data integrity ############################################*/ 29 for (i = 0; (i < BUFFER_SIZE); i++) 30 { 31 if (aRxBuffer[i] != aTxBuffer[i]) 32 uwWriteReadStatus++; 33 } 34 if(uwWriteReadStatus == 0 ) /* check date */ 35 printf("rn SDRAM Test OKrn"); 36 else 37 printf("rn SDRAM Test Falsern"); 38 /* USER CODE END 2 */ 这里详细说一下BSP_SDRAM_Initialization_sequence函数,主要是实现上SDRAM初始化的步骤3~8 01 void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount) 02 { 03 __IO uint32_t tmpmrd = 0; 04 05 /* 时钟配置使能,对应STM32初始化SDRAM步骤3 */ 06 Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; 07 Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; 08 Command.AutoRefreshNumber = 1; 09 Command.ModeRegisterDefinition = 0; 10 11 /* Send the command */ 12 HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); 13 14 /* 等待指定延迟周期,对应STM32初始化SDRAM步骤4 */ 15 /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */ 16 HAL_Delay(1); 17 18 /* PALL(“预充电所有存储区域”)命令,对应STM32初始化SDRAM步骤5 */ 19 Command.CommandMode = FMC_SDRAM_CMD_PALL; 20 Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; 21 Command.AutoRefreshNumber = 1; 22 Command.ModeRegisterDefinition = 0; 23 24 /* Send the command */ 25 HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); 26 27 /* 自刷新命令,8个自刷新周期,对应STM32初始化SDRAM步骤6 */ 28 Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; 29 Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; 30 Command.AutoRefreshNumber = 8; 31 Command.ModeRegisterDefinition = 0; 32 33 /* Send the command */ 34 HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); 35 36 /* 配置SDRAM模式寄存器,对应STM32初始化SDRAM步骤7 */ 37 /* 突发长度:1 38 突发传输方式:顺序 39 CAS潜伏期:2 40 操作模式:标准 41 操作模式:突发读/单一写 42 */ 43 tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | 44 SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | 45 SDRAM_MODEREG_CAS_LATENCY_2 | 46 SDRAM_MODEREG_OPERATING_MODE_STANDARD | 47 SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; 48 49 Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; 50 Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; 51 Command.AutoRefreshNumber = 1; 52 Command.ModeRegisterDefinition = tmpmrd; 53 54 /* Send the command */ 55 HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); 56 57 /* 刷新率设置,对应STM32初始化SDRAM步骤8 */ 58 HAL_SDRAM_ProgramRefreshRate(&sdramHandle, RefreshCount); 59 } |
|
|
|
|
|
步骤8刷新率设置由于我们使用的SDRAM芯片是4096行,所以这里的刷新率是64ms ÷(4096行) = 15.7us
SDRAM使用108MHz,刷新周期为:15.7us × 108MHz = 1695.6 COUNT = 1695.6 - 20 = 1675 在执行完BSP_SDRAM_Initialization_sequence函数后,就可以像操作SRAM一样,操作SDRAM了 六、实验现象 编译下载,正常可以看到串口输出如下信息(波特率115200) |
|
|
|
|
|
《DNESP32S3使用指南-IDF版_V1.6》第二章 常用的C语言知识点
377 浏览 0 评论
【RA-Eco-RA2E1-48PIN-V1.0开发板试用】(第三篇)ADC采集+PWM输出
536 浏览 0 评论
《DNK210使用指南 -CanMV版 V1.0》第四十五章 人脸识别实验
540 浏览 0 评论
950 浏览 0 评论
如何用OpenCV的相机捕捉视频进行人脸检测--基于米尔NXP i.MX93开发板
1403 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
11760 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 06:19 , Processed in 0.850558 second(s), Total 94, Slave 76 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号