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

STM32CubeMX系列教程21:SDRAM

watrt6年前 (2017-12-17)Cortex-M318610

在看下面教程之前,如果你之前没有使用过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系列教程8:数模转换(DAC)

STM32CubeMX系列教程8:数模转换(DAC)

1.DAC单次转换       本章程序在串口printf工程的基础上修改,复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。PA5管脚配置为DAC输出通道2。 DAC配置为默认配置不需修改。生成报告以及代码,编译程序。在adc.c文件中可以看到ADC初始化函数。在stm32f7xx_hal_dac.h头文件中可以看到DAC的操作函数。/** @addtogroup ...

STM32CubeMX系列教程15:看门狗(WDG)

STM32CubeMX系列教程15:看门狗(WDG)

一、看门狗简介        看门狗其实就是一个定时器,从功能上说它可以让微控制器在程序发生意外(程序进入死循环或跑飞)的时候,能重新回复到系统刚上电状态,以保障系统出问题的时候可以重启一次。说的复杂一点,看门狗就是能让程序出问题是能重新启动系统。二、独立看门狗(IWDG)         前文再续,书接上一会,上一章说到待机模式可以通过IWDG唤醒,独立看门口功能框图如下。实际上独立看门口狗就是一个递减计...

STM32CubeMX系列教程19:Quad-SPI

STM32CubeMX系列教程19:Quad-SPI

一.Quad-SPI简介        在第十章和第十一章中,我们介绍了标准的SPI总线,SPI由四根线控制,NSS为片选,SCK为时钟信号线。MISO,MOSI为数据线,一根作为输入,一根作为输出。        Quad-SPI,即四线SPI,由此可知其数据线比标准的SPI接口要多,最多支持四条数据线同时传输。连接单、双或四(条数据线) SPI Flash 存储介质。Quad-SPI总共有6根...

STM32CubeMX系列教程22:LCD-TFT控制器(LDTC)

STM32CubeMX系列教程22:LCD-TFT控制器(LDTC)

一、LTDC简介        LCD-TFT(液晶显示器 —— 薄膜晶体管)显示器控制器提供并行数字 RGB(红色、绿色、蓝色)以及水平同步、垂直同步、像素时钟和数据使能信号,这些信号直接输出到不同 LCD和 TFT 面板的接口。本章通过Open746I-C开发板控制微雪7inch Capacitive Touch LCD (F)型LCD。其原理图如下:(注:本章介绍的是通过LDTC控制RGB接...

发表评论

访客

看不清,换一张

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