STM32H7X系列笔记
STM32H750X驱动SDRAM
本文介绍了W9825G6KH芯片一些参数的计算方法,可对照自己的开发板进行配置,计算方法都是一样的
查看SDRAM芯片型号,,野火系列开发板H750X核心板板载两片SDRAM芯片,目前使用的是W9825G6KH
查看STM32芯片型号,分别是V版还是Y版,为了方便,设置主频率为400MHz
- V版:最高480MHz
- Y版:最高400MHz
配置时钟,PLL2R2时钟设置为240MHz,为SDRAM芯片提供时钟。
- 时钟选择为外部时钟
配置SDRAM 参数
参数配置如下:
- Clock and chip enable:
查看核心板原理图
SDRAM芯片CKE引脚连接开发板PH7引脚,查看STM32参考手册
可以看到PH7对应的是FMC_SDCKE1。
-
Internal bank number:W9825G6KH是有4个BANK,13位地址线,具体看芯片数据手册。
-
Data:数据总线,W9825G6KH是16位,但是野火H750X核心板板载了两片,所以选择32bits
-
Byte enable:这个可以先不管,暂时用不上
配置SDRAM
参数配置如下
SDRAM control
-
Bank:默认即可
-
Number of column address bits:列地址位数:9位,查W9825G6KH手册
-
Number of row address bitsCAS latency:行地址位数:13位,查W9825G6KH手册
-
Write protection:关闭写保护
-
SDRAM common clock:SDRAM时钟是PLL2R时钟提供,在前面设置的240MHz,此选项选择2分频,所以SDRAM时钟频率为120MHz
-
SDRAM common burst read:冲突写,可选择打开
-
SDRAM common read pipe delay:1个时钟周期即可
SDRAM timing in memory clock cycles(时序寄存器配置)
- Load mode register to active delay:
最小 2 个周期
这两个参数解释其实是一样的,TMRD 和 tRSC 两个意思是一样的,不同的芯片厂商,命名不一样,意思是一样的
- Exit self-refresh delay:
最小 72 ns
计算-- TXSR:SDRAM的时钟周期通过单片机提供的240MHz分频得到120MHz
1/120000000 = 8.3333333 (ns)
W9825G6KH-6经过TRCD一个周期需要15ns
72/8.33333 = 8.64
向上取整得9
- Self-refresh time:
最小 42 ns
计算同上
- SDRAM common row cycle delay:
最小 60 ns
计算同上
- Write recovery time:
这个参数最好是留着最后配置,因为有一些约束条件,例如:
先把其他参数配置好,然后选择这个配置的时候直接选择最小周期数就行了
- SDRAM common row precharge delay:
最小 15ns
计算同上
- Row to column delay:
计算-- TRCD:SDRAM的时钟周期通过单片机提供的240MHz分频得到120MHz
1/120000000 = 8.3333333 (ns)
W9825G6KH-6经过TRCD一个周期需要15ns
15/8.33333 = 1.8
向上取整得2
上面完整的表格如下图所示
具体选择要看W9825G6KH是哪个版本,核心版板载的是 -6 版本的,所以列就选择 -6 这一列去计算
配置好SDRAM基本信息后,需要查看cubemx默认设置的引脚和开发板的引脚是否一样
生成代码
fmc.c文件里面的SDRAM初始化,cubemx生成代码里面没有这个,需要加上
uint32_t tmpr = 0;
FMC_SDRAM_CommandTypeDef Command;
SDRAM_HandleTypeDef hsdram2;
// 第一步,给 SDRAM 提供时钟
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
// 第二步,延迟至少 200 us
HAL_Delay(1); // 延时 1 ms
// 第三步,对所有 Banks 预充电
Command.CommandMode = FMC_SDRAM_CMD_PALL;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
// 第四步,插入 8 个自动刷新周期
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 8;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram2, &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_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = tmpr;
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
// 第六步,配置STM32FMC的 SDRAM 控制器的自动刷新周期
HAL_SDRAM_ProgramRefreshRate(&hsdram2, 918);
讲解一下第六步函数HAL_SDRAM_ProgramRefreshRate(&hsdram2, 918)
的第二个参数计算:
官方例子:
计算我们的开发板,先看W9825G6KH芯片手册。
rows = 2^13 = 8192rows
SDRAM refresh rate = 64ms / 8192rows = 7.81 us
Refresh rate = (7.81 * 120) - 20 = 937.2 - 20 = 917.2 = 918
main.c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "memorymap.h"
#include "usart.h"
#include "gpio.h"
#include "fmc.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "sdram_rw.h"
#include <stdlib.h>
/* USER CODE END Includes */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_FMC_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("\r\n Welcome to Cheney's SDRAM !! \r\n");
// 在SDRAM地址中写入一个数
*(uint32_t *)(SDRAM_BANK2_ADDR + 0x0010) = 100;
// 读取出来
uint32_t tmp = *(uint32_t *)(SDRAM_BANK2_ADDR + 0x0010);
// 打印--需配置usart串口
printf("tmp : %d \r\n", tmp);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY))
{
}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 2;
RCC_OscInitStruct.PLL.PLLN = 64;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
fmc.c
/* Includes ------------------------------------------------------------------*/
#include "fmc.h"
/* USER CODE BEGIN 0 */
FMC_SDRAM_CommandTypeDef Command;
/* USER CODE END 0 */
SDRAM_HandleTypeDef hsdram2;
/* FMC initialization function */
void MX_FMC_Init(void)
{
/* USER CODE BEGIN FMC_Init 0 */
/* USER CODE END FMC_Init 0 */
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
/* USER CODE BEGIN FMC_Init 1 */
/* USER CODE END FMC_Init 1 */
/** Perform the SDRAM2 memory initialization sequence
*/
hsdram2.Instance = FMC_SDRAM_DEVICE;
/* hsdram2.Init */
hsdram2.Init.SDBank = FMC_SDRAM_BANK2;
hsdram2.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
hsdram2.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
hsdram2.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
hsdram2.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram2.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram2.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram2.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram2.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram2.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 9;
SdramTiming.SelfRefreshTime = 6;
SdramTiming.RowCycleDelay = 8;
SdramTiming.WriteRecoveryTime = 4;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram2, &SdramTiming) != HAL_OK)
{
Error_Handler( );
}
/* USER CODE BEGIN FMC_Init 2 */
uint32_t tmpr = 0;
// 第一步,给 SDRAM 提供时钟
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
// 第二步,延迟至少 200 us
HAL_Delay(1); // 延时 1 ms
// 第三步,对所有 Banks 预充电
Command.CommandMode = FMC_SDRAM_CMD_PALL;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
// 第四步,插入 8 个自动刷新周期
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 8;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram2, &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_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = tmpr;
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
// 第六步,配置STM32FMC的 SDRAM 控制器的自动刷新周期
HAL_SDRAM_ProgramRefreshRate(&hsdram2, 918);
/* USER CODE END FMC_Init 2 */
}
static uint32_t FMC_Initialized = 0;
static void HAL_FMC_MspInit(void){
/* USER CODE BEGIN FMC_MspInit 0 */
/* USER CODE END FMC_MspInit 0 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (FMC_Initialized) {
return;
}
FMC_Initialized = 1;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FMC;
PeriphClkInitStruct.PLL2.PLL2M = 10;
PeriphClkInitStruct.PLL2.PLL2N = 192;
PeriphClkInitStruct.PLL2.PLL2P = 2;
PeriphClkInitStruct.PLL2.PLL2Q = 10;
PeriphClkInitStruct.PLL2.PLL2R = 2;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_1;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_PLL2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_FMC_CLK_ENABLE();
/** FMC GPIO Configuration
PI6 ------> FMC_D28
PI5 ------> FMC_NBL3
PI4 ------> FMC_NBL2
PI1 ------> FMC_D25
PI0 ------> FMC_D24
PI7 ------> FMC_D29
PE1 ------> FMC_NBL1
PI2 ------> FMC_D26
PH15 ------> FMC_D23
PH14 ------> FMC_D22
PE0 ------> FMC_NBL0
PI3 ------> FMC_D27
PG15 ------> FMC_SDNCAS
PD0 ------> FMC_D2
PH13 ------> FMC_D21
PI9 ------> FMC_D30
PD1 ------> FMC_D3
PI10 ------> FMC_D31
PG8 ------> FMC_SDCLK
PF2 ------> FMC_A2
PF1 ------> FMC_A1
PF0 ------> FMC_A0
PG5 ------> FMC_BA1
PF3 ------> FMC_A3
PG4 ------> FMC_BA0
PG2 ------> FMC_A12
PF5 ------> FMC_A5
PF4 ------> FMC_A4
PC0 ------> FMC_SDNWE
PE10 ------> FMC_D7
PF13 ------> FMC_A7
PF14 ------> FMC_A8
PE9 ------> FMC_D6
PE11 ------> FMC_D8
PH10 ------> FMC_D18
PH11 ------> FMC_D19
PD15 ------> FMC_D1
PD14 ------> FMC_D0
PF12 ------> FMC_A6
PF15 ------> FMC_A9
PE12 ------> FMC_D9
PE15 ------> FMC_D12
PH9 ------> FMC_D17
PH12 ------> FMC_D20
PF11 ------> FMC_SDNRAS
PG0 ------> FMC_A10
PE8 ------> FMC_D5
PE13 ------> FMC_D10
PH6 ------> FMC_SDNE1
PH8 ------> FMC_D16
PD10 ------> FMC_D15
PD9 ------> FMC_D14
PG1 ------> FMC_A11
PE7 ------> FMC_D4
PE14 ------> FMC_D11
PH7 ------> FMC_SDCKE1
PD8 ------> FMC_D13
*/
/* GPIO_InitStruct */
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_5|GPIO_PIN_4|GPIO_PIN_1
|GPIO_PIN_0|GPIO_PIN_7|GPIO_PIN_2|GPIO_PIN_3
|GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
/* GPIO_InitStruct */
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0|GPIO_PIN_10|GPIO_PIN_9
|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_15|GPIO_PIN_8
|GPIO_PIN_13|GPIO_PIN_7|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* GPIO_InitStruct */
GPIO_InitStruct.Pin = GPIO_PIN_15|GPIO_PIN_14|GPIO_PIN_13|GPIO_PIN_10
|GPIO_PIN_11|GPIO_PIN_9|GPIO_PIN_12|GPIO_PIN_6
|GPIO_PIN_8|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
/* GPIO_InitStruct */
GPIO_InitStruct.Pin = GPIO_PIN_15|GPIO_PIN_8|GPIO_PIN_5|GPIO_PIN_4
|GPIO_PIN_2|GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/* GPIO_InitStruct */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_15|GPIO_PIN_14
|GPIO_PIN_10|GPIO_PIN_9|GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* GPIO_InitStruct */
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_1|GPIO_PIN_0|GPIO_PIN_3
|GPIO_PIN_5|GPIO_PIN_4|GPIO_PIN_13|GPIO_PIN_14
|GPIO_PIN_12|GPIO_PIN_15|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/* GPIO_InitStruct */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* USER CODE BEGIN FMC_MspInit 1 */
/* USER CODE END FMC_MspInit 1 */
}
void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* sdramHandle){
/* USER CODE BEGIN SDRAM_MspInit 0 */
/* USER CODE END SDRAM_MspInit 0 */
HAL_FMC_MspInit();
/* USER CODE BEGIN SDRAM_MspInit 1 */
/* USER CODE END SDRAM_MspInit 1 */
}
static uint32_t FMC_DeInitialized = 0;
static void HAL_FMC_MspDeInit(void){
/* USER CODE BEGIN FMC_MspDeInit 0 */
/* USER CODE END FMC_MspDeInit 0 */
if (FMC_DeInitialized) {
return;
}
FMC_DeInitialized = 1;
/* Peripheral clock enable */
__HAL_RCC_FMC_CLK_DISABLE();
/** FMC GPIO Configuration
PI6 ------> FMC_D28
PI5 ------> FMC_NBL3
PI4 ------> FMC_NBL2
PI1 ------> FMC_D25
PI0 ------> FMC_D24
PI7 ------> FMC_D29
PE1 ------> FMC_NBL1
PI2 ------> FMC_D26
PH15 ------> FMC_D23
PH14 ------> FMC_D22
PE0 ------> FMC_NBL0
PI3 ------> FMC_D27
PG15 ------> FMC_SDNCAS
PD0 ------> FMC_D2
PH13 ------> FMC_D21
PI9 ------> FMC_D30
PD1 ------> FMC_D3
PI10 ------> FMC_D31
PG8 ------> FMC_SDCLK
PF2 ------> FMC_A2
PF1 ------> FMC_A1
PF0 ------> FMC_A0
PG5 ------> FMC_BA1
PF3 ------> FMC_A3
PG4 ------> FMC_BA0
PG2 ------> FMC_A12
PF5 ------> FMC_A5
PF4 ------> FMC_A4
PC0 ------> FMC_SDNWE
PE10 ------> FMC_D7
PF13 ------> FMC_A7
PF14 ------> FMC_A8
PE9 ------> FMC_D6
PE11 ------> FMC_D8
PH10 ------> FMC_D18
PH11 ------> FMC_D19
PD15 ------> FMC_D1
PD14 ------> FMC_D0
PF12 ------> FMC_A6
PF15 ------> FMC_A9
PE12 ------> FMC_D9
PE15 ------> FMC_D12
PH9 ------> FMC_D17
PH12 ------> FMC_D20
PF11 ------> FMC_SDNRAS
PG0 ------> FMC_A10
PE8 ------> FMC_D5
PE13 ------> FMC_D10
PH6 ------> FMC_SDNE1
PH8 ------> FMC_D16
PD10 ------> FMC_D15
PD9 ------> FMC_D14
PG1 ------> FMC_A11
PE7 ------> FMC_D4
PE14 ------> FMC_D11
PH7 ------> FMC_SDCKE1
PD8 ------> FMC_D13
*/
HAL_GPIO_DeInit(GPIOI, GPIO_PIN_6|GPIO_PIN_5|GPIO_PIN_4|GPIO_PIN_1
|GPIO_PIN_0|GPIO_PIN_7|GPIO_PIN_2|GPIO_PIN_3
|GPIO_PIN_9|GPIO_PIN_10);
HAL_GPIO_DeInit(GPIOE, GPIO_PIN_1|GPIO_PIN_0|GPIO_PIN_10|GPIO_PIN_9
|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_15|GPIO_PIN_8
|GPIO_PIN_13|GPIO_PIN_7|GPIO_PIN_14);
HAL_GPIO_DeInit(GPIOH, GPIO_PIN_15|GPIO_PIN_14|GPIO_PIN_13|GPIO_PIN_10
|GPIO_PIN_11|GPIO_PIN_9|GPIO_PIN_12|GPIO_PIN_6
|GPIO_PIN_8|GPIO_PIN_7);
HAL_GPIO_DeInit(GPIOG, GPIO_PIN_15|GPIO_PIN_8|GPIO_PIN_5|GPIO_PIN_4
|GPIO_PIN_2|GPIO_PIN_0|GPIO_PIN_1);
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_15|GPIO_PIN_14
|GPIO_PIN_10|GPIO_PIN_9|GPIO_PIN_8);
HAL_GPIO_DeInit(GPIOF, GPIO_PIN_2|GPIO_PIN_1|GPIO_PIN_0|GPIO_PIN_3
|GPIO_PIN_5|GPIO_PIN_4|GPIO_PIN_13|GPIO_PIN_14
|GPIO_PIN_12|GPIO_PIN_15|GPIO_PIN_11);
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0);
/* USER CODE BEGIN FMC_MspDeInit 1 */
/* USER CODE END FMC_MspDeInit 1 */
}
void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef* sdramHandle){
/* USER CODE BEGIN SDRAM_MspDeInit 0 */
/* USER CODE END SDRAM_MspDeInit 0 */
HAL_FMC_MspDeInit();
/* USER CODE BEGIN SDRAM_MspDeInit 1 */
/* USER CODE END SDRAM_MspDeInit 1 */
}
fmc.h
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FMC_H
#define __FMC_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
extern SDRAM_HandleTypeDef hsdram2;
/* USER CODE BEGIN Private defines */
#define SDRAM_SIZE_64M 0x4000000 // 64M字节,两片W9825G6KH-6,32MB@16bit组成64M@32bit
#define SDRAM_SIZE_32M 0x2000000 // 32M字节,
/**
* @brief FMC SDRAM 数据基地址
*/
#define SDRAM_BANK1_ADDR ((uint32_t)0xC0000000) // BANK1 起始地址
#define SDRAM_BANK2_ADDR ((uint32_t)0xD0000000) // BANK2 起始地址
/**
* @brief FMC 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)
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
/*信息输出*/
#define SDRAM_DEBUG_ON 1
#define SDRAM_INFO(fmt,arg...) printf("<<-SDRAM-INFO->> "fmt"\n",##arg)
#define SDRAM_ERROR(fmt,arg...) printf("<<-SDRAM-ERROR->> "fmt"\n",##arg)
#define SDRAM_DEBUG(fmt,arg...) do{\
if(SDRAM_DEBUG_ON)\
printf("<<-SDRAM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
}while(0)
/* USER CODE END Private defines */
void MX_FMC_Init(void);
void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* hsdram);
void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef* hsdram);
/* USER CODE BEGIN Prototypes */
uint8_t SDRAM_Test(void);
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__FMC_H */
结语
本文没有介绍串口配置,可见其他博主进行配置
芯片手册可找我获取