[原创] 【STM32F769-discovery开发板】第10篇 SDRAM详细配置测试

常见泽1   2023-11-1 23:04 楼主

 

查看F7的原理图,

SDRAM部分如下

image-20231101230403-1.png  

可以看出SDRAM选型的是MT48LC4M32B2B5(MICRON)

几个关键点:1Mx32x4banks  刷新的话64ms 4096cycle refresh

 

image-20231101230403-2.png  

 

 

 

 

1.clock and chip enable:看原理图用的是SDNE0

2.banK num:手册里都有

3.ADDRESS DATA:看下图,PS address是12bit,截图接错了

image-20231101230403-3.png  

 

 

 

image-20231101230403-4.png  

 

4.SDRAM common clock为SDRAM 时钟配置,可选HCLK的2分频\3分频\不使能SDCLK时钟

主频配置为200MHz,SDRAM common clock设置为2分频,那SDCLK时钟为100MHz,每个时钟周期为10ns

设置一个整数,为了方便计算

 

SDRAM common burst read 字面意思应该是突发读,这里选择使能

突发读的讲解,摘自网络:读/写操作,都是一次对一个存储单元进行寻址,如果要想要连续的向SDRAM中读数据或者写数据,就需要对当前存储单元的下一个单元进行寻址,也即是需要不停给SDRAM列激活信号以及读/写命令(行地址不变,所以不用再对行寻址)。虽然由于读/写延迟相同可以让数据的传输在I/O端是连续的,但它占用了大量的内存控制资源,在数据进行连续传输时无法输入新的命令,效率很低。为此,人们开发了突发传输技术,只要指定起始列地址与突发长度,SDRAM就会不再需要控制器连续地提供列地址,依次地自动对后面相应数量的存储单元进行读/写操作。 作者:明德扬易老师 https://www.bilibili.com/read/cv20016015/ 出处:bilibili

 

5.SDRAM common read pipe delay 表示CAS潜伏期后延迟多少个时钟在进行读数据,这里选择0 HCLK clock cycle

 

上面是对SDRAM控制寄存器1,2(FMC_SDCR1,FMC_SDCR2)相关位进行的配置

image-20231101230403-5.png  

6.SDAM BANK选择BANK1 上面决定了只能选BANK1

image-20231101230403-6.png  

7.CAS LANTENCY:CAS潜伏期 没找到设置的要求

image-20231101230403-7.png  

 

接下来的是对SDRAM时序寄存器1,2(FMC_SDTR1,FMC_SDTR2)相关位的配置

image-20231101230403-8.png  

8.Load mode register to active delay : 加载模式寄存器命令和激活或刷新命令之间的延迟,按存储器时钟周期计

Cube里对参数的定义:Parameter Description: Specifies the delay between a Load Mode Register command and an Active or Refresh command in number of memory clock cycles.

image-20231101230403-9.png  

9.Exit self-refresh delay : 从发出自刷新命令到发出激活命令之间的延迟,按存储器时钟周期数计

Parameter Description: Specifies the delay from releasing the Self-refresh command to issuing the Activate command in number of memory clock cycles.

查数据手册知道其最小值为70ns,由于我们每个时钟周期为10ns,所以设为7

image-20231101230403-10.png  

10.Self refresh time : 最短的自刷新周期,tRAS

Parameter Description: Specifies the minimum Self-refresh period in number of memory clock cycles.

查数据手册知道其最小值为42ns,最大值为100000ns,由于我们每个时钟周期为10ns,所以设为4

image-20231101230403-11.png  

 

11.SDRAM common row cycle delay :  大概意思就是刷新命令和激活命令之间的delay,以及两个相邻刷新命令之间的delay,应该就是tRC

Parameter Description: Specifies the delay between the Refresh command and the Activate command, as well as the delay between two consecutive Refresh commands. It is expressed in number of memory clock cycles.

看手册tRC在60-70ns之间,我们周期是10ns,所以tRC赋值了7

image-20231101230403-12.png  

 

12. Write recovery time : 大概意思就是写命令和预充电命令间的delay时间,tWR

Parameter Description: Specifies the delay between a Write and a Precharge command in number of memory clock cycles.

image-20231101230403-13.png  

按照上面tWR配置成2就够了

 

13.SDRAM common row precharge delay : 大概意思就是预充电命令与其它命令间的delay,即tRP

Parameter Description:Specifies the delay between a Precharge command and another command in number of memory clock cycles.

查数据手册知道其最小值为18ns,由于我们每个时钟周期为10ns,所以设为2

image-20231101230403-14.png  

 

14.Row to column delay : 激活命令与读/写命令之间的delay即tRCD

Parameter Description:Specifies the delay between the Activate command and a Read/Write command in number of memory clock cycles.

image-20231101230403-15.png  

18ns最小

100MHZ 每个时钟周期是10ns,就取2个HCLK

 

网上看到的,说必须要满足下面的公式

tWR ≥ tRAS - TRCD

tWR ≥ tRC - tRCD - tRP

其中:TWR = Write recovery time =

TRAS = Self refresh time = 4

TRC = SDRAM common row cycle delay = 7

TRP = SDRAM common row precharge delay = 2

TRCD = Row to column delay =2
 

tRC-tRCD-tRP=7-2-2=3,tWD >=3,所以前面tWR取值2改为3

 

用cubemx创建工程,这个SDRAM是必须要添加代码的。

MX_FMC_Init() 函数实现对FMC的配置, HAL_SDRAM_Init() 中 HAL_SDRAM_MspInit() 对FMC用到的pin初始化,调用 FMC_SDRAM_Init() 和 FMC_SDRAM_Timing_Init() 对FMC的控制进行初始化。但还不能正确读写SDRAM,因为SDRAM在正式工作之前,还需要一个SDRAM初始化的函数。


我们需要从STM32F769I-DISCO的工程里找到SDRAM的例程,在从例程里复制SDRAM做初始化的函数:BSP_SDRAM_Initialization_Sequence() 到我们的main.c 中

 

static void BSP_SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command)

{

  __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_2           |

                     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));



}

 

这个函数有2个需要注意修改的地方:

 

(1)例程 FMC_SDRAM  中的 CAS Latency 是2,对应地设置SDRAM模式寄存器时也是2。而我们在CUBEMX中将CAS Latency 配置为2,则设置SDRAM模式寄存器时SDRAM_MODEREG_CAS_LATENCY_2:

 

(2) SDRTR的值

要求最慢在64ms内对4096行(对应12-bit行地址空间)完成刷新,就是说64ms要刷4096次,所以每刷一次的时间间隔是 64ms÷4096=15.625us。

image-20231101230403-16.png  

换算成SDRAM的CLK(即SDCLK,100MHz):15.625us÷(1/100us)=1562。

image-20231101230403-17.png  

 

看F7的参考手册,刷新率必须要在上面公式的基础上再减去20个SDRAM的时钟周期,即1562-20=1542。例程中用的数字是1292,则刷新周期在54ms左右。一旦完成刷新参数设置(写到 SDRTR 寄存器中),FMC立即自动开始刷新,即每隔大约60ms,MCU通过FMC向SDRAM发送一条刷新指令。

 

添加SDRAM测试的函数

void SDRAM_Test()

{

  Fill_Buffer(aTxBuffer, 0x10, 0xA244250F);

#define SDRAM_BANK_ADDR                 ((uint32_t)0xC0000000)

  /* Write data to the SDRAM memory */

  for (uwIndex = 0; uwIndex < 0x10; uwIndex++)

  {

    *(__IO uint32_t*) (SDRAM_BANK_ADDR + 0xc00 + 4*uwIndex) = aTxBuffer[uwIndex];

  }



  /* Read back data from the SDRAM memory */

  for (uwIndex = 0; uwIndex < 0x10; uwIndex++)

  {

    aRxBuffer[uwIndex] = *(__IO uint32_t*) (SDRAM_BANK_ADDR + 0xc00 + 4*uwIndex);

  }

}

BANK的地址看手册

因为之前选的是BANK1

image-20231101230403-18.png  

下面开始测试了

 

image-20231101230403-19.png  

 

image-20231101230403-20.png  

 

 

再查看下我们配置的地址

image-20231101230403-21.png  

 

正确 OK

 

 

 

本帖最后由 常见泽1 于 2023-11-1 23:06 编辑

回复评论 (2)

SDRAM感觉很复杂,又感觉不是很复杂

点赞  2023-11-2 10:26

拜读大佬的作品,深感配置的复杂,还好我是借用了开源的源码,直接略过了这个复杂的配置。同时也感受到stm32cubeIDE的好用。

点赞  2023-11-3 08:06
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复