HAL库记录-SDRAM的使用

正点原子--阿波罗开发板STM32F429IGT6

HAL库记录-SDRAM的使用_第1张图片

 CLK           时钟信号,在该时钟的上升沿采集输入信号
CKE          时钟使能,禁止时钟时,SDRAM 会进入自刷新模式
CS#          片选信号,低电平有效
RAS#        行地址选通信号,低电平时,表示行地址
CAS#        列地址选通信号,低电平时,表示列地址
WE#         写使能信号,低电平有效
A0~A12     地址线(行/列)
BS0,BS1         BANK 地址线
DQ0~15            数据线
LDQM,UDQM   数据掩码,表示 DQ 的有效部分

W9825G6KH 同 STM32F429 的连接关系:


A[0:12]接 FMC_A[0:12]
BA[0:1]接 FMC_BA[0:1]
D[0:15]接 FMC_D[0:15]
CKE    接 FMC_SDCKE0
CLK     接 FMC_SDCLK
UDQM 接 FMC_NBL1
LDQM 接 FMC_NBL0
WE      接 FMC_SDNWE
CAS    接 FMC_SDNCAS
RAS    接 FMC_SDNRAS
CS      接 FMC_SDNE0

1.STM32CubeMX 的配置

HAL库记录-SDRAM的使用_第2张图片

 注意:正点原子 HAL库开发指南  Byte-enable 选择了disable,这个是不对,他自己写的驱动里有初始化PE0,PE1 ,  Byte-enable 只有选择了16bit-byte enable ,生成的代码才会初始PE0,PE1

 2.添加代码

/* USER CODE BEGIN 0 */
//SDRAM配置参数
#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)

static SDRAM_HandleTypeDef * psdram = &hsdram1;
//=============================================================
 uint8_t SDRAM_SendCmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint8_t regval);
 void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram);


//SDRAM 序列初始化
int SDRAM_AutoInit(void)
{
    SDRAM_Initialization_Sequence(psdram);//发送SDRAM初始化序列

	//刷新频率计数器(以SDCLK频率计数),计算方法:
	//COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
    //我们使用的SDRAM刷新周期为64ms,SDCLK=180/2=90Mhz,行数为8192(2^13).
	//所以,COUNT=64*1000*90/8192-20=683
	HAL_SDRAM_ProgramRefreshRate(psdram,683);//设置刷新频率
	return 0;
}

//=============================================================
//发送SDRAM初始化序列
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
    uint32_t temp=0;
                                                                                          //SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM
 SDRAM_SendCmd                       (0,FMC_SDRAM_CMD_CLK_ENABLE,1,0);                   //时钟配置使能
 for(volatile uint32_t i=0;i<0xFFFFFF;i++){}                                               //最少延时200us
 SDRAM_SendCmd                       (0,FMC_SDRAM_CMD_PALL,1,0);                         //对所有存储区预充电
 SDRAM_SendCmd                       (0,FMC_SDRAM_CMD_AUTOREFRESH_MODE,8,0);             //设置自刷新次数
                                                                                          //配置模式寄存器,SDRAM的bit0~bit2为指定突发访问的长度,
                                                                                          //bit3为指定突发访问的类型,bit4~bit6为CAS值,bit7和bit8为运行模式
                                                                                          //bit9为指定的写突发模式,bit10和bit11位保留位
 temp                                 =(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |  //设置突发长度:1(可以是1/2/4/8)
                                                 SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |  //设置突发类型:连续(可以是连续/交错)
                                                 SDRAM_MODEREG_CAS_LATENCY_3           |  //设置CAS值:3(可以是2/3)
                                                 SDRAM_MODEREG_OPERATING_MODE_STANDARD |  //设置操作模式:0,标准模式
                                       SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;              //设置突发写模式:1,单点访问
 SDRAM_SendCmd                       (0,FMC_SDRAM_CMD_LOAD_MODE,1,temp);                 //设置SDRAM的模式寄存器
}
/**
 * @brief :函数作用 : SDRAM配置
 * @note  :附加说明 :
 * @param :函数入口 : bankx: 0(向BANK5上面的SDRAM发送指令) 1(向BANK6上面的SDRAM发送指令)
 *                    cmd :指令(0,正常模式/1,时钟配置使能/2,预充电所有存储区/3,自动刷新/4,加载模式寄存器/5,自刷新/6,掉电)
 *                    refresh:自刷新次数
 *                    regval :模式寄存器的定义
 * @retval:函数返回 : 0,正常;1,失败.
 */
 uint8_t SDRAM_SendCmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint8_t regval)
 {
    uint32_t target_bank=0;
    FMC_SDRAM_CommandTypeDef Command;

    if  (bankx==0) target_bank          = FMC_SDRAM_CMD_TARGET_BANK1;
    else if(bankx==1) target_bank       = FMC_SDRAM_CMD_TARGET_BANK2;
         Command.CommandMode            = cmd;                         //命令
         Command.CommandTarget          = target_bank;                 //目标SDRAM存储区域
         Command.AutoRefreshNumber      = refresh;                     //自刷新次数
         Command.ModeRegisterDefinition = regval;                      //要写入模式寄存器的值
    if(HAL_SDRAM_SendCommand(psdram,&Command,0X1000)==HAL_OK) //向SDRAM发送命令
    {
        return 0;
    }
    else{
		//COM_Printf("SDRAM_SendCmd Err = %d\r\n",cmd);
		return 1;
	}
 }
/* USER CODE END 0 */

初始化完FMC后, 调用这个函数初始化SDRAM
int SDRAM_AutoInit(void); //SDRAM 序列初始化

3.测试代码

//uint16_t testsram[250000] __attribute__((at(0XC0000000)));//测试用数组  编译器V5 版本
uint16_t testsram[250000] __attribute__((section(".ARM.__at_0xC0000000")));  //编译器V6版本

//SDRAM内存测试
void fsmc_sdram_test(void)
{
	static volatile uint32_t i   =0;
	static volatile uint32_t temp=0;
	static volatile uint32_t sval=0;	//在地址0读到的数据
	i   =0;
	temp=0;	
	sval=0;	
  	COM_Printf("Ex Memory Test:    0KB \r\n");
	//每隔16K字节,写入一个数据,总共写入2048个数据,刚好是32M字节
	for(i=0;i<32*1024*1024;i+=16*1024)
	{
		*(volatile uint32_t*)(Bank5_SDRAM_ADDR+i)=temp;
		temp++;
	}
	
	//依次读出之前写入的数据,进行校验
 	for(i=0;i<32*1024*1024;i+=16*1024)
	{
  		temp=*(volatile uint32_t*)(Bank5_SDRAM_ADDR+i);
		if(i==0)sval=temp;
 		else if(temp<=sval)break;//后面读出的数据一定要比第一次读到的数据大.
		COM_Printf("SDRAM Capacity:%dKB\r\n",(uint16_t)(temp-sval+1)*16);//打印SDRAM容量			
 	}
}

你可能感兴趣的:(HAL库,单片机,stm32,嵌入式硬件)