[STM32F4] 【STM32F469I试用】+SDRAM的容量测试程序

[复制链接]
 楼主| 湛只为无双 发表于 2015-12-24 21:11 | 显示全部楼层 |阅读模式
本帖最后由 湛只为无双 于 2016-1-14 14:41 编辑

前段时间见有人讨论F469板子上SDRAM容量的大小问题,根据官方给出的DISCOVERY例程来看,里面的容量大小为8M字节,但是根据原理图推算出来的大小确实16M字节,然后就有了今天这个测试程序,通过实践来验证板载SDRAM大小以及主控可用容量大小。

一、SDRAM硬件电路
首先是要写出SDRAM的底层驱动程序,我个人比较倾向于使用标准库,感觉标准库用起来知道自己都对芯片做了啥,不像HAL库那样对底层不了解,并且觉得使用标准库更符合以前的编程习惯,编出来的代码效率要高一些,当然这个是没有理论依据的。

SDRAM原理图

SDRAM原理图

在SDRAM的原理图里面需要注意的是写入使能引脚为PC0,我参考开发板以前的资料中SDRAM写入使能引脚就不是PC0。除了这个地方需要注意外,SDRAM使用的数据线为32位,提高了总线带宽,这个在大容量数据交互中显得十分重要。
二、SDRAM软件底层设计及其宏定义
根据以上原理图编写初始化程序,如下:
  1. void SDRAM_Init(void)
  2. {
  3.         FMC_SDRAMInitTypeDef  FMC_SDRAMInitStructure;
  4.         FMC_SDRAMTimingInitTypeDef  FMC_SDRAMTimingInitStructure;

  5.         /* GPIO configuration for FMC SDRAM bank */
  6.         SDRAM_GPIOConfig();

  7.         /* Enable FMC clock */
  8.         RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);

  9.         /* FMC Configuration ---------------------------------------------------------*/
  10.         /* FMC SDRAM Bank configuration */
  11.         /* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */
  12.         /* TMRD: 2 Clock cycles */
  13.         FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay    = 2;
  14.         /* TXSR: min=70ns (7x11.11ns) */
  15.         FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7;
  16.         /* TRAS: min=42ns (4x11.11ns) max=120k (ns) */
  17.         FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime      = 4;
  18.         /* TRC:  min=70 (7x11.11ns) */
  19.         FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay        = 7;
  20.         /* TWR:  min=1+ 7ns (1+1x11.11ns) */
  21.         FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime    = 2;
  22.         /* TRP:  20ns => 2x11.11ns */
  23.         FMC_SDRAMTimingInitStructure.FMC_RPDelay              = 2;
  24.         /* TRCD: 20ns => 2x11.11ns */
  25.         FMC_SDRAMTimingInitStructure.FMC_RCDDelay             = 2;

  26.         /* FMC SDRAM control configuration */
  27.         FMC_SDRAMInitStructure.FMC_Bank               = FMC_Bank1_SDRAM;
  28.         /* Row addressing: [7:0] */
  29.         FMC_SDRAMInitStructure.FMC_ColumnBitsNumber   = FMC_ColumnBits_Number_8b;
  30.         /* Column addressing: [11:0] */
  31.         FMC_SDRAMInitStructure.FMC_RowBitsNumber      = FMC_RowBits_Number_12b;
  32.         FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth  = SDRAM_MEMORY_WIDTH;
  33.         FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
  34.         /* CL: Cas Latency = 3 clock cycles */
  35.         FMC_SDRAMInitStructure.FMC_CASLatency         = FMC_CAS_Latency_3;
  36.         FMC_SDRAMInitStructure.FMC_WriteProtection    = FMC_Write_Protection_Disable;
  37.         FMC_SDRAMInitStructure.FMC_SDClockPeriod      = SDCLOCK_PERIOD;
  38.         FMC_SDRAMInitStructure.FMC_ReadBurst          = FMC_Read_Burst_Enable;
  39.         FMC_SDRAMInitStructure.FMC_ReadPipeDelay      = FMC_ReadPipe_Delay_0;
  40.         FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct  = &FMC_SDRAMTimingInitStructure;

  41.         /* FMC SDRAM bank initialization */
  42.         FMC_SDRAMInit(&FMC_SDRAMInitStructure);

  43.         /* FMC SDRAM device initialization sequence */
  44.         SDRAM_InitSequence();

  45. }
在这个初始化程序里面,比较中的部分由行列地址的说明和总线宽度:
  1. /* Row addressing: [7:0] */
  2.         FMC_SDRAMInitStructure.FMC_ColumnBitsNumber   = FMC_ColumnBits_Number_8b;
  3.         /* Column addressing: [11:0] */
  4.         FMC_SDRAMInitStructure.FMC_RowBitsNumber      = FMC_RowBits_Number_12b;
  5.         FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth  = SDRAM_MEMORY_WIDTH;


其中总线宽度的宏定义为:
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  FMC SDRAM Memory Width
  3.   */
  4. #define SDRAM_MEMORY_WIDTH    FMC_SDMemory_Width_32b


这样就完成了主要参数的初始化,当然里面还包括了GPIO初始换和SDRAM矩阵的初始化,具体的参考楼下给出的源代码,可以自行下载编译查看现象。
根据以上设置参数就可以得到SDRAM内存映射到芯片内部的地址和存储空间大小,如下:
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  FMC SDRAM Bank address
  3.   */
  4. #define SDRAM_BANK_ADDR     ((uint32_t)0xC0000000)

  5. /**
  6.   * [url=home.php?mod=space&uid=247401]@brief[/url]  FMC SDRAM Device size
  7.   */
  8. #define SDRAM_DEVICE_SIZE  ((uint32_t)0x1000000)
三、基于大容量SDRAM的测试程序开发
针对以上软件和硬件设计可以知道,SDRAM的起始地址为0xc0000000,大小为0x1000000(16M字节),那么我们可以采取对SDRAM写入数据,然后读取数据并与原始数据比较的方式,来验证SDRAM的大小。
本设计使用了STM32F469内部集成的随机数发生器,来产生10000个4字节的随机数,并将随机数循环写入SDRAM,然后读取SDRAM并与原始随机数比较,来验证写入与读取的数据是否相同,从而达到验证SDRAM容量大小的目的。
①定义随机数存储数组,并生成随机数
  1. u32 RadomBuffer[10000];

  2. RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG,ENABLE);
  3. RNG_Cmd(ENABLE);

  4. for(count=0;count<10000;count++)
  5. {
  6.         while(RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET);
  7.         RadomBuffer[count]=RNG->DR;
  8. }
通过等待随机数生成,然后依次赋值于随机数存储数组RadomBuffer方式,完成测试数组序列。


②将测试序列依次写入SDRAM
  1. pSDRAM=(u32*)SDRAM_BANK_ADDR;
  2. count=0;

  3. for(sdram_count=0;sdram_count<SDRAM_SIZE;sdram_count++)
  4. {
  5.         *pSDRAM=RadomBuffer[count];
  6.         count++;
  7.         pSDRAM++;
  8.         if(count>=10000)
  9.         {
  10.                 count=0;
  11.         }
  12. }
在设计中使用指向SDRAM起始地址指针的方式,向SDRAM依次写入数据,由于写入的数据为4字节,而SDRAM总字数为SDRAM_DEVICE_SIZE,故测试用的SDRAM_SIZE大小为SDRAM_DEVICE_SIZE/4。

③读取SDRAM并与原始测试序列逐个比较
  1. pSDRAM=(u32*)SDRAM_BANK_ADDR;
  2. sdram_count=0;
  3. for(;sdram_count<SDRAM_SIZE;sdram_count++)
  4. {
  5.         if(*pSDRAM != RadomBuffer[count])
  6.         {
  7.                 break;
  8.         }
  9.         count++;
  10.         pSDRAM++;
  11.         if(count>=10000)
  12.         {
  13.                 count=0;
  14.         }
  15. }
在与原始序列逐个比较的过程中,如果出现数据与原始测试序列不符的情况,马上停止比较,说明SDRAM容量大小不对。


④根据测试结果点亮LED灯
为了能够看到测试比较的结果,通过程序设置点亮不同的LED灯来说明最后测试结果,程序设计如下:
  1. if(sdram_count == SDRAM_SIZE)
  2. {
  3.         LED1=0;
  4. }
  5. else
  6. {
  7.         LED2=0;
  8. }


四、主文件总体设计
为了能够看到程序的运行过程,以及知道程序的在运行中的具体情况,引入串口向电脑发送数据的方式来增强对程序的了解。
故主文件程序设计如下:
  1. #include "stm32f4xx.h"
  2. #include "LED.h"
  3. #include "USART3.h"
  4. #include "delay.h"
  5. #include "DISCO_SDRAM.h"

  6. u32 RadomBuffer[10000];
  7. u32 ReadBuffer[10000];
  8. #define SDRAM_SIZE (SDRAM_DEVICE_SIZE/4)
  9. u32 *pSDRAM;
  10. long long count=0,sdram_count=0;
  11. int main(void)
  12. {
  13.         LED_Init();
  14.         USART3_Init(115200);
  15.         SDRAM_Init();
  16.         
  17.         RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG,ENABLE);
  18.         RNG_Cmd(ENABLE);
  19.         u3_printf("*******************************\r\n");
  20.         u3_printf("中国电子网技术论坛_bbs.21ic.com\r\n");
  21.         u3_printf("*********SDRAM测试程序**********\r\n");
  22.         u3_printf("*******************************\r\n");
  23.         u3_printf("开始生成10000个SDRAM测试随机数\r\n");
  24.         for(count=0;count<10000;count++)
  25.         {
  26.                 while(RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET);
  27.                 RadomBuffer[count]=RNG->DR;
  28.         }
  29.         u3_printf("10000个SDRAM测试随机数生成完毕\r\n");
  30.         
  31.         pSDRAM=(u32*)SDRAM_BANK_ADDR;
  32.         count=0;
  33.         u3_printf("开始写入SDRAM\r\n");
  34.         for(sdram_count=0;sdram_count<SDRAM_SIZE;sdram_count++)
  35.         {
  36.                 *pSDRAM=RadomBuffer[count];
  37.                 count++;
  38.                 pSDRAM++;
  39.                 if(count>=10000)
  40.                 {
  41.                         count=0;
  42.                 }
  43.         }
  44.         u3_printf("写入总字节数:%d\r\n",(u32)pSDRAM-SDRAM_BANK_ADDR);
  45.         
  46.         count=0;
  47.         pSDRAM=(u32*)SDRAM_BANK_ADDR;
  48.         u3_printf("开始读取SDRAM并与原随机数比较\r\n");
  49.         sdram_count=0;
  50.         for(;sdram_count<SDRAM_SIZE;sdram_count++)
  51.         {
  52.                 if(*pSDRAM != RadomBuffer[count])
  53.                 {
  54.                         u3_printf("数据比较错误——退出~\r\n");
  55.                         break;
  56.                 }
  57.                 count++;
  58.                 pSDRAM++;
  59.                 if(count>=10000)
  60.                 {
  61.                         count=0;
  62.                 }
  63.         }
  64.         u3_printf("比较通过总字节数:%d\r\n",(u32)pSDRAM-SDRAM_BANK_ADDR);
  65.         
  66.         if(sdram_count == SDRAM_SIZE)
  67.         {
  68.                 LED1=0;
  69.                 u3_printf("SDRAM测试成功\r\n");
  70.         }
  71.         else
  72.         {
  73.                 LED2=0;
  74.                 u3_printf("SDRAM测试失败\r\n");
  75.         }
  76.         u3_printf("中国电子网技术论坛_bbs.21ic.com\r\n");
  77.         while(1)
  78.         {
  79.                 LED3^=1;
  80.                
  81.                 delay_ms(500);
  82.         }
  83. }

通过开启串口调试助手,可以很清晰看到程序的运行过程和运行结果。

五、测试结果
将以上程序设计编译后下载至DISCOVERY板,打开串口调试助手查看运行结果,得到如下所示的结果。

板子实际运行情况

板子实际运行情况

通过板子的实际运行情况可以看到,LED1被点亮,证明程序测试通过,容量大小测试通过。

串口接收到数据

串口接收到数据

同样的,根据串口接收到的数据表明,SDRAM测试通过,测试通过的字节数为16777216,换算成以M为单位,大小为16M字节。
由以上可知,DISCOVERY板上板载SDRAM容量大小16M,芯片可访问大小也为16M。
最后,祝大家平安夜平安,圣诞节快乐。

HappyChristmas

HappyChristmas





 楼主| 湛只为无双 发表于 2015-12-24 21:12 | 显示全部楼层
本帖最后由 湛只为无双 于 2015-12-24 21:57 编辑

这一层楼用于放置测试用工程,基于keil5.15的IDE开发平台。 STM32F469_SDRAM_Test.zip (686.11 KB, 下载次数: 32)
 楼主| 湛只为无双 发表于 2015-12-24 21:13 | 显示全部楼层
占楼 等待编辑 编辑。。。。。。。
天灵灵地灵灵 发表于 2015-12-24 22:48 | 显示全部楼层
DISCOVERY板上板载SDRAM容量大小16M,芯片可访问大小也为16M.
可以存好多内容啊。
zhangbin_abc 发表于 2015-12-24 23:58 | 显示全部楼层
楼主,你好,请你有空试一下PC6和PC7所在的USART6串口打印测试,我测试时程序一直停在发送完成标志的循环检测上,不知道啥问题,向你请教一下,谢谢。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

171

帖子

9

粉丝
快速回复 在线客服 返回列表 返回顶部