【STM32F769-discovery开发板】第10篇 SDRAM详细配置测试
<div class='showpostmsg'> 本帖最后由 常见泽1 于 2023-11-1 23:06 编辑<p> </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;"> </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 刷新的话64ms 4096cycle refresh</span></span></p>
<p> </p>
<p align="center"><span style="font-family:宋体;"><span style="font-size:16px;"> </span></span></p>
<p align="center"> </p>
<p align="left"> </p>
<p align="left"> </p>
<p align="left"> </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;"> </span></span></p>
<p> </p>
<p> </p>
<p> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;"> </span></span></p>
<p> </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> </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> </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> </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;"> </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;"> </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;"> </span></span></p>
<p> </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;"> </span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">8.Load mode register to active delay : 加载模式寄存器命令和激活或刷新命令之间的延迟,按存储器时钟周期计</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;"> </span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">9.Exit self-refresh delay : 从发出自刷新命令到发出激活命令之间的延迟,按存储器时钟周期数计</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;"> </span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">10.Self refresh time : 最短的自刷新周期,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;"> </span></span></p>
<p> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">11.SDRAM common row cycle delay : 大概意思就是刷新命令和激活命令之间的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;"> </span></span></p>
<p> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">12. Write recovery time : 大概意思就是写命令和预充电命令间的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;"> </span></span></p>
<p align="left"><span style="font-family:宋体;"><span style="font-size:16px;">按照上面tWR配置成2就够了</span></span></p>
<p align="left"> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">13.SDRAM common row precharge delay : 大概意思就是预充电命令与其它命令间的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;"> </span></span></p>
<p align="left"> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">14.Row to column delay : 激活命令与读/写命令之间的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;"> </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> </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 ≥ tRAS - TRCD</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">tWR ≥ tRC - tRCD - tRP</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">其中:TWR = Write recovery time =</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">TRAS = Self refresh time = 4</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">TRC = SDRAM common row cycle delay = 7</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">TRP = SDRAM common row precharge delay = 2</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">TRCD = Row to column delay =2</span></span><br />
</p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">tRC-tRCD-tRP=7-2-2=3,tWD >=3,所以前面tWR取值2改为3</span></span></p>
<p> </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() 中 HAL_SDRAM_MspInit() 对FMC用到的pin初始化,调用 FMC_SDRAM_Init() 和 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"> </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->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));
}</code></pre>
<p align="left"> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">这个函数有2个需要注意修改的地方:</span></span></p>
<p> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">(1)例程 FMC_SDRAM 中的 CAS Latency 是2,对应地设置SDRAM模式寄存器时也是2。而我们在CUBEMX中将CAS Latency 配置为2,则设置SDRAM模式寄存器时SDRAM_MODEREG_CAS_LATENCY_2:</span></span></p>
<p> </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÷4096=15.625us。</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;"> </span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">换算成SDRAM的CLK(即SDCLK,100MHz):15.625us÷(1/100us)=1562。</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;"> </span></span></p>
<p> </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> </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 < 0x10; uwIndex++)
{
*(__IO uint32_t*) (SDRAM_BANK_ADDR + 0xc00 + 4*uwIndex) = aTxBuffer;
}
/* Read back data from the SDRAM memory */
for (uwIndex = 0; uwIndex < 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;"> </span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">下面开始测试了</span></span></p>
<p align="left"> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;"> </span></span></p>
<p> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;"> </span></span></p>
<p> </p>
<p> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">再查看下我们配置的地址</span></span></p>
<p><span style="font-family:宋体;"><span style="font-size:16px;"> </span></span></p>
<p> </p>
<p><span style="font-family:宋体;"><span style="font-size:16px;">正确 OK</span></span></p>
<p> </p>
<p> </p>
<p> </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> <p>SDRAM感觉很复杂,又感觉不是很复杂</p>
<p>拜读大佬的作品,深感配置的复杂,还好我是借用了开源的源码,直接略过了这个复杂的配置。同时也感受到stm32cubeIDE的好用。</p>
页:
[1]