常见泽1 发表于 2023-11-1 23:04

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

<div class='showpostmsg'> 本帖最后由 常见泽1 于 2023-11-1 23:06 编辑

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">查看F7的原理图,</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">SDRAM部分如下</span></span></p>

<p align="center"><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">可以看出SDRAM选型的是MT48LC4M32B2B5(MICRON)</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">几个关键点:1Mx32x4banks&nbsp; 刷新的话64ms 4096cycle refresh</span></span></p>

<p>&nbsp;</p>

<p align="center"><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p align="center">&nbsp;</p>

<p align="left">&nbsp;</p>

<p align="left">&nbsp;</p>

<p align="left">&nbsp;</p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">1.clock and chip enable:看原理图用的是SDNE0</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">2.banK num:手册里都有</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">3.ADDRESS DATA:看下图,PS address是12bit,截图接错了</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">4.SDRAM common clock为SDRAM 时钟配置,可选HCLK的2分频\3分频\不使能SDCLK时钟</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">主频配置为200MHz,SDRAM common clock设置为2分频,那SDCLK时钟为100MHz,每个时钟周期为10ns</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">设置一个整数,为了方便计算</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">SDRAM common burst read 字面意思应该是突发读,这里选择使能</span></span></p>

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

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">5.SDRAM common read pipe delay 表示CAS潜伏期后延迟多少个时钟在进行读数据,这里选择0 HCLK clock cycle</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">上面是对SDRAM控制寄存器1,2(FMC_SDCR1,FMC_SDCR2)相关位进行的配置</span></span></p>

<p align="center"><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"><b>6.SDAM BANK</b><b>选择</b><b>BANK1 </b><b>上面决定了只能选</b><b>BANK1</b></span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"><b>7.CAS LANTENCY:CAS</b><b>潜伏期</b><b> </b><b>没找到设置的要求</b></span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">接下来的是对SDRAM时序寄存器1,2(FMC_SDTR1,FMC_SDTR2)相关位的配置</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">8.Load mode register to active&nbsp;delay :&nbsp;加载模式寄存器命令和激活或刷新命令之间的延迟,按存储器时钟周期计</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">Cube里对参数的定义:Parameter Description: Specifies the delay between a Load Mode Register command and an Active or Refresh command in number of memory clock cycles.</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">9.Exit self-refresh delay :&nbsp;从发出自刷新命令到发出激活命令之间的延迟,按存储器时钟周期数计</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">Parameter Description: Specifies the delay from releasing the Self-refresh command to issuing the Activate command in number of memory clock cycles.</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">查数据手册知道其最小值为70ns,由于我们每个时钟周期为10ns,所以设为7</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">10.Self refresh time :&nbsp;最短的自刷新周期,tRAS</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">Parameter Description: Specifies the minimum Self-refresh period in number of memory clock cycles.</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">查数据手册知道其最小值为42ns,最大值为100000ns,由于我们每个时钟周期为10ns,所以设为4</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">11.SDRAM common row cycle delay&nbsp;: &nbsp;大概意思就是刷新命令和激活命令之间的delay,以及两个相邻刷新命令之间的delay,应该就是tRC</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">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.</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">看手册tRC在60-70ns之间,我们周期是10ns,所以tRC赋值了7</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">12. Write recovery&nbsp;time :&nbsp;大概意思就是写命令和预充电命令间的delay时间,tWR</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">Parameter Description: Specifies the delay between a Write and a Precharge command in number of memory clock cycles.</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">按照上面tWR配置成2就够了</span></span></p>

<p align="left">&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">13.SDRAM common row precharge delay :&nbsp;大概意思就是预充电命令与其它命令间的delay,即tRP</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">Parameter Description:Specifies the delay between a Precharge command and another command in number of memory clock cycles.</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">查数据手册知道其最小值为18ns,由于我们每个时钟周期为10ns,所以设为2</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p align="left">&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">14.Row to column delay :&nbsp;激活命令与读/写命令之间的delay即tRCD</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">Parameter Description:Specifies the delay between the Activate command and a Read/Write command in number of memory clock cycles.</span></span></p>

<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">18ns最小</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">100MHZ 每个时钟周期是10ns,就取2个HCLK</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">网上看到的,说必须要满足下面的公式</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">tWR&nbsp;&ge; tRAS - TRCD</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">tWR&nbsp;&ge; tRC - tRCD - tRP</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">其中:TWR =&nbsp;Write recovery&nbsp;time&nbsp;=</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">TRAS =&nbsp;Self refresh time&nbsp;= 4</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">TRC&nbsp;=&nbsp;SDRAM common row cycle delay&nbsp;= 7</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">TRP =&nbsp;SDRAM common row precharge delay&nbsp;= 2</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">TRCD&nbsp;=&nbsp;Row to column delay =2</span></span><br />
&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">tRC-tRCD-tRP=7-2-2=3,tWD &gt;=3,所以前面tWR取值2改为3</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">用cubemx创建工程,这个SDRAM是必须要添加代码的。</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">MX_FMC_Init() 函数实现对FMC的配置, HAL_SDRAM_Init() 中&nbsp;HAL_SDRAM_MspInit() 对FMC用到的pin初始化,调用&nbsp;FMC_SDRAM_Init() 和&nbsp;FMC_SDRAM_Timing_Init() 对FMC的控制进行初始化。但还不能正确读写SDRAM,因为SDRAM在正式工作之前,还需要一个SDRAM初始化的函数。</span></span></p>

<p align="left"><br />
<span style="font-family:宋体;"><span style="font-size:16px;">我们需要从STM32F769I-DISCO的工程里找到SDRAM的例程,在从例程里复制SDRAM做初始化的函数:BSP_SDRAM_Initialization_Sequence() 到我们的main.c 中</span></span></p>

<p align="left">&nbsp;</p>

<pre>
<code class="language-cpp">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-&gt;CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;

  Command-&gt;CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;

  Command-&gt;AutoRefreshNumber = 1;

  Command-&gt;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-&gt;CommandMode = FMC_SDRAM_CMD_PALL;

  Command-&gt;CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;

  Command-&gt;AutoRefreshNumber = 1;

  Command-&gt;ModeRegisterDefinition = 0;



  /* Send the command */

  HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);



  /* Step 6 : Configure a Auto-Refresh command */

  Command-&gt;CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;

  Command-&gt;CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;

  Command-&gt;AutoRefreshNumber = 8;

  Command-&gt;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-&gt;CommandMode = FMC_SDRAM_CMD_LOAD_MODE;

  Command-&gt;CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;

  Command-&gt;AutoRefreshNumber = 1;

  Command-&gt;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-&gt;Instance-&gt;SDRTR |= ((uint32_t)((1292)&lt;&lt; 1));



}</code></pre>

<p align="left">&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">这个函数有2个需要注意修改的地方:</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">(1)例程&nbsp;FMC_SDRAM&nbsp; 中的 CAS Latency 是2,对应地设置SDRAM模式寄存器时也是2。而我们在CUBEMX中将CAS Latency 配置为2,则设置SDRAM模式寄存器时SDRAM_MODEREG_CAS_LATENCY_2:</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">(2) SDRTR的值</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">要求最慢在64ms内对4096行(对应12-bit行地址空间)完成刷新,就是说64ms要刷4096次,所以每刷一次的时间间隔是 64ms&divide;4096=15.625us。</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">换算成SDRAM的CLK(即SDCLK,100MHz):15.625us&divide;(1/100us)=1562。</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

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

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">添加SDRAM测试的函数</span></span></p>

<pre>
<code class="language-cpp">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 &lt; 0x10; uwIndex++)

  {

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

  }



  /* Read back data from the SDRAM memory */

  for (uwIndex = 0; uwIndex &lt; 0x10; uwIndex++)

  {

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

  }

}</code></pre>

<p><span style="font-family:宋体;"><span style="font-size:16px;">BANK的地址看手册</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">因为之前选的是BANK1</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">下面开始测试了</span></span></p>

<p align="left">&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">再查看下我们配置的地址</span></span></p>

<p><span style="font-family:宋体;"><span style="font-size:16px;"> &nbsp;</span></span></p>

<p>&nbsp;</p>

<p><span style="font-family:宋体;"><span style="font-size:16px;">正确 OK</span></span></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

lemonboard 发表于 2023-11-2 10:26

<p>SDRAM感觉很复杂,又感觉不是很复杂</p>

lugl4313820 发表于 2023-11-3 08:06

<p>拜读大佬的作品,深感配置的复杂,还好我是借用了开源的源码,直接略过了这个复杂的配置。同时也感受到stm32cubeIDE的好用。</p>
页: [1]
查看完整版本: 【STM32F769-discovery开发板】第10篇 SDRAM详细配置测试