跳转到主要内容

4. 外部RAM

动机

在该步骤中,我们将使能外部SDRAM。 图形应用通常需要外部RAM,在许多分辨率下所需帧缓存较大,而无法使用内部RAM。 某些应用可能使用两到三个帧缓存,因此更加需要外部RAM。

Note
如果所用开发板不外扩RAM,请跳过此步。

当帧缓存要放在外部RAM时,确保外部RAM

  • 可读可写。
  • 并以所需速度(通常为最大速度)运行。

目标

本节旨在启用外部RAM,并从中读取和写入数据。

验证

以下是本节的验证点:

验证点基本原理
外部RAM可读外部RAM可用于帧缓冲区位置
外部RAM可写外部RAM可用于帧缓冲区位置
外部RAM性能使用外部RAM作为帧缓存时,图形处理性能可接受

先决条件

以下是此步骤的先决条件:

  • 有关RAM的信息,通常为数据手册
  • 有关MCU与外部RAM之间的连接的信息

执行

在STM32CubeMX中,通过“Connectivity”->“FMC”->“SDRAM1”来配置外部SDRAM控制器:

配置SDRAM

AHB时钟(HCLK) 是FMC存储控制器的参考时钟。 检查“时钟配置”下的时钟频率,并使用该频率计算各种SDRAM时钟周期。

请记住配置用于SDRAM的所有GPIO:

配置SDRAM GPIO

进一步配置

对于某些RAM芯片,还必须进行其他特定的配置。 这部分不能在STM32CubeMX中配置,而必须在C代码中完成。 STM32Cube HAL包含用户向设备发送命令的函数。 下面为一个示例:

main.c
FMC_SDRAM_CommandTypeDef Command;

/* Step 1: Configure a clock configuration enable command */
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;

/* Send the command */
HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);

测试 RAM

配置外部RAM后,务必对其进行测试。 我们应至少测试以下内容:

  • RAM在调试器中可见
  • RAM在整个范围内可读可写
  • 性能符合预期

存储控制器根据外部存储器的类型使用其固定地址映射。 检查微控制器的数据手册以确认其地址。 SDRAM通常映射到0xC0000000(存储区域1) 或0xD0000000(存储区域2) 。

测试RAM在调试器中可见。

使能RAM后的第一个测试为借助调试器访问它。 这样就可以轻松确认是否可以读写存储器。 只需使用存储器浏览器打开以下地址:

通过调试器测试存储区域2中以0xD0000000起始的存储段

RAM在整个范围内可读可写

下一个测试为编写小程序,将更多数据写入外部存储器。 最好测试整个存储器。 以下是起点:

uint32_t *externalRAM = 0xC000000;
const uint32_t size = 1000;

//write external RAM
for(int i = 0; i < size; i++)
{
externalRAM[i] = i;
}

现在,在调试器中再次检查存储器。 这可以显示某些类型的错误,例如,某些地址引脚是否未连接或未交换。 您还应尝试不同大小的写入值。 仅仅写入小数字(如0、1、2、3) 往往无法揭示某些数据引脚是否正常连接或损坏。

我们可以通过简单程序来读取存储器:

uint32_t *externalRAM = 0xC000000;
const uint32_t size = 1000;

//read external RAM
for(int i = 0; i < size; i++)
{
ASSERT(externalRAM[i] == i, "external RAM not as expected");
}

请记住,此类测试无法确定地址是否错误。

欲测试所有存储单元。 要么通过运行更长的循环,要么随意更改起始地址。

性能符合预期

我们现在需要测试外部RAM的性能。 当帧缓存位于外部存储器中时,性能很重要。 缓慢的存储器会使系统的图形处理性能降低。

测试读取、写入和修改RAM的速度。 通常,图形应用会将许多数据从一个存储器复制到另一个存储器。 在绘图操作期间将大量写入帧缓冲,而在传输至显示屏时将进行大量读取操作。 我们可通过测试程序来模拟这些操作:

volatile uint32_t *externalRAM = 0xC000000;
uint32_t sourcedata[10000];
const uint32_t size = 10000;

int begin = HAL_GetTick();
//write external RAM
for(int i = 0; i < size; i++)
{
externalRAM[i] = sourcedata[i];
}
int end = HAL_GetTick();
int begin = HAL_GetTick();
//Read external RAM
for(int i = 0; i < size; i++)
{
sourcedata[i] = externalRAM[i];
}
int end = HAL_GetTick();

当在背景上混合图形时,图形处理软件可在帧缓冲中读取和写入数据。

//Time modifying external RAM
int begin = HAL_GetTick();
for(int i = 0; i < size; i++)
{
externalRAM[i] += 2;
}
int end = HAL_GetTick();

根据您的存储器速度和想要的精度,您可能希望循环测试100次,以使结果更可靠。

如果外部RAM时钟过快,则可能在读取或写入操作期间导致错误。 通过这些较简单的测试可能很难看到这一点,但这在显示屏上可以直观地感受到。