文章的目的是快速使用SDRAM芯片,没有详细讲解原理。
1、环境:
单片机:STM32F429VIT6
CUBE版本:STM32CUBMX 6.12.1
编译:KEIL MDK
硬件:安富莱STM32-V6开发板
SDRAM芯片:MT48LC4M32B2TG
2、配置步骤
1、系统时钟,我的开发版外部8M晶振有问题了,所以用的是内部16M。主要AHB的时钟频率,因为SDRAM芯片要根据他来计算参数。
2、FMC配置
参数按上面配置,上面的参数具体是根据MT48LC4M32B2TG的规格书与AHB时钟频率计算所得,具体详情请搜索。
3、注意
注意:配置玩FMC的参数后,需要根据硬件实际连接情况,调整引脚配置,安富莱的硬件引脚与FMC的默认引脚有些许变动,需要调整。
引脚使用得比较多,要仔细检查
可以参考下面的使用情况,在cube上引脚重新选择一下即可。
c
/* GPIOD */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8| GPIO_PIN_9 | GPIO_PIN_10 |\
GPIO_PIN_14 | GPIO_PIN_15;
HAL_GPIO_Init(GPIOD, &GPIO_Init_Structure);
/* GPIOE */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7| GPIO_PIN_8 | GPIO_PIN_9 |\
GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\
GPIO_PIN_15;
HAL_GPIO_Init(GPIOE, &GPIO_Init_Structure);
/* GPIOF */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\
GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\
GPIO_PIN_15;
HAL_GPIO_Init(GPIOF, &GPIO_Init_Structure);
/* GPIOG */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 |
GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15;
HAL_GPIO_Init(GPIOG, &GPIO_Init_Structure);
/* GPIOH */
GPIO_Init_Structure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_9 |\
GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\
GPIO_PIN_15;
HAL_GPIO_Init(GPIOH, &GPIO_Init_Structure);
/* GPIOI */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\
GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOI, &GPIO_Init_Structure);
4、驱动编写及使用
1、头文件
上面的配置完成后,可以生成工程文件,然后就开始编写SDRAM的驱动程序。
c
/***
* SDRAM型号MT48LC4M32B2TG-7, 32位带宽, 容量16MB, 7ns速度(143MHz)。
* 外部SDRAM使用方法
* 绝对定位方式访问 SDRAM,这种方式必须定义成全局变量
1.直接定义变量,分配到外部EXT_SDRAM_ADDR
uint8_t testValue __attribute__((at(EXT_SDRAM_ADDR)));
2.函数直接操作引用
testValue = 0xaa;
**/
#ifndef _SDRAM_FMC_DRV_H_
#define _SDRAM_FMC_DRV_H_
#include "fmc.h"
#define EXT_SDRAM_ADDR ((uint32_t)0xC0000000)
#define EXT_SDRAM_SIZE (16 * 1024 * 1024)
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command);
#endif /* _SDRAM_FMC_DRV_H_ */
//
2、C文件
c
#include "bsp_sdram.h"
/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_8 */
/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 */
//#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_32
//#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2
/* #define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_3 */
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
#define REFRESH_COUNT ((uint32_t)1293) /* SDRAM自刷新计数 */
/* 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)
/*
*********************************************************************************************************
* 函 数 名: SDRAM初始化序列
* 功能说明: 完成SDRAM序列初始化
* 形 参: hsdram: SDRAM句柄
* Command: 命令结构体指针
* 返 回 值: None
*********************************************************************************************************
*/
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command)
{
__IO uint32_t tmpmrd =0;
/*##-1- 时钟使能命令 ##################################################*/
Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* 发送命令 */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/*##-2- 插入延迟,至少100us ##################################################*/
HAL_Delay(1);
/*##-3- 整个SDRAM预充电命令,PALL(precharge all) #############################*/
Command->CommandMode = FMC_SDRAM_CMD_PALL;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* 发送命令 */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/*##-4- 自动刷新命令 #######################################################*/
Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 8;
Command->ModeRegisterDefinition = 0;
/* 发送命令 */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/*##-5- 配置SDRAM模式寄存器 ###############################################*/
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
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;
/* 发送命令 */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/*##-6- 设置自刷新率 ####################################################*/
/*
SDRAM refresh period / Number of rows)*SDRAM时钟速度 -- 20
= 64ms / 4096 *84MHz - 20
= 1292.5 取值1293
*/
HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
}
3、初始化
添加上面的文件到工程目录,打开"fmc.c"文件,找到"void MX_FMC_Init(void)"函数,按如下操作添加内容:
4、编译即可
debug查看内容。注意:SDRAM按如上配置的话,映射的起始地址为:0XC0000000。可以修改、使用了。
- 外部SDRAM使用方法
- 绝对定位方式访问 SDRAM,这种方式必须定义成全局变量
1.直接定义变量,分配到外部EXT_SDRAM_ADDR
uint8_t testValue attribute ((at(EXT_SDRAM_ADDR)));
2.函数直接操作引用
testValue = 0xaa;