其他分享
首页 > 其他分享> > Nios ii 实战篇--- DDR2

Nios ii 实战篇--- DDR2

作者:互联网

目的:通过nios II上的实现软核读写DDR2

      相比之前的hello world项目的区别在于1. 在 Qsys 系统中添加 DDR2 的 IP 核,以及DDR2 IP 核的参数配置;2. 在 Eclipse开发环境里对 DDR2 的存储空间进行读写数据和校验程序不同。

下面是针对本项目实现过程中一些疑惑点的见解:

1. 为何需要在QSYS中添加DDR2的IP核?为何不能直接访问外部DDR2?

        无论是通过FPGA程序读写DDR2还是通过内嵌的CPU软核来读取,都无法直接简单的控制DDR2的读写。DDR2的IP核,相当于对DDR2进行了一层操作的包装,用户可以通过的简单操作来完成对DDR2的控制。而DDR2 IP核放在FPGA代码里或者内嵌的NIOS里均可以,只不过放到内核中,就可以把DDR2当作内部存储器访问,更为方便。

2. 工程移植

        将之前的工程文件都复制到新的文件夹下,然后删除software目录下的文件。这样就可以直接在NIOS中修改内核的参数。以及software目录下主要是对内核的编程,即在eclipse环境下的工程。

        在打开Qsys时,需要重新选择kernel.qsys文件,因为项目移植后,这个文件的位置也发生了变化,需要在新的工程文件中打开此文件进行设计。

3.  在本项目中,不使用RAM核,MCU直接将程序和数据存储在DDR2中,因此使用外部存储器,可以节省FPGA资源。

4. 配置DDR2 IP核,包含以下内容:

1)Device family

2)Speed grade

3)输入参考时钟频率

4)DDR2 时钟频率

5)Controller data rate: FULL---verilog 逻辑部分数据位宽 X2,速度/2,达到了降频的目的。
6) Memory Presets List 里双击选择 Custom(Micro MT47H64M16)。

        若没有,修改现有的IC的参数然后生成我们需要IC。在Memory Presets List里选择Memory vendor为Micron, Memory fomart为Dicrete Device, 这样在右边的 Memory Presets 列表中会出现配置好的 DDR2 芯片,选择型号差不多的 MT47H32M16-5E, 再点击 Modify parameters..按钮。            打开 Preset Editor 设置 DDR 的参数,这里的 DDR2 的参数设置分为 3 种:DDR2 SDRAM属性设置,DDR2 SDRAM 初始化选项和DDR2 SDRAM 时序参数设置。其中All Parameters里包含这三项的全部内容。  Parameters 里设置的参数需要参考 DDR2(MT47H64H16)的 datasheet, 我们这里只需要修改 Row address width 行的参数为 13,其它参数都不需要修改,因为这些参数MT47H64H16 跟MT47H32M16-5E 芯片都是一样的。

        参数配置可以参考实现和参数化存储器IP.pdf

5. 生成的NIOS II软核会自动将DDR2相关的时序文件添加进工程。如下: 

6. 打开TCL Scripts,可以看到关于DDR2的相关pin .tcl文件,运行后打开Pin planning可以发现所有的ddr2的PIN的属性均被配置过了,除了需要自己手动根据IC型号和板子去连接PIN脚。

7. 在eclipse中新建BSP模板的项目,为何需要选择.sopcinfo文件?这个文件主要是干嘛的?

        info文件主要是关于软件的信息,软件的用途、名称、操作系统、需要的磁盘空间等。因此,.sopcinfo主要包含了我们生成的软核的一些信息。添加此文件,就相当于限定我们的编译环境,使编译的程序能直接运行在软核内。

7. 通过调用memtest_small模板中代码来实现功能。

int main(void)
{

  int ch;

  /* Print the Header */
  MenuHeader();

  while (1)
  {
    printf("\nPress enter to continue or 'q' to quit.\n");
    ch = alt_getchar();
    putchar(ch);
    if(ch == 'q' || ch == 'Q')
    {
        printf( "\nExiting from Memory Test.\n");
        break;
    }
    else if (ch == '\n')
    {
        TestRam();
    }
  }
  return (0);
}

从上面代码看出,一共使用了4个函数:

        1)MenuHeader(),打印出本代码的功能

        2)ch =alt_getchar(),读取用户键盘按下的字符

        3)putchar(ch),该函数以无符号 char 强制转换为 int 的形式返回写入的字符,如果发生错误则返回 EOF。

        4)TestRam(),实现ddr2的测试,如下:

static void TestRam(void)
{
  
  int memory_base, memory_end, memory_size;
  int ret_code = 0x0;

  /* Find out what range of memory we are testing */
  MemGetAddressRange(&memory_base, &memory_end);
  memory_size = (memory_end - memory_base);

  printf("\n");
  printf("Testing RAM from 0x%X to 0x%X\n", memory_base, (memory_base + memory_size));

  /* Test Data Bus. */
  ret_code = MemTestDataBus(memory_base);

  if (ret_code)
   printf(" -Data bus test failed at bit 0x%X", (int)ret_code);
  else
    printf(" -Data bus test passed\n");

  /* Test Address Bus. */
  if (!ret_code)
  {
    ret_code  = MemTestAddressBus(memory_base, memory_size);
    if  (ret_code)
      printf(" -Address bus test failed at address 0x%X", (int)ret_code);
    else
      printf(" -Address bus test passed\n");
  }

  /* Test byte and half-word access. */
  if (!ret_code)
  {
    ret_code = MemTest8_16BitAccess(memory_base);
    if  (ret_code)
      printf(" -Byte and half-word access test failed at address 0x%X", (int)ret_code);
    else
      printf(" -Byte and half-word access test passed\n");
  }

  /* Test that each bit in the device can store both 1 and 0. */
  if (!ret_code)
  {
    printf(" -Testing each bit in memory device.");
    ret_code = MemTestDevice(memory_base, memory_size);
    if  (ret_code)
      printf("  failed at address 0x%X", (int)ret_code);
    else
      printf("  passed\n");
  }
      
  if (!ret_code)
    printf("Memory at 0x%X Okay\n", memory_base);
}

问题:

1. 这个项目是通过使用模板工程来实现功能,即直接调用现有的程序。如果出现问题,那么要么是内核的配置问题,要么是软件的配置问题。

标签:---,实战篇,code,DDR2,printf,ret,ii,base,memory
来源: https://blog.csdn.net/weixin_41155462/article/details/122192145