今天给大侠带来基于FPGA的乒乓ram设计,话不多说,上货。

一、概述

在现在的数据采集分析系统中,随着采集数据的速度剧增,每次都对这些庞大的数据量直接进行分析,这将会占用很多的CPU,使得CPU不能及时的去做其它的事情。我们可以在传输这些数据的时候提供适当的通道,建立一个缓冲电路,来实现数据流的无缝缓存和处理,提高系统的处理速度和性能。

输入输出缓存电路一般有三种结构和形式:

1、双口ram结构:双口RAM是在一个SRAM存储器上具有两套完全独立的数据线、地址线、读写控制线、并允许两个独立的系统同时对该存储器进行随机访问。

2、FIFO结构:FIFO(First In First Out)是一种先进先出的数据缓存器,可以进行双端操作,但是数据必须先进先出,不能进行随机性的访问。从容量大小来看,双口RAM比FIFO要大一些,但总的来说,这两种缓冲结构的存储容量还是相对较小,对高速图像处理系统而言,还不是特别适合。

3、乒乓ram结构:这种结构是将输入数据流通过输入数据选择单元等时地将数据流分配到两个ram缓冲区。通过两个ram读和写的切换,来实现数据的流水式传输。

综上所述,乒乓缓存结构实际上相当于一个双口RAM,但它与普通的双口RAM又有所不同。普通双口RAM是单个存储体构成的IC,乒乓ram结构则由包含两个相互独立存储体的多片IC构成,从而使其在结构、速度、容量等方面具有更大的灵活性;若双口在访问同一地址时,普通双口SAM指向的必定是存储体内的同一存储单元,而乒乓ram结构则分别指向属于SRAM1和SRAM2的两个不同的存储单元,更易操作。乒乓缓存结构的上述特点决定了可以相对较便宜的高速大容量SRAM、外围逻辑器件构成比双口RAM以及高速FIFO更适合视频处理的系统所需要的缓冲存储器。

乒乓ram结构的上述特点决定了可以相对较便宜的高速大容量RAM、外围逻辑器件构成比双口RAM以及高速FIFO更适合大数据传输系统所需要的缓冲存储器。

二、乒乓ram控制原理

"乒乓操作"是一个常用的数据流控制处理技巧。典型的乒乓操作结构如图1所示。

图1 乒乓操作结果示意图

乒乓操作的处理流程为:

输入数据流通过输入数据选择单元将数据流等时分配到两个数据缓冲区,数据缓冲模块一般为ram。在第一个缓冲周期,将输入的数据流缓存到数据缓冲模块ram A;在第2个缓冲周期,通过输入数据选择单元的切换,将输入的数据流缓存到数据缓冲模块ram B,同时将ram A缓存的第1个周期数据传给输出数据选择单元。在第3个缓冲周期通过输入数据选择单元的再次切换,将输入的数据流缓存到ram A同时将ram B缓存的第2个周期的数据传给输出数据选择单元。如此循环。

乒乓操作的最大特点是通过“输入数据选择单元”和“输出数据选择单元”按节拍、相互配合的切换,将经过缓冲的数据流没有停顿地送到“数据流运算处理模块”进行运算与处理。把乒乓操作模块当做一个整体,站在这个模块的两端看数据,输入数据流和输出数据流都是连续不断的,没有任何停顿,因此非常适合对数据流进行流水线式处理。所以乒乓操作常常应用于流水线式算法,完成数据的无缝缓冲与处理。

三、乒乓ram控制的FPGA设计

当保存数据到ram时,在输入数据时同时要产生相应的地址,这样ram才会把数据与地址一一对应,按顺序存取。FPGA读写控制模块需要给出两组地址线,两组输入、输出数据总线以及读、写片选等控制ram的控制信号线,分别单独的控制ram A和ram B,以便输入的信号总线交替输出。

为了解决共用总线时的资源冲突问题,还需适当的控制两片ram的通断。可以用一个信号控制ram A和ram B的切换。实际上,ram的数据线也有两组,其工作方式和地址线一样。为了给数据处理模块以充裕的时间读取ram中的数据,还要对每次存入ram中的数据做一定量的处理,选择出有用的信号。

如下图,图2为乒乓ram的模块示意图。先在时钟控制下输入两路信号,经过粗略处理,产生两路数据线和地址线,以及两个ram模块的控制线,分别控制两个ram的读和写,并且两个ram的读(或者写)互锁,即一个若处于读状态,则另一个处于写状态。最后把另个ram保存的数据经过一个二选一模块输出,分时复用,产生在时间上连续的数据流输出。

图2 乒乓ram模块示意图

四、乒乓ram的设计流程

乒乓ram的输入数据流宽度是16位,ram深度是1024位。其主要外围接口包括输入、控制和输出几个部分,采用verilog DHL进行编写。

输入部分包括两路输入数据in0[15:0],in1[15:0],时钟信号clk,复位信号rst;控制部分包括两个ram的读写切换信号pingpang,控制两个ram的写信号,还有数据的地址信号in0_addr_wr[9:0],in1_addr_wr[9:0];输出部分包括ram模块的输出out0[15:0],out1[15:0],以及两个选择后的最终输出out[15:0]。其大概流程图如下:

图3 乒乓ram设计流程图

其中,ram是调用IP核产生的,这可以直接选择FPGA自带的ram器件,从而极大的减少了寄存器组的使用,提高了FPGA的利用率。

五、设计代码

参考代码如下:

module lcd12864(     clock, //系统时钟输入     reset_n, //系统复位输入     //in_data,  //输入的要显示的数据     LCD_RS, //LCD的寄存器选择输出信号     LCD_RW, //LCD的读、写操作选择输出信号     LCD_E, //LCD使能信号     lcd_data, //LCD的数据总线(不进行读操作,故为输出)  );                  input clock;  input reset_n;   //input in_data;  output reg LCD_RS; //LCD的寄存器选择输出信号  output LCD_RW; //LCD的读、写操作选择输出信号  output LCD_E; //LCD使能信号  output reg [7:0]lcd_data; //LCD的数据总线(不进行读操作,故为输出)            reg [31:0] in_data = 32'd2294967296;       // wire [31:0] in_data;        reg clock_lcd; //LCD时钟信号        reg [15:0]cnt;            // CLK频率为50MHz, 产生LCD时钟信号, 10Hz                  always @(posedge clock or negedge reset_n)      begin        if (!reset_n)          begin              cnt <= 16'b0;clock_lcd <= 0;          end           else if(cnt == 49999)          begin              cnt <= 0;clock_lcd <= ~clock_lcd;          end           else cnt <= cnt +1'b1;      end/*******************************************************************/   reg[8:0] state; //State Machine code    parameterIDLE  = 9'b00000000;                    //初始状态,下一个状态为CLEAR  parameterSETFUNCTION = 9'b00000001;              //功能设置:8位数据接口  parameterSETFUNCTION2 = 9'b00000010;  parameterSWITCHMODE = 9'b00000100;               //显示开关控制:开显示,光标和闪烁关闭  parameterCLEAR = 9'b00001000;                    //清屏  parameterSETMODE      = 9'b00010000;             //输入方式设置:数据读写操作后,地址自动加一/画面不动  parameterSETDDRAM     = 9'b00100000;             //设置DDRAM的地址:第一行起始为0x80/第二行为0x90  parameterWRITERAM     = 9'b01000000;             //数据写入DDRAM相应的地址  parameterSTOP = 9'b10000000;                     //LCD操作完毕,释放其控制    wire[7:0] disp_1,disp_2,disp_3,disp_4,disp_5,disp_6,disp_7,disp_8,disp_9,disp_10;    //+8'h30为转换为ASCII  assign  disp_1 =in_data/32'd1000000000+8'h30;  assign  disp_2 =in_data%32'd1000000000/32'd100000000+8'h30; //1011 1110 1011 1100 0010 0000 000  assign  disp_3 =in_data%32'd100000000/32'd10000000+8'h30;  //1001 1000 1001 0110 1000 0000  assign  disp_4 =in_data%32'd10000000/32'd1000000+8'h30;  //1111 0100 0010 0100 0000  assign  disp_5 =in_data%32'd1000000/32'd100000+8'h30;  //1100 0011 0101 0000 0  assign  disp_6 =in_data%32'd100000/32'd10000+8'h30;  //1001 1100 0100 00  assign  disp_7 =in_data%32'd10000/32'd1000+8'h30;  assign  disp_8 =in_data%32'd1000/32'd100+8'h30;  assign  disp_9 =in_data%32'd100/32'd10+8'h30;  assign  disp_10 =in_data%32'd10+8'h30;      reg flag; //标志位,LCD操作完毕为0  reg [5:0] char_cnt;  reg [7:0] data_disp;     assign LCD_RW = 1'b0; //没有读操作,R/W信号始终为低电平  assign LCD_E  = (flag == 1)?clock_lcd:1'b0; //E信号出现高电平以及下降沿的时刻与LCD时钟相同    always @(posedge clock_lcd or negedge reset_n) //只有在写数据操作时,RS信号才为高电平,其余为低电平    begin      if(!reset_n)          LCD_RS <= 1'b0;      else if(state == WRITERAM)   //写数据          LCD_RS <= 1'b1;      else          LCD_RS <= 1'b0;          //写指令    end    /*********************************************************// State Machine*********************************************************/  always @(posedge clock_lcd or negedge reset_n)    begin      if(!reset_n)        begin          state <= IDLE;          lcd_data <= 8'bzzzzzzzz;          char_cnt <= 5'b0;          flag <= 1'b1;        end      else         begin         case(state)         IDLE:             begin               state <= SETFUNCTION;             lcd_data <= 8'bzzzzzzzz;             end                    SETFUNCTION:          begin           state <= SETFUNCTION2;           lcd_data <= 8'h30; // 8-bit 控制界面,基本指令集动作          end                   SETFUNCTION2:          begin           state <= SWITCHMODE;           lcd_data <= 8'h30; // 清屏          end                   SWITCHMODE:          begin           state <= CLEAR;           lcd_data <= 8'h0c; // 显示开关:开显示,光标和闪烁关闭          end                   CLEAR:          begin           state <= SETMODE;           lcd_data <= 8'h01;          end                   SETMODE:          begin           state <= SETDDRAM;           lcd_data <= 8'h06; // 输入方式设置: 数据读写后,地址自动加1,画面不动          end                   SETDDRAM:          begin           state <= WRITERAM;              if(char_cnt == 0) //如果显示的是第一个字符,则设置第一行的首字符地址                begin                 lcd_data <= 8'h80; //Line1                end              else if(char_cnt ==16)//第二次设置时,是设置第二行的首字符地址                begin                 lcd_data <= 8'h90;                 end              else if(char_cnt == 32)                begin                  lcd_data <= 8'h88;                end                else if(char_cnt == 48)                 begin                   lcd_data <= 8'h98;                 end                 end                       WRITERAM:             begin               if(char_cnt <= 15)                 begin                  char_cnt <= char_cnt + 1'b1;                  lcd_data <= data_disp;                    if( char_cnt == 15 )                       state <= SETDDRAM;                    else                       state <= WRITERAM;                      end                 else if( char_cnt >= 16 && char_cnt <= 31)                  begin                   lcd_data <= data_disp;                   state <= WRITERAM;                   char_cnt <= char_cnt + 1'b1;                     if( char_cnt == 31 )   //返回SETDDRAM修改写地址                       state <= SETDDRAM;                     else                       state <= WRITERAM;   //                   end                  else if(char_cnt >= 32 && char_cnt <= 47)                  begin                    lcd_data <= data_disp;                    state <= WRITERAM;                    char_cnt <= char_cnt + 1'b1;                      if( char_cnt == 47 )                        state <= SETDDRAM;                      else                        state <= WRITERAM;                   end                   else if(char_cnt >= 48 && char_cnt <= 63)                   begin                    lcd_data <= data_disp;                    state <= WRITERAM;                    char_cnt <= char_cnt + 1'b1;                      if( char_cnt == 63 )                        state <= SETDDRAM;                      else                        state <= WRITERAM;                   end                  end                        STOP: state <= STOP;            default: state <= IDLE;           endcase        end    end      always @(char_cnt) //输出的字符     begin      case (char_cnt)       6'd0:  data_disp <= 8'h20;       6'd1:  data_disp <= 8'h20; //       6'd2:  data_disp <= 8'hB5;       6'd3:  data_disp <= 8'hE7;  //       6'd4:  data_disp <= 8'hD7;       6'd5:  data_disp <= 8'hD3;  //       6'd6:  data_disp <= 8'hB9;       6'd7:  data_disp <= 8'hA4;  //       6'd8:  data_disp <= 8'hB3;       6'd9:  data_disp <= 8'hCC;       6'd10:  data_disp <= 8'hCA;       6'd11:  data_disp <= 8'hC0;       6'd12:  data_disp <= 8'hBD;       6'd13:  data_disp <= 8'hE7;       6'd14:  data_disp <= 8'h20;       6'd15:  data_disp <= 8'h20;              6'd16:  data_disp <= 1;       6'd17:  data_disp <= 1;       6'd18:  data_disp <= 1;       6'd19:  data_disp <= 1;       6'd20:  data_disp <= "E";       6'd21:  data_disp <= "E";       6'd22:  data_disp <= "W";       6'd23:  data_disp <= "O";       6'd24:  data_disp <= "R";       6'd25:  data_disp <= "L";       6'd26:  data_disp <= "D";       6'd27:  data_disp <= 1;       6'd28:  data_disp <= 1;       6'd29:  data_disp <= 1;       6'd30:  data_disp <= 1;       6'd31:  data_disp <= 1;              6'd32:  data_disp <= "F";       6'd33:  data_disp <= "P";       6'd34:  data_disp <= "G";       6'd35:  data_disp <= "A";       6'd36:  data_disp <= 8'hD6;       6'd37:  data_disp <= 8'hFA;       6'd38:  data_disp <= 8'hD1;       6'd39:  data_disp <= 8'hA7;                                              6'd40:  data_disp <= 8'hCF;       6'd41:  data_disp <= 8'hB5;       6'd42:  data_disp <= 8'hC1;       6'd43:  data_disp <= 8'hD0;        6'd44:  data_disp <= 8'h20;       6'd45:  data_disp <= 8'h20;       6'd46:  data_disp <= 8'h20;       6'd47:  data_disp <= 8'h20;              6'd48:  data_disp <= disp_1;       6'd49:  data_disp <= disp_2; //       6'd50:  data_disp <= disp_3;       6'd51:  data_disp <= disp_4;                                              6'd52:  data_disp <= disp_5;       6'd53:  data_disp <= disp_6;       6'd54:  data_disp <= disp_7;       6'd55:  data_disp <= disp_8;        6'd56:  data_disp <= disp_9;       6'd57:  data_disp <= disp_10;       6'd58:  data_disp <= 8'h20;       6'd59:  data_disp <= 8'h20;       6'd60:  data_disp <= 8'h20;       6'd61:  data_disp <= 8'h20;       6'd62:  data_disp <= 8'h20;       6'd63:  data_disp <= 8'h20;                                                                             //default :   data_disp <= 8'd20;      endcase     end     endmodule 

六、仿真测试

仿真测试波形图

调用IP核产生的ram要存满数据后才会逐步读出数据,即在下一个地址周期才会读出该ram中保存的数据。开始ram中无数据,此地址周期内输出0;第二个地址周期读出ram1,也是0;第三个地址周期读出ram0,第四个周期读出ram1,可以看出in0和in1的数据逐渐输出,并且在乒乓信号切换时数据流也相应切换,衔接得刚好。说明了乒乓ram实现大量高速数据流的无缝缓冲和处理。

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!

精彩推荐

基于FPGA的CRC校验码生成器设计

FPGA 高级设计:时序分析和收敛

FPGA设计中,RAM的两种实现方法详解

时序分析理论和timequest使用_中文电子版

基于FPGA的乒乓ram控制系统设计相关推荐

  1. java交通信号灯毕业论文范文_信号灯设计论文,关于基于FPGA的交通信号灯控制系统设计相关参考文献资料-免费论文范文...

    导读:本文关于信号灯设计论文范文,可以做为相关参考文献. 文/ 胡桂戎 陕西警官职业学院 陕西 西安 710021 [摘 要]本文采用FPGA 设计,结合了道路传感器,设计了交通信号灯全感应自适应的控 ...

  2. 基于树莓派的智能家居控制系统设计论文参考

    完整论文咨询可WX联系:gyf1842965496 智能家居控制系统功能实现详细介绍:基于树莓派的智能家居控制系统设计https://blog.csdn.net/G1842965496/article ...

  3. 【分享】基于单片机嵌入式的家用智能节水淋浴控制器的设计-基于单片机的电子贺卡控制系统设计-基于单片机的倒计时牌控制系统设计-基于单片机的彩灯控制器系统设计-多模式彩灯-单片机的八路路数字电压表控制设计

    1334基于单片机嵌入式的家用智能节水淋浴控制器的设计-全套毕设课设设计资料 三个ds18b20分别采集进水口热水  冷水 和温水的水温,然后分别显示出来,按下开始按键,系统初始化,自动设置出水温度为 ...

  4. 基于FPGA的实时图像边缘检测系统设计(上)

    今天给大侠带来基于FPGA的实时图像边缘检测系统设计,由于篇幅较长,分三篇.今天带来第一篇,上篇,话不多说,上货. 导读 随着科学技术的高速发展,FPGA在系统结构上为数字图像处理带来了新的契机.图像 ...

  5. 基于FPGA的直流电机PWM控制+毕业论文

    基于FPGA的直流电机PWM控制+开题+毕业论文+源码(VHDL or verilog) 基于FPGA的直流电机PWM控制电路主要由四部分组成:控制命令输入模块.控制命令处理模块.控制命令输出模块.电 ...

  6. 处理器指令编码可重定义的方法_RISC-V学习笔记1 《基于FPGA与RISC-V的嵌入式系统设计》第3章 RISC-V指令集...

    今天读了顾长怡的<基于FPGA与RISC-V的嵌入式系统设计>第3章 RISC-V指令集,做了一些简单的笔记. 1.这本书既然要基于RISC-V讲嵌入式系统设计,就必须要介绍RISC-V的 ...

  7. 智能窗帘传感器c语言程序,基于单片机的智能窗帘控制系统设计(附程序代码)

    基于单片机的智能窗帘控制系统设计(附程序代码)(论文18000字,程序代码) 摘要:二十一世纪初以来,科学技术不断发展,智能家居涌现于各家各户,人们越来越重视生活质量的提高.但是传统的手动开合窗帘耗时 ...

  8. matlab最小拍控制怎么求传递函数,基于Matlab 的最少拍控制系统设计

    - 计算机控制技术实验 -基于Matlab 的最少拍控制系统设计 学院:计算机科学与技术 班级: 姓名: 学号: 指导老师: 日期: 基于Matlab 的最少拍控制系统设计 一. 实验目的 学习使用 ...

  9. 基于数字电路交通灯信号灯控制系统设计-基于单片机病房温度监测与呼叫系统设计-基于STM32的无线蓝牙心电监护仪系统设计-基于STM32的智能蓝牙温控风扇控制设计-基于STM32的智能温室控制系统设计

    1617基于数字电路交通灯信号灯控制系统设计(仿真电路,论文报告)  摘  要:交通灯控制系统在城市交通控制中发挥着重要的作用,本次课程设计就是以城市交通灯控制系统为背景的,主要通过运用学过的数字电路 ...

  10. 模拟地铁自动售票系统C语言,基于PLC的地铁自动售票机控制系统设计.doc

    基于PLC的地铁自动售票机控制系统设计 基于PLC的地铁自动售票机控制系统设计 摘 要:随着社会经济的迅速发展,地铁列车也开始广泛出现于人们视野中.地铁列车具有形式速度快,价格低廉的优势,因此在各大城 ...

最新文章

  1. .Net转Java自学之路—Hibernate框架篇三(查询方式)
  2. BOOL与bool的区别(bool不是c的关键字,c++中bool也不是int)
  3. MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
  4. 浅析Windows7的睡眠、休眠、混合睡眠、离开模式
  5. 牛客多校9 - Groundhog Looking Dowdy(尺取)
  6. jqgrid删除某一列(隐藏)
  7. mysql 数据库 文件夹_mysql 数据库 文件夹
  8. 计算机考研英语词汇书,考研英语词汇参考书推荐
  9. Oracle数据库的状态查询
  10. 网站选择按钮点击无反应?_Win10系统电脑鼠标左键单击没有反应的解决办法
  11. python numpy 里面的[:, None]是个什么鬼?[..., None]呢?
  12. 极验滑动验证码的识别
  13. 由对称性知定点一定在x轴上_圆锥曲线解答题的经典答案:由椭圆的对称性知,定点在x轴上?...
  14. 微信开发服务器端口号,微信公众号开发步骤
  15. 水逆期自我救赎:MacBook pro进水
  16. 怎么让背景铺满整个页面_word怎么让背景图片铺满整个页面
  17. 公众号网页授权php,微信公众号里的PHP网站进行网页授权
  18. 公鸡五钱,母鸡三钱,小鸡三只一文钱,求百钱买百鸡
  19. grok logstash配置_logstash grok匹配
  20. 一些互联网标准化组织

热门文章

  1. s3c2440存储控制器详解
  2. 【Nginx】Nginx配置文件详解
  3. RecyclerView的canScrollVertically方法踩坑
  4. Unity IOS包在IPhone出现闪退
  5. 台式计算机usb口不能用,电脑usb接口不能用怎么办【图文教程】
  6. 管理大师德鲁克管理学精髓
  7. 提升自己的最好方式是什么呢?
  8. 程序员平时如何学习提高技术
  9. 基于高德地图实现Marker聚合效果
  10. 【KnewOne Talk】芋头君:不想做码农