[STM32F769IDISCO返场]SDRAM扩展系统内存
<div class='showpostmsg'>### 背景一张800x480x分辨率的bmp文件足有1.09MB大小,即使是16位的bmp文件也有187KB。再看STM32F769芯片片上SRAM比较大,但也仅有512KB的容量大小。如果在GUI显示应用上面,以太网应用场景里负荷较重下,则相当吃紧。这里需要SDRAM芯片的协助了。
### SDRAM
SDRAM(Synchronous Dynamic Random Access Memory)是同步动态随机存取存储器,是一种常用的内存类型。它是在时钟信号的控制下进行数据读取和写入的,具有高速、高效的特点。SDRAM的特点是高速、高效、灵活性强。它可以在一个时钟周期内进行一次数据读写操作,比传统的DRAM操作更快。此外,SDRAM的功耗相对较低,体积较小,质量也轻,适用于各种电子产品中。
### 配置SDRAM
从原理图上可以看到在STM32F769IDISCO开发板上面,SDRAM与STM32F769的FMC外设相连接。
阅读芯片手册,可以看到通过FMC外设驱动SDRAM内存,其地址空间可以选择2个bank。我选择了bank1,即SDRAM的地址空间起始为0xC000_0000。
在本次实验中,我们仍然通过STM32CubeMX工具软件来生成硬件配置代码。
### 测试代码
在main.c中,我们再编写简单的测试代码。本次我设计通过读写SDRAM内存中某个地址,把读写结果进行简单的对比,再将读写操作的结果通过串口输出出来。如果写入数据与读取数据相同,则代表SDRAM配置以及读写成功。
~~~c
main.c
static void sdram_init(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command)
{
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));
}
void sdram_write_reg(uint32_t addr, uint32_t val)
{
volatile uint32_t *ptr = (volatile uint32_t *)addr;
*ptr = val;
}
uint32_t sdram_read_reg(uint32_t addr)
{
volatile uint32_t *ptr = (volatile uint32_t *)addr;
return (*ptr);
}
/* FMC initialization function */
static void MX_FMC_Init(void)
{
/* USER CODE BEGIN FMC_Init 0 */
FMC_SDRAM_CommandTypeDef command;
/* USER CODE END FMC_Init 0 */
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
/* USER CODE BEGIN FMC_Init 1 */
/* USER CODE END FMC_Init 1 */
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 6;
SdramTiming.SelfRefreshTime = 4;
SdramTiming.RowCycleDelay = 6;
SdramTiming.WriteRecoveryTime = 2;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN FMC_Init 2 */
sdram_init(&hsdram1, &command);
/* USER CODE END FMC_Init 2 */
}
main.c
sdram_write_reg(SDRAM_BANK_ADDR, 0x12345678);
rx_buf = sdram_read_reg(SDRAM_BANK_ADDR);
JDEBUG_PRINTF("rx=%08X\r\n", rx_buf);
~~~
### 结果展示
串口输出结果显示SDRAM读写操作正确。
</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){
} </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>谢谢分享,期待后续深度评测!</p>
<p>不可多得的好东西,多谢楼主分享,接下来花点时间研究研究</p>
<div class="quote">
<blockquote><font size="2"><a href="forum.php?mod=redirect&goto=findpost&pid=3274616&ptid=1261115" target="_blank"><font color="#999999">孤独的单刀 发表于 2023-11-1 14:02</font></a></font> 不可多得的好东西,多谢楼主分享,接下来花点时间研究研究</blockquote>
</div>
<p>这个SDRAM确实要再仔细的多做些实验,尤其是稳定性的。</p>
<p> </p>
<p>谢谢 关注</p>
页:
[1]