参考文档:

https://zhuanlan.zhihu.com/p/657819569
https://blog.csdn.net/weixin_41613969/article/details/126822480
https://blog.csdn.net/m0_69169562/article/details/143217380
https://blog.csdn.net/qq_42039294/article/details/112221396
https://blog.csdn.net/qq_45467083/article/details/109425825
https://blog.51cto.com/u_15262460/3243123
https://blog.51cto.com/u_15830484/5761618
https://blog.csdn.net/Simon223/article/details/107819310
https://blog.csdn.net/Ningjianwen/article/details/90940570
https://blog.csdn.net/chen18221987993/article/details/128970443

https://www.bilibili.com/video/BV13a411c7UK/?vd_source=2a185775b9481ebf3be36db7d3ece99a

一、配置STM32CUBEMX

配置信息安装芯片要求配置,这里使用的是W9825G6KH-6,配置在SDRAM1,起始地址为0xC0000000。

按照下列配置,配置相关数据:

二、初始化函数

sdram_fmc.h :

#ifndef __SDRAM_FMC_H__
#define __SDRAM_FMC_H__

#include "main.h"

#define EXT_SDRAM_ADDR  	((uint32_t)0xC0000000)     // BANK1 0XC000 0000   BANK2 0XD000 0000
#define EXT_SDRAM_SIZE		(32 * 1024 * 1024)         // 内存大小 32MB = 256Mbit
#define SDRAM_TEST_SIZE     (4 * 16 * 1024)            // 单次读写间隔

#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)

void SDRAM_Init(void);

void fsmc_sdram_test(void);
void sdram_test(void);
#endif

sdram_fmc.c :

#include "sdram_fmc.h"
#include "fmc.h"
#include "usart.h"

static int SDRAM_SendCommand(uint32_t CommandMode, uint32_t Bank, uint32_t RefreshNum, uint32_t RegVal)
{
    uint32_t CommandTarget;
    FMC_SDRAM_CommandTypeDef Command;
    
    if (Bank == 1) 
    {
        CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    } 
    else if (Bank == 2) 
    {
        CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
    }
    
    Command.CommandMode = CommandMode;
    Command.CommandTarget = CommandTarget;
    Command.AutoRefreshNumber = RefreshNum;
    Command.ModeRegisterDefinition = RegVal;
    
    if (HAL_SDRAM_SendCommand(&hsdram1, &Command, 0x1000) != HAL_OK) {
        return -1;
    }
    
    return 0;
}

void SDRAM_Init(void)
{
    uint32_t temp;
    
    /* 1. 时钟使能命令 */
    SDRAM_SendCommand(FMC_SDRAM_CMD_CLK_ENABLE, 1, 1, 0);
    
    /* 2. 延时,至少100us */
    HAL_Delay(1);
    
    /* 3. SDRAM全部预充电命令 */
    SDRAM_SendCommand(FMC_SDRAM_CMD_PALL, 1, 1, 0);
    
    /* 4. 自动刷新命令 */
    SDRAM_SendCommand(FMC_SDRAM_CMD_AUTOREFRESH_MODE, 1, 8, 0);
    
    /* 5. 配置SDRAM模式寄存器 */   
    temp = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1            |          //设置突发长度:1
                     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL     |          //设置突发类型:连续
                     SDRAM_MODEREG_CAS_LATENCY_3             |          //设置CL值:3
                     SDRAM_MODEREG_OPERATING_MODE_STANDARD   |          //设置操作模式:标准
                     SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;              //设置突发写模式:单点访问  
    SDRAM_SendCommand(FMC_SDRAM_CMD_LOAD_MODE, 1, 1, temp);
    
    /* 6. 设置自刷新频率 */
    /*
        SDRAM refresh period / Number of rows)*SDRAM时钟速度 – 20
      = 64000(64 ms) / 2^13 *84MHz - 20
    */
    HAL_SDRAM_ProgramRefreshRate(&hsdram1, 636);
}                                                

//uint16_t testsdram[250000] __attribute__((at(0XC0000000)));   /* 测试用数组 */


//SDRAM内存测试	    
void fsmc_sdram_test(void)
{  
	__IO uint32_t i=0;  	  
	__IO uint32_t temp=0;	   
	__IO uint32_t sval=0;//在地址0读到的数据	  
    
	//每隔16K字节,写入一个数据,总共写入2048个数据,刚好是32M字节

    for(i=0; i<EXT_SDRAM_SIZE; i+=SDRAM_TEST_SIZE)
	{
        HAL_SDRAM_Write_32b(&hsdram1, (uint32_t *)(EXT_SDRAM_ADDR+i), (uint32_t *)&temp, 1);

//		*(__IO uint32_t *)(EXT_SDRAM_ADDR+i) = temp; 
		temp++;
	}
    
     printf("write over temp:%d \r\n", temp);
    
    //依次读出之前写入的数据,进行校验		  
 	for(i=0; i<EXT_SDRAM_SIZE; i+=SDRAM_TEST_SIZE) 
	{	
        HAL_SDRAM_Read_32b(&hsdram1, (uint32_t *)(EXT_SDRAM_ADDR+i), (uint32_t *)&temp, 1);

        printf("[%d] addr:%04x  temp:%d \r\n",i/(SDRAM_TEST_SIZE) ,EXT_SDRAM_ADDR+i, temp);
 	}	
}

注:

绘制PCB,sdram的布线需要考虑等长阻抗匹配,随便连接的导线可能导致数据传输错乱。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐