STM32使用HAL库驱动SDRAM

1、驱动平台

开发板使用的是野火的STM32H750,需要驱动核心板上的SDRAM(2片装),SDRAM使用的是W9825G6KH-6,32MB@,组合一起成为64M。驱动方式使用STM32H750XB上的FMC进行驱动。通过使用HAL库上的stm32h7xx_hal_sdram.c里面的API进行配置。

2、SDRAM配置方式

1、初始化FMC对应的GPIO

1、开启FMC对应的GPIO时钟
2、将GPIO复用成FMC模式
3、使用HAL库初始化
代码如下:

  GPIO_InitStructure.Mode      = GPIO_MODE_AF_PP;//配置为复用功能
  GPIO_InitStructure.Pull      = GPIO_PULLUP;
  GPIO_InitStructure.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
  GPIO_InitStructure.Pin = FMC_A0_GPIO_PIN; 
  HAL_GPIO_Init(FMC_A0_GPIO_PORT, &GPIO_InitStructure);
  .....

因为管脚太多了,就不一一列举了。

2、初始化SDRAM的时钟源

通过PLL分频,可以获得SDRAM的控制时钟,具体配置代码如下:

  RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;

  RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FMC;
  RCC_PeriphClkInit.PLL2.PLL2M = 5;
  RCC_PeriphClkInit.PLL2.PLL2N = 144;
  RCC_PeriphClkInit.PLL2.PLL2P = 2;
  RCC_PeriphClkInit.PLL2.PLL2Q = 2;
  RCC_PeriphClkInit.PLL2.PLL2R = 3;
  RCC_PeriphClkInit.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_2;
  RCC_PeriphClkInit.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
  RCC_PeriphClkInit.PLL2.PLL2FRACN = 0;
  RCC_PeriphClkInit.FmcClockSelection = RCC_FMCCLKSOURCE_PLL2;

3 、使能FMC时钟,并配置FMC的控制参数,写入SDRAM的时序参数

代码如下:

  __FMC_CLK_ENABLE();                             //使能FMC时钟

  hsdram1.Instance = FMC_SDRAM_DEVICE;
  /* hsdram1结构体初始化*/
  hsdram1.Init.SDBank = FMC_SDRAM_BANK2;
  hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;//SDRAM列数
  hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;//SDRAM行数
  hsdram1.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH;//总线数据宽度为32位
  hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;//4个扇区
  hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;//列地址选通信延时
  hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;//禁止写保护
  hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;//SDRAM时钟120MHz
  hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;     //使能突发传输模式
  hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1; //读通道延时
  /* SDRAM时序 */
  SdramTiming.LoadToActiveDelay = 2;//加载模式寄存器命令与行有效或刷新命令之间的延迟
  SdramTiming.ExitSelfRefreshDelay = 8;//退出自我刷新到行有效命令之间的延迟
  SdramTiming.SelfRefreshTime = 5;//行有效与预充电命令之间的延迟
  SdramTiming.RowCycleDelay = 8;//两个刷新命令或两个行有效命令之间的延迟
  SdramTiming.WriteRecoveryTime = 2;//写入命令到预充电命令之间的延迟
  SdramTiming.RPDelay = 2;//预充电与行有效命令之间的延迟
  SdramTiming.RCDDelay = 2;//行有效与列读写命令之间的延迟

  HAL_SDRAM_Init(&hsdram1, &SdramTiming); 

4、初始化SDRAM,并进行预充电等处理

代码如下:

    uint32_t tmpr = 0;
    
	/* 配置命令:开启提供给SDRAM的时钟 */
	Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
	Command.CommandTarget = FMC_COMMAND_TARGET_BANK;
	Command.AutoRefreshNumber = 1;
	Command.ModeRegisterDefinition = 0;
	/* 发送配置命令 */
	HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);

	/* Step 2: 延时100us */ 
	SDRAM_delay(1);

	/* 配置命令:对所有的bank预充电 */ 
	Command.CommandMode = FMC_SDRAM_CMD_PALL;
	Command.CommandTarget = FMC_COMMAND_TARGET_BANK;
	Command.AutoRefreshNumber = 1;
	Command.ModeRegisterDefinition = 0;
	/* 发送配置命令 */
	HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);   

	/* 配置命令:自动刷新 */   
	Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
	Command.CommandTarget = FMC_COMMAND_TARGET_BANK;
	Command.AutoRefreshNumber = 8;
	Command.ModeRegisterDefinition = 0;
	/* 发送配置命令 */
	HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);

	/* 设置sdram寄存器配置 */
	tmpr = (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;

	/* 配置命令:设置SDRAM寄存器 */
	Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
	Command.CommandTarget = FMC_COMMAND_TARGET_BANK;
	Command.AutoRefreshNumber = 1;
	Command.ModeRegisterDefinition = tmpr;
	/* 发送配置命令 */
	HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);

	/* 设置刷新计数器 */
	/* 刷新周期=64ms/8192行=7.8125us */
	/* COUNT=(7.8125us x Freq) - 20 */
	/* 设置自刷新速率 */
	HAL_SDRAM_ProgramRefreshRate(&sdramHandle, 824);

配置参数来自于芯片手册,并通过自己配置的时钟进行计算得到的,注释上有些写。

完成后基本上SDRAM的初始化就完成了,剩下就是自行配置SDRAM相关的接口函数,比如:

SDRAM_ReadBuffer();
SDRAM_WriteBuffer();

等等、看个人需求。

5、遇坑提醒

在没有使用STM32CubeMX配置的工程中,很多人都会将stm32h7xx_ll_xxx.c等文件去掉,我在移植使用的时候,编译时出现了这么几个错误:

Error[Li005]: no definition for "FMC_SDRAM_ProgramRefreshRate" [referenced from 
Error[Li005]: no definition for "FMC_SDRAM_SendCommand" [referenced from 
Error[Li005]: no definition for "FMC_SDRAM_Init" [referenced from 
Error[Li005]: no definition for "FMC_SDRAM_Timing_Init" [referenced from 

出现这问题就是源于没有将stm32h7xx_ll_fmc.c这个文件包含进来,因为这个文件包含了FMC的底层驱动,而stm32h7xx_hal_sdram.c是依赖stm32h7xx_ll_fmc.c里面的底层驱动来编写的。

发布了45 篇原创文章 · 获赞 52 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42312125/article/details/98477101