目录
前言
在嵌入式系统开发中,当需要处理大量数据或者运行复杂的程序时,STM32 内部的存储资源可能会显得不足。这时,外接 SDRAM(同步动态随机存取存储器)就成为了一种有效的解决方案。本文将详细介绍 STM32 与 SDRAM 的连接和使用方法。
一、SDRAM 简介
SDRAM 是一种同步动态随机存取存储器,它具有容量大、速度快、价格相对较低等优点。SDRAM 需要外部时钟信号进行同步操作,并且可以进行高速的数据读写。在嵌入式系统中,SDRAM 通常被用作程序运行空间、数据存储区或者图形缓冲区等。
二、SDRAM的组成原理
2.1存储单元阵列
SDRAM 的核心是存储单元阵列,它由大量的存储单元组成。每个存储单元可以存储一位数据(在某些类型的 SDRAM 中也可以存储多位数据)。存储单元通常以矩阵的形式排列,行和列的交叉点就是一个存储单元。
2.1.1地址译码
- 通过行地址和列地址译码器来选择特定的存储单元。当给定一个地址时,地址译码器将其转换为行地址和列地址,分别激活相应的行线和列线,从而选中特定的存储单元。
- 这种地址译码方式可以有效地减少地址线的数量,提高存储密度。
2.1.2存储电容
- 每个存储单元通常由一个存储电容和一个访问晶体管组成。存储电容用于存储数据,其充电状态表示逻辑 “1”,放电状态表示逻辑 “0”。
- 由于存储电容会逐渐漏电,因此需要定期进行刷新操作,以保持数据的有效性。
2.2控制逻辑
SDRAM 的控制逻辑负责接收外部的控制信号,并根据这些信号来控制存储单元阵列的读写操作和刷新操作。
2.2.1时钟同步
- SDRAM 是同步存储器,它需要一个外部时钟信号来进行同步操作。所有的读写操作和刷新操作都必须与时钟信号同步,以确保数据的正确传输。
- 时钟信号的上升沿和下降沿可以分别用于触发不同的操作,例如在上升沿进行数据读取,在下降沿进行数据写入。
2.2.2命令解码
- 控制逻辑接收来自外部的命令信号,例如读命令、写命令、刷新命令等。这些命令信号经过解码后,控制逻辑会执行相应的操作。
- 例如,当接收到读命令时,控制逻辑会激活相应的地址译码器,选中特定的存储单元,并将存储单元中的数据输出到数据总线上。
2.2.3模式寄存器
- SDRAM 通常具有一个模式寄存器,用于存储一些配置参数,例如 CAS 延迟、突发长度、刷新周期等。
- 这些参数可以通过外部的命令来设置,以满足不同的应用需求。
2.3数据输入 / 输出缓冲
SDRAM 的数据输入 / 输出缓冲用于在存储单元阵列和外部数据总线之间传输数据。
2.3.1数据总线
- SDRAM 通常具有一个数据总线,用于传输数据。数据总线的宽度可以是 8 位、16 位、32 位等,具体取决于 SDRAM 的类型和应用需求。
- 在进行读写操作时,数据通过数据总线在存储单元阵列和外部设备之间传输。
2.3.2数据锁存
- 数据输入 / 输出缓冲通常具有数据锁存功能,用于在数据传输过程中保持数据的稳定性。
- 当进行写操作时,外部数据首先被锁存在数据输入缓冲中,然后在适当的时候被写入存储单元阵列。当进行读操作时,存储单元阵列中的数据首先被读取到数据输出缓冲中,然后在适当的时候被输出到外部数据总线上。
2.4刷新电路
由于存储电容会逐渐漏电,因此 SDRAM 需要定期进行刷新操作,以保持数据的有效性。刷新电路负责产生刷新信号,并控制存储单元阵列的刷新操作。
2.4.1自动刷新
- SDRAM 通常具有自动刷新功能,可以在一定的时间间隔内自动进行刷新操作。自动刷新可以通过外部的命令来启动,也可以由内部的定时器自动触发。
- 在自动刷新过程中,刷新电路会依次选中存储单元阵列中的每一行,并对该行进行刷新操作。
2.4.2自刷新
SDRAM 还可以进入自刷新模式,在这种模式下,SDRAM 会停止接收外部的命令信号,并自动进行刷新操作。自刷新模式通常用于系统进入低功耗状态时,以保持数据的有效性。
三、STM32 与 SDRAM 的连接
1.硬件连接
- STM32F429 通常通过 FMC(Flexible Memory Controller,灵活存储控制器)与 SDRAM 进行连接。FMC 可以配置为不同的存储模式,以适应不同类型的外部存储器。
- 在连接 SDRAM 时,需要注意引脚的连接、时钟信号的提供、片选信号的控制等。通常,SDRAM 的数据线、地址线、控制线等需要与 STM32F429 的相应引脚进行连接,SDRAM信号线如下图所示:
2.时钟配置
SDRAM 需要外部时钟信号来进行同步操作。STM32F429 可以通过外部时钟源或者内部 PLL(锁相环)来提供 SDRAM 所需的时钟信号。在配置时钟时,需要根据 SDRAM 的规格要求来设置合适的时钟频率。
四、应用实例
以下是一个简单的应用实例,展示了如何在 STM32 上使用 SDRAM。在这个实例中,我们将使用 STM32F4 系列微控制器和一个 16MB 的 SDRAM 芯片。
1.硬件连接
- 将 SDRAM 的数据线、地址线、控制线等与 STM32 的 FMC 引脚进行连接。具体的连接方式可以参考 STM32 的数据手册和 SDRAM 的数据手册。
- 为 SDRAM 提供外部时钟信号。可以使用外部晶振或者其他时钟源来提供时钟信号。
2.软件实现
- 首先,需要在 STM32 的工程中添加 FMC 的驱动库。可以从 STM32 的官方网站上下载相应的驱动库,并将其添加到工程中。
- 然后,在代码中初始化 FMC 和 SDRAM。可以使用以下代码来初始化 FMC 和 SDRAM:
#include "stm32f4xx.h"
#include "stm32f4xx_fmc.h"
#define SDRAM_BASE_ADDR ((uint32_t)0xC0000000)
#define SDRAM_SIZE (16 * 1024 * 1024)
void SDRAM_Init(void)
{
FMC_SDRAM_InitTypeDef SDRAM_InitStructure;
FMC_SDRAM_TimingTypeDef SDRAM_Timing;
/* 使能 FMC 时钟 */
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);
/* 配置 SDRAM 时序参数 */
SDRAM_Timing.LoadToActiveDelay = 2;
SDRAM_Timing.ExitSelfRefreshDelay = 7;
SDRAM_Timing.SelfRefreshTime = 4;
SDRAM_Timing.RowCycleDelay = 7;
SDRAM_Timing.WriteRecoveryTime = 2;
SDRAM_Timing.RPDelay = 2;
SDRAM_Timing.RCDDelay = 2;
/* 配置 SDRAM 初始化参数 */
SDRAM_InitStructure.SDBank = FMC_SDRAM_Bank2;
SDRAM_InitStructure.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
SDRAM_InitStructure.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
SDRAM_InitStructure.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
SDRAM_InitStructure.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
SDRAM_InitStructure.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
SDRAM_InitStructure.WriteProtection = DISABLE;
SDRAM_InitStructure.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
SDRAM_InitStructure.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
SDRAM_InitStructure.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* 初始化 SDRAM */
FMC_SDRAM_Init(&SDRAM_InitStructure, &SDRAM_Timing);
/* 使能 SDRAM */
FMC_SDRAM_CommandSequenceEnable();
FMC_SDRAM_RefreshRateSet(SDRAM_InitStructure.SDClockPeriod, SDRAM_InitStructure.ReadBurst, 768);
FMC_SDRAM_CommandEnable(ENABLE);
}
在初始化完成后,就可以对 SDRAM 进行读写操作了。可以使用以下代码来对 SDRAM 进行读写操作:
void SDRAM_Write(uint32_t addr, uint16_t *data, uint32_t size)
{
uint16_t *p = (uint16_t *)(SDRAM_BASE_ADDR + addr);
for (uint32_t i = 0; i < size; i++)
{
*p++ = data[i];
}
}
void SDRAM_Read(uint32_t addr, uint16_t *data, uint32_t size)
{
uint16_t *p = (uint16_t *)(SDRAM_BASE_ADDR + addr);
for (uint32_t i = 0; i < size; i++)
{
data[i] = *p++;
}
}
3.测试程序
为了验证 SDRAM 的读写操作是否正确,可以编写一个测试程序。以下是一个简单的测试程序:
int main(void)
{
uint16_t data[] = {0x1111, 0x2222, 0x3333, 0x4444};
uint16_t read_data[4];
/* 初始化 SDRAM */
SDRAM_Init();
/* 向 SDRAM 写入数据 */
SDRAM_Write(0, data, 4);
/* 从 SDRAM 读取数据 */
SDRAM_Read(0, read_data, 4);
while (1)
{
}
}
在这个测试程序中,我们首先初始化了 SDRAM,然后向 SDRAM 写入了一些数据,最后从 SDRAM 读取数据并进行比较。如果读取的数据与写入的数据一致,则说明 SDRAM 的读写操作正确。
五、总结
STM32 与 SDRAM 的连接和使用可以为嵌入式系统提供更大的存储容量和更高的运行速度。在使用 SDRAM 时,需要注意硬件连接、时钟配置、初始化、读写操作和刷新操作等方面的问题。通过合理地使用 SDRAM,可以提高嵌入式系统的性能和功能。希望本文对大家在使用 STM32 和 SDRAM 时有所帮助。