1 前言
第五次记录一下使用CubeMX配置SDRAM的过程。STM32F429IGT6有两个SDRAM Bank,地址分别从0xC0000000, 0xD0000000开始,对应CubeMX配置里的SDRAM1和SDRAM2。每一个SDRAM控制器只可以连接一块SDRAM芯片。
注意:本文以前文为基础。默认配置好了FREERTOS,printf重定向
2 硬件
w9825G6KH-6I(32M字节16位宽)
3 Cubemx配置
3.1 SDRAM 2 的配置
芯片使能的选择需要看硬件上接的引脚。
其余参数参考芯片手册
4 工程内的修改
注意:到此为止,只是初始化好了单片机对RAM的接口,这块RAM需要发送一些初始化指令才可以正常工作,所以我们需要移植SDRAM的初始化文件,再进行测试。
以下代码仅供参考
4.1 移植文件
#include "sdram.h"
#include "stdio.h"
#include "fmc.h"
FMC_SDRAM_CommandTypeDef command; // 控制指令
/*************************0*****************************************************************************
* 函 数 名: SDRAM_delay
* 入口参数: 无
* 返 回 值: 无
* 函数功能: 简易延时函数,单位约为5ms
* 说 明: 无
*******************************************************************************************************/
void SDRAM_delay(__IO uint32_t nCount)
{
__IO uint32_t index = 0;
for(index = (100000 * nCount); index != 0; index--);
}
/******************************************************************************************************
* 函 数 名: SDRAM_Initialization_Sequence
* 入口参数: hsdram - SDRAM_HandleTypeDef定义的变量,即表示定义的sdram
* Command - 控制指令
* 返 回 值: 无
* 函数功能: SDRAM 参数配置
* 说 明: 配置SDRAM相关时序和控制方式
*******************************************************************************************************/
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command)
{
__IO uint32_t tmpmrd = 0;
/* Configure a clock configuration enable command */
Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; // 开启SDRAM时钟
Command->CommandTarget = FMC_COMMAND_TARGET_BANK; // 选择要控制的区域
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT); // 发送控制指令
SDRAM_delay(1); // 延时等待
/* Configure a PALL (precharge all) command */
Command->CommandMode = FMC_SDRAM_CMD_PALL; // 预充电命令
Command->CommandTarget = FMC_COMMAND_TARGET_BANK; // 选择要控制的区域
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT); // 发送控制指令
/* Configure a Auto-Refresh command */
Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; // 使用自动刷新
Command->CommandTarget = FMC_COMMAND_TARGET_BANK; // 选择要控制的区域
Command->AutoRefreshNumber = 8; // 自动刷新次数
Command->ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT); // 发送控制指令
/* Program the external memory mode register */
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |
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_COMMAND_TARGET_BANK; // 选择要控制的区域
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = tmpmrd;
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT); // 发送控制指令
hsdram->Instance->SDRTR |= ((uint32_t)((1386)<< 1)); // 设置刷新计数器
}
/******************************************************************************************************
* 函 数 名: MX_FMC_Init
* 入口参数: 无
* 返 回 值: 无
* 函数功能: SDRAM初始化
* 说 明: 初始化FMC和SDRAM配置
*******************************************************************************************************/
void SDRAM_Cmd_Init(void)
{
SDRAM_Initialization_Sequence(&hsdram2,&command);
}
uint8_t SDRAM_Test(void)
{
uint32_t i = 0; // 计数变量
uint16_t ReadData = 0; // 读取到的数据
uint8_t ReadData_8b;
printf("STM32F429 SDRAM test\r\n");
printf("test start, 16bits dat write in...\r\n");
for (i = 0; i < SDRAM_Size/2; i++)
{
*(__IO uint16_t*) (SDRAM_BANK_ADDR + 2*i) = (uint16_t)i; // 写入数据
}
printf("write done. read and compare...\r\n");
for(i = 0; i < SDRAM_Size/2;i++ )
{
ReadData = *(__IO uint16_t*)(SDRAM_BANK_ADDR + 2 * i ); // 从SDRAM读出数据
if( ReadData != (uint16_t)i ) //检测数据,若不相等,跳出函数,返回检测失败结果。
{
printf("16bit SDRAM test fail\r\n");
return ERROR; // 返回失败标志
}
}
printf("16bit test pass, 8 bit test start\r\n");
for (i = 0; i < 255; i++)
{
*(__IO uint8_t*) (SDRAM_BANK_ADDR + i) = (uint8_t)i;
}
printf("write done. read and compare....\r\n");
for (i = 0; i < 255; i++)
{
ReadData_8b = *(__IO uint8_t*) (SDRAM_BANK_ADDR + i);
if( ReadData_8b != (uint8_t)i ) //检测数据,若不相等,跳出函数,返回检测失败结果。
{
printf("8bit SDRAM test fail\r\n");
printf("check NBL0 NBL1\r\n");
return ERROR; // 返回失败标志
}
}
printf("16bit test pass\r\n");
printf("SDRAM test pass\r\n");
return SUCCESS; // 返回成功标志
}
#ifndef __SDRAM_H
#define __SDRAM_H
#include "main.h"
#define SDRAM_Size 0x02000000 //32M字节
#define SDRAM_BANK_ADDR ((uint32_t)0xD0000000) // FMC SDRAM 数据基地址
#define FMC_COMMAND_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK2 // SDRAM 的bank选择
#define SDRAM_TIMEOUT ((uint32_t)0x1000) // 超时判断时间
#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)
/*--------------------------------------- 函数声明 -------------------------------------*/
uint8_t SDRAM_Test(void); // SDRAM测试函数
void SDRAM_Cmd_Init(void);
#endif
4.2 测试
主函数里调用 SDRAM_Cmd_Init(),SDRAM_Test();
注意,如果初始化指令出问题,或者忘记初始化直接测试的话,会出现以下状况
不需要改动BOOT引脚重新烧录,修改下载方式为under reset,然后按着复位键,点击keil下载键,复位立即松开即可。
有问题请留言,需要源码请评论区下方留邮箱
.
.
.
——END