jobszheng5 发表于 2023-10-28 10:57

[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>

freebsder 发表于 2023-10-30 15:56

<p>谢谢分享,期待后续深度评测!</p>

孤独的单刀 发表于 2023-11-1 14:02

<p>不可多得的好东西,多谢楼主分享,接下来花点时间研究研究</p>

jobszheng5 发表于 2023-11-1 15:45

<div class="quote">
<blockquote><font size="2"><a href="forum.php?mod=redirect&amp;goto=findpost&amp;pid=3274616&amp;ptid=1261115" target="_blank"><font color="#999999">孤独的单刀 发表于 2023-11-1 14:02</font></a></font> 不可多得的好东西,多谢楼主分享,接下来花点时间研究研究</blockquote>
</div>

<p>这个SDRAM确实要再仔细的多做些实验,尤其是稳定性的。</p>

<p>&nbsp;</p>

<p>谢谢 关注</p>
页: [1]
查看完整版本: [STM32F769IDISCO返场]SDRAM扩展系统内存