20.1CubeMx配置FMC控制SDRAM【W9825G6KH-6】

news2025/4/26 20:13:14

本文使用stm32h723zgt6的fmc驱动sdram,实现内存扩展
sdram型号W9825G6KH-6

原理图:

在这里插入图片描述

MCU引脚与SDRAM对应关系
在这里插入图片描述

引脚说明:

SDRAM引脚:
DQ[15:0]:数据线;数据位宽16
A[12:0]:地址线;行地址A[0:12],列地址A[0:8];
在这里插入图片描述
BS[1:0]:Bank 地址输入,选择要控制的 Bank;本芯片4个Bank;4M words x 4 banks x 16 bits ;块地址其它简写名称BA,
FMC_BA0 对应 BS0;
FMC_BA1 对应 BS1
LDQM,UDQM:数据输入/输出掩码信号,表示 DQ 信号线的有效部分;
FMC_NBL0 对应 LDQM
FMC_NBL1 对应 UDQM
WE:写入使能,低电平有效;对应FMC_SDNWE
RAS:行地址选通,为低电平时地址线表示的是行地址;对应FMC_SDNRAS
CAS:列地址选通,为低电平时地址线表示的是列地址;对应FMC_SDNCAS
CS:片选信号,低电平有效;对应FMC_SDNE0或FMC_SDNE1
CKE:时钟使能信号,禁止时钟信号时 SDRAM 会启动自刷新操作;对应FMC_SDCKE0或FMC_SDCKE1
CLK:同步时钟信号,所有输入信号都在 CLK 为上升沿的时候被采集;对应FMC_SDCLK
注:SDRAM的线尽量等长走线 阻抗50ohm,此款芯片最高频率166MHz,不走等长会达不到这么高的频率,我画的板最大稳定运行100MHz;但是走等长确实有点困难,因为线束较多,分布比较散乱,不走等长时建议留出探测点
在这里插入图片描述
此图是我的SDRAM走线图
在这里插入图片描述
在这里插入图片描述
FMC引脚名参考:
在这里插入图片描述

CubeMx工程配置:

常规配置

配置工程时钟、串口、SWDIO
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

FMC配置

SDRAM硬件相关配置

Clock and chip enable:SDRAM选择:SDRAM1|SDRAM2
FMC内部包含两个SDRAM存储区
在这里插入图片描述
在这里插入图片描述
Clock and chip enable选择SDRAM1
在这里插入图片描述
Internal bank number:内部Bank数;本芯片4个banks
在这里插入图片描述
Address:地址线13根【A0-A12】
Data:数据线16根【DQ0-DQ15】
16-bit byte enable:使能数据掩码功能;见LDQM,UDQM

SDRAM1控制参数:

Bank:使用的是FMC的SDRAM bank1
Number of colum address bit:列地址线9根
Number of row address bits:行地址线13根
在这里插入图片描述CAS latency:列地址选通延迟,简称CL。在发出读命令后需要等待几个时钟周期数据线DQ才是有效数据,仅在读命令时才有这个;
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
CAS latency此芯片配置为3
Write protection:设置是否使能写保护模式,如果使能了写保护则不能向 SDRAM 写入数据,正常使用都是禁止写保护的;
SDRAM common clock:设置 FMC 与外部 SDRAM 通讯时的同步时钟参数,可以设置成 STM32的 HCLK 时钟频率的 1/2、1/3 或禁止输出时钟 (FMC_SDRAM_CLOCK_PERIOD_2/3 或FMC_SDRAM_CLOCK_DISABLE)。
FMC此工程配置的200MHz
在这里插入图片描述
SDRAM common clock选择2分频,所以SDRAM 时钟100MHz,此时钟不能大于芯片要求的166MHz
在这里插入图片描述
SDRAM common burst read:设置是否使能突发读取模式,禁止时等效于 BL=1,使能时 BL 的值等于模式寄存器中的配置。本配置禁止
SDRAM timing read pipe delay:配置在 CASLatency 个时钟周期后,再等待多少个 HCLK 时钟周期才进行数据采样,在确保正确的前提下,这个值设置为越短越好,可选择设置的参数值为 0、1 或 2 个 HCLK 时钟周期 (FMC_SDRAM_RPIPE_DELAY_0/1/2)。
本芯片0等待:
在这里插入图片描述

SDRAM1时序参数配置

Load mode register to active delay:[TMRD]加载模式寄存器命令与行或刷新命令之间的延迟。
Exit self-refresh delay:[TXSR]退出 TXSR 延迟 (Exit Self-refresh delay),即退出自我刷新命令后要等待的时间,过了这段时间才可以发送行有效命令
Self-refresh time:【TRAS】自我刷新时间 TRAS,即发送行有效命令后要等待的时间,过了这段时间才执行预充电命令。
SDRAM common row cycle delay:【TRC】 (Row cycle delay),即两个行有效命令之间的延迟,以及两个相邻刷新命令之间的延迟
Write recovery time:[TWR] (Recovery delay)即写命令和预充电命令之间的延迟,等待这段时间后才开始执行预充电命令
SDRAM common row precharge delay: TRP 延迟 (Row precharge delay),即预充电命令与其它命令之间的延迟
Row to column delay:TRCD 延迟 (Row to column delay),即行有效命令到列读写命令之间的延迟

SDRAM时序简单示意图:

SDRAM 初始化流程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

W9825G6KH-6时序参数

在这里插入图片描述
本工程SDRAM配置的时钟等于FMC / SDRAM common clock = 200MHz / 2 = 100MHz = 10ns
在这里插入图片描述

SDRAM引脚全部上拉
在这里插入图片描述
在这里插入图片描述

MPU配置

在这里插入图片描述
注意看,SDRAM内存为Extern device
一定要配置SDRAM的MPU属性为Write back, Read allocate,Write allocate
在这里插入图片描述
生成工程代码…

CubeMx工程代码编写:

添加文件:

sdram_driver.c|sdram_driver.h:负责初始化SDRAM时序,及测试SDRAM内存
common_driver.c|common_driver.h:负责实现printf
common_driver.c

/**********************************************************************
*file:开发常用函数|宏文件
*author:残梦
*versions:V1.2
*date:2023.08.10
*note:
**********************************************************************/
#include "common_driver.h"

/*开始1、基础功能******************************************************/
/****************************************************
@function:计算数据的拟合系数
@param:*pA,*pB--系数
		x[],y[]--数据源
		dataSize--数据个数
@return:void
@note:拟合曲线y=Ax+B
****************************************************/
void LinearFitCoefficient(double *pA,double *pB,double x[],double y[],unsigned short int dataSize)
{
	unsigned short int i= 0;
	double AverX = 0.0f,AverY = 0.0f,a1 = 0.0f,a2 = 0.0f;

	if(dataSize == 0){*pA = *pB = 0.0;return;}
	else if(dataSize == 1){*pA = 0.0;*pB = y[0];return;}
	while(i < dataSize)	{AverX += x[i];AverY += y[i];i++;}
	AverX /= (double)(dataSize);AverY /= (double)(dataSize);

	a1 = a2 = 0.0f;
	for(i=0;i<dataSize;i++)
	{
		a1 += (x[i] - AverX)*(y[i] - AverY);
		a2 += (x[i] - AverX)*(x[i] - AverX);
	}
	*pA = a1/a2;
	*pB = AverY - (*pA)*AverX;
}

/****************************************
@function:二分法查找target在数组pdata中的最相邻位置
@param:target--目标数据,pdata--源数据,len--源数据长度
@return:[0,len-1]
@note:
****************************************/
unsigned long int DichotomyFindPos(float target,float *pdata,unsigned long int len)
{
	unsigned long int pos = 0,posl = 0,posr = 0;
	unsigned char flag = 0;

	//for(unsigned long int z = 0;z < len;z++){printf("[%d]=%f\n",z,*(pdata+z));}
	if(len <= 2){return 0;}
	//判定数据是否在区间外
	flag = (*(pdata + len -1) > *pdata)?1:0;
	if(flag == 1)//递增数据
	{
		if(target < *pdata)return 0;
		else if(target > *(pdata + len -1))return (len -1);
	}
	else
	{
		if(target > *pdata)return 0;
		else if(target < *(pdata + len -1))return (len -1);
	}

	unsigned long int num = 0;
	//区间内的数据
	posl = 0;posr = len -1;
	while((posl != (posr-1)) && (posl != posr))
	{
		pos = (posr + posl)/2;
		if(flag == 1)
		{
			if(target < (*(pdata + pos))){posr = pos;}
			else{posl = pos;}
		}
		else
		{
			if(target > (*(pdata + pos))){posr = pos;}
			else{posl = pos;}
		}
		num++;
		//printf("%d [%d,%d]=[%f,%f]\n",num,posl,posr,*(pdata + posl),*(pdata + posr));
	}
	//printf("[pos,tar]=[%d,%f] num=%d\n",posl,target,num);
	return posl;
}

/*结束****************************************************************/

/*开始1、STM32支持区***************************************************/
#ifdef dcommonEnable_STM32
#include "usart.h"

/******************************
@function:printf打印使用
@param:
@return:
@remark:
******************************/
int fputc(int ch,FILE *f)
{
	unsigned char temp[1] = {ch};
	HAL_UART_Transmit(&huart1,temp,1,2);
	return(ch);
}
#endif
/*结束****************************************************************/

/*开始1、PID功能支持区*************************************************/
#ifdef dcommonEnable_PID
/****************************************
@function:增量式PID算法
@param:	pid--PID_ParameterStructDef
		actual_val--当前采集值
		Min--输出限幅最小值
		Max--输出限幅最大值
@return:
@note:
****************************************/
float PID_realize_increment(PID_ParameterStructDef *pid,float actual_val,unsigned long int Min,unsigned long int Max)
{
	/*计算目标值与实际值的误差*/
	pid->err=pid->target-actual_val;
	/*PID算法实现*/
	pid->actual += pid->Kp*(pid->err - pid->err_next)
					+ pid->Ki*pid->err
					+ pid->Kd*(pid->err - 2 * pid->err_next + pid->err_last);
	/*传递误差*/
	pid->err_last = pid->err_next;
	pid->err_next = pid->err;

	pid->actual = (pid->actual < Min)?Min:pid->actual;
	pid->actual = (pid->actual > Max)?Max:pid->actual;

   /*返回当前实际值*/
   return pid->actual;
}

/****************************************
@function:位置式PID算法
@param:	pid--PID_ParameterStructDef
		actual_val--当前采集值
		Min--输出限幅最小值
		Max--输出限幅最大值
@return:
@note:
****************************************/
float PID_realize_location(PID_ParameterStructDef *pid,float actual_val,unsigned long int Min,unsigned long int Max)
{
	/*计算目标值与实际值的误差*/
	pid->err=pid->target-actual_val;
	/*误差累积*/
	pid->integral+=pid->err;
	/*PID算法实现*/
	pid->actual=pid->Kp*pid->err + pid->Ki*pid->integral + pid->Kd * (pid->err - pid->err_last);
	/*误差传递*/
	pid->err_last=pid->err;

	pid->actual = (pid->actual < Min)?Min:pid->actual;
	pid->actual = (pid->actual > Max)?Max:pid->actual;
	return pid->actual;
}

#endif


common_driver.h

#ifndef _common_driver_H_
#define _common_driver_H_
#ifdef __cplusplus
extern "C" {
#endif

//本文件使用宏的方式开启附加功能
#define dcommonEnable_STM32 //使能stm32功能
//#define dcommonEnable_PID //使能PID功能

#include "stdint.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "math.h"

#define dBOOL(x) (x?eStatus_Valid:eStatus_Invalid)//逻辑值:真-1,假-0

typedef  uint8_t    u8;
typedef  uint16_t   u16;
typedef  uint32_t   u32;
typedef  int8_t    s8;
typedef  int16_t   s16;
typedef  int32_t   s32;

typedef struct
{
	unsigned char byte1;
	unsigned char byte2;
	unsigned char byte3;
	unsigned char byte4;
}Byte4_MemoryParameterStructDef;

typedef struct
{
	unsigned char byte1;
	unsigned char byte2;
}Byte2_MemoryParameterStructDef;

typedef union
{
	short int Value;
	Byte2_MemoryParameterStructDef Memory;
}Convert_ShortIntParameter_UnionDef;

typedef union
{
	unsigned short int Value;
	Byte2_MemoryParameterStructDef Memory;
}Convert_UnsignedShortIntParameter_UnionDef;

typedef union
{
	unsigned long int Value;
	Byte4_MemoryParameterStructDef Memory;
}Convert_UnsignedLongIntParameter_UnionDef;

typedef union
{
	float Value;
	Byte4_MemoryParameterStructDef Memory;
}Convert_FloatParameter_UnionDef;

typedef struct
{
    uint8_t hour;
    uint8_t minute;
    uint8_t second;
    uint8_t millisecond;
}Time24Format_StructDef;

typedef enum
{
    eStatus_Invalid = 0,
    eStatus_Valid = 1
}status_EnumDef;

void LinearFitCoefficient(double *pA,double *pB,double x[],double y[],unsigned short int dataSize);
unsigned long int DichotomyFindPos(float target,float *pdata,unsigned long int len);

//STM32支持区
#ifdef dcommonEnable_STM32
#include "main.h"
#pragma diag_suppress 177 //忽略编译时函数定义但是没有引用的警告

#define dSET_PIN(GPIOx,Pin)         GPIOx->BSRR = Pin  //引脚置1
#define dRESET_PIN(GPIOx,Pin)       GPIOx->BSRR =  ((uint32_t)Pin << 16u) //引脚置0
#define dPIN_WRITE(GPIOx,Pin,x)     GPIOx->BSRR = ((uint32_t)Pin << ((x)?0u:16u))
#define dPIN_READ(GPIOx,Pin)        (GPIOx->IDR & Pin)?1:0 //获取引脚状态
#define dxPIN_MODE_IN(gpio,pin)     {gpio->MODER &= ~(3<<(pin*2));gpio->MODER |= 0<<(pin*2);}//配置引脚为输入模式
#define dxPIN_MODE_OUT(gpio,pin)    {gpio->MODER &= ~(3<<(pin*2));gpio->MODER |= 1<<(pin*2);}//配置引脚为输出模式
#define dPIN_TURN(GPIOx,Pin)        HAL_GPIO_TogglePin(GPIOx,Pin)

#endif

//PID功能支持区
#ifdef dcommonEnable_PID
typedef struct
{
  float target;//目标值
  float actual;//当前输出值
  float err;//本次偏差值
  float err_last;//上一次偏差值
  float err_next;//上上次的偏差值
  float integral;//累计误差
  float Kp;
  float Ki;
  float Kd;
}PID_ParameterStructDef;//PID参数结构体

float PID_realize_increment(PID_ParameterStructDef *pid,float actual_val,unsigned long int Min,unsigned long int Max);
float PID_realize_location(PID_ParameterStructDef *pid,float actual_val,unsigned long int Min,unsigned long int Max);

#endif

#ifdef __cplusplus
}
#endif
#endif


sdram_driver.c

/**********************************************************************
*file:SDRAM驱动文件
*author:残梦
*versions:V1.2
*date:2023.10.12
*note:
**********************************************************************/
#include "sdram_driver.h"
#include "common_driver.h"

/****************************************************
@function:初始化SDRAM时序
@param:hsdram--sdram句柄
@return:void
@note:
****************************************************/
void sdram_InitialTimingSequence(SDRAM_HandleTypeDef *hsdram)
{
    FMC_SDRAM_CommandTypeDef Command;

    //时钟使能
    Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
    Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    Command.AutoRefreshNumber = 1;
    Command.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(hsdram,&Command,0xFFFF);

    //延时至少200us
    HAL_Delay(1);

    //对所有的Banks预充电
    Command.CommandMode = FMC_SDRAM_CMD_PALL;
    Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    Command.AutoRefreshNumber = 1;
    Command.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(hsdram,&Command,0xFFFF);

    //插入8个自动刷新周期
    Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
    Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    Command.AutoRefreshNumber = 8;
    Command.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(hsdram,&Command,0xFFFF);

    //编程sdram的加载模式寄存器
    Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
    Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    Command.AutoRefreshNumber = 1;
    Command.ModeRegisterDefinition = 0x230;
    HAL_SDRAM_SendCommand(hsdram,&Command,0xFFFF);

    //配置stm32 FMC的sdram控制器的自动刷新周期
    //Refresh rate = (SDRAM refresh rate  * SDRAM clock frequency) - 20
    //SDRAM refresh rate = SDRAM refresh period / Number of rows
    //SDRAM refresh rate = 64ms / 8196(rows) = 7.81us
    //Refresh rate = 7.81us * 100Mhz  - 20 = 761
    HAL_SDRAM_ProgramRefreshRate(hsdram,761);
}

/****************************************************
@function:SDRAM内存简单测试
@param:void
@return:void
@note:
****************************************************/
uint32_t pbuffer[(32*1024*1024)/4] __attribute__((at(0xC0000000)));//0xC0000000是SDRAM1的起始地址
void sdram_test(void)
{
    uint32_t i = 0,err = 0;
    while(1)
    {
        for(i=0;i < (32*1024*1024)/4;i++)
        {
            pbuffer[i] = i;
        }

        err = 0;
        for(i=0;i < (32*1024*1024)/4;i++)
        {
            if(pbuffer[i] != i)err++;
            else if(i < 10)printf("pbuffer[%d]=%d\n",i,pbuffer[i]);
        }
        if(err){printf("err:%d\n",err);while(1)HAL_Delay(25);}
    }
}


sdram_driver.h

#ifndef _sdram_driver_H_
#define _sdram_driver_H_
#include "fmc.h"

void sdram_InitialTimingSequence(SDRAM_HandleTypeDef *hsdram);
void sdram_test(void);

#endif

编写工程

在fmc.c文件中MX_FMC_Init函数初始化SDRAM后添加SDRAM时序初始化函数,及添加相应头文件

#include "sdram_driver.h"
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 SDRAM1 memory initialization sequence
  */
  hsdram1.Instance = FMC_SDRAM_DEVICE;
  /* hsdram1.Init */
  hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
  hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
  hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
  hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
  hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_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;
  hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
  hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
  /* SdramTiming */
  SdramTiming.LoadToActiveDelay = 2;
  SdramTiming.ExitSelfRefreshDelay = 8;
  SdramTiming.SelfRefreshTime = 5;
  SdramTiming.RowCycleDelay = 6;
  SdramTiming.WriteRecoveryTime = 4;
  SdramTiming.RPDelay = 2;
  SdramTiming.RCDDelay = 2;

  if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
  {
    Error_Handler( );
  }

  /* USER CODE BEGIN FMC_Init 2 */
  sdram_InitialTimingSequence(&hsdram1);//SDRAM时序初始化
  /* USER CODE END FMC_Init 2 */
}

main.c文件添加SDRAM初始化及测试函数

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "fmc.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "sdram_driver.h"
#include "common_driver.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MPU_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_FMC_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  sdram_test();//测试SDRAM内存
  /* 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_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  /** Macro to configure the PLL clock source
  */
  __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSE);
  /** 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 = 44;
  RCC_OscInitStruct.PLL.PLLP = 1;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  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_3) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/* MPU Configuration */

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0xC0000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

/**
  * @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();
  printf("void Error_Handler(void)\n");
  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 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

如此即可完成,见信息窗:
在这里插入图片描述
在这里插入图片描述

未报错说明SDRAM内存正常,可以使用

完整工程下载:

链接:https://pan.baidu.com/s/1j173Z9Yx1D2yItmBCZNf9w
提取码:p2j4

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1088899.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

10月13日丨第十六届智慧城市大会《实景三维技术创新与应用》论坛日程抢先看!

第十六届智慧城市大会 智慧城市是数字中国、智慧社会的核心载体&#xff0c;是数字时代城市发展的高级形态。由中国服务贸易协会中国测绘学会、中国遥感委员会主办的第十六届智慧城市大会&#xff0c;将以“数实融合开放创新智引未来为主题&#xff0c;邀请行业主管单位和智慧…

【UE 插件】UE4 虚幻引擎 插件开发(带源码插件打包、无源码插件打包) 有这一篇文章就够了!!!

目录 0 引言1 快速入门1.1 新建插件的前提1.2 创建插件步骤1.3 打包插件 2 无源代码的插件制作3 插件详细介绍3.1 插件的使用方法3.1 UE 预置插件模版3.1.1 空白3.1.2 纯内容3.1.3 编辑器独立窗口3.1.4 编辑器工具栏按钮3.1.5 编辑器模式3.1.6 第三方库3.1.7 蓝图库 3.2 插件中…

milvus和相似度检索

流程 milvus的使用流程是 创建collection -> 创建partition -> 创建索引(如果需要检索) -> 插入数据 -> 检索 这里以Python为例, 使用的milvus版本为2.3.x 首先按照库&#xff0c; python3 -m pip install pymilvus Connect from pymilvus import connections c…

Java初学者容易犯的错误,Java程序员必须知道的学习路线

万事开头难&#xff0c;java 编程的初学者常常会遇到各种各样的问题。对于自学的读者来说&#xff0c;则是需要花费更多的时间、精力来解决这些问题&#xff0c;而且一旦遇到的问题几天都得不到解决&#xff0c;往往会带来很大的挫败感。 所以本节介绍一些初学者经常出现的错误…

Flutter笔记:电商中文货币显示插件Money Display

Flutter笔记 电商中文货币显示插件 Money Display 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/1338…

【数据结构】什么是线性表?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 线性表的定义 生活中常见的线性表 结语 线性表的定义 线性结构的特点: 在数据元素的非空有限集中: 存在唯一的一个被称作"第一个"的数据元素;存在唯一的一个…

Linux系统编程_文件编程第1天:打开、写入、读取、关闭文件等编程

1. 文件编程概述&#xff08;399.1&#xff09; 内容超多&#xff1a; 文件系统原理及访问机制文件在内核中的管理机制什么是文件信息节点inode文件的共享文件权限&#xff0c;各种用户对其权限。。。。。。 应用为王&#xff0c;如&#xff1a; 账单游戏进度配置文件等 关心如…

WEditor的安装和使用

WEditor 编辑器能够提供辅助编写脚本&#xff0c;查看组件信息&#xff0c;调试代码等功能。 Screenshot 安装 依赖项目 Python3.6 uiautomator2facebook-wda Only tested in Google Chrome, IE seems not working well. pip3 install -U weditor # uiautomator2, faceboo…

龙迅LT86102UXE HDMI2.0转二路HDMI2.0/1.4,支持音频剥离,支持4K60HZ

龙迅LT86102UXE 1.描述&#xff1a; 龙迅 LT86102UXE HDMI2.0 分路器具有符合 HDMI2.0/1.4 规范的 1&#xff1a;2 分路器、最大 6Gbps 高速 数据速率、自适应均衡 RX 输入和预加重 TX 输出&#xff08;用于支持长电缆应用&#xff09;、内部 TX 通道交换以 实现灵活的 PCB…

天眼查最新方式工商信息爬取(公开信息)

本章教程,主要介绍利用python效率提取天眼查公开工商信息。 官网地址:天眼查-商业查询平台_企业信息查询_公司查询_工商查询_企业信用信息系统 教程仅供参考,请勿滥用,由此带来的法律责任,需由自己承担。 1、数据预览 2、程序代码 #!/usr/bin/python # -*- coding: UTF-…

vue3结合elemplent-plus组件初始化选择日期范围

实现的效果&#xff1a; 在使用时踩了个坑&#xff0c;耽搁了俩小时时间&#xff0c;气人&#xff01;&#xff01;&#xff01;&#xff01; 注意&#xff1a; 1.获取上个月时间时必须使用正确的时间格式去获取&#xff0c;在获取时间的时候不能操作-等 2.获取到的时间必须…

物联网AI MicroPython传感器学习 之 HX711称重传感器

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 下图是一款量程为5kg的称重传感器&#xff0c;采用悬臂梁方式安装。传感器主体结构是一个开孔金属条&#xff0c;金属条上下表面各贴有两个应变电阻&#xff0c;当金属条受力发生变形时时&…

接口测试如何高效管理接口文档 !

痛点 如果你负责测试的项目是一个前后端分离的项目。 回忆下是不是有如下场景: 某个项目开发完成,接口文档发布在了 swagger 上,前后端各自进行开发。此时你负责这个项目的服务端测试。 首先进行接口测试,熟练的打开 postman 导入 swagger 文档,然后开始进行接口测试。 接口…

自动化办公篇之python

1、如果没有安装xlwings库&#xff0c;先在控制台pip install xlwings,然后点击运行&#xff0c;创建四个空excel表 。 import xlwings as xw app xw.App(visibleTrue,add_bookFalse) for dept in ["技术部","销售部","运营部","财务部&q…

2023年中国渔业研究报告

第一章 行业概况 1.1 定义 渔业&#xff0c;作为全球经济的重要支柱之一&#xff0c;其核心活动包括捕捞、水产养殖、产品加工与销售等。其不仅是食物安全的重要保障&#xff0c;还是许多沿海和内陆地区经济发展的重要动力。 首先&#xff0c;捕捞活动是渔业的基础。通过海洋…

中国走向碳中和:零碳联盟的关键角色

随着近期联合国大会上主席宣布的中国碳中和目标&#xff0c;国家的低碳转型和绿色可持续发展再次成为焦点。面对这样的国家大政方针&#xff0c;不少企业和机构纷纷响应&#xff0c;其中零碳联盟的努力与成果更是备受瞩目。 零碳联盟&#xff0c;作为中国投资协会联合多家机构…

微信小程序生成海报

效果: js1: const cloudHelper = require(../../../helper/cloud_helper.js);async function config1({cover,title,desc,qr,bg = }) {var qr1 ="images/qr.png"var qr2 ="https://636c-cloud1-0gu29f2j63906b7e-1319556650.tcb.qcloud.la/activitycomm/setu…

C++入门 —— 命名空间

命名空间 前言1. 什么是命名空间2. 命名空间的定义3. 命名空间的使用3.1 域作用限定符 ::3.2 使用using将命名空间中某个成员引入3.3 使用using namespace 命名空间名称 引入 4. cin/cout 输入输出4.1 C中的输入输入与C中的输入输出对比 所属专栏&#xff1a;C“嘎嘎" 系统…

快速自动化处理JavaScript渲染页面

在进行网络数据抓取时&#xff0c;许多网站使用了JavaScript来动态加载内容&#xff0c;这给传统的网络爬虫带来了一定的挑战。本文将介绍如何使用Selenium和ChromeDriver来实现自动化处理JavaScript渲染页面&#xff0c;并实现有效的数据抓取。 1、Selenium和ChromeDriver简介…