element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
FPGA
  • Technologies
  • More
FPGA
Blog Exploring 7 Series MIG Part – 2
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join FPGA to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: hrishi98
  • Date Created: 3 Jul 2022 6:43 AM Date Created
  • Views 2373 views
  • Likes 6 likes
  • Comments 0 comments
  • 7 Ways to Leave Your Spartan-6
  • ddr
  • Spartan_Migration
Related
Recommended

Exploring 7 Series MIG Part – 2

hrishi98
hrishi98
3 Jul 2022
Exploring 7 Series MIG Part – 2

Exploring 7 Series MIG Part – 2

 

Hello, in the previous blog we explored how to use DDR present on the Arty S7 board and made sure it is working fine by running Memory Tests bare-metal application using SDK. The previous example made use of the AXI Interface to access the DDR, AXI interface is simple to use along with a soft processor like MicroBlaze but when we want to use DDR with custom Verilog logic AXI interface might be difficult to use. MIG also provides a simple User Interface (UI) to access the DDR, in this blog we will explore how to make use of it.

Please refer to [1] for more details about the signals and timing diagram of the UI interface of MIG IP. The signals can be divided into 3 different paths, the signals are synchronized to ui_clk and are briefly described as follows.

Command Path: The command path is used to provide commands from the user.

image

  • MIG indicates it is ready to accept user commands by making app_rdy signal high
  • User needs to provide app_cmd (WRITE = 000, READ = 001) along with app_addr and app_en
  • If app_rdy is low user command needs to be held stable until app_rdy goes high as shown by the timing diagram

 

Write Path: Write path is used to provide write data from the user.

image

  • Write data and write enable can be provided along with the command, 1 cycle before command or maximum of within 2 cycles after providing command
  • App_wdf_data, app_wdf_wren must be provided when the app_wdf_rdy signal is high indicating MIG is ready to accept incoming data from the user
  • By default, BL8 burst mode will be enabled for MIG, the size of each burst is calculated as follows for BL8 mode

Burst Length = 8 x DDR Data Width = 8 x 16 = 128 bits

Next Increment = (ui_data width/8) = (128/8) = 16

Read Path: The read path is used to read the data from DDR using MIG.

image

  • Data can be read from MIG when app_rdy is high by providing the READ command and app_addr.
  • The read data is presented to the user using app_rd_data bus.
  • app_rd_data_valid signal is made high when valid data is present on app_rd_data bus

Creating Vivado Project:

Create a new vivado project targeting Arty S7 board, and add MIG IP using IP catalog.

image

Make sure the AXI Interface option is not selected so that MIG IP will expose UI interface.

image

Steps to configure MIG IP from here onwards are same as mentioned in previous blog complete the configuration and generation steps.

Now its time to instantiate clocking wizard. Add clocking wizard IP from the IP catalog in a similar way as MIG IP was added. Configure input clock as shown below.

image

Configure output clock and reset as shown below. After completing the configuration generate the IP.

image

Simple Verilog code to write and read from 1000 locations of DDR is described as below.

  • After completing DDR calibration move to write state where 1000 locations are written
  • After completing move to wait state and wait there for 1 cycle
  • Move to read state and read 1000 locations

Data read from DDR is compared with data written, if test is passed RGB LED LD1 turns out green if test is failed led turns red.

RGB LD0 turns out to green after completing ddr calibration.

//-------------------------------------------------------------------------------
// Description : Perform 1000 write transactions
//               Perform 1000 read transactions and check for data integrity
//-------------------------------------------------------------------------------
module ddr3_read_write(
  input           ddr_clk_i      , // 100 MHz clock
  input           sys_clk_i      , // 12 MHz system clock
  input           sys_rst_n_i    , // Active low system reset
  output          calib_done_o   , // DDR calibration is complete
  output [ 1:0]   test_status_o  , // test status, Red - Fail, Green - Pass
  
  // Signals going towards DDR3 chip
  output [13:0]   ddr3_addr      ,
  output [ 2:0]   ddr3_ba        ,
  output          ddr3_cas_n     ,
  output          ddr3_ras_n     ,
  output [ 0:0]   ddr3_ck_p      ,
  output [ 0:0]   ddr3_ck_n      ,
  output [ 0:0]   ddr3_cke       ,
  output          ddr3_reset_n   ,
  output          ddr3_we_n      ,
  inout  [15:0]   ddr3_dq        ,
  inout  [ 1:0]   ddr3_dqs_n     ,
  inout  [ 1:0]   ddr3_dqs_p     ,
  output [ 0:0]   ddr3_cs_n      ,
  output [ 1:0]   ddr3_dm        ,
  output [ 0:0]   ddr3_odt       
);

  // FSM States
  parameter IDLE_S   = 4'd0;
  parameter WRITE_S  = 4'd1;
  parameter WAIT_S   = 4'd2;
  parameter READ_S   = 4'd3;
  parameter STOP_S   = 4'd4;
  
  parameter ADDR_INCR      = 16     ;
  parameter TRANSCATIONS   = 100    ;
  
  (* mark_debug = "true" *) reg  [  3:0] curr_state        ; // FSM current state register
  (* mark_debug = "true" *) reg  [  3:0] next_state        ; // FSM next state register

  (* mark_debug = "true" *) wire         app_en            ; // enable user command
  (* mark_debug = "true" *) wire         app_wdf_wren      ; // write enable
  (* mark_debug = "true" *) wire         app_wdf_end       ; // last data of current write transaction
  (* mark_debug = "true" *) wire [  2:0] app_cmd           ; // user command, Write - 000, Read - 001
  (* mark_debug = "true" *) reg  [127:0] app_wdf_data      ; // write data
  (* mark_debug = "true" *) reg  [ 27:0] app_addr          ; // ui interface address
  (* mark_debug = "true" *) wire [127:0] app_rd_data       ; // read data
  (* mark_debug = "true" *) wire         app_rd_data_end   ; // last data current read transaction
  (* mark_debug = "true" *) wire         app_rd_data_valid ; // read data valid                                         
  (* mark_debug = "true" *) wire         app_rdy           ; // mig is ready to accept new command
  (* mark_debug = "true" *) wire         app_wdf_rdy       ; // mig is ready to accept new write command
  
  (* mark_debug = "true" *) reg  [ 27:0] rd_addr_cnt       ; // write address counter
  (* mark_debug = "true" *) reg  [ 27:0] wr_addr_cnt       ; // read address counter
  (* mark_debug = "true" *) reg  [ 27:0] rd_cnt            ; // read data counter
  (* mark_debug = "true" *) wire         error             ; // read data validation error
  (* mark_debug = "true" *) wire         wr_proc           ; // condition for writing
  (* mark_debug = "true" *) wire         wr_last           ; // last write transaction
  (* mark_debug = "true" *) wire         rd_addr_last      ; // last read transaction
  (* mark_debug = "true" *) reg  [ 15:0] error_count       ; // total number of read error encountered

  wire         ui_clk                ; // ui interface clock
  wire         ui_rst                ; // ui interface reset
  wire         clk_ref               ; // 200 MHz reference clock for MIG
  
  assign app_en        = app_rdy && ((curr_state == WRITE_S && app_wdf_rdy) || (curr_state == READ_S));
  assign app_wdf_wren  = (curr_state == WRITE_S) && wr_proc;
  assign app_wdf_end   = app_wdf_wren;
  assign app_cmd       = (curr_state == READ_S) ? 3'h1 : 3'h0;
                       
  assign wr_proc       = ~app_cmd && app_rdy && app_wdf_rdy;
  assign wr_last       = app_wdf_wren && (wr_addr_cnt == TRANSCATIONS - 1);
  assign rd_addr_last  = app_cmd && app_rdy && (rd_addr_cnt == TRANSCATIONS - 1);   
  assign error         = (app_rd_data_valid && (rd_cnt != app_rd_data));
  assign test_status_o = (error_count == 16'h0) ? 2'b10 : 2'b01;
  
  // read data counter
  always@(posedge ui_clk) begin
    if(ui_rst) begin
      rd_cnt <= 'h0          ;
    end else if(app_rd_data_valid && rd_cnt == TRANSCATIONS - 1) begin
      rd_cnt <= 'h0          ;
    end else if (app_rd_data_valid) begin
      rd_cnt <= rd_cnt + 1'b1;
    end
  end
  
  // error counter
  always@(posedge ui_clk) begin
    if(ui_rst) begin
      error_count  <= 'h0;
    end else begin
      error_count  <= error ? error_count + 1'b1 : error_count;
    end
  end
  
  // Sequential state change logic
  always@(posedge ui_clk) begin
    if(ui_rst) begin
      curr_state <= IDLE_S    ;
    end else begin
      curr_state <= next_state;
    end
  end
  
  // Combinational next state decoder logic
  always@(*) begin
    if(ui_rst) begin
      next_state = IDLE_S ;
    end else begin
      case(curr_state)
      
        IDLE_S  : begin
          if(calib_done_o) begin
          // move to write state when ddr calibration is completed
            next_state = WRITE_S;
          end else begin
            next_state = IDLE_S;
          end
        end
        
        WRITE_S :begin
          if(wr_last) begin
          // move to wait state when all write transactiona are completed
            next_state = WAIT_S;
          end else begin
            next_state = WRITE_S;
          end
        end
        
        WAIT_S  : begin
        // 1 cycle delay before entering read state
          next_state = READ_S;
        end
        
        READ_S  : begin
          if(rd_addr_last) begin
          // move to wait state when all write transactiona are completed
            next_state = STOP_S;
          end else begin
            next_state = READ_S;
          end
        end
        
        STOP_S  : begin
        // halt in stop state after completing all transactions
          next_state = STOP_S;
        end
        
        default : begin
          next_state = IDLE_S;
        end
        
      endcase
    end
  end
  
  // Registered output logic
  always@(posedge ui_clk) begin
    if(ui_rst) begin
      app_wdf_data <= 'h0;
      wr_addr_cnt  <= 'h0;
      rd_addr_cnt  <= 'h0;
      app_addr     <= 'h0;
    end else begin
      case(curr_state)
      
        IDLE_S  : begin
          app_wdf_data <= 'h0;
          wr_addr_cnt  <= 'h0;
          rd_addr_cnt  <= 'h0;
          app_addr     <= 'h0;
        end
        
        WRITE_S : begin
          if(wr_proc) begin
            app_wdf_data <= app_wdf_data + 1;
            wr_addr_cnt  <= wr_addr_cnt + 1;
            app_addr     <= app_addr + ADDR_INCR;
          end
        end
        
        WAIT_S  : begin
          app_addr <= 'h0;
        end
        
        READ_S  : begin
          if(app_rdy) begin
            rd_addr_cnt <= rd_addr_cnt + 1'b1;
            app_addr    <= app_addr + ADDR_INCR;
          end
        end
        
        STOP_S  : begin
          app_wdf_data <= 'h0;
          wr_addr_cnt  <= 'h0;
          rd_addr_cnt  <= 'h0;
          app_addr     <= 'h0;
        end
        
        default : begin
          app_wdf_data <= 'h0;
          wr_addr_cnt  <= 'h0;
          rd_addr_cnt  <= 'h0;
          app_addr     <= 'h0;
        end
        
      endcase
    end
  end

  mig_7series_0 u_mig_7series_0 (
    // Global Ports
    .sys_clk_i                      ( ddr_clk_i           ),
    .clk_ref_i                      ( clk_ref             ),
    .sys_rst                        ( sys_rst_n_i         ),
    .init_calib_complete            ( calib_done_o        ),
                                                            
    // Memory interface ports
    .ddr3_dq                        ( ddr3_dq             ),
    .ddr3_dqs_n                     ( ddr3_dqs_n          ),
    .ddr3_dqs_p                     ( ddr3_dqs_p          ),
    .ddr3_addr                      ( ddr3_addr           ),
    .ddr3_ba                        ( ddr3_ba             ),
    .ddr3_ras_n                     ( ddr3_ras_n          ),
    .ddr3_cas_n                     ( ddr3_cas_n          ),
    .ddr3_we_n                      ( ddr3_we_n           ),
    .ddr3_reset_n                   ( ddr3_reset_n        ),
    .ddr3_ck_p                      ( ddr3_ck_p           ),
    .ddr3_ck_n                      ( ddr3_ck_n           ),
    .ddr3_cke                       ( ddr3_cke            ),
    .ddr3_cs_n                      ( ddr3_cs_n           ),
    .ddr3_dm                        ( ddr3_dm             ),
    .ddr3_odt                       ( ddr3_odt            ),
                                                            
    // Application interface ports     
    .app_addr                       ( app_addr            ),
    .app_cmd                        ( app_cmd             ),
    .app_en                         ( app_en              ),
    .app_wdf_data                   ( app_wdf_data        ),
    .app_wdf_end                    ( app_wdf_end         ),
    .app_wdf_mask                   ( 32'd0               ),
    .app_wdf_wren                   ( app_wdf_wren        ),
    .app_rd_data                    ( app_rd_data         ),
    .app_rd_data_end                ( app_rd_data_end     ),
    .app_rd_data_valid              ( app_rd_data_valid   ),
    .app_rdy                        ( app_rdy             ),
    .app_wdf_rdy                    ( app_wdf_rdy         ),
    .app_sr_req                     ( 'b0                 ),
    .app_ref_req                    ( 'b0                 ),
    .app_zq_req                     ( 'b0                 ),
    .app_sr_active                  (                     ),
    .app_ref_ack                    (                     ),
    .app_zq_ack                     (                     ),
    .ui_clk                         ( ui_clk              ),
    .ui_clk_sync_rst                ( ui_rst              ) 
  );
  
  clk_wiz_0 clk_wiz_inst(
    .clk_out1  ( clk_ref     ), // 200 MHz
    .resetn    ( sys_rst_n_i ),
    .locked    (             ),
    .clk_in1   ( sys_clk_i   )  // 12 MHz 
  );
        
endmodule

XDC constraints are given below.

# System Clock
set_property -dict {PACKAGE_PIN F14 IOSTANDARD LVCMOS33} [get_ports sys_clk_i]
create_clock -period 83.333 -name sys_clk_pin -waveform {0.000 41.667} -add [get_ports sys_clk_i]

# DDR Clock
set_property -dict {PACKAGE_PIN R2 IOSTANDARD SSTL135} [get_ports ddr_clk_i]
create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports ddr_clk_i]

# RGB LEDs
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports calib_done_o]
set_property -dict {PACKAGE_PIN E15 IOSTANDARD LVCMOS33} [get_ports {test_status_o[0]}]
set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS33} [get_ports {test_status_o[1]}]

# System Reset
set_property -dict {PACKAGE_PIN C18 IOSTANDARD LVCMOS33} [get_ports sys_rst_n_i]

Setting Up debug:

The code includes debug signals which will help in visualizing the transactions happening on ui_interface.

To add a signal for debug, add (* mark_debug = “true” *) attribute in front of signal.

Open synthesized design and select Set Up Debug.

 image

Click on Next.

image

Click on Next after making sure right clock is selected for debug signals.

image

Click Next and Finish. Save the synthesized design and generate bitstream.

image

After Loading the bitstream open ILA window to observe the DDR transactions, for capturing ILA only 100 writes and reads are performed.

image

Write Transactions.

image

Read Transactions.

 image

References:

[1] 7 Series Memory Interface Solutions User Guide

[2] Blog which was referred

  • Sign in to reply
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube