欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32f746gdiscovery SDRAM 驱动

程序员文章站 2024-02-25 10:36:52
...

STM32f746gdiscovery 开发板使用的是16MB的SDRAM,由于少了一根地址线,只有8MB可用。

STM32f746gdiscovery SDRAM 驱动

 

/*************************************************************************************************************
 * 文件名		:	stm32f7_sdram.c
 * 功能			:	STM32F7 外部SDRAM驱动
 * 作者			:	aaa@qq.com
 * 创建时间		:	2019-09-08
 * 最后修改时间	:	2019-09-08
 * 详细			:	2019-10-31 设置突发长度:4(可以是1/2/4/8)-测试过1/2/4发现都正常,唯独8的时候,屏幕会出现随机噪点
*************************************************************************************************************/	
#include "stm32f7_sdram.h"
#include "SYSTEM.H" 



//BANK选择
typedef enum
{
	SDRAM_CMD_BANK1 = 2,	//命令模板存储区域1
	SDRAM_CMD_BANK2 = 1,	//命令模板存储区域2
	SDRAM_CMD_BANK1_2 = 3,	//命令模板存储区域1与2
}SDRAM_CMD_BANK_SELECT;


//命令
typedef enum 
{
	SDRAM_CMD_NORMAL 		= 0,	//正常模式
	SDRAM_CMD_CLOCK_CONFIG 	= 1,	//时钟配置使能
	SDRAM_CMD_PALL 			= 2,	//预充电所有存储区域
	SDRAM_CMD_AR 			= 3,	//自刷新命令
	SDRAM_CMD_LOAD_MODE 	= 4,	//加载模式寄存器
	//SDRAM_CMD_AR = 5,	//自刷新命令
	SDRAM_CMD_POWER_DOWN 	= 6,	//掉电命令
}SDRAM_CMD_TYPE;


bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mode, u8 AutoRefresh, SDRAM_CMD_TYPE cmd);//SDRAM 命令模式设置


/*************************************************************************************************************************
* 函数	:			void SDRAM_Init(void)
* 功能	:			SDRAM 接口初始化
* 参数	:			无
* 返回	:			无
* 依赖	:			底层宏定义
* 作者	:			aaa@qq.com
* 时间	:			2019-09-08
* 最后修改时间 : 	2019-09-08
* 说明	: 			用于初始化STM32F7 SDRAM 接口
*************************************************************************************************************************/  
void SDRAM_Init(void)
{
	u32 temp;
	
	SYS_DeviceClockEnable(DEV_FSMC, TRUE);	//FSMC时钟使能
	SYS_DeviceClockEnable(DEV_GPIOC, TRUE);	//使能GPIOC时钟
	SYS_DeviceClockEnable(DEV_GPIOD, TRUE);	//使能GPIOD时钟
	SYS_DeviceClockEnable(DEV_GPIOE, TRUE);	//使能GPIOE时钟
	SYS_DeviceClockEnable(DEV_GPIOF, TRUE);	//使能GPIOF时钟
	SYS_DeviceClockEnable(DEV_GPIOG, TRUE);	//使能GPIOG时钟
	SYS_DeviceClockEnable(DEV_GPIOH, TRUE);	//使能GPIOH时钟
	
	//初始化IO
	SYS_GPIOx_Init(GPIOC, BIT3, AF_PP_OPU, SPEED_100M);													//PC3			
	SYS_GPIOx_Init(GPIOD, BIT0|BIT1|BIT8|BIT9|BIT10|BIT14|BIT15, AF_PP_OPU, SPEED_100M);							//PD0/1/8/9/10/14/15		
	SYS_GPIOx_Init(GPIOE, BIT0|BIT1|(0X1FF<<7), AF_PP_OPU, SPEED_100M);												//PE0/1/7~15	
	SYS_GPIOx_Init(GPIOF, BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT11|BIT12|BIT13|BIT14|BIT15, AF_PP_OPU, SPEED_100M);		//PF0~5/11~15					
	SYS_GPIOx_Init(GPIOG, BIT0|BIT1|BIT4|BIT5|BIT8|BIT15, AF_PP_OPU, SPEED_100M);								//PG0/1/4/5/8/15
	SYS_GPIOx_Init(GPIOH, BIT3|BIT5, AF_PP_OPU, SPEED_100M);
	
 	SYS_GPIOx_SetAF(GPIOC, 3, AF12_FSMC);	//PC3,AF12
	
 	SYS_GPIOx_SetAF(GPIOD, 0, AF12_FSMC);	//PD0,AF12 
 	SYS_GPIOx_SetAF(GPIOD, 1, AF12_FSMC);	//PD1,AF12 
 	SYS_GPIOx_SetAF(GPIOD, 8, AF12_FSMC);	//PD8,AF12
 	SYS_GPIOx_SetAF(GPIOD, 9, AF12_FSMC);	//PD9,AF12
 	SYS_GPIOx_SetAF(GPIOD, 10, AF12_FSMC);	//PD10,AF12  
 	SYS_GPIOx_SetAF(GPIOD, 14, AF12_FSMC);	//PD14,AF12
 	SYS_GPIOx_SetAF(GPIOD, 15, AF12_FSMC);	//PD15,AF12
	
 	SYS_GPIOx_SetAF(GPIOE, 0, AF12_FSMC);	//PE0,AF12 
 	SYS_GPIOx_SetAF(GPIOE, 1, AF12_FSMC);	//PE1,AF12 
 	SYS_GPIOx_SetAF(GPIOE, 7, AF12_FSMC);	//PE7,AF12
 	SYS_GPIOx_SetAF(GPIOE, 8, AF12_FSMC);	//PE8,AF12
 	SYS_GPIOx_SetAF(GPIOE, 9, AF12_FSMC);	//PE9,AF12
 	SYS_GPIOx_SetAF(GPIOE, 10, AF12_FSMC);	//PE10,AF12
 	SYS_GPIOx_SetAF(GPIOE, 11, AF12_FSMC);	//PE11,AF12
 	SYS_GPIOx_SetAF(GPIOE, 12, AF12_FSMC);	//PE12,AF12
 	SYS_GPIOx_SetAF(GPIOE, 13, AF12_FSMC);	//PE13,AF12
 	SYS_GPIOx_SetAF(GPIOE, 14, AF12_FSMC);	//PE14,AF12
 	SYS_GPIOx_SetAF(GPIOE, 15, AF12_FSMC);	//PE15,AF12

 	SYS_GPIOx_SetAF(GPIOF, 0, AF12_FSMC);	//PF0,AF12 
 	SYS_GPIOx_SetAF(GPIOF, 1, AF12_FSMC);	//PF1,AF12 
 	SYS_GPIOx_SetAF(GPIOF, 2, AF12_FSMC);	//PF2,AF12
 	SYS_GPIOx_SetAF(GPIOF, 3, AF12_FSMC);	//PF3,AF12
 	SYS_GPIOx_SetAF(GPIOF, 4, AF12_FSMC);	//PF4,AF12
 	SYS_GPIOx_SetAF(GPIOF, 5, AF12_FSMC);	//PF5,AF12
 	SYS_GPIOx_SetAF(GPIOF, 11, AF12_FSMC);	//PF11,AF12
 	SYS_GPIOx_SetAF(GPIOF, 12, AF12_FSMC);	//PF12,AF12
 	SYS_GPIOx_SetAF(GPIOF, 13, AF12_FSMC);	//PF13,AF12
 	SYS_GPIOx_SetAF(GPIOF, 14, AF12_FSMC);	//PF14,AF12
 	SYS_GPIOx_SetAF(GPIOF, 15, AF12_FSMC);	//PF15,AF12
	
 	SYS_GPIOx_SetAF(GPIOG, 0, AF12_FSMC);	//PG0,AF12 
 	SYS_GPIOx_SetAF(GPIOG, 1, AF12_FSMC);	//PG1,AF12 
 	SYS_GPIOx_SetAF(GPIOG, 4, AF12_FSMC);	//PG4,AF12
 	SYS_GPIOx_SetAF(GPIOG, 5, AF12_FSMC);	//PG5,AF12  
 	SYS_GPIOx_SetAF(GPIOG, 8, AF12_FSMC);	//PG8,AF12
 	SYS_GPIOx_SetAF(GPIOG, 15, AF12_FSMC);	//PG15,AF12
	
	SYS_GPIOx_SetAF(GPIOH, 3, AF12_FSMC);	//PH3,AF12
 	SYS_GPIOx_SetAF(GPIOH, 5, AF12_FSMC);	//PH5,AF12  
	

	temp = 0;
	temp |= 0<<0;					//8位列地址
	temp |= 1<<2;					//12位行地址
	temp |= 1<<4;					//16位数据位宽
	temp |= 1<<6;					//4个内部存区(4 BANKS)
	temp |= 2<<7;					//2个CAS延迟
	temp |= 0<<9;					//允许写访问
	temp |= 2<<10;					//SDRAM时钟=HCLK/2
	temp |= 1<<12;					//使能突发访问 
	temp |= 0<<13;					//读通道延迟0个HCLK
 	FMC_Bank5_6->SDCR[0] = temp;	//设置FMC BANK5 SDRAM控制寄存器(BANK5和6用于管理SDRAM).

	temp = 0;
	temp|=1<<0;						//加载模式寄存器到**时间的延迟为2个时钟周期
	temp|=5<<4;						//退出自刷新延迟为6个时钟周期
	temp|=3<<8;						//自刷新时间为4个时钟周期
	temp|=5<<12;					//行循环延迟为6个时钟周期
	temp|=1<<16;					//恢复延迟为2个时钟周期
	temp|=1<<20;					//行预充电延迟为2个时钟周期
	temp|=1<<24;					//行到列延迟为2个时钟周期
 	FMC_Bank5_6->SDTR[0] = temp;	//设置FMC BANK5 SDRAM时序寄存器 

	SDRAM_SendCmd(SDRAM_CMD_BANK1, 0, 1, SDRAM_CMD_CLOCK_CONFIG);	//时钟配置使能	
	Delay_US(300);					//至少延迟200us.
	SDRAM_SendCmd(SDRAM_CMD_BANK1,0, 1, SDRAM_CMD_PALL);			//对所有存储区预充电
	SDRAM_SendCmd(SDRAM_CMD_BANK1,0, 8, SDRAM_CMD_AR);				//设置自刷新次数 
	
	temp = 0;
	temp |= 2<<0;					//设置突发长度:4(可以是1/2/4/8)	-测试过1/2/4发现都正常,唯独8的时候,屏幕会出现随机噪点
	temp |= 0<<3;					//设置突发类型:连续(可以是连续/交错)
	temp |= 2<<4;					//设置CAS值:2
	temp |= 0<<7;					//设置操作模式:0,标准模式
	temp |= 1<<9;					//设置突发写模式:1,单点访问
	SDRAM_SendCmd(SDRAM_CMD_BANK1,temp, 1, SDRAM_CMD_LOAD_MODE);				//设置SDRAM模式
	
	//COUNT=SDRAM刷新周期/行数-20
	//SDRAM刷新周期为64ms,SDCLK=AHB/2=100Mhz,行数为4096.
	//计算方法为64*1000*AHB/2/4096-20
	temp = 64*1000*(SYS_GetAHBClockSpeed()/1000000/2)/4096-20;
	FMC_Bank5_6->SDRTR = temp<<1;		//设置刷新频率计数器 
}


/*************************************************************************************************************************
* 函数	:			bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mdr, u8 AutoRefresh, SDRAM_CMD_TYPE mode)
* 功能	:			SDRAM 命令模式设置
* 参数	:			BankSelect:bank选择;mdr:模式;AutoRefresh:自刷新设置;mode:模式命令
* 返回	:			TRUE:成功;FALSE:失败
* 依赖	:			底层宏定义
* 作者	:			aaa@qq.com
* 时间	:			2019-09-08
* 最后修改时间 : 	2019-09-08
* 说明	: 			
*************************************************************************************************************************/  
bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mdr, u8 AutoRefresh, SDRAM_CMD_TYPE mode)
{
	u32 retry=0;
	u32 temp = 0; 
	
	temp |= mode<<0;					//设置指令
	temp |= BankSelect<<3;				//设置发送指令到bank5还是6
	temp |= (AutoRefresh&0xf)<<5;		//设置自刷新次数
	temp |= mdr<<9;						//设置模式寄存器的值
	FMC_Bank5_6->SDCMR = temp;			//配置寄存器
	
	//temp = FMC_Bank5_6->SDCMR;
	//uart_printf("FMC_Bank5_6->SDCMR=%X\r\n", temp);
	while((FMC_Bank5_6->SDSR&(1<<5)))	//等待指令发送完成 
	{
		retry++;
		Delay_US(1);
		if(retry > 50000)return FALSE; 
	}
	
	
	return TRUE;
}

	
/*************************************************************************************************************
 * 文件名		:	stm32f7_sdram.h
 * 功能			:	STM32F7 外部SDRAM驱动
 * 作者			:	aaa@qq.com
 * 创建时间		:	2019-09-08
 * 最后修改时间	:	2019-09-08
 * 详细:	
*************************************************************************************************************/		
#ifndef __STM32F7_SDRAM_H_
#define	__STM32F7_SDRAM_H_	   
#include "system.h"


//========================================================================
// SRAM硬件相关配置
//------------------------------------------------------------------------
#define 	Bank5_SDRAM_ADDR    ((u32)0XC0000000)
	
void SDRAM_Init(void);	//SDRAM初始化


#endif //__STM32F7_SDRAM_H_