本帖最后由 湛只为无双 于 2016-1-14 14:41 编辑
前段时间见有人讨论F469板子上SDRAM容量的大小问题,根据官方给出的DISCOVERY例程来看,里面的容量大小为8M字节,但是根据原理图推算出来的大小确实16M字节,然后就有了今天这个测试程序,通过实践来验证板载SDRAM大小以及主控可用容量大小。
一、SDRAM硬件电路
首先是要写出SDRAM的底层驱动程序,我个人比较倾向于使用标准库,感觉标准库用起来知道自己都对芯片做了啥,不像HAL库那样对底层不了解,并且觉得使用标准库更符合以前的编程习惯,编出来的代码效率要高一些,当然这个是没有理论依据的。
在SDRAM的原理图里面需要注意的是写入使能引脚为PC0,我参考开发板以前的资料中SDRAM写入使能引脚就不是PC0。除了这个地方需要注意外,SDRAM使用的数据线为32位,提高了总线带宽,这个在大容量数据交互中显得十分重要。
二、SDRAM软件底层设计及其宏定义
根据以上原理图编写初始化程序,如下:
void SDRAM_Init(void)
{
FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure;
FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitStructure;
/* GPIO configuration for FMC SDRAM bank */
SDRAM_GPIOConfig();
/* Enable FMC clock */
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);
/* FMC Configuration ---------------------------------------------------------*/
/* FMC SDRAM Bank configuration */
/* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */
/* TMRD: 2 Clock cycles */
FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2;
/* TXSR: min=70ns (7x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7;
/* TRAS: min=42ns (4x11.11ns) max=120k (ns) */
FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4;
/* TRC: min=70 (7x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 7;
/* TWR: min=1+ 7ns (1+1x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2;
/* TRP: 20ns => 2x11.11ns */
FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2;
/* TRCD: 20ns => 2x11.11ns */
FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2;
/* FMC SDRAM control configuration */
FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank1_SDRAM;
/* Row addressing: [7:0] */
FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;
/* Column addressing: [11:0] */
FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b;
FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH;
FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
/* CL: Cas Latency = 3 clock cycles */
FMC_SDRAMInitStructure.FMC_CASLatency = FMC_CAS_Latency_3;
FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable;
FMC_SDRAMInitStructure.FMC_SDClockPeriod = SDCLOCK_PERIOD;
FMC_SDRAMInitStructure.FMC_ReadBurst = FMC_Read_Burst_Enable;
FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_0;
FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure;
/* FMC SDRAM bank initialization */
FMC_SDRAMInit(&FMC_SDRAMInitStructure);
/* FMC SDRAM device initialization sequence */
SDRAM_InitSequence();
}
在这个初始化程序里面,比较中的部分由行列地址的说明和总线宽度:
/* Row addressing: [7:0] */
FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;
/* Column addressing: [11:0] */
FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b;
FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH;
其中总线宽度的宏定义为:
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] FMC SDRAM Memory Width
*/
#define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_32b
这样就完成了主要参数的初始化,当然里面还包括了GPIO初始换和SDRAM矩阵的初始化,具体的参考楼下给出的源代码,可以自行下载编译查看现象。
根据以上设置参数就可以得到SDRAM内存映射到芯片内部的地址和存储空间大小,如下:
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] FMC SDRAM Bank address
*/
#define SDRAM_BANK_ADDR ((uint32_t)0xC0000000)
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] FMC SDRAM Device size
*/
#define SDRAM_DEVICE_SIZE ((uint32_t)0x1000000)
三、基于大容量SDRAM的测试程序开发
针对以上软件和硬件设计可以知道,SDRAM的起始地址为0xc0000000,大小为0x1000000(16M字节),那么我们可以采取对SDRAM写入数据,然后读取数据并与原始数据比较的方式,来验证SDRAM的大小。
本设计使用了STM32F469内部集成的随机数发生器,来产生10000个4字节的随机数,并将随机数循环写入SDRAM,然后读取SDRAM并与原始随机数比较,来验证写入与读取的数据是否相同,从而达到验证SDRAM容量大小的目的。
①定义随机数存储数组,并生成随机数
u32 RadomBuffer[10000];
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG,ENABLE);
RNG_Cmd(ENABLE);
for(count=0;count<10000;count++)
{
while(RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET);
RadomBuffer[count]=RNG->DR;
}
通过等待随机数生成,然后依次赋值于随机数存储数组RadomBuffer方式,完成测试数组序列。
②将测试序列依次写入SDRAM
pSDRAM=(u32*)SDRAM_BANK_ADDR;
count=0;
for(sdram_count=0;sdram_count<SDRAM_SIZE;sdram_count++)
{
*pSDRAM=RadomBuffer[count];
count++;
pSDRAM++;
if(count>=10000)
{
count=0;
}
}
在设计中使用指向SDRAM起始地址指针的方式,向SDRAM依次写入数据,由于写入的数据为4字节,而SDRAM总字数为SDRAM_DEVICE_SIZE,故测试用的SDRAM_SIZE大小为SDRAM_DEVICE_SIZE/4。
③读取SDRAM并与原始测试序列逐个比较
pSDRAM=(u32*)SDRAM_BANK_ADDR;
sdram_count=0;
for(;sdram_count<SDRAM_SIZE;sdram_count++)
{
if(*pSDRAM != RadomBuffer[count])
{
break;
}
count++;
pSDRAM++;
if(count>=10000)
{
count=0;
}
}
在与原始序列逐个比较的过程中,如果出现数据与原始测试序列不符的情况,马上停止比较,说明SDRAM容量大小不对。
④根据测试结果点亮LED灯
为了能够看到测试比较的结果,通过程序设置点亮不同的LED灯来说明最后测试结果,程序设计如下:
if(sdram_count == SDRAM_SIZE)
{
LED1=0;
}
else
{
LED2=0;
}
四、主文件总体设计
为了能够看到程序的运行过程,以及知道程序的在运行中的具体情况,引入串口向电脑发送数据的方式来增强对程序的了解。
故主文件程序设计如下:#include "stm32f4xx.h"
#include "LED.h"
#include "USART3.h"
#include "delay.h"
#include "DISCO_SDRAM.h"
u32 RadomBuffer[10000];
u32 ReadBuffer[10000];
#define SDRAM_SIZE (SDRAM_DEVICE_SIZE/4)
u32 *pSDRAM;
long long count=0,sdram_count=0;
int main(void)
{
LED_Init();
USART3_Init(115200);
SDRAM_Init();
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG,ENABLE);
RNG_Cmd(ENABLE);
u3_printf("*******************************\r\n");
u3_printf("中国电子网技术论坛_bbs.21ic.com\r\n");
u3_printf("*********SDRAM测试程序**********\r\n");
u3_printf("*******************************\r\n");
u3_printf("开始生成10000个SDRAM测试随机数\r\n");
for(count=0;count<10000;count++)
{
while(RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET);
RadomBuffer[count]=RNG->DR;
}
u3_printf("10000个SDRAM测试随机数生成完毕\r\n");
pSDRAM=(u32*)SDRAM_BANK_ADDR;
count=0;
u3_printf("开始写入SDRAM\r\n");
for(sdram_count=0;sdram_count<SDRAM_SIZE;sdram_count++)
{
*pSDRAM=RadomBuffer[count];
count++;
pSDRAM++;
if(count>=10000)
{
count=0;
}
}
u3_printf("写入总字节数:%d\r\n",(u32)pSDRAM-SDRAM_BANK_ADDR);
count=0;
pSDRAM=(u32*)SDRAM_BANK_ADDR;
u3_printf("开始读取SDRAM并与原随机数比较\r\n");
sdram_count=0;
for(;sdram_count<SDRAM_SIZE;sdram_count++)
{
if(*pSDRAM != RadomBuffer[count])
{
u3_printf("数据比较错误——退出~\r\n");
break;
}
count++;
pSDRAM++;
if(count>=10000)
{
count=0;
}
}
u3_printf("比较通过总字节数:%d\r\n",(u32)pSDRAM-SDRAM_BANK_ADDR);
if(sdram_count == SDRAM_SIZE)
{
LED1=0;
u3_printf("SDRAM测试成功\r\n");
}
else
{
LED2=0;
u3_printf("SDRAM测试失败\r\n");
}
u3_printf("中国电子网技术论坛_bbs.21ic.com\r\n");
while(1)
{
LED3^=1;
delay_ms(500);
}
}
通过开启串口调试助手,可以很清晰看到程序的运行过程和运行结果。
五、测试结果
将以上程序设计编译后下载至DISCOVERY板,打开串口调试助手查看运行结果,得到如下所示的结果。
通过板子的实际运行情况可以看到,LED1被点亮,证明程序测试通过,容量大小测试通过。
同样的,根据串口接收到的数据表明,SDRAM测试通过,测试通过的字节数为16777216,换算成以M为单位,大小为16M字节。
由以上可知,DISCOVERY板上板载SDRAM容量大小16M,芯片可访问大小也为16M。
最后,祝大家平安夜平安,圣诞节快乐。
|