#include "fmc.h" #include "bsp_sdram.h" extern SDRAM_HandleTypeDef hsdram1; static FMC_SDRAM_CommandTypeDef Command; static SDRAM_HandleTypeDef *sdramHandle = &hsdram1; MY_SDRAM_TypeDef my_sdram ={ SDRAM_Init, SDRAM_Test, }; static void SDRAM_delay(__IO uint32_t nCount) { __IO uint32_t index = 0; for (index = (100000 * nCount); index != 0; index--) { } } void SDRAM_Init() { // MX_FMC_Init(); SDRAM_Initialization_Sequence(sdramHandle); } void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram) { uint32_t temp = 0; // SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM SDRAM_Send_Cmd(2, FMC_SDRAM_CMD_CLK_ENABLE, 1, 0); // 时钟配置使能 HAL_Delay(1); // delay_us(500); //至少延时200us SDRAM_Send_Cmd(2, FMC_SDRAM_CMD_PALL, 1, 0); // 对所有存储区预充电 SDRAM_Send_Cmd(2, FMC_SDRAM_CMD_AUTOREFRESH_MODE, 8, 0); // 设置自刷新次数 // 配置模式寄存器,SDRAM的bit0~bit2为指定突发访问的长度, // bit3为指定突发访问的类型,bit4~bit6为CAS值,bit7和bit8为运行模式 // bit9为指定的写突发模式,bit10和bit11位保留位 temp = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | // 设置突发长度:1(可以是1/2/4/8) SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | // 设置突发类型:连续(可以是连续/交错) SDRAM_MODEREG_CAS_LATENCY_3 | // 设置CAS值:3(可以是2/3) SDRAM_MODEREG_OPERATING_MODE_STANDARD | // 设置操作模式:0,标准模式 SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; // 设置突发写模式:1,单点访问 SDRAM_Send_Cmd(2, FMC_SDRAM_CMD_LOAD_MODE, 1, temp); // 设置SDRAM的模式寄存器 // 刷新频率计数器(以SDCLK频率计数),计算方法: // COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数 // 我们使用的SDRAM刷新周期为64ms,SDCLK=216/2=108Mhz,行数为8192(2^13). // 所以,COUNT=64*1000*108/8192-20=823 // 168 MHz COUNT=64*1000*84 /8192-20= 3656 HAL_SDRAM_ProgramRefreshRate(sdramHandle, 823); } // 向SDRAM发送命令 // bankx:2,向BANK2上面的SDRAM发送指令 FMC_SDRAM_CMD_TARGET_BANK2 SDCKE1+SDNE1 // 1,向BANK1上面的SDRAM发送指令 FMC_SDRAM_CMD_TARGET_BANK1 SDCKE0+SDNE0 // cmd:指令(0,正常模式/1,时钟配置使能/2,预充电所有存储区/3,自动刷新/4,加载模式寄存器/5,自刷新/6,掉电) // refresh:自刷新次数 // regval:模式寄存器的定义 // 返回值:0,正常;1,失败. uint8_t SDRAM_Send_Cmd(uint8_t bankx, uint8_t cmd, uint8_t refresh, uint16_t regval) { uint32_t target_bank = 0; FMC_SDRAM_CommandTypeDef Command; if (bankx == 1) target_bank = FMC_SDRAM_CMD_TARGET_BANK1; else if (bankx == 2) target_bank = FMC_SDRAM_CMD_TARGET_BANK2; Command.CommandMode = cmd; // 命令 Command.CommandTarget = target_bank; // 目标SDRAM存储区域 Command.AutoRefreshNumber = refresh; // 自刷新次数 Command.ModeRegisterDefinition = regval; // 要写入模式寄存器的值 if (HAL_SDRAM_SendCommand(sdramHandle, &Command, 0X1000) == HAL_OK) // 向SDRAM发送命令 { return 0; } else return 1; } // 在指定地址(WriteAddr+Bank5_SDRAM_ADDR)开始,连续写入n个字节. // pBuffer:字节指针 // WriteAddr:要写入的地址 // n:要写入的字节数 void FMC_SDRAM_WriteBuffer(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t n) { for (; n != 0; n--) { *(volatile unsigned char *)(Bank4_SDRAM_ADDR + WriteAddr) = *pBuffer; WriteAddr++; pBuffer++; } } // 在指定地址((WriteAddr+Bank5_SDRAM_ADDR))开始,连续读出n个字节. // pBuffer:字节指针 // ReadAddr:要读出的起始地址 // n:要写入的字节数 void FMC_SDRAM_ReadBuffer(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t n) { for (; n != 0; n--) { *pBuffer++ = *(volatile unsigned char *)(Bank4_SDRAM_ADDR + ReadAddr); ReadAddr++; } } uint8_t SDRAM_Test(uint32_t count) { /*写入数据计数器*/ uint32_t counter = 0; uint8_t ubWritedata_8b = 0, ubReaddata_8b = 0; uint16_t uhWritedata_16b = 0, uhReaddata_16b = 0; /*按8位格式读写数据,并校验*/ for (counter = 0x00; counter < count; counter++) { *(__IO uint8_t *)(Bank4_SDRAM_ADDR + counter) = (uint8_t)0x0; } /* 向整个SDRAM写入数据 8位 */ for (counter = 0; counter < count; counter++) { *(__IO uint8_t *)(Bank4_SDRAM_ADDR + counter) = (uint8_t)(ubWritedata_8b + counter); } /* 读取 SDRAM 数据并检测*/ for (counter = 0; counter < count; counter++) { ubReaddata_8b = *(__IO uint8_t *)(Bank4_SDRAM_ADDR + counter); // 从该地址读出数据 if (ubReaddata_8b != (uint8_t)(ubWritedata_8b + counter)) // 检测数据,若不相等,跳出函数,返回检测失败结果。 { // SDRAM_ERROR("8位数据读写错误!"); return 0; } } /*按16位格式读写数据,并检测*/ /* 把SDRAM数据全部重置为0 */ for (counter = 0x00; counter < count / 2; counter++) { *(__IO uint16_t *)(Bank4_SDRAM_ADDR + 2 * counter) = (uint16_t)0x00; } /* 向整个SDRAM写入数据 16位 */ for (counter = 0; counter < count / 2; counter++) { *(__IO uint16_t *)(Bank4_SDRAM_ADDR + 2 * counter) = (uint16_t)(uhWritedata_16b + counter); } /* 读取 SDRAM 数据并检测*/ for (counter = 0; counter < count / 2; counter++) { uhReaddata_16b = *(__IO uint16_t *)(Bank4_SDRAM_ADDR + 2 * counter); // 从该地址读出数据 if (uhReaddata_16b != (uint16_t)(uhWritedata_16b + counter)) // 检测数据,若不相等,跳出函数,返回检测失败结果。 { // SDRAM_ERROR("16位数据读写错误!"); return 0; } } /*检测正常,return 1 */ return 1; }