LPC54608 之 SDRAM 应用

关键字 :LPC54608SDRAM


一、概述


LPC54608 拥有支持外部存储器的设备的外部存储器控制器 EMC ( External Memory Controller ) 。 LPC54608 的 EMC 是 ARM PrimeCell™ 的多端口内存控制器外设,为异步静态内存设备提供支持,如 RAM、ROM 和 Flash,此外,它还可以用作与芯片外内存映射设备和外围设备的接口,如支持 SDRAM ( synchronous dynamic random-access memory,简称 SDRAM ) 等。EMC 是一个先进的微控制器总线架构 ( AMBA ) 兼容外设。


1.1 SDRAM
简介


SDRAM : Synchronous Dynamic Random Access Memory,同步动态随机存储器。同步是指其时钟频率和 CPU 前端总线的系统时钟相同,并且内部命令的发送与数据的传输都以它为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失;随机是指数据不是线性依次存储,而是自由指定地址进行数据的读写。


二、SDRAM 基础知识


2.1
逻辑 Bank


简单地说,SDRAM 的内部是一个存储阵列。因为如果是管道式存储(就如排队买票),就很难做到随机访问了。阵列就如同表格一样,将数据“填”进去,你可以把它想象成一张表格。和表格的检索原理一样,先指定一个行 ( Row ),再指定一个列 ( Column ),我们就可以准确地找到所需要的单元格,这就是内存芯片寻址的基本原理。对于内存,这个单元格可称为存储单元,那么这个表格(存储阵列)就是逻辑 Bank( Logical Bank,下文简称 L-Bank )。


图 1. 存储阵列 ( L-Bank ) 示意图

由于技术、成本等原因,不可能只做一个全容量的 L-Bank,而且最重要的是,由于 SDRAM 的工作原理限制,单一的 L-Bank 将会造成非常严重的寻址冲突,大幅降低内存效率。所以人们在 SDRAM 内部分割成多个 L-Bank,较早以前是两个,目前基本都是 4 个,这也是 SDRAM 规范中的最高 L-Bank 数量。这样,在进行寻址时就要先确定是哪个 L-Bank,然后再在这个选定的 L-Bank 中选择相应的行与列进行寻址。


图 2. 64Mbit SDRAM 内部结构框图


2.2 SDRAM
的容量计算


SDRAM 内存芯片一次传输率的数据量就是芯片位宽,那么这个存储单元的容量就是 SDRAM 芯片的位宽(也是 L-Bank 的位宽)。显然,SDRAM 内存芯片的容量就是所有 L-Bank 中的存储单元的容量总和。即:

存储单元数量 = 行数 × 列数(得到一个 L-Bank 的存储单元数量)× L-Bank 的数量

在很多 SDRAM 的数据手册中,都会用 M × W 的方式来表示芯片的容量(或规格 / 组织结构)。M 为该芯片中存储单元的总数,单位是兆(英文简写 M,即 2^20),W 代表每个存储单元的容量,也就是 SDRAM 芯片的位宽,单位是 bit。计算出来的芯片容量也是以 bit 为单位,我们可以采用除以 8 的方法换算为字节 ( Byte )。比如 4M × 16,这是一个 16bit 位宽芯片,有 4M 个存储单元,总容量是 64Mbit( 8MB )。


2.3 SDRAM
信号线

信号

说明

CLK

时钟信号,在该时钟的上升沿采集输入信号

CKE

时钟使能,禁止时钟时,SDRAM 会进入自刷新模式

CS

片选信号,低电平有效

RAS

行地址选通信号,低电平时,表示行地址

CAS

列地址选通信号,低电平时,表示列地址

WE

写使能信号,低电平有效

BS0,BS1

BANK 地址线

A0~A12

地址线(行 / 列)

DQ0~15

数据线

LDQM, UDQM

数据掩码,表示 DQ 的有效部分

表 1. SDRAM 信号线


三、SDRAM 工作时序


以下内容均以 W9864G2JH 为例,此 SDRAM 位宽为 32bit,包含 4 个 Bank,每个 Bank 大小为 512K。


3.1
初始化


在 SDRAM 芯片内部还有一个逻辑控制单元,并且有一个模式寄存器为其提供控制参数。因此,每次开机时 SDRAM 都要先对这个控制逻辑核心进行初始化。关键的阶段就在于模式寄存器( MR,Mode Register )的设置,简称 MRS( MR Set ),在设置到 MR 之后,就开始了进入正常的工作状态。


图 3. 设置 W9864G2JH SDRAM 模式寄存器

通过上图可以看到,Mode Register 的控制参数是通过地址线提供不同的 0 / 1 信号来写入的,具体的信号在上图表中有列出。这些参数中,Burst Length 是一个比较重要的参数,具体含义以及其设置将在下文谈到,这里我们先对它有个印象即可。


3.2
数据读取


初始化完成后,要想对一个 L-Bank 中的阵列进行寻址,首先就要确定行 ( Row ),使之处于活动状态 ( Active ),然后再确定列。虽然之前要进行片选和 L-Bank 的定址,但它们与行有效可以同时进行。行地址确定之后,就要对列地址进行寻址了。在行地址 CAS ( Column Address Strobe,列地址选通脉冲 )信号发出之后,仍要经过一定的时间才能有数据输出,从 CAS 与读取命令发出到第一笔数据输出的这段时间,被定义为 CL ( CAS Latency,CAS 潜伏期 )。由于 CL 只在读取时出现,所以 CL 又被称为读取潜伏期 ( RL,Read Latency )。CL 的单位为时钟周期数,具体耗时由时钟频率决定。


图 4. 读取数据时序


3.3
数据写入


数据写入的操作没有 CL (记住,CL 只出现在读取操作中),数据可以与 CAS 同时发送,也就是说写入延迟为 0。


图 5. 写入数据时序


3.4 Burst Length


大多数地方把这个翻译成“突发长度”,Burst 在这里更多的有着一种“连续”的意思。所谓的“突发”是指当我们对一个地址进行寻址并操作完成后,不必再重新对下一个地址进行寻址,而是直接进行操作。这样就节省了很多的时间,具体的情况也很简单,就是节省了延时的那段时间。

现在我们再回头看看模式寄存器里的参数,是不是知道了这个“Burst Length”的含义了,这里设置的长度受 SDRAM 本身和你所使用的 MCU 的限制,具体最大能设置为多少要看手册。这里以 LPC54608 为例,如下图。


图 6. MCU 手册描述

这里我们可以看到,LPC54608 这款单片机支持的最大突发长度为 128 bit,而这里我们使用的 W9864G2JH SDRAM 位宽为 32 bit,所以我们的突发长度最大可以设置为 4。即对于 32bit ,32 × 4 = 128,即最多支持 burst = 4;对于 16bit,则 16 × 8 = 128,即支持 burst = 8。


3.5
预充电


由于 SDRAM 的寻址具体独占性,所以在进行完读写操作后,如果要对同一 L-Bank 的另一行进行寻址,就要将原来有效(工作)的行关闭,重新发送行 / 列地址。L-Bank 关闭现有工作行,准备打开新行的操作就是预充电( Precharge )。预充电可以通过命令控制,也可以通过辅助设定让芯片在每次读写操作之后自动进行预充电。实际上,预充电是一种对工作行中所有存储体进行数据重写,并对行地址进行复位,以准备新行的工作。


图 7. 预充电


3.6
刷新


之所以称为 DRAM,就是因为它要不断进行刷新 ( Refresh ) 才能保留住数据,因此它是 DRAM 最重要的操作。刷新操作分为两种:自动刷新 ( Auto Refresh,简称 AR ) 与自刷新 ( Self Refresh,简称 SR )。不论是何种刷新方式,都不需要外部提供行地址信息,因为这是一个内部的自动操作。对于 AR,  SDRAM 内部有一个行地址生成器(也称刷新计数器)用来自动的依次生成行地址。由于刷新是针对一行中的所有存储体进行,所以无需列寻址。由于刷新涉及到所有 L-Bank,因此在刷新过程中,所有 L-Bank 都停止工作,而每次刷新所占用的时间为 9 个时钟周期( PC133 标准 ),之后就可进入正常的工作状态,也就是说在这 9 个时钟期间内,所有工作指令只能等待而无法执行。64ms 之后则再次对同一行进行刷新,如此周而复始进行循环刷新。显然,刷新操作肯定会对 SDRAM 的性能造成影响,但这是没办法的事情,也是 DRAM 相对于 SRAM (静态内存,无需刷新仍能保留数据)取得成本优势的同时所付出的代价。SR 则主要用于休眠模式低功耗状态下的数据保存,这里不做介绍。


四、LPC54608 读写 SDRAM 实验


4.1
实验目的


通过本实验,理解并掌握 SDRAM 的读写功能


4.2
开发环境


硬件:LPC54608 Demo 板

软件:MDK5 开发环境


4.3
实验描述


本实验以 W9864G2JH 为例,对 SDRAM 进行读写测试。W9864G2JH 是一个 512K * 4Bank * 32bit 的 SDRAM。


4.4
软件设计


(1)对 SDRAM 的参数进行配置,这些参数在 Datasheet 上都能找到。

 


图 8. 配置 SDRAM 参数

(2)初始化引脚,配置时钟,由于 SDRAM 引脚比较多,这里就不详细列举了,每个引脚配置到相应的功能即可。


图 9. 初始化引脚,配置时钟

(3)向 SDRAM 写入数据。


图 10. 写入 SDRAM

(4)读取刚刚写入的数据,并与写入的数据比较,看是否一致。


图 11. 读取 SDRAM


4.5
实验结果


在串口助手上可以看到 SDRAM 读写数据的比较,若没有错误提示,则说明读写数据一致,SDRAM 读写实验成功完成。


4.6
实验代码

/***********************  Standard C Included Files  ***********************/
#include "board.h"
#include "fsl_debug_console.h"
#include "fsl_emc.h"
#include "stdbool.h"
#include "pin_mux.h"

/****************************** Definitions ******************************/
#define SDRAM_BASE_ADDR 0xa0000000
#define SDRAM_SIZE_BYTES (8 * 1024 * 1024)
#define SDRAM_EXAMPLE_DATALEN (SDRAM_SIZE_BYTES / 4)

/********************************* Code *********************************/
status_t SDRAM_DataBusCheck(volatile uint32_t *address)
{
uint32_t data = 0;

/* Write the walking 1's data test. */
for (data = 1; data != 0; data <<= 1)
{
*address = data;

/* Read the data out of the address and check. */
if (*address != data)
{
return kStatus_Fail;
}
}
return kStatus_Success;
}

status_t SDRAM_AddressBusCheck(volatile uint32_t *address, uint32_t bytes)
{
uint32_t pattern = 0x55555555;
uint32_t size = bytes / 4;
uint32_t offset;
uint32_t checkOffset;

/* write the pattern to the power-of-two address. */
for (offset = 1; offset < size; offset <<= 1)
{
address[offset] = pattern;
}
address[0] = ~pattern;

/* Read and check. */
for (offset = 1; offset < size; offset <<= 1)
{
if (address[offset] != pattern)
{
return kStatus_Fail;
}
}

if (address[0] != ~pattern)
{
return kStatus_Fail;
}

/* Change the data to the revert one address each time
* and check there is no effect to other address. */
for (offset = 1; offset < size; offset <<= 1)
{
address[offset] = ~pattern;
for (checkOffset = 1; checkOffset < size; checkOffset <<= 1)
{
if ((checkOffset != offset) && (address[checkOffset] != pattern))
{
return kStatus_Fail;
}
}
address[offset] = pattern;
}
return kStatus_Success;
}

int main(void)
{
uint32_t index;
uint32_t *sdram = (uint32_t *)SDRAM_BASE_ADDR; /* SDRAM start address. */

/* Hardware Initialization */
CLOCK_EnableClock(kCLOCK_InputMux);
/* attach 12 MHz clock to FLEXCOMM0 (debug console) */
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

BOARD_InitPins();
BOARD_BootClockPLL180M();
BOARD_InitDebugConsole();
BOARD_InitSDRAM();

// Data/address bus check. //BL = 4
if (SDRAM_DataBusCheck(sdram) != kStatus_Success)
{
PRINTF("\r\n SDRAM data bus check is failure.\r\n");
}

if (SDRAM_AddressBusCheck(sdram, SDRAM_SIZE_BYTES) != kStatus_Success)
{
PRINTF("\r\n SDRAM address bus check is failure.\r\n");
}

PRINTF("\r\n Start.\r\n");

//Prepare data and write to SDRAM.
for (index = 0; index < SDRAM_EXAMPLE_DATALEN; index++)
{
*(uint32_t *)(sdram + index) = 0x11223344; //0xAABBCCDD
}

//Read data from the SDRAM.
for (index = 0; index < SDRAM_EXAMPLE_DATALEN; index++)
{
if (*(uint32_t *)(sdram + index) != 0x11223344)
{
PRINTF("\r\n Error: %8X\n , %8X\n \r\n", (sdram + index), *(uint32_t *)(sdram + index));
}
}

PRINTF("\r\n SDRAM Write Data and Read Data Succeed.\r\n");

while (1)
{
}
}

 


五、参考资料


(1)LPC546XX 系列相关资料均可在 NXP 官网下载,网址如下:

https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc54000-cortex-m4-/power-efficient-microcontrollers-mcus-with-advanced-peripherals-based-on-arm-cortex-m4-core:LPC546XX?&tid=vanLPC546XX

(2)《高手进阶,终极内存技术指南》,网址如下:https://wenku.baidu.com/view/acfdfed733d4b14e8524687f.html

(3)《W9864G2JH Datasheet》,网址如下:https://pdf1.alldatasheet.com/datasheet-pdf/view/555629/WINBOND/W9864G2JH.html

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论