回答

收藏

8..STM32F469I---SDRAM使用及测试

STMCU STMCU 2635 人阅读 | 0 人回复 | 2018-01-12

【STM32F469I试用】SDRAM使用及测试【转】



SDRAM概述

为了更好的体验显示效果,板载一块16MB的美光内存,型号为MT48LC4M32B2B5-6A,构成4 Meg x 32 (1 Meg x 32 x 4 banks),12位行地址,8位列地址。主要特性参考数据手册如下:





关于SDRAM的使用,详细情况请参考对应的手册,这里只介绍几个重要的参数,包括TRCD, TRP, CL。

RCD 在发送列读写命令时必须要与行有效命令有一个间隔,这个间隔被定义为tRCD,即RAS to CASDelay(RAS至CAS延迟),大家也可以理解为行选通周期,这应该是根据芯片存储阵列电子元件响应时间(从一种状态到另一种状态变化的过程)所制定的延迟。tRCD是SDRAM的一个重要时序参数,可以通过主板BIOS经过北桥芯片进行调整,但不能超过厂商的预定范围。广义的tRCD以时钟周期(tCK,Clock Time)数为单位,比如tRCD=2,就代表延迟周期为两个时钟周期,具体到确切的时间,则要根据时钟频率而定,对于PC100SDRAM,tRCD=2,代表20ns的延迟,对于PC133则为15ns
RP 在发出预充电命令之后,要经过一段时间才能允许发送RAS行有效命令打开新的工作行,这个间隔被称为tRP(Precharge command Period,预充电有效周期)。和tRCD、CL一样,tRP的单位也是时钟周期数,具体值视时钟频率而定。
CL 在选定列地址后,就已经确定了具体的存储单元,剩下的事情就是数据通过数据I/O通道(DQ)输出到内存总线上了。但是在CAS发出之后,仍要经过一定的时间才能有数据输出,从CAS与读取命令发出到第一笔数据输出的这段时间,被定义为CL(CAS Latency,CAS潜伏期)。由于CL只在读取时出现,所以CL又被称为读取潜伏期(RL,Read Latency)。CL的单位与tRCD一样,为时钟周期数,具体耗时由时钟频率决定。

这些参数都可以参考上面的表1,需要注意的是这个值一般是指时钟周期,具体到不同的SDRAM时钟上的话,需要进行换算。数据手册上给出了具体的时间数,其值对应为18-18-18NS,单位是纳秒。

具体来说,在F469-DISCO开发板上,SDRAM的时钟周期最大可以达到HCLK/2,如果配置HCLK为180MHZ的话,则2分频后,SDRAM的时钟频率为90MHZ,一个周期长度约为11.1纳秒,所以在初始化的时候应该分别指定这些值为2, 2, 2。

GPIO配置

参考官方原理图,GPIO用到的主要包括地址线,这些是复用的,还是数据线,BANK选择等。见下图



只不过这些引脚有些多,可以参考官方例程查看具体用到的引脚。

FMC控制器配置

F469MCU内置FMC控制器,可以访问SRAM, SDRAM, NORFLASH等常见存储器件,这里主要指定一些基本的参数,先看代码,再做一个简单的说明。

  /* SDRAM device configuration */
  hsdram.Instance = FMC_SDRAM_DEVICE;

  SDRAM_Timing.LoadToActiveDelay    = 2;
  SDRAM_Timing.ExitSelfRefreshDelay = 6;
  SDRAM_Timing.SelfRefreshTime      = 4;
  SDRAM_Timing.RowCycleDelay        = 6;
  SDRAM_Timing.WriteRecoveryTime    = 2;
  SDRAM_Timing.RPDelay              = 2;
  SDRAM_Timing.RCDDelay             = 2;

  hsdram.Init.SDBank             = FMC_SDRAM_BANK1;
  hsdram.Init.ColumnBitsNumber   = FMC_SDRAM_COLUMN_BITS_NUM_8;
  hsdram.Init.RowBitsNumber      = FMC_SDRAM_ROW_BITS_NUM_12;
  hsdram.Init.MemoryDataWidth    = SDRAM_MEMORY_WIDTH;
  hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
  hsdram.Init.CASLatency         = FMC_SDRAM_CAS_LATENCY_3;
  hsdram.Init.WriteProtection    = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
  hsdram.Init.SDClockPeriod      = SDCLOCK_PERIOD;
  hsdram.Init.ReadBurst          = FMC_SDRAM_RBURST_ENABLE;
  hsdram.Init.ReadPipeDelay      = FMC_SDRAM_RPIPE_DELAY_0;

  /* Initialize the SDRAM controller */
  HAL_SDRAM_Init(&hsdram, &SDRAM_Timing);

注意看TRP, TRCD及CL的配置,这里指定的都是2,因为SDRAM工作在90MHZ频率之下,2个时钟周期大约为20NS,刚好满足要求,不能再小了。

后面的一些参数,如行列地址线的数目,BANK的个数,基本都可以从SDRAM的数据手册上获取。

SDRAM的初始化序列

按官方手册上的介绍,在使用SDRAM之前,先要执行一系列的初始化命令,然后才能正常访问SDRAM。基本步骤如下:

同时给VDD及VDDQ上电
提供稳定的时钟信号
在发送命令前至少等待100US,在此期间拉高CKE,直到结束
发送PRECHARGE ALL命令
等待至少TRP指定的时间,直到预充电完成
发磅AUTO REFRESH命令,等待TRFC指定的时间
现在SDRAM可以进入模式选择阶段,这里如果不指定的话,SDRAM会进入默认的工作模式,也许不是用户需要的状态。
等待TMRD指定的时间后,SDRAM就可以正常访问了。

结合下面的代码可以看看

  __IO uint32_t tmpmrd =0;
  /* Step 3:  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(hsdram, Command, SDRAM_TIMEOUT);

  /* Step 4: Insert 100 us minimum delay */
  /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
  HAL_Delay(1);

  /* Step 5: Configure a PALL (precharge all) command */
  Command->CommandMode = FMC_SDRAM_CMD_PALL;
  Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
  Command->AutoRefreshNumber = 1;
  Command->ModeRegisterDefinition = 0;

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

  /* Step 6 : Configure a Auto-Refresh command */
  Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
  Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
  Command->AutoRefreshNumber = 8;
  Command->ModeRegisterDefinition = 0;

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

  /* Step 7: Program the external memory mode register */
  tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |
                     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
                     SDRAM_MODEREG_CAS_LATENCY_3           |
                     SDRAM_MODEREG_OPERATING_MODE_STANDARD |
                     SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;

  Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
  Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
  Command->AutoRefreshNumber = 1;
  Command->ModeRegisterDefinition = tmpmrd;

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

  /* Step 8: Set the refresh rate counter */
  /* (15.62 us x Freq) - 20 */
  /* Set the device refresh counter */
  hsdram->Instance->SDRTR |= ((uint32_t)((1292)<< 1));

至此,SDRAM的初始化就全部完成了,现在可以正常访问SDRAM了。

SDRAM的映射地址

SDRAM在MCU的地址空间中的映射地址为0xC0000000到0xC0FFFFFF,可随机线性访问。

代码测试

这里设计了一段简单的代码来测试所有的内存是否正常。首先将数据写入到SDRAM中,然后读出来,进行比较后判断是否正常。

SDRAM_Init();

HAL_UART_Transmit(&huart3, (uint8_t *)msg1, strlen(msg1), 100);

for(uwIndex = 0; uwIndex < uwCount; uwIndex += 4)
{
  *(__IO uint32_t*) (SDRAM_BANK_ADDR + 4*uwIndex) = 0x01234567;
  if(*(__IO uint32_t*) (SDRAM_BANK_ADDR + 4*uwIndex) == 0x01234567)
  {
   percent2 = uwIndex * 100 / uwCount;

   if(percent1 != percent2)
   {
    sprintf(msg, "PASSED: %3d%%\r\n", percent2);
    HAL_UART_Transmit(&huart3, (uint8_t *)msg, strlen(msg), 100);
   }
   percent1 = percent2;

  }
  else
   while(1);

}

下面是测试结果





SDRAM数据手册:
MT48LC4M32B2B5-6A.pdf (3.52 MB, 下载次数: 0, 售价: 1 与非币)


工程文件:
sdram.zip (3.71 MB, 下载次数: 0, 售价: 1 与非币)


分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条