20、stm32使用FMC驱动SDRAM(IS42S32800G-6BLI)

本文将使用安富莱的STM32H743XIH板子驱动SDRAM
引脚连接情况
在这里插入图片描述

一、CubeMx配置工程

在这里插入图片描述
在这里插入图片描述

1、开启调试口

在这里插入图片描述

2、开启外部高速时钟

在这里插入图片描述
配置时钟树
在这里插入图片描述
在这里插入图片描述

3、开启串口1

在这里插入图片描述

4、配置MPU

按照安富莱的例程配置:

/*
*********************************************************************************************************
*	函 数 名: MPU_Config
*	功能说明: 配置MPU
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{MPU_Region_InitTypeDef MPU_InitStruct;/* 禁止 MPU */HAL_MPU_Disable();/* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */MPU_InitStruct.Enable           = MPU_REGION_ENABLE;MPU_InitStruct.BaseAddress      = 0x24000000;MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;MPU_InitStruct.Number           = MPU_REGION_NUMBER0;MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */MPU_InitStruct.Enable           = MPU_REGION_ENABLE;MPU_InitStruct.BaseAddress      = 0x60000000;MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;	/* 不能用MPU_ACCESS_CACHEABLE;会出现2次CS、WE信号 */MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;MPU_InitStruct.Number           = MPU_REGION_NUMBER1;MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* 配置SDRAM的MPU属性为Write back, Read allocate,Write allocate */MPU_InitStruct.Enable           = MPU_REGION_ENABLE;MPU_InitStruct.BaseAddress      = 0xC0000000;MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;MPU_InitStruct.Number           = MPU_REGION_NUMBER2;MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/*使能 MPU */HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}/*
*********************************************************************************************************
*	函 数 名: CPU_CACHE_Enable
*	功能说明: 使能L1 Cache
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)
{/* 使能 I-Cache */SCB_EnableICache();/* 使能 D-Cache */SCB_EnableDCache();
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5、配置FMC

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

调整引脚和硬件接线图一致
在这里插入图片描述
注意FMC时钟
在这里插入图片描述
生成代码工程…

二、编写代码

1、添加文件至工程

common_driver.c|common_driver.h
bsp.c|bsp.h
sdram_driver.c|sdram_driver.h
在这里插入图片描述

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,假-0typedef  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

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_ParameterStructDefactual_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_ParameterStructDefactual_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

bsp.h

#ifndef _bsp_H_
#define _bsp_H_
#ifdef __Cplusplus
#extern "C" {
#endif
#include "stdint.h"int32_t bsp_init(void);#ifdef __Cplusplus
}
#endif
#endif

bsp.c

/**********************************************************************
*file:板级支持包文件
*author:残梦
*versions:V1.0
*date:2023.08.10
*note:
**********************************************************************/
#include "bsp.h"
#include "common_driver.h"/****************************************
@function:板硬件初始化
@param:void
@return:小于0--失败,0--成功
@note:
****************************************/
int32_t bsp_init(void)
{return 0;
}

sdram_driver.h

#ifndef _sdram_driver_H_
#define _sdram_driver_H_
#ifdef __Cplusplus
#extern "C" {
#endif
#include "main.h"#define EXT_SDRAM_ADDR  	((uint32_t)0xC0000000)
#define EXT_SDRAM_SIZE		(32 * 1024 * 1024)/* LCD显存,第1页, 分配2M字节 */
#define SDRAM_LCD_BUF1 		EXT_SDRAM_ADDR/* LCD显存,第2页, 分配2M字节 */
#define SDRAM_LCD_BUF2		(EXT_SDRAM_ADDR + SDRAM_LCD_SIZE)#define SDRAM_LCD_SIZE		(2 * 1024 * 1024)		/* 每层2M */
#define SDRAM_LCD_LAYER		2						/* 2层 *//* 剩下的12M字节,提供给应用程序使用 */
#define SDRAM_APP_BUF		(EXT_SDRAM_ADDR + SDRAM_LCD_SIZE * SDRAM_LCD_LAYER)
#define SDRAM_APP_SIZE		(EXT_SDRAM_SIZE - SDRAM_LCD_SIZE * SDRAM_LCD_LAYER)void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram);
uint32_t bsp_TestExtSDRAM1(void);#ifdef __Cplusplus
}
#endif
#endif

sdram_driver.c

/**********************************************************************
*file:外部SDRAM驱动文件:SDRAM型号IS42S32800G-6BLI, 32位带宽, 容量32MB, 6ns速度(166MHz)
*author:残梦
*versions:V1.0
*date:2023.06.02
*note:-- 安富莱STM32-V7发板 SDRAM GPIO 定义+-------------------+--------------------+--------------------+--------------------++                       SDRAM pins assignment                                      ++-------------------+--------------------+--------------------+--------------------+| PD0  <-> FMC_D2   | PE0  <-> FMC_NBL0  | PF0  <-> FMC_A0    | PG0 <-> FMC_A10    || PD1  <-> FMC_D3   | PE1  <-> FMC_NBL1  | PF1  <-> FMC_A1    | PG1 <-> FMC_A11    || PD8  <-> FMC_D13  | PE7  <-> FMC_D4    | PF2  <-> FMC_A2    | PG4 <-> FMC_A14    || PD9  <-> FMC_D14  | PE8  <-> FMC_D5    | PF3  <-> FMC_A3    | PG5 <-> FMC_A15    || PD10 <-> FMC_D15  | PE9  <-> FMC_D6    | PF4  <-> FMC_A4    | PG8 <-> FC_SDCLK   || PD14 <-> FMC_D0   | PE10 <-> FMC_D7    | PF5  <-> FMC_A5    | PG15 <-> FMC_NCAS  || PD15 <-> FMC_D1   | PE11 <-> FMC_D8    | PF11 <-> FC_NRAS   |--------------------++-------------------| PE12 <-> FMC_D9    | PF12 <-> FMC_A6    | PG2  --- FMC_A12 (预留64M字节容量,和摇杆上键复用)| PE13 <-> FMC_D10   | PF13 <-> FMC_A7    || PE14 <-> FMC_D11   | PF14 <-> FMC_A8    || PE15 <-> FMC_D12   | PF15 <-> FMC_A9    |+-------------------+--------------------+--------------------+| PH2 <-> FMC_SDCKE0| PI4 <-> FMC_NBL2   || PH3 <-> FMC_SDNE0 | PI5 <-> FMC_NBL3   || PH5 <-> FMC_SDNW  |--------------------++-------------------++-------------------+------------------++   32-bits Mode: D31-D16              ++-------------------+------------------+| PH8 <-> FMC_D16   | PI0 <-> FMC_D24  || PH9 <-> FMC_D17   | PI1 <-> FMC_D25  || PH10 <-> FMC_D18  | PI2 <-> FMC_D26  || PH11 <-> FMC_D19  | PI3 <-> FMC_D27  || PH12 <-> FMC_D20  | PI6 <-> FMC_D28  || PH13 <-> FMC_D21  | PI7 <-> FMC_D29  || PH14 <-> FMC_D22  | PI9 <-> FMC_D30  || PH15 <-> FMC_D23  | PI10 <-> FMC_D31 |+------------------+-------------------++-------------------++  Pins remapping   ++-------------------+| PC0 <-> FMC_SDNWE || PC2 <-> FMC_SDNE0 || PC3 <-> FMC_SDCKE0|+-------------------+hsdram1.Instance = FMC_SDRAM_DEVICE;hsdram1.Init.SDBank = FMC_SDRAM_BANK1;hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;//CAS Latency可以设置Latency1,2和3,实际测试Latency3稳定hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;//禁止写保护hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;//FMC时钟200MHz,2分频后给SDRAM,即100MHzhsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;//使能读突发hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;//此位定CAS延时后延后多少个SDRAM时钟周期读取数据,实际测此位可以设置无需延迟FMC使用的HCLK3时钟,200MHz,用于SDRAM的话,至少2分频,也就是100MHz,即1个SDRAM时钟周期是10ns下面参数单位均为10ns。Timing.LoadToActiveDelay    = 2; 20ns, TMRD定义加载模式寄存器的命令与激活命令或刷新命令之间的延迟Timing.ExitSelfRefreshDelay = 7; 70ns, TXSR定义从发出自刷新命令到发出激活命令之间的延迟Timing.SelfRefreshTime      = 4; 50ns, TRAS定义最短的自刷新周期Timing.RowCycleDelay        = 7; 70ns, TRC定义刷新命令和激活命令之间的延迟Timing.WriteRecoveryTime    = 2; 20ns, TWR定义在写命令和预充电命令之间的延迟Timing.RPDelay              = 2; 20ns, TRP定义预充电命令与其它命令之间的延迟Timing.RCDDelay             = 2; 20ns, TRCD定义激活命令与读/写命令之间的延迟
*********************************************************************/
#include "sdram_driver.h"#define SDRAM_TIMEOUT                    ((uint32_t)0xFFFF)
#define REFRESH_COUNT                    ((uint32_t)1543)    /* SDRAM自刷新计数 */  /* 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)/****************************************************
@function:SDRAM初始化序列
@param:hsdram: SDRAM句柄
@return:void
@note:完成SDRAM序列初始化
****************************************************/
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{FMC_SDRAM_CommandTypeDef Command;__IO uint32_t tmpmrd =0;/*##-1- 时钟使能命令 ##################################################*/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, SDRAM_TIMEOUT);/*##-2- 插入延迟,至少100us ##################################################*/HAL_Delay(1);/*##-3- 整个SDRAM预充电命令,PALL(precharge all) #############################*/Command.CommandMode = FMC_SDRAM_CMD_PALL;Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;Command.AutoRefreshNumber = 1;Command.ModeRegisterDefinition = 0;/* 发送命令 */HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);/*##-4- 自动刷新命令 #######################################################*/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, SDRAM_TIMEOUT);/*##-5- 配置SDRAM模式寄存器 ###############################################*/tmpmrd = (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;Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;Command.AutoRefreshNumber = 1;Command.ModeRegisterDefinition = tmpmrd;/* 发送命令 */HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);/*##-6- 设置自刷新率 ####################################################*//*SDRAM refresh period / Number of rows)*SDRAM时钟速度 – 20= 64ms / 4096 *100MHz - 20= 1542.5 取值1543*/HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT); 
}/*
*********************************************************************************************************
*	函 数 名: bsp_TestExtSDRAM
*	功能说明: 扫描测试外部SDRAM的全部单元。
*	形    参: 无
*	返 回 值: 0 表示测试通过; 大于0表示错误单元的个数。
*********************************************************************************************************
*/
uint32_t bsp_TestExtSDRAM1(void)
{uint32_t i;uint32_t *pSRAM;uint8_t *pBytes;uint32_t err;const uint8_t ByteBuf[4] = {0x55, 0xA5, 0x5A, 0xAA};/* 写SRAM */pSRAM = (uint32_t *)EXT_SDRAM_ADDR;for (i = 0; i < EXT_SDRAM_SIZE / 4; i++){*pSRAM++ = i;}/* 读SRAM */err = 0;pSRAM = (uint32_t *)EXT_SDRAM_ADDR;for (i = 0; i < EXT_SDRAM_SIZE / 4; i++){if (*pSRAM++ != i){err++;}}if (err >  0){return  (4 * err);}/* 对SRAM 的数据求反并写入 */pSRAM = (uint32_t *)EXT_SDRAM_ADDR;for (i = 0; i < EXT_SDRAM_SIZE / 4; i++){*pSRAM = ~*pSRAM;pSRAM++;}/* 再次比较SDRAM的数据 */err = 0;pSRAM = (uint32_t *)EXT_SDRAM_ADDR;for (i = 0; i < EXT_SDRAM_SIZE / 4; i++){if (*pSRAM++ != (~i)){err++;}}if (err >  0){return (4 * err);}/* 测试按字节方式访问, 目的是验证 FSMC_NBL0 、 FSMC_NBL1 口线 */pBytes = (uint8_t *)EXT_SDRAM_ADDR;for (i = 0; i < sizeof(ByteBuf); i++){*pBytes++ = ByteBuf[i];}/* 比较SDRAM的数据 */err = 0;pBytes = (uint8_t *)EXT_SDRAM_ADDR;for (i = 0; i < sizeof(ByteBuf); i++){if (*pBytes++ != ByteBuf[i]){err++;}}if (err >  0){return err;}return 0;
}

2、fmc.c初始化后添加SDRAM初始序列

添加头文件

/* USER CODE BEGIN 0 */
#include "sdram_driver.h"
/* USER CODE END 0 */

void MX_FMC_Init(void)函数中添加

  /* USER CODE BEGIN FMC_Init 2 */SDRAM_Initialization_Sequence(&hsdram1);//添加SDRAM初始序列/* USER CODE END FMC_Init 2 */

3、main.c文件对sdram读写测试

main.c文件

/* 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 "bsp.h"
#include "common_driver.h"
#include "sdram_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 */if(bsp_init() < 0){printf("error:bsp_init()\r\n");Error_Handler();}/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */printf("错误数:%d\r\n",bsp_TestExtSDRAM1());//SDRAM读写测试HAL_Delay(1000);}/* 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 = 5;RCC_OscInitStruct.PLL.PLLN = 160;RCC_OscInitStruct.PLL.PLLP = 2;RCC_OscInitStruct.PLL.PLLQ = 2;RCC_OscInitStruct.PLL.PLLR = 2;RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;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 *//* 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 = 0x24000000;MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;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);/** Initializes and configures the Region and the memory to be protected*/MPU_InitStruct.Number = MPU_REGION_NUMBER1;MPU_InitStruct.BaseAddress = 0x60000000;MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/** Initializes and configures the Region and the memory to be protected*/MPU_InitStruct.Number = MPU_REGION_NUMBER2;MPU_InitStruct.BaseAddress = 0xC0000000;MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_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)\r\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****/

三、测试结果及完整工程

测试结果ok
在这里插入图片描述
完整工程:
链接:https://pan.baidu.com/s/1SfxQO7QM_e1GsVD_yJOckg
提取码:hk7u

三、本章学习笔记(待写)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双链表的插入,删除以及遍历

在上一节我们讲解了单链表的头插法和尾插法 http://t.csdn.cn/RixAu 但是单链表无法反向检索&#xff0c;对于某些情景可能造成不便&#xff0c;所以我们今天学习双链表 目录 1.双链表的初始化 2.双链表的插入 3.双链表的删除 4.遍历双链表 1.双链表的初始化 typedef i…

(二)结构型模式:8、代理模式(Proxy Pattern)(C++示例)

目录 1、代理模式&#xff08;Proxy Pattern&#xff09;含义 2、代理模式的UML图学习 3、代理模式的应用场景 4、代理模式的优缺点 5、C实现代理模式的实例 1、代理模式&#xff08;Proxy Pattern&#xff09;含义 代理模式&#xff08;Proxy&#xff09;&#xff0c;为…

离谱的Bug

离谱的 Bug Bug 情况发现 Bug修改 Bug其他感受历史 Bug火星Spirit号Mars Global Surveyor任务 Bug 情况 有一次&#xff0c;我在开发一个网页应用程序时&#xff0c;遇到了一个令人目瞪口呆的Bug。这个Bug出现在一个特定的页面上&#xff0c;当用户点击某个按钮时&#xff0c;…

智安网络|深入比较:Sass系统与源码系统的差异及选择指南

随着前端开发的快速发展&#xff0c;开发人员需要使用更高效和灵活的工具来处理样式表。在这个领域&#xff0c;Sass系统和源码系统是两个备受关注的选项。 Sass系统 Sass&#xff08;Syntactically Awesome Style Sheets&#xff09;是一种CSS预处理器&#xff0c;它扩展了CS…

在 OpenCV 中使用深度学习进行年龄检测-附源码

文末附完整源码和模型文件下载链接 在本教程中,我们将了解使用 OpenCV 创建年龄预测器和性别分类器项目的整个过程。 年龄检测 我们的目标是创建一个程序,使用图像来预测人的性别和年龄。但预测年龄可能并不像你想象的那么简单,为什么呢?您可能会认为年龄预测是一个回归问…

【Linux命令详解 | wget命令】 wget命令用于从网络下载文件,支持HTTP、HTTPS和FTP协议

文章标题 简介一&#xff0c;参数列表二&#xff0c;使用介绍1. 基本文件下载2. 递归下载整个网站3. 限制下载速率4. 防止SSL证书校验5. 断点续传6. 指定保存目录7. 自定义保存文件名8. 增量下载9. 使用HTTP代理10. 后台下载 总结 简介 在编程世界中&#xff0c;处理网络资源是…

快速搭建图书商城小程序的简易流程与优势

很多人喜欢阅读电子书&#xff0c;又有很多人依旧喜欢实体书&#xff0c;而实体书店拥有一个图书商城小程序便成为了满足用户需求的理想选择。如果您也想进入这一充满潜力的领域&#xff0c;但担心开发难度和复杂流程&#xff0c;别担心&#xff01;您能做到快速搭建一个专业、…

CXL 寄存器介绍 (1) - 寄存器分类

&#x1f525;点击查看精选 CXL 系列文章&#x1f525; &#x1f525;点击进入【芯片设计验证】社区&#xff0c;查看更多精彩内容&#x1f525; &#x1f4e2; 声明&#xff1a; &#x1f96d; 作者主页&#xff1a;【MangoPapa的CSDN主页】。⚠️ 本文首发于CSDN&#xff0c…

Mac安装opencv后无法导入cv2的解决方法

前提条件&#xff1a;以下两个插件安装成功 pip install opencv-python pip install --user opencv-contrib-python 注&#xff1a;直接用pip install opencv-contrib-python如果报错&#xff0c;就加上“–user" 第一步&#xff1a; 设置–添加python解释器 第二步&am…

机器学习|Softmax 回归的数学理解及代码解析

机器学习&#xff5c;Softmax 回归的数学理解及代码解析 Softmax 回归是一种常用的多类别分类算法&#xff0c;适用于将输入向量映射到多个类别的概率分布。在本文中&#xff0c;我们将深入探讨 Softmax 回归的数学原理&#xff0c;并提供 Python 示例代码帮助读者更好地理解和…

Python入门--关键字

关键字是Python编程语言中具有特殊含义的保留单词&#xff0c;不能用作变量名、函数名、类名或其他标识符。以下是Python 3.9.0版本中的关键字列表&#xff1a; False, None, True, and, as, assert, async, await, break, class, continue, def, del, elif, else, except, f…

Microsoft 图像BERT,基于大规模图文数据的跨模态预训练

视觉语言任务是当今自然语言处理&#xff08;NLP&#xff09;和计算机视觉领域的热门话题。大多数现有方法都基于预训练模型&#xff0c;这些模型使用后期融合方法融合下游任务的多模态输入。然而&#xff0c;这种方法通常需要在训练期间进行特定的数据注释&#xff0c;并且对于…

web前端开发基础入门html5+css3+js学习笔记(一)

目录 1.第一个前端程序2.前端工具的选择与安装3.VSCode开发者工具快捷键4.HTML5简介与基础骨架4.1 HTML5的DOCTYPE声明4.2 HTML5基本骨架4.2.1 html标签4.2.2 head标签4.2.3 body标签4.2.4 title标签4.2.5 meta标签 5.标签之标题5.1 快捷键5.1 标题标签位置摆放 6.标签之段落、…

Docker实战专栏简介

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

星星之火:国产讯飞星火大模型的实际使用体验(与GPT对比)

#AIGC技术内容创作征文&#xff5c;全网寻找AI创作者&#xff0c;快来释放你的创作潜能吧&#xff01;# 文章目录 1 前言2 测试详情2.1 文案写作2.2 知识写作2.3 阅读理解2.4 语意测试&#xff08;重点关注&#xff09;2.5 常识性测试&#xff08;重点关注&#xff09;2.6 代码…

深入学习SpringCloud Alibaba微服务架构,揭秘Nacos、Sentinel、Seata等核心技术,助力构建高效系统!

课程链接&#xff1a; 链接: https://pan.baidu.com/s/1hRN0R8VFcwjyCTWCEsz-8Q?pwdj6ej 提取码: j6ej 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; &#x1f4da;【第01阶段】课程简介&#xff1a;全…

flinksql实时统计程序背压延迟优化

问题&#xff1a; flinkcdcflinksql做实时读取sls日志和实时统计业务指标&#xff0c;今天发现程序背压了&#xff0c;业务延迟了6个小时。解决办法&#xff1a; 1、资源优化 作业并发大时&#xff1a;在作业的高级配置的资源配置中&#xff0c;增加JobManager的资源&#xf…

2023国赛数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

创新零售,京东重新答题?

继新一轮组织架构调整后&#xff0c;京东从低价到下沉动作不断。 新成立的创新零售部在京东老将闫小兵的带领下悄然完成了整合。近日&#xff0c;京喜拼拼已改名为京东拼拼&#xff0c;与七鲜、前置仓等业务共同承载起京东线上线下加速融合的梦想。 同时&#xff0c;拼拼的更…

接口自动化测试

1、生活中面临的问题:当前我们面临的这个bug修改好了&#xff0c;但是在其他地方又出现了新的bug&#xff0c;如何能够提前发现bug那 1.1 功能测试----是通过页面发送请求 1.2 接口测试---可以直接利用工具向服务器发送数据做一个结果验证 1.3 功能测试是在联调通过后进行开展的…