当前位置:首页 > 技术 > Cortex-M3 > 正文内容

STM32CubeMX系列教程21:SDRAM

Watrt7年前 (2017-12-17)Cortex-M322790

在看下面教程之前,如果你之前没有使用过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℃。如下为芯片数据手册:

42-45s16400j.pdf


SDRAM的内部是一个存储阵列,阵列就如同表格一样,先指定一个行(Row),再指定一个列(Column),我们就可以准确地找到所需要的单元格,这就是内存芯片寻址的基本原理。对于内存,这个单元格可称为存储单元,那么这个表格就是逻辑Bank(Logical Bank,下文简称L-Bank)。SDRAM内部分割成多个L-Bank。IC42S16400J分为四个Bank。

二、SDRAM硬件简介

上图是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来说,有三个参数对其性能影响至关重要,它们是tRCDCLtRP,对于这三个参数的详细描述可以查看“高手进阶,终极内存技术指南——完整.doc”。下面是对三个参数的一些简要摘录(顺便加多了一个tWR):
tRCD:
在发送列读写命令时必须要与行有效命令有一个间隔,这个间隔被定义为tRCD,即RAS to CAS Delay(RAS至CAS延迟),可以理解为行选通周期,这应该是根据芯片存储阵列电子元件响
应时间(从一种状态到另一种状态变化的过程)所制定的延迟。广义的tRCD以时钟周期tCKClock 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可取23个周期
tRP:在发出预充电命令之后,要经过一段时间才能允许发送RAS行有效命令打开新的工作行,这个间隔被称为tRP(Precharge command Period,预充电有效周期)。和tRCDCL一样,tRP的单位也是时钟周期数,具体值视时钟频率而定。对于IS42S16400J-7TL,tRP为15ns
tWR:数据并不是即时地写入存储电容,因为选通三极管(就如读取时一样)与电容的充电必须要有一段时间,所以数据的真正写入需要一定的周期。为了保证数据的可靠写入,都会留出足够的写入/校正时间tWRWriteRecovery Time),这个操作也被称作写回(Write Back)。对于IS42S16400J-7TL,tWR为2个周期

三、FMC之SDRAM控制器简介
这里贴一下SDRAM控制器的特性,详细可查看数据手册:

操作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):

FMC配置如下

下面详细说明,各个选项的配置: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 写保护,一般配置为Disabled6.SDRAM common clock为SDRAM 时钟配置,可选HCLK的2分频\3分频\不使能SDCLK时钟前面主频配置为216MHz,SDRAM common clock设置为2分频,那SDCLK时钟为108MHz,每个时钟周期为9.25ns
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)相关位的配置9.Load mode register to active delay : 加载模式寄存器命令和激活或刷新命令之间的延迟,按存储器时钟周期计

10.Exit self-refresh delay : 从发出自刷新命令到发出激活命令之间的延迟,按存储器时钟周期数计查数据手册知道其最小值为70ns,由于我们每个时钟周期为9.25ns,所以设为8 (70÷9.25,向上取整)

11.Self refresh time : 最短的自刷新周期,按存储器时钟周期数计查数据手册知道其最小值为42ns,最大值为100000ns,由于我们每个时钟周期为9.25ns,所以设为5 (40÷9.25,向上取整)


12.SDRAM common row cycle delay :  刷新命令和激活命令之间的延迟,以及两个相邻刷新命令之间的延迟, 以存储器时钟周期数表示查数据手册知道其最小值为63ns,由于我们每个时钟周期为9.25ns,所以设为7 (63÷9.25,向上取整)


13.Write recovery 
time : 写命令和预充电命令之间的延迟,按存储器时钟周期数计

14.SDRAM common row precharge delay : 预充电命令与其它命令之间的延迟,按存储器时钟周期数计查数据手册知道其最小值为15ns,由于我们每个时钟周期为9.25ns,所以设为2 (15÷9.25,向上取整)


15.Row to column delay : 激活命令与读/写命令之间的延迟,按存储器时钟周期数计查数据手册知道其最小值为15ns,由于我们每个时钟周期为9.25ns,所以这里本应该设为2 (15÷9.25,向上取整)但要注意,时序必须满足以下式子:TWR ≥ TRAS - TRCDTWR ≥ TRC - TRCD - TRP其中:TWR = Write recovery time = 2TRAS = Self refresh time = 5TRC = SDRAM common row cycle delay = 7TRP = SDRAM common row precharge delay = 2TRCD = Row to column delay
所以这里Row to column delay应该取3


生成报告以及代码,编译程序。在fmc.c文件中可以看到初始化函数。在stm32f7xx_hal_sdram.h头文件中可以看到sdram的操作函数。
五、应用程序编写
下载这个应用文件解压并添加到工程中:

stm32746g_sdram.zip

在main.c中包含头文件"stm32746g_sdram.h"

/* USER CODE BEGIN Includes */
#include "stm32746g_sdram.h"
/* USER CODE END Includes */

添加变量,aRxBuffer,aTxbuffer为读写缓存,我uwWriteReadStatus存储读写状态。

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
#define BUFFER_SIZE         ((uint32_t)0x0100)
#define WRITE_READ_ADDR     ((uint32_t)0x0800)
/* Read/Write Buffers */
uint32_t aTxBuffer[BUFFER_SIZE];
uint32_t aRxBuffer[BUFFER_SIZE];
/* Status variables */
__IO uint32_t uwWriteReadStatus = 0;
int i;
/* USER CODE END PFP */

在main函数中添加以下测试代码:

/* USER CODE BEGIN 2 */
    BSP_SDRAM_Initialization_sequence(&hsdram1, REFRESH_COUNT);
    /*##-2- SDRAM memory read/write access #####################################*/
    /* Fill the buffer to write */
    for(i=0; i<BUFFER_SIZE; i++)
    {
            aTxBuffer[i]=0xC178A562+i;     /* TxBuffer init */
    }
  
    /* Write data to the SDRAM memory */
    BSP_SDRAM_WriteData(&hsdram1, SDRAM_DEVICE_ADDR+WRITE_READ_ADDR,aTxBuffer, BUFFER_SIZE);
    printf("\r\n/* Write data to the SDRAM memory */\r\n\r\n");
    for(i=0;i< BUFFER_SIZE;i++)
    {
            printf("%02X:0x%08X ",i,aTxBuffer[i]);
    }
    printf("\r\n");
  
    /* Read back data from the SDRAM memory */
    BSP_SDRAM_ReadData(&hsdram1, SDRAM_DEVICE_ADDR+WRITE_READ_ADDR, aRxBuffer, BUFFER_SIZE);
    printf("\r\n/* Read back data from the SDRAM memory */\r\n\r\n");
    for(i=0;i< BUFFER_SIZE;i++)
    {
            printf("%02X:0x%08X ",i,aRxBuffer[i]);
    }
    printf("\r\n");
  
    /*##-3- Checking data integrity ############################################*/    
    for (i = 0; (i < BUFFER_SIZE); i++)
    {
            if (aRxBuffer[i] != aTxBuffer[i])
                    uwWriteReadStatus++;
    }    
    if(uwWriteReadStatus == 0 ) /* check date */
            printf("\r\n SDRAM Test OK\r\n");
    else
            printf("\r\n SDRAM Test False\r\n");
    /* USER CODE END 2 */

这里详细说一下BSP_SDRAM_Initialization_sequence函数,主要是实现上SDRAM初始化步骤3~8

void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount)
{
  __IO uint32_t tmpmrd = 0;
    
  /* 时钟配置使能,对应STM32初始化SDRAM步骤3 */
  Command.CommandMode            = FMC_SDRAM_CMD_CLK_ENABLE;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = 0;
  
  /* Send the command */
  HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
  
  /* 等待指定延迟周期,对应STM32初始化SDRAM步骤4 */ 
  /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
  HAL_Delay(1);
      
  /* PALL(“预充电所有存储区域”)命令,对应STM32初始化SDRAM步骤5 */ 
  Command.CommandMode            = FMC_SDRAM_CMD_PALL;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = 0;
  
  /* Send the command */
  HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);  
    
  /* 自刷新命令,8个自刷新周期,对应STM32初始化SDRAM步骤6 */ 
  Command.CommandMode            = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 8;
  Command.ModeRegisterDefinition = 0;
  
  /* Send the command */
  HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
    
  /* 配置SDRAM模式寄存器,对应STM32初始化SDRAM步骤7 */
  /* 突发长度:1
     突发传输方式:顺序
     CAS潜伏期:2
     操作模式:标准
     操作模式:突发读/单一写
  */
  tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |\
                     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |\
                     SDRAM_MODEREG_CAS_LATENCY_2           |\
                     SDRAM_MODEREG_OPERATING_MODE_STANDARD |\
                     SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
    
  Command.CommandMode            = FMC_SDRAM_CMD_LOAD_MODE;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = tmpmrd;
  
  /* Send the command */
  HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
    
  /* 刷新率设置,对应STM32初始化SDRAM步骤8 */
  HAL_SDRAM_ProgramRefreshRate(&sdramHandle, RefreshCount); 
}

步骤7对应于设置下图中的各个位,以配置SDRAM模式寄存器

步骤8刷新率设置由于我们使用的SDRAM芯片是4096行,所以这里的刷新率是64ms ÷(4096行) = 15.7us SDRAM使用108MHz,刷新周期为:15.7us × 108MHz = 1695.6COUNT = 1695.6 - 20 = 1675



分享给朋友:

相关文章

STM32CubeMX系列教程6:直接存储器访问 (DMA)

STM32CubeMX系列教程6:直接存储器访问 (DMA)

直接存储器访问 (DMA) 用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。说白了DMA就是一个搬运工,将数据从一个地方搬到另一个地方而不需要CPU处理。        作为一个搬运工,要他正常工作必须要确定几个重要的参数。1.传输模式:数据从哪里搬到哪里。...

STM32CubeMX系列教程9:内部集成电路(I2C)

STM32CubeMX系列教程9:内部集成电路(I2C)

1.I2C总线简介        I2C(Inter-Integrated Circuit ,内部集成电路)总线是一种由飞利浦Philip公司开发的串行总线。是两条串行的总线,它由一根数据线(SDA)和一根 时钟线(SDL)组成。I2C总线上可以接多个I2C设备,每个器件都有一个唯一的地址识别。同一时间只能有一个主设备,其他为从设备。通常MCU作为主设备控制,外设作为从设备。2.I2C硬件电路    &nb...

STM32CubeMX系列教程11:串行外设接口SPI(二)

STM32CubeMX系列教程11:串行外设接口SPI(二)

1.新建工程        本章程序在串口printf工程的基础上修改,复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。SPI1选择全双工主模式,不开启NSS。配置PA7为SPI_MOSI,PA6为SPI_MISO,PA5为SPI_SCK,PA4配置为GPIO输出模式,作为片选信号。      SPI配置中设置数据长度为8bit,MSB先输出分频为64分...

STM32CubeMX系列教程20:Nand Flash

STM32CubeMX系列教程20:Nand Flash

一、Nand Flash 简介        Flash 中文名字叫闪存,是一种长寿命的非易失性(断电数据不丢失)的存储器。可以对称为块的存储器单元块进行擦写和再编程,在进行写入操作之前必须先执行擦除。功能性分为两种:NOR Flash:允许随机存取存储器上的任何区域,以编码应用为主,其功能多与运算相关Nand Flash:主要功能是存储资料,适合储存卡之类的大量数据的存储。本章以K9F1G08U0E芯片为例讲解Nand Flash。如下为此芯片的数据手册...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。