爱板网论坛

查看: 308|回复: 0

[教程] 43..STM32F469I---SDRAM的容量测试程序

[复制链接]

主题

好友

1万

积分

翰林

  • TA的每日心情
    郁闷
    6 小时前
  • 签到天数: 711 天

    连续签到: 6 天

    [LV.9]以坛为家II

    发表于 2018-1-12 22:50:44 |显示全部楼层
    【STM32F469I试用】+SDRAM的容量测试程序【转】

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

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

    1.jpg


    在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;

    其中总线宽度的宏定义为:
    /**
      * @brief  FMC SDRAM Memory Width
      */
    #define SDRAM_MEMORY_WIDTH    FMC_SDMemory_Width_32b

    这样就完成了主要参数的初始化,当然里面还包括了GPIO初始换和SDRAM矩阵的初始化,具体的参考楼下给出的源代码,可以自行下载编译查看现象。
    根据以上设置参数就可以得到SDRAM内存映射到芯片内部的地址和存储空间大小,如下:

    /**
      * @brief  FMC SDRAM Bank address
      */
    #define SDRAM_BANK_ADDR     ((uint32_t)0xC0000000)

    /**
      * @brief  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板,打开串口调试助手查看运行结果,得到如下所示的结果。

    2.jpg


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

    3.jpg


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

    4.jpg


    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    关闭

    站长推荐上一条 /3 下一条

    手机版|爱板网

    GMT+8, 2018-9-22 06:18 , Processed in 0.096269 second(s), 14 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-5   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001056号

    Powered by Discuz!

    返回顶部