【连载】【FPGA黑金开发板】NIOS II那些事儿--SDRAM实验(十二)

声明:本文为原创作品,版权归本博文作者所有,如需转载,请注明出处http://www.cnblogs.com/kingst/

4

一、简介

      这一节,我们来聊聊SDRAM吧。作为NIOS系统中最重要的一个外部器件,它担任着重要的角色,大家对它也应该很熟悉。每次上电的时候,FPGA都会把FLASH中的程序送到SDRAM中运行,之所以这样来做就是因为它的速度很快,但它掉电是要丢失数据的,所以要把数据存到FLASH中。

      有关SDRAM的理论知识我在这里不说了,不知道的百度google一下都可以。其实在NIOS II开发过程中,就算你对SDRAM的理论知识不了解,也不耽误你对它的使用。SOPC builder都已经完美的将它驱动起来,我们只要知道怎么使用它就可以了。下面,我们就来讲讲他的使用方法,其实真的很简单。

      在我们讲第一节的时候,我们就已经讲了如何构建SDRAM的控制器了,我在这里不再重复了,假设你已经构建好了,我主要讲一下有关软件的部分。

二、软件开发

      首先打开NIOS II 9.0 IDE软件,打开后,我们来看看system.h文件,确定一下SDRAM控制器模块是否已经加入进来。如果加入,有下面的内容出现

#define SDRAM_NAME "/dev/sdram"

#define SDRAM_TYPE "altera_avalon_new_sdram_controller"

#define SDRAM_BASE 0x01000000

……
 

接下来,我们开始编写有关SDRAM的软件代码,代码很简单,如下所示

/*
 * ==================================================================
*       Filename:  main.c
*    Description:  SDRAM读写试验
 *        Version:  1.0.0
 *        Created:  2010.4.16
 *       Revision:  none
 *       Compiler:  Nios II 9.0 IDE
 *         Author:  马瑞 (AVIC)
 *          Email:  avic633@gmail.com  
 * =================================================================
 */

/*----------------------------------------------------------------
 * Include 
 *----------------------------------------------------------------*/
#include <stdio.h>
#include "../inc/sopc.h"
#include "system.h"
#include "string.h"

/*---------------------------------------------------------------
 *  Variable
 *---------------------------------------------------------------*/
unsigned short * ram = (unsigned short *)(SDRAM_BASE+0x10000); //SDRAM地址

/* 
 * ===  FUNCTION  ===================================================
 *         Name:  main
 *  Description:  函数主程序
 * =================================================================
 */
int main(void)
{
    int i;
    
    memset(ram,0,100);
    //向ram中写数据,当ram写完以后,ram的地址已经变为(SDRAM_BASE+0x10100)
    for(i=0;i<100;i++){
        *(ram++) = i;
    }

    //逆向读取ram中的数据
    for(i=0;i<100;i++){
        printf("%d\n",*(--ram));
    }
       
    return 0;
}

      程序很简单,就是向指定的SDRAM中赋值。在这个程序里面有几个地方需要说明一下。首先,我在程序前面定义了一个unsigned short类型的指针变量ram,并将其指向SDRAM+0x10000这个位置。之所以设置为unsigned short数据类型,是因为我们用的SDRAM是16位数据总线的。而将其指向SDRAM+0x10000是因为在NIOS II运行时会用到SDRAM的部分空间,我们必须避开这部分空间,以免运行错误。0x10000这个值不是固定的,只要避开SDRAM的那部分空间就可以了。除此之外还有一个地方需要注意,就是当我们对sdram赋值以后,指针就会向后移动,指向下一个地址空间,每加一次,地址都会向后面移动16位。假如我们现在是在SDRAM+0X10000这个位置,当指针向后移动一次以后,地址就变为了SDRAM+0X10002,再加一次就变为了SDRAM+0X10004,以此类推。这些都是内部自动处理的,不需要我们来参与,我们只要知道就可以了。

      其实我讲这部分内容是想告诉大家,SDRAM控制器一旦构建好以后,我们对SDRAM的处理就像对内部地址一样,我们可以随意的进行赋值和读取。对于开发板上的64Mbit的SDRAM其实有很少一部分用给NIOS系统,其余部分都在空闲,大家是不是觉得很浪费呢。其实在有些情况下,我们就可以利用起这部分资源,比如在某个系统中,我们需要将外设接收到的数据缓存一下,我们就可以用这部分空闲的SDRAM空间来处理。

      在C语言中,如果我们要接收比较大的数据,还有另一种处理方法,那就是借助堆(heap)。可能有些人对堆和栈还分不清楚,我在这简单解释一下。栈(stack) 由系统自动分配。 例如,声明在函数中一个局部变量 int b,系统自动在栈中为b开辟空间。而堆(heap)需要程序员自己申请,并指明大小。有人用这样一个比喻来解释堆和栈的区别,非常形象贴切:使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大,这个人真是太有才了。下面我来写一个堆的代码,这部分代码是节选的,并不完全,功能是通过xmodem协议接收数据,并将其内容放到堆里面。如下所示

/* 
 * ===  FUNCTION  ==================================================
 *         Name:  main
 *  Description:  主函数
 * =================================================================
 */
int main()
{    
    char *ram = (char *)malloc ( sizeof(char)* 500000 );

    if ( ram==NULL ) {
        fprintf ( stderr, "\ndynamic memory allocation failed\n" );
        exit (EXIT_FAILURE);
    }        

    uart.init();
    
    /*------------------- FLASH -----------------------------*/
    
    while(1){
        if(uart.mode_flag){ 
            xmodem.xmodem_rx();
            printf("ram_cnt:%d\n",ram_cnt);
            parse_srecord_buf(ram,ram_cnt);
            printf("successful!");
            ram_cnt = 0;
            uart.mode_flag = 0;
        }
                        
    }

    free (ram);
        
    return 0;
}

      看了上面的代码大家应该了解了堆的用法了吧,它是通过malloc向系统中申请空间的。申请成功以后,就会返回申请地址的首地址,失败则返回NULL。到底申请在什么地方,我们可以通过打印指针来得知,但并没这个必要,因为这些都是系统来处理的,我们得到了首地址然后用就可以了。需要注意一点,我们申请完的地址用完以后需要释放,用free来释放就可以了。如果不释放,可能会出现内存泄露问题,到时候麻烦就大了,具体大到什么程度我也不知道,呵呵。

      可能有人会问,为什么不用栈来处理这个问题呢?这就跟编译有关系了,在编译过程中,系统会将栈需要的空间加到代码中,也就是说如果你在代码中用栈来处理大的数据,那么你编译以后的代码会非常大,你下载到flash以后,加载到sdram中的时间也会非常之长。而堆这不会,系统对堆的处理方式是何时用合适分配,并不占代码空间。

      说到这,有关SDRAM部分的内容讲完了。总结一下,使用SDRAM有两种方法,第一种是直接对SDRAM地址处理;第二种方法就是利用堆来处理。好了,这部分内容就讲到这吧,如果大家对此有疑问,或者发现我讲的内容有问题可以直接跟我联系,邮箱:avic633@gmail.com;qq:984597569。

posted on 2010-05-01 00:27  FPGA黑金开发板  阅读(3209)  评论(8编辑  收藏  举报