STM32H723 驱动SDRAM芯片 W9825G6KH,CubeMX
摘要:本文记录了STM32H723替换F429时遇到的HardFault问题及解决方案。主要差异包括主频提升、MPU/cache引入和多电源域设计。问题出现在SDRAM初始化阶段,通过调整时钟配置(480MHz主频下FMC工作于120MHz)、FMC-GPIO设置、SDRAM参数配置(适配W9825G6KH芯片)以及关键MPU配置(解除SDRAM地址保护)得以解决。文中引用CSDN相关教程,特别强
前言
之前我开发的设备使用主控芯片是STM32F429,查询资料STM32H723系列和F429是完全pin-to-pin。故使用原主控板焊接H723测试下效果。
在我看来STM32H723和之前F429系列最大的不同有以下方面:
- 主频和内部RAM增强扩容;
- 引入了MPU和cache;
- 电源域复杂,H7引入了(D1/D2/D3),更有利于低功耗处理;
- 整体上接近SOC芯片了
目前网上看到的关于STM32H723的资料较少,自己在调试过程中遇到了HardFault问题.当代码语句运行到MX_FMC_Init()时触发。先将解决问题的过程记录如下,供其它开发的童鞋参考。
1. 时钟配置

2. FMC-GPIO配置
注意:在STM32H7、STM32F429系列的芯片其外设是FMC,而STM32F1\F407系列的芯片其外设是FSMC,两者的区别请参考以下文章:
【STM32】HAL库 STM32CubeMX教程十五---FMC-SDRAM(一)_fmc 自动刷新sdram-CSDN博客

3. FMC-SDRAM配置
特别说明:主控工作在480MHz时,FMC的工作频率是240MHz.

选择SDRAM1,SDRAM芯片W9825G6KH的最大工作频率是200MHz。
FMC驱动SDRAM使用了二分频,工作在120MHz,那么一个时钟周期是1/120M=8.33ns



这部分参考了以下的文章:
【STM32】HAL库 STM32CubeMX教程十五---FMC-SDRAM(一)_fmc 自动刷新sdram-CSDN博客
4. MPU配置 CORTEX-M7
Cortex-m7的默认配置是无法使用SDRAM的,因为SDRAM的地址有默认的MPU保护限制。
必须关闭这部分的mpu设置,否则会直接HardFault.
这部分参考了以下的文章:
STM32H743+CubeMX-梳理MPU的设置_background region privileged accesses only-CSDN博客
STM32H7XX的MPU和Cache总结_stm32h7 mpu-CSDN博客

5. 具体代码
#define SDRAM_Size (32*1024*1024) // 32M字节
#define SDRAM_BANK_ADDR ((uint32_t)0xC0000000) // FMC SDRAM 数据基地址
#define FMC_COMMAND_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK1 // 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)
FMC_SDRAM_CommandTypeDef command;// 控制指令
/******************************************************************************************************
* 函 数 名: 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); // 发送控制指令
HAL_Delay(1); // 延时等待,至少200us
/* 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; // 自动刷新次数,发送 至少 2 个(通常是 8 个)Auto-Refresh 命令
Command->ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT); // 发送控制指令
/* Program the external memory mode register */
//配置模式寄存器,SDRAM的bit0-bit2为指定突发访问的长度
//bit3为指定突发访问的类型,bit4-bit6为CAS值,bit7和bit8为运行模式
//bit9为指定的写突发模式,bit10和bit11位保留位
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |//设置突发长度:2(可以是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,单点访问
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); // 发送控制指令
//刷新频率计数器(以SDCLK频率计数),计算方法:
//COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
//我们使用的SDRAM刷新周期为64ms,行数为8192(2^13).SDCLK=240/2=120Mhz,8.33ns;
//所以,COUNT=(64*1000/8192)us*120-20=918(20为刷新等待冗余)
// Refresh_Count = (SDRAM_Refresh_Period_us × FMC_Clock_MHz) / Number_of_Rows - 20
HAL_SDRAM_ProgramRefreshRate(hsdram, 918); // 配置刷新率
}
6. 测试效果
void fsmc_sdram_test(void)
{
__IO uint32_t i=0;
__IO uint32_t temp=0;
__IO uint32_t sval=0;
for(i=0;i<32*1024*1024;i+=16*1024)
{
*(__IO uint32_t *)(SDRAM_BANK_ADDR+i)=temp;
temp++;
}
for(i=0;i<32*1024*1024;i+=16*1024)
{
temp=*(__IO uint32_t *)(SDRAM_BANK_ADDR+i);
if(i==0)
sval=temp;
else if(temp<=sval)
break;
printf("SDRAM Capacity:%dKB\r\n",(uint16_t )(temp-sval+1)*16);
}
}

7. 其它参考资料
参考手册:《rm0468-stm32h723733-stm32h725735-and-stm32h730-value-line-advanced-armbased-32bit-mcus-stmicroelectronics》
用户手册:《STM32H723ZGT6_规格书_ST(意法半导体)单片机(MCUMPUSOC)规格书》
《安富莱_STM32-V7开发板_用户手册,含BSP驱动包设计(V3.5)》
《C62246_同步动态随机存取内存(SDRAM)_W9825G6KH-6_规格书_WJ279889》
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)