建设网站公司哪家好,深圳住房城乡建设局网站,长春通信网络,福田公司名称及地址引入 随着单片机的性能提高#xff0c;我们想要在单片机上实现的功能有时需要外扩彩色屏幕#xff0c;但是单片机的内存太小#xff0c;而屏幕需要的缓存又太大#xff0c;因此扩展出了外置的RAM#xff0c;RAM又分为静态随机存储器和动态随机存储器#xff0c;在这里我介…引入 随着单片机的性能提高我们想要在单片机上实现的功能有时需要外扩彩色屏幕但是单片机的内存太小而屏幕需要的缓存又太大因此扩展出了外置的RAMRAM又分为静态随机存储器和动态随机存储器在这里我介绍动态随机存储器SDRAM在STM32上的配置。
一、SDRAM简介 SDRAM是动态随机存储器Synchronous Dynamic Random-Access Memory的简称相比较SRAM他的读写速率可能没有SRAM那么快因为需要留时间给刷新但是他的造价低容量一般可以做的很大。本章节用的是基于野火的STM32F429-V1开发板。
二、SDRAM在STM32上的配置 SDRAM的使用需要用到FMC即“可变存储控制器”本章节以STM32F429IGT6为例FMC在F4系列中支持的型号仅仅只有“STM32F42xxx 和 STM32F43xxx”且在STM32F4的中文草考手册中没有反而在另外一个F4的参考手册中提及。、 本章节代码采用HAL库要用FMC驱动SDRAM就得进行初始化。 初始化代码大概分为以下步骤 1.初始化GPIO开启时钟,并且复用为FMC GPIO的初始化可以由CubeMX配置因为引脚很多这里配置BANK2。
static void SDRAM_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct {0};/* Peripheral clock enable */__HAL_RCC_FMC_CLK_ENABLE();__HAL_RCC_GPIOF_CLK_ENABLE();__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOG_CLK_ENABLE();__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/* GPIO_InitStruct *//** FMC GPIO ConfigurationPF0 ------ FMC_A0PF1 ------ FMC_A1PF2 ------ FMC_A2PF3 ------ FMC_A3PF4 ------ FMC_A4PF5 ------ FMC_A5PC0 ------ FMC_SDNWEPF11 ------ FMC_SDNRASPF12 ------ FMC_A6PF13 ------ FMC_A7PF14 ------ FMC_A8PF15 ------ FMC_A9PG0 ------ FMC_A10PG1 ------ FMC_A11PE7 ------ FMC_D4PE8 ------ FMC_D5PE9 ------ FMC_D6PE10 ------ FMC_D7PE11 ------ FMC_D8PE12 ------ FMC_D9PE13 ------ FMC_D10PE14 ------ FMC_D11PE15 ------ FMC_D12PH6 ------ FMC_SDNE1PH7 ------ FMC_SDCKE1PD8 ------ FMC_D13PD9 ------ FMC_D14PD10 ------ FMC_D15PD14 ------ FMC_D0PD15 ------ FMC_D1PG4 ------ FMC_BA0PG5 ------ FMC_BA1PG8 ------ FMC_SDCLKPD0 ------ FMC_D2PD1 ------ FMC_D3PG15 ------ FMC_SDNCASPE0 ------ FMC_NBL0PE1 ------ FMC_NBL1*/GPIO_InitStruct.Pin GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;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);/* GPIO_InitStruct */GPIO_InitStruct.Pin GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15;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_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|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(GPIOE, GPIO_InitStruct);/* GPIO_InitStruct */GPIO_InitStruct.Pin GPIO_PIN_6|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_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14|GPIO_PIN_15|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(GPIOD, GPIO_InitStruct);} 2.初始化SDRAM控制器 SDRAM控制器的相关参数可以在手册中找到 SDRAM_HandleTypeDef hsdram2;FMC_SDRAM_TimingTypeDef SdramTiming {0};hsdram2.Instance FMC_SDRAM_DEVICE;/* hsdram2.Init */hsdram2.Init.SDBank FMC_SDRAM_BANK2; // 初始化 BANK2hsdram2.Init.ColumnBitsNumber FMC_SDRAM_COLUMN_BITS_NUM_8; // 列地址位 8hsdram2.Init.RowBitsNumber FMC_SDRAM_ROW_BITS_NUM_12; //行地址位 12hsdram2.Init.MemoryDataWidth FMC_SDRAM_MEM_BUS_WIDTH_16; //数据宽度 16位hsdram2.Init.InternalBankNumber FMC_SDRAM_INTERN_BANKS_NUM_4; //SDRAM的BANK的数量 4hsdram2.Init.CASLatency FMC_SDRAM_CAS_LATENCY_3; //CAS延时 3 个周期hsdram2.Init.WriteProtection FMC_SDRAM_WRITE_PROTECTION_DISABLE; //失能写保护hsdram2.Init.SDClockPeriod FMC_SDRAM_CLOCK_PERIOD_2; //SDRAM时钟分频 2 分频 180/2 143hsdram2.Init.ReadBurst FMC_SDRAM_RBURST_ENABLE; //使能读突发hsdram2.Init.ReadPipeDelay FMC_SDRAM_RPIPE_DELAY_0; //管道延时 0/* SdramTiming */SdramTiming.LoadToActiveDelay 2; //退出自刷新延时 tXSRSdramTiming.SelfRefreshTime 5; //加载模式寄存器到激活 tMRDSdramTiming.ExitSelfRefreshDelay 7; //自刷新延时tRASSdramTiming.RowCycleDelay 7; //行循环延时 tRCSdramTiming.WriteRecoveryTime 3; //写恢复时间 tWRSdramTiming.RPDelay 2; //行预充电延时 tRPSdramTiming.RCDDelay 2; //行到列延时 tRCDHAL_SDRAM_Init(hsdram2, SdramTiming);//初始化SDRAM外设 此图的Row Address 代表行地址引脚一共12个Column Address代表列地址的引脚一共8个他们是分时复用的第一个参数页提示了这个SDRAM有四个bank以及数据宽度。 图一显示的是不同芯片的最大时钟以及其他配置选项429的始终是180MHz而核心板的芯片是-7因此最大频率不超过143CAS为3这里配置为3因此配置 hsdram2.Init.SDClockPeriod FMC_SDRAM_CLOCK_PERIOD_2; //SDRAM时钟分频 2 分频 180/2 143 90MHz对应的时间大致为11ns 此外的其他配置如写保护给失能管道延时跟在CAS延时后边为0并且使能突发读。
此外还需配置“7个时间”用来配合SDRAM控制器和SDRAM的通信。 1.退出自刷新时间 tXSR
他在手册中定义如下从左到右依次是-5 -6 -7 这里为不小于70ns那就配置为7
SdramTiming.ExitSelfRefreshDelay 7; 2.加载模式寄存器到激活时间 tMRD 这里为两个时钟周期那么就为2
SdramTiming.LoadToActiveDelay 2; 3.自刷新时间tRAS 这里为不小于42ns就填为5
SdramTiming.SelfRefreshTime 5; 4.行循环延时 tRC 这里最小为63ns则配置为7
SdramTiming.RowCycleDelay 7; 5.写恢复时间 tWR 这里最小为两个时钟则配置为3满足某个特定条件 tWR tRAS - tRCD
SdramTiming.WriteRecoveryTime 3; 6.行预充电延时 tRP 这里不低于15ns则配置为2
SdramTiming.RPDelay 2; 7.行到列延时 tRCD 这里不低于15ns则配置为2
SdramTiming.RCDDelay 2;
最后初始化SDRAM控制器 3.发送控制命令到SDRAM
发送命令由函数HAL_SDRAM_SendCommand完成 a.给 SDRAM 提供时钟 b.延时至少100us c.给 SDRAM 的所有 BANK 预充电 d.插入8个自动刷新周期 e.配置加载模式寄存器 f.配置 SDRAM 自动刷新周期
发送命令代码如下 static void SDRAM_Cmmand(void)
{FMC_SDRAM_CommandTypeDef FMC_SDRAM_CommandStruct {0};//1 给 SDRAM 提供时钟FMC_SDRAM_CommandStruct.CommandMode FMC_SDRAM_CMD_CLK_ENABLE; //启用时钟FMC_SDRAM_CommandStruct.AutoRefreshNumber 1; //自动刷新数无关命令写默认值FMC_SDRAM_CommandStruct.CommandTarget FMC_SDRAM_CMD_TARGET_BANK2; //发送到BANK2FMC_SDRAM_CommandStruct.ModeRegisterDefinition 0; //加载模式寄存器值无关命令写默认值HAL_SDRAM_SendCommand(hsdram2,FMC_SDRAM_CommandStruct,TIME_OUT);
//2 延时至少100usHAL_Delay(1);//3 给 SDRAM 的所有 BANK 预充电FMC_SDRAM_CommandStruct.CommandMode FMC_SDRAM_CMD_PALL; //预充电FMC_SDRAM_CommandStruct.AutoRefreshNumber 1; //自动刷新数无关命令写默认值FMC_SDRAM_CommandStruct.CommandTarget FMC_SDRAM_CMD_TARGET_BANK2; //发送到BANK2FMC_SDRAM_CommandStruct.ModeRegisterDefinition 0; //加载模式寄存器值无关命令写默认值HAL_SDRAM_SendCommand(hsdram2,FMC_SDRAM_CommandStruct,TIME_OUT);//4 插入8个自动刷新周期FMC_SDRAM_CommandStruct.CommandMode FMC_SDRAM_CMD_AUTOREFRESH_MODE; //自动刷新FMC_SDRAM_CommandStruct.AutoRefreshNumber 4; //自动刷新数FMC_SDRAM_CommandStruct.CommandTarget FMC_SDRAM_CMD_TARGET_BANK2; //发送到BANK2FMC_SDRAM_CommandStruct.ModeRegisterDefinition 0; //加载模式寄存器值无关命令写默认值HAL_SDRAM_SendCommand(hsdram2,FMC_SDRAM_CommandStruct,TIME_OUT);
//5 配置加载模式寄存器uint32_t ModeRegister SDRAM_MODEREG_BURST_LENGTH_4 \| SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL\| SDRAM_MODEREG_CAS_LATENCY_3\| SDRAM_MODEREG_OPERATING_MODE_STANDARD\| SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;FMC_SDRAM_CommandStruct.CommandMode FMC_SDRAM_CMD_LOAD_MODE; //加载模式寄存器FMC_SDRAM_CommandStruct.AutoRefreshNumber 1; //自动刷新数无关命令写默认值FMC_SDRAM_CommandStruct.CommandTarget FMC_SDRAM_CMD_TARGET_BANK2; //发送到BANK2FMC_SDRAM_CommandStruct.ModeRegisterDefinition ModeRegister; //加载模式寄存器值HAL_SDRAM_SendCommand(hsdram2,FMC_SDRAM_CommandStruct,TIME_OUT);//6 配置 SDRAM 自动刷新周期 HAL_SDRAM_ProgramRefreshRate(hsdram2,1386); //(64x10^-6 s /4096) x 90x10^6Hz - 20}其中初始阿虎过程可以在手册中找到 翻译大致如下可能不准确以英文原文为主
初始化Initialization
SDRAM 必须按照预定义的方式上电并初始化。 当电源同时加到 VDD 和 VDDQ上并且时钟稳定DQM 为高电平CKE 为高电平之后64Mb 的 SDRAM 才会开始初始化。 在发送除 COMMAND INHIBIT 或 NOP 命令之外的任何命令之前需要等待 100 微秒。在这 100 微秒期间可以持续发送 COMMAND INHIBIT 或 NOP 命令并应至少持续到 100 微秒结束。 在至少发送一次 COMMAND INHIBIT 或 NOP 命令之后一旦 100 微秒延时完成就应发送 PRECHARGE 命令所有的 bank 必须被预充电Precharged。这将使所有 bank 进入空闲状态。 随后至少执行两次自动刷新AUTO REFRESH命令。自动刷新命令完成之后SDRAM 就可以准备好进行模式寄存器Mode Register的设置。 在执行任何操作命令之前应先加载模式寄存器因为上电后 SDRAM 处于未知状态。执行完 Load Mode Register 命令之后至少要执行一次 NOP 命令然后才可以执行其他命令。 总结起来和以上配置并无二异不过最后还得配置 SDRAM 自动刷新周期 他的计算公式如下图手册中 由SDRAM手册可知 行数为4096行SDRAM的时钟已经被设置为90MHz刷新4096次需要64ms
那么最后的结果就是 (64x10^-6 s /4096) x 90x10^6Hz - 20 1386 整个初始化代码就是
void SDRAM_Init(void)
{SDRAM_GPIO_Init();//初始化GPIOFMC_SDRAM_TimingTypeDef SdramTiming {0};hsdram2.Instance FMC_SDRAM_DEVICE;/* hsdram2.Init */hsdram2.Init.SDBank FMC_SDRAM_BANK2; // 初始化 BANK2hsdram2.Init.ColumnBitsNumber FMC_SDRAM_COLUMN_BITS_NUM_8; // 列地址位 8hsdram2.Init.RowBitsNumber FMC_SDRAM_ROW_BITS_NUM_12; //行地址位 12hsdram2.Init.MemoryDataWidth FMC_SDRAM_MEM_BUS_WIDTH_16; //数据宽度 16位hsdram2.Init.InternalBankNumber FMC_SDRAM_INTERN_BANKS_NUM_4; //SDRAM的BANK的数量 4hsdram2.Init.CASLatency FMC_SDRAM_CAS_LATENCY_3; //CAS延时 3 个周期hsdram2.Init.WriteProtection FMC_SDRAM_WRITE_PROTECTION_DISABLE; //失能写保护hsdram2.Init.SDClockPeriod FMC_SDRAM_CLOCK_PERIOD_2; //SDRAM时钟分频 2 分频 180/2 133hsdram2.Init.ReadBurst FMC_SDRAM_RBURST_ENABLE; //使能读突发hsdram2.Init.ReadPipeDelay FMC_SDRAM_RPIPE_DELAY_0; //管道延时 0/* SdramTiming */SdramTiming.LoadToActiveDelay 2; //加载模式寄存器到激活 tMRDSdramTiming.ExitSelfRefreshDelay 7; //退出自刷新延时 tXSRSdramTiming.SelfRefreshTime 5; //自刷新延时tRASSdramTiming.RowCycleDelay 7; //行循环延时 tRCSdramTiming.WriteRecoveryTime 3; //写恢复时间 tWRSdramTiming.RPDelay 2; //行预充电延时 tRPSdramTiming.RCDDelay 2; //行到列延时 tRCDHAL_SDRAM_Init(hsdram2, SdramTiming);//初始化SDRAM外设SDRAM_Cmmand();//初始化SDRAM
} 在主函数调用即可通过指针访问SDRAM由于这里是用的BANK2因此它的起始地址是0xD0000000 。 在主函数中将一张150kb的图片复制到SDRAM然后读出来显示在屏幕中
int main()
{HAL_Init();SystemClock_Config();UsartInit(115200);SDRAM_Init();SPI_LCD_Init();LCD_SetColor(COLOR_LIME);LCD_SetBackColor(COLOR_BLACK);LCD_Clear();LCD_SetDirection(Direction_H_Flip);LCD_SetTextFont(CH_Font32);uint32_t* add1 (uint32_t*)0xD0000000;memcpy(add1,gImage_cat,153600);LCD_DrawColorImage(0,0,320,240,(uint8_t*)add1);while(1){}
} 最后的结果