找回密码
 立即注册
首页 业界区 业界 【STM32H743IIT6 系列】将外部SDRAM作为内部RAM使用的超 ...

【STM32H743IIT6 系列】将外部SDRAM作为内部RAM使用的超简单方法

撷监芝 5 天前
前言

因为最近要配置 RGB LCD(LTDC) 屏幕要用到 SDRAM,虽然之前也写过一篇这个文章,不过当时太忙,写的也比较潦草,某些细节可能没有写清楚,现在会在这篇文章一一道来,后面也会有一篇 LTDC 配置的文章。
STM32CubeMX 配置

MPU(内存保护单元配置)

跟下面的图片一个个配置就好啦。
1.png

2.png

3.png

4.png

FMC 配置

FMC 基本配置

这里也是跟着下面的图片配置,不过要特别注意的是 SDRAM 的引脚有很多,要对应好板子上的引脚不要搞错!否则可能会发生某些问题,如:放在 SDRAM 里面的变量初始化不了、进入硬件故障中断等等。
5.png

FMC 时钟配置

我使用的 SDRAM 型号为 "W9825G6KH-6I",其最高时钟频率为166MHz,所以我们这里通过锁相环给到 FMC 的时钟为240MHz 即可,分频后就是120MHz。
6.png

程序部分

分散式内存管理

想要将 SDRAM 作为内部 RAM 使用,就要将变量主动分配到这一块内存中,但是应该如何将变量精准分配呢?那么可以看一下这一篇文章,使用分散式管理内存的方式,可以更加方便的管理内存空间:
【STM32H743IIT6 系列】理清 xxRAM、xxROM、xxFlash 的核心作用,附 H7 系列五种内存详解,以及超便捷的内存区域管理方法
startup_stm32h743xx.s 启动文件修改

首先我们要知道,全局变量的定义和初始化是先于 main() 函数的,但是在 main() 函数之前,FMC 所连接的的 SDRAM又没有初始化,所以当你直接用分散式管理内存的方法使用 SDRAM 的时候,必会在没有进入 main() 函数之前就会跳到硬故障中断函数。
由于一定要使用分散式管理内存的方法,那么我们就想到可以在 startup_stm32h743xx.s 启动文件上面动手脚。(其实不将 SDRAM 作为内部 RAM 使用的话可以不用那么操作,直接配置好就可以
点击查看代码
  1. Reset_Handler    PROC
  2.                  EXPORT  Reset_Handler                    [WEAK]
  3.         IMPORT  ExitRun0Mode
  4.         IMPORT  SystemInit
  5.         IMPORT  __main
  6.                 IMPORT        SystemInit_ExtMemCtl
  7.                  LDR     R0, =ExitRun0Mode
  8.                  BLX     R0
  9.                  LDR     R0, =SystemInit
  10.                  BLX     R0
  11.                                  LDR     R0, =SystemInit_ExtMemCtl
  12.                  BLX     R0
  13.                  LDR     R0, =__main
  14.                  BX      R0
  15.                  ENDP
复制代码
7.png

在你的启动文件中这个位置加上红色框框中的代码,即可,虽然现在还没有定义,但是后面就会说到了。(假如你的程序没有:ExitRun0Mode,可能因为你的软件是旧版本的)。
提前初始化 FMC SDRAM

SDRAM 写寄存器函数

SDRAM 通过内部寄存器来配置,所以我们要写入其寄存器控制其功能,这是必不可少的。
在 fmc.c 文件加上第一个程序,如下所示:
点击查看代码
  1. FMC_SDRAM_CommandTypeDef command;// 控制指令
  2. /******************************************************************************************************
  3. *        函 数 名: SDRAM_Initialization_Sequence
  4. *        入口参数: hsdram - SDRAM_HandleTypeDef定义的变量,即表示定义的sdram
  5. *                                 Command        - 控制指令
  6. *        返 回 值: 无
  7. *        函数功能: SDRAM 参数配置
  8. *        说    明: 配置SDRAM相关时序和控制方式
  9. *******************************************************************************************************/
  10. void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command)
  11. {
  12.         __IO uint32_t tmpmrd = 0;
  13.    register __IO uint32_t index;
  14.         /* Configure a clock configuration enable command 时钟配置使能*/
  15.         Command->CommandMode                                 = FMC_SDRAM_CMD_CLK_ENABLE;        // 开启SDRAM时钟
  16.         Command->CommandTarget                                 = FMC_COMMAND_TARGET_BANK;         // 选择要控制的区域
  17.         Command->AutoRefreshNumber                     = 1;
  18.         Command->ModeRegisterDefinition         = 0;
  19.         HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);        // 发送控制指令
  20.           /* Delay */
  21.   for (index = 0; index<10000; index++);
  22.         /* Configure a PALL (precharge all) command 对所有存储区域预充电*/
  23.         Command->CommandMode                                 = FMC_SDRAM_CMD_PALL;                // 预充电命令
  24.         Command->CommandTarget                                 = FMC_COMMAND_TARGET_BANK;        // 选择要控制的区域
  25.         Command->AutoRefreshNumber                     = 1;
  26.         Command->ModeRegisterDefinition         = 0;
  27.         HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);  // 发送控制指令
  28.         /* Configure a Auto-Refresh command 设置自动刷新次数*/
  29.         Command->CommandMode                                 = FMC_SDRAM_CMD_AUTOREFRESH_MODE;        // 使用自动刷新
  30.         Command->CommandTarget                                 = FMC_COMMAND_TARGET_BANK;          // 选择要控制的区域
  31.         Command->AutoRefreshNumber                        = 8;                                // 自动刷新次数
  32.         Command->ModeRegisterDefinition         = 0;
  33.         HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);        // 发送控制指令
  34.         /* Program the external memory mode register */
  35.     //配置模式寄存器,SDRAM的bit0-bit2为指定突发访问的长度
  36.     //bit3为指定突发访问的类型,bit4-bit6为CAS值,bit7和bit8为运行模式
  37.     //bit9为指定的写突发模式,bit10和bit11位保留位
  38.         tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2               |//设置突发长度:2(可以是1/2/4/8)
  39.                                                         SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |//设置突发类型:连续(可以是连续/交错)
  40.                                                         SDRAM_MODEREG_CAS_LATENCY_3           |//设置CAS值:3(可以是2/3)
  41.                                                         SDRAM_MODEREG_OPERATING_MODE_STANDARD |//设置操作模式:0,标准模式
  42.                                                         SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;  //设置突发写模式:1,单点访问
  43.         Command->CommandMode            = FMC_SDRAM_CMD_LOAD_MODE;        // 加载模式寄存器命令
  44.         Command->CommandTarget          = FMC_COMMAND_TARGET_BANK;        // 选择要控制的区域
  45.         Command->AutoRefreshNumber                 = 1;
  46.         Command->ModeRegisterDefinition = tmpmrd;
  47.         HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);        // 发送控制指令
  48.    
  49.         //刷新频率计数器(以SDCLK频率计数),计算方法:
  50.         //COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
  51.     //我们使用的SDRAM刷新周期为64ms,SDCLK=240/2=120Mhz,行数为8192(2^13).
  52.         //所以,COUNT=64*1000*120/8192-20=918(20为刷新等待冗余)
  53.         HAL_SDRAM_ProgramRefreshRate(hsdram, 918);  // 配置刷新率
  54. }
复制代码
然后再对应在 fmc.h 加上对应的宏定义:(注意这里已经提前包含了后面还没加上的程序的全局声明)
点击查看代码
  1. #define SDRAM_Size 32*1024*1024                                 //32M字节
  2. #define SDRAM_BANK_ADDR     ((uint32_t)0xC0000000)                                 // FMC SDRAM 数据基地址
  3. #define FMC_COMMAND_TARGET_BANK   FMC_SDRAM_CMD_TARGET_BANK1        // SDRAM 的bank选择
  4. #define SDRAM_TIMEOUT     ((uint32_t)0x1000)                                         // 超时判断时间
  5. #define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
  6. #define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
  7. #define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
  8. #define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
  9. #define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
  10. #define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
  11. #define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
  12. #define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
  13. #define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
  14. #define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
  15. #define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)
  16. extern FMC_SDRAM_CommandTypeDef command;// 控制指令
  17. extern void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command);
  18. extern void SystemInit_ExtMemCtl(void);
  19. extern void fsmc_sdram_test(void);
复制代码
集成初始化函数

这里的初始化函数 SystemInit_ExtMemCtl() 就是添加在启动文件中、_main函数前的函数,就是用于提前初始化FMC,可以先看一下程序,后面会进行解读:
点击查看代码
  1. ///******************************************************************************************************
  2. //*        函 数 名: SystemInit_ExtMemCtl
  3. //*        入口参数: 无
  4. //*        返 回 值: 无
  5. //*        函数功能: 初始化外部 SDRAM 控制器
  6. //*        说    明: 此函数用于初始化 FMC 外设,配置 GPIO 引脚,并对 SDRAM 进行初始化和参数配置。
  7. //*             仅在定义了 DATA_IN_ExtSDRAM 时执行相关操作。
  8. //* 作用:                在进入main函数之前就对FMC进行初始化(很重要!!!!!)
  9. //*******************************************************************************************************/
  10. void SystemInit_ExtMemCtl(void)
  11. {
  12.         #if defined (DATA_IN_ExtSDRAM)
  13.        
  14.         //--------------------------------------------------------------------
  15.         // 变量定义
  16.         //--------------------------------------------------------------------
  17.         FMC_SDRAM_TimingTypeDef SdramTiming = {0};
  18.         GPIO_InitTypeDef GPIO_InitStruct = {0};
  19.         __IO uint32_t tmpmrd = 0;
  20.         uint32_t FMC_Initialized = 0;
  21.         if (FMC_Initialized) {
  22.                         return;
  23.         }FMC_Initialized = 1;
  24.        
  25.         //--------------------------------------------------------------------
  26.         // 时钟使能
  27.         //--------------------------------------------------------------------
  28.         __HAL_RCC_FMC_CLK_ENABLE();
  29.        
  30.         //--------------------------------------------------------------------
  31.         // GPIO初始化
  32.         //--------------------------------------------------------------------
  33.         __HAL_RCC_GPIOF_CLK_ENABLE();
  34.         __HAL_RCC_GPIOH_CLK_ENABLE();
  35.         __HAL_RCC_GPIOG_CLK_ENABLE();
  36.         __HAL_RCC_GPIOE_CLK_ENABLE();
  37.         __HAL_RCC_GPIOB_CLK_ENABLE();
  38.         __HAL_RCC_GPIOD_CLK_ENABLE();
  39.         GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
  40.                                                   |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12
  41.                                                   |GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  42.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  43.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  44.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  45.         GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  46.         HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
  47.         GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_5;
  48.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  49.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  50.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  51.         GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  52.         HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
  53.         GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4
  54.                                                   |GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15;
  55.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  56.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  57.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  58.         GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  59.         HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
  60.         GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
  61.                                                   |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14
  62.                                                   |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1;
  63.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  64.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  65.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  66.         GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  67.         HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  68.         GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14
  69.                                                   |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1;
  70.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  71.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  72.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  73.         GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  74.         HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
  75.        
  76.         //--------------------------------------------------------------------
  77.         // FMC-SDRAM初始化
  78.         //--------------------------------------------------------------------
  79.         hsdram1.Instance = FMC_SDRAM_DEVICE;
  80.         /* hsdram1.Init */
  81.         hsdram1.Init.SDBank = FMC_SDRAM_BANK1;                                                                // 选择BANK区
  82.         hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;                // 行地址宽度
  83.         hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;             // 列地址线宽度
  84.         hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;          // 数据宽度  
  85.         hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;     // bank数量
  86.         hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;                  //        CAS
  87.         hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;  // 禁止写保护
  88.         hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;              // 分频
  89.         hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;                   // 突发模式  
  90.         hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;               // 读延迟
  91.         /* SdramTiming */                                                   
  92.         SdramTiming.LoadToActiveDelay = 2;
  93.         SdramTiming.ExitSelfRefreshDelay = 8;
  94.         SdramTiming.SelfRefreshTime = 6;
  95.         SdramTiming.RowCycleDelay = 6;
  96.         SdramTiming.WriteRecoveryTime = 4;
  97.         SdramTiming.RPDelay = 2;
  98.         SdramTiming.RCDDelay = 2;
  99.         if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
  100.         {
  101.                 Error_Handler( );
  102.         }
  103.        
  104. //        HAL_SDRAM_Init(&hsdram1, &SdramTiming);
  105.        
  106.         SDRAM_Initialization_Sequence(&hsdram1,&command);//配置SDRAM
  107.        
  108.         #endif
  109. }
复制代码
8.png

9.png

最后添加

在 MX_FMC_Init() 函数最后面再添加配置函数,防止在提前初始化后配置丢失。
10.png

内存测试

测试程序

添加如下代码,然后放到 main() 函数中测试:
点击查看代码[code]//SDRAM内存测试            void fsmc_sdram_test(void){          __IO uint32_t i=0;                    __IO uint32_t temp=0;                   __IO uint32_t sval=0;//在地址0读到的数据                                                     //每隔16K字节,写入一个数据,总共写入2048个数据,刚好是32M字节        for(i=0;i

相关推荐

您需要登录后才可以回帖 登录 | 立即注册