历史上的今天
返回首页

历史上的今天

今天是:2025年06月04日(星期三)

正在发生

2018年06月04日 | 基于STM32F429的SDRAM使用

2018-06-04 来源:eefocus

使用ST的HAL库进行开发,SDRAM使用的是W9825G6KH-6。

W9825G6KH-6共有4个Bank,13位行地址,9位列地址,位宽是16位,

所以芯片的容量是:4x8192x512x16=256Mbits=32MBytes。

W9825G6KH-6的原理图如下:


FMC_D0~15:16位数据线;

FMC_A0~12:13位地址线,行地址与列地址是公用的,作为行地址时使用了0~12位,作为列地址时使用了0~8位;

FMC_SDNWE:低电平时写,高电平时读;

FMC_SDNCAS:列地址选通信号,低电平有效;

FMC_SDNRAS:行地址选通信号,低电平有效;

FMC_SDNE0:片选信号,低电平有效;

FMC_BA0~1:Bank选择信号;

FMC_SDCKE0:时钟使能信号;

FMC_SDCLK:时钟信号;

FMC_NBL0~1:写访问的输出字节屏蔽。


STM32F429自带FMC外设,可以对多种外部存储器进行控制,存储区域对应如下:


我们使用的是Bank5,也就是SDRAM Bank1。

我们要做的就是对SDRAM进行初始化配置,初始化成功后即可对指定的内存进行访问,单片机和外部SDRAM之间的读写时序

是由外设自动产生的,不需要程序进行控制,非常方便。

STM32F4xx参考手册中对SDRAM的初始化过程如下:


使用STM32CubeMx生成FMC的初始化代码,如下:

void MX_FMC_Init(void)  

{  

    FMC_SDRAM_TimingTypeDef SdramTiming;  

  

    /** Perform the SDRAM1 memory initialization sequence 

    */  

    hsdram1.Instance = FMC_SDRAM_DEVICE;  

    /* hsdram1.Init */  

    hsdram1.Init.SDBank = FMC_SDRAM_BANK1;                              //使用SDRAM Bank1  

    hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;        //列宽度9位  

    hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;             //行宽度13位  

    hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;          //数据总线为16位  

    hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;     //SDRAM内部Bank数为4个  

    hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;                  //CAS为3,表示发送完读时序后延迟3个时钟周期返回数据  

    hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;  //忽略写保护  

    hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;              //SDRAM时钟SDCLK = HCLK/2 = 180MHz / 2 = 90MHz  

    hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;                   //失能突然读模式  

    hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;               //读通道延时1个时钟周期,在CAS延时后延时读取数据的时钟个数  

    /* SdramTiming */  

    SdramTiming.LoadToActiveDelay = 2;                                  //TMRD/TRSC,2个时钟周期  

    SdramTiming.ExitSelfRefreshDelay = 8;                               //TXSR,8个时钟周期  

    SdramTiming.SelfRefreshTime = 6;                                    //TRAS,6个时钟周期  

    SdramTiming.RowCycleDelay = 6;                                      //TRC,6个时钟周期  

    SdramTiming.WriteRecoveryTime = 4;                                  //TWR,4个时钟周期  

    SdramTiming.RPDelay = 2;                                            //TRP,2个时钟周期  

    SdramTiming.RCDDelay = 2;                                           //TRCD,2个时钟周期  

      

    if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)  

    {  

        _Error_Handler(__FILE__, __LINE__);  

    }  

}  

上述FMC的初始化代码完成了SDRAM初始化中的1、2两个步骤;

接下来添加SDRAM初始化中的步骤3~8:



uint8_t SDRAM_SendCommand(uint32_t CommandMode, uint32_t Bank, uint32_t RefreshNum, uint32_t RegVal)  

{  

    uint32_t CommandTarget;  

    FMC_SDRAM_CommandTypeDef Command;  

      

    if(Bank == 1)  

        CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;  

    else if(Bank == 2)  

        CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;  

      

    Command.CommandMode = CommandMode;  

    Command.CommandTarget = CommandTarget;  

    Command.AutoRefreshNumber = RefreshNum;  

    Command.ModeRegisterDefinition = RegVal;  

    if(HAL_SDRAM_SendCommand(&hsdram1, &Command, 0x1000) == HAL_OK)  

        return 1;  

    else  

        return 0;  

}  


void SDRAM_Init(void)  

{  

    uint32_t temp;  

      

    SDRAM_SendCommand(FMC_SDRAM_CMD_CLK_ENABLE, 1, 1, 0);           //步骤3:使能时钟信号,SDCKE0 = 1  

    Delay_us(500);                                                  //步骤4:至少延时200us  

    SDRAM_SendCommand(FMC_SDRAM_CMD_PALL, 1, 1, 0);                 //步骤5:发送全部预充电命令  

    SDRAM_SendCommand(FMC_SDRAM_CMD_AUTOREFRESH_MODE, 1, 8, 0);     //步骤6:设置自动刷新次数  

      

    temp = SDRAM_MODEREG_BURST_LENGTH_1     |                       //设置突发长度:1  

    SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL     |                       //设置突发类型:连续  

    SDRAM_MODEREG_CAS_LATENCY_3             |                       //设置CAS值:3  

    SDRAM_MODEREG_OPERATING_MODE_STANDARD   |                       //设置操作模式:标准  

    SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;                           //设置突发写模式:单点访问  

    SDRAM_SendCommand(FMC_SDRAM_CMD_LOAD_MODE, 1, 1, temp);         //步骤7:装载模式寄存器的值  

      

    //SDRAM刷新周期是64ms,行数是8192行,时钟频率是180MHz/2=90MHz  

    //所有COUNT = (64ms/8192)/(1/90us)-20 = 64000*90/8192-20 = 683  

    HAL_SDRAM_ProgramRefreshRate(&hsdram1, 683);                    //步骤8:设置刷新速率  

}  

函数SDRAM_SendCommand()用来发送命令,内部调用了HAL的库函数HAL_SDRAM_SendCommand()发送配置命令;


函数SDRAM_Init()完成了SDRAM初始化中的步骤3~8。


至此,我们就完成了对SDRAM的初始化操作,此时外部SDRAM已经被映射到了相应的内存地址;需要注意的是,

SDRAM Bank1的地址是从0xC0000000~0xCFFFFFFF,SDRAM Bank2的地址是从0xD0000000~0xDFFFFFFF,

我们使用的是SDRAM Bank1,并且外部SDRAM的大小是32M字节,所以对应的内存地址范围是0xC0000000~0xC1FFFFFF。

接下来就测试一下SDRAM的读写:


#define     SDRAM_BANK1_BASE_ADDRESS    0xC0000000                                  //SDRAM Bank1起始地址  

#define     SDRAM_HALF_WORD_SIZE        0x1000000                                   //定义16M个的16bits数据,共32M字节  

  

__no_init uint16_t uhSdramArray[SDRAM_HALF_WORD_SIZE] @SDRAM_BANK1_BASE_ADDRESS;    //强制定义数组在SDRAM的内存中  

  

void SDRAM_Test(void)  

{  

    uint32_t i;  

      

    for(i = 0; i < SDRAM_HALF_WORD_SIZE; i++)  

    {  

        uhSdramArray[i] = i;                                        //对整个数组进行赋值  

    }  

      

    for(i = 0; i < SDRAM_HALF_WORD_SIZE; i += 4096)  

    {  

        printf("uhSdramArray[%d] = %d\r\n", i, uhSdramArray[i]);    //对数组中的数据间隔4096个进行串口打印  

    }  

}  

串口打印结果如下,数据太多,没有全部显示,




推荐阅读

史海拾趣

H&D Wireless公司的发展小趣事

高创科技起源于1987年的以色列,最初是一家专注于直驱运动控制驱动器开发的厂商。在以色列的三十多年里,高创积累了丰富的软件算法技术,特别是在运动控制领域形成了独特优势。这种积累不仅体现在其产品的稳定性和高性能上,更为后续的技术创新和市场拓展奠定了坚实基础。

Corex Intervest Inc公司的发展小趣事

Corex Intervest Inc公司在电子行业的发展历程中,始终保持着稳健的步伐和进取的精神。公司不断适应市场变化和技术更新,不断调整战略方向和发展重点。在未来,公司将继续加大研发投入,拓展新的应用领域和市场空间,为电子行业的发展贡献更多的力量。

这五个故事展示了Corex Intervest Inc公司在电子行业中的发展历程和取得的成就。从创立初期的艰难起步到技术创新、市场拓展、战略合作和持续发展的不断推进,Corex Intervest Inc公司始终保持着积极进取的精神和不断创新的态度,在电子行业中取得了显著的成绩。

3E SECURITY公司的发展小趣事

随着公司业务的不断扩张,3E SECURITY积极寻求与国际同行的合作机会。通过与国外知名安全公司开展技术合作、市场共享等方式,公司成功打开了国际市场的大门。同时,公司还积极参与国际安全标准的制定和推广,提升了公司在国际舞台上的影响力和竞争力。

Hi-Light Electronic Co Ltd公司的发展小趣事

3E SECURITY公司自创立之初,便以技术创新为核心竞争力。在电子安全领域,公司不断投入研发,推出了一系列具有自主知识产权的安全产品。其中,一款智能安全监控系统凭借其高度集成和智能化特点,迅速在市场上占据了一席之地。通过不断的技术革新,3E SECURITY逐渐在电子安全行业树立了技术领先的形象,吸引了大量合作伙伴和客户的关注。

EMBEST公司的发展小趣事

随着公司业务的不断拓展和市场规模的逐步扩大,EMBEST在XXXX年成立了Timll和Giayee两个子公司。其中,Timll主要负责ARM工控业务,而Giayee则专门负责PDA/Smart Phone等业务。这两个子公司的成立不仅进一步拓展了EMBEST的业务领域,也为其未来的发展注入了新的活力。通过多元化的业务布局和精细化的管理,EMBEST在电子行业中的影响力日益增强。

Caltron Devices Ltd公司的发展小趣事

在电子市场竞争日益激烈的背景下,Caltron Devices Ltd公司始终坚持品质至上的原则。公司建立了严格的质量管理体系,从原材料的采购到生产过程的控制,再到产品的出厂检验,每一个环节都严格把关。正是这种对品质的执着追求,使得Caltron的产品在市场上获得了良好的口碑,赢得了客户的信赖。

问答坊 | AI 解惑

模拟电子技术重点难点及典型题精解

模拟电子技术重点难点及典型题精解,继续!…

查看全部问答>

LM358做比较器违反常理的现象~~~

如图,LM358单电源15V供电,第6脚(-)电压为1.66V,第5脚(+)通过IC的输出管脚拉高或者拉低。 现象是,无论第5脚(+)电压实测为3.3V还是0V,第7脚输出电压一直为高(+14V),很是困惑~ …

查看全部问答>

PC机与嵌入式系统的多线程串行通信实现.pdf

PC机与嵌入式系统的多线程串行通信实现.pdf…

查看全部问答>

设置Linker 标准库函数为Redlib(semihost),避免link时undefined reference错误

    昨天晚上用LPCXpresso v3.3新建一个project,完成以后编译出错:sqrt.c:(\" />\" />\" />.text.sqrt+0xfc): undefined reference to `errno\'。     对比LPCXpresso 带的例子终于发现:MCU Linker下面的T ...…

查看全部问答>

超简单,100分求[电脑控制12个led的跑马灯的电路图及程序!]

电脑控制12个led的跑马灯的电路图及程序! 谢谢!…

查看全部问答>

WINCE开发,需要学那些方面的内容

WINCE开发,需要学那些方面的内容…

查看全部问答>

▓▓▓如何获得数据总线的宽度(windows mobile 6)▓▓▓

▓▓▓如何获得数据总线的宽度(windows   mobile   6)▓▓▓ 用什么API…

查看全部问答>

MSP430预计要到12月份才有货!!

有想学430的坛友,TI公司回复说要到12月份才有430的板子下来,现在应该是处于无货状态,这段时间大家如果想学习的,最好在12份之前下订单,顺便说一下,430网上购买用的是美元,你必须有一个双币值的信用卡才能购买。…

查看全部问答>

后天就要出差了!不知道能不能赶上这次的团购了!

后天就要出差了!好想知道这次的团购是什么呀!结果好难产啊!不知道能不能赶上了!每次团购的时间好短!呵呵!在纠结中期待ing……………

查看全部问答>