Skocz do zawartości

Kontroler statycznej pamięci RAM 512x8 (IS61WV5128BLL-10BLI) dla zestawu FPGA Digilent Cmod-A7


FlyingDutch

Pomocna odpowiedź

Witam. By wysterować zapis pamięci SRAM wystarczy podać na linie adresowe , danych i we sygnały jednocześnie i odczekać czas propagacji układu. Np: 10ns. Dane będą automatycznie zapisane w pamięci. W przypadku odczytu unikać kolizji na wyjściu danych z układu pamięci. Czyli pamiętać by porty danych w kontrolerze były ustawione jako wejścia. 

Łatwe w użyciu pamięci SRAM są moimi ulubionymi w projektach. W przypadku użycia ich do wyświetlania grafiki szybko się okazało że są małej pojemności i dość drogie . 

Użycie ich jako pamięci do przechowywania danych kontrolera z szybkim dostępem jest moim zdaniem dobrym rozwiązaniem. 

Edytowano przez kroszkanorber
  • Lubię! 2
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)

Cześć,

ostatnio znowu mam mało czasu, jakiś czas temu chciałem przetestować większą pamięć SRAM 2Megax16-bit z układem FPGA, ale z braku czasu tego nie dokończyłem. Dzisiaj miałem trochę czasu i wróciłem do tematu testu pamięci IS61WV204816BLL-10TLI - link do datasheet'a tutaj:

https://www.micro-semiconductor.com/datasheet/d6-IS61WV204816BLL-10TLI.pdf

Ta pamięć SRAM ma organizację 2Mega słowa 16-to bitowe i czas dostepu 10 ns - jest więc dostatecznie duża i szybka na bufor obraz o rozdzielczości do Full HD (1920 × 1080). Postanowiłem zrobić test sterownika dla tej pamięci na zestawie FPGA firmy Gowin zaprojektowanym wcześniej :

Tak wygląda układ testowy. Napisałem nowy (mniejszy i prostszy projekt testowy) dla IDE "Gowin EDA".

FPGA_SRAM.thumb.jpg.69ae65ab763a2e7c1a5a2f5dadd7a629.jpg

Napisałem nowy (mniejszy i prostszy projekt testowy) dla IDE "Gowin EDA". Projekt składa się z trzech modułów Verilog'a:

1) top.v: główny moduł projektu

2) uart.v : zaimplementowany jest minimalistyczny UART (tylko Tx)

3) sram_ctrl2.v : bardzo prosty sterownik SRAM oparty na informacjach ze strony WWW:

https://www.hackster.io/salvador-canas/a-practical-introduction-to-sram-memories-using-an-fpga-i-3f3992?_ga=2.213596829.847914096.1684218873-101257246.1682077800\

Tutaj żródło "top.v" :

`timescale 1ns / 1ps

module top
  ( 
    input wire clk,         //24 Mhz
    input wire reset,
    // to/from SRAM
    output wire [20:0] ad,   
    inout wire [15:0] dio_a, 
    output wire we_n,
    output wire oe_n,
    output wire ce_a_n,
    output wire lb_n,
    output wire ub_n,
    //--------------------
    output wire uart_tx_pin,
    input wire btn1_pin
  );

  reg [15:0] data_f2s_bus;    //FPGA 2 SRAM
  wire [15:0] data_s2f_r_bus;
  reg  [15:0] data_s2f_r_bus_reg;
  reg [20:0] addr_bus;
  reg rw = 1'b1;
  reg lb_top = 1'b0;
  reg ub_top = 1'b0;
  reg trig2 = 1'b1;
  wire clk100MHz;


  Gowin_rPLL your_instance_name(
        .clkout(clk100MHz), //output clkout
        .clkin(clk) //input clkin
  );



sram_ctrl2 SRAM_IC (
    .clk(clk100MHz),
    .reset(reset), 
    .rw(rw), 
    .addr(addr_bus), 
    .data_f2s(data_f2s_bus), 
    .data_s2f_r(data_s2f_r_bus), 
    .lb_in(lb_top),
    .ub_in(ub_top),
    .ad(ad), 
    .we_n(we_n), 
    .oe_n(oe_n), 
    .dio_a(dio_a), 
    .ce_a_n(ce_a_n),
    .lb_n(lb_n), 
    .ub_n(ub_n)
    );

uart #( .DELAY_FRAMES(208),
        .NCH(8)
      ) UART_TX
	 (
		.clk(clk),
		.uart_tx(uart_tx_pin),
        .btn1(trig2),
		.data_byte_low(data_s2f_r_bus_reg[7:0]),
		.data_byte_high(data_s2f_r_bus_reg[15:8])
	 );

reg [3:0] varState = 0;

localparam STATE_IDLE = 0;
localparam STATE_READ_SET_ADDRESS = 1;
localparam STATE_READ_GET_VALUE = 2;
localparam STATE_WRITE_C1_WE_HIGH = 3;
localparam STATE_WRITE_C1_SET_ADDR = 4;
localparam STATE_WRITE_C1_SET_WE = 5;
localparam STATE_READ_U= 6;
localparam STATE_WRITE_C2A = 7;
localparam STATE_WRITE_C2B = 8;
localparam STATE_IDLE2 = 9;
localparam STATE_READ2_SET_ADDRESS = 10;
localparam STATE_READ2_GET_VALUE = 11;
localparam STATE_SEND_UART = 12;

//SRAM top state machine
always @(posedge clk100MHz) begin
    case (varState)
        STATE_IDLE: begin
            if (btn1_pin == 0) begin
              trig2 = 1'b1;
              data_f2s_bus <= 16'b1010101010101010;    //FPGA 2 SRAM
              addr_bus <= 21'b000000000000000000011;
              lb_top = 1'b0;
              ub_top = 1'b0;
              rw = 1'b1;
              varState <= STATE_READ_SET_ADDRESS;
            end
        end 
       STATE_READ_SET_ADDRESS: begin
             addr_bus <= 21'b000000000000000000111;
             varState <= STATE_READ_GET_VALUE;
        end
       STATE_READ_GET_VALUE: begin            
             data_s2f_r_bus_reg <= data_s2f_r_bus;
             varState <= STATE_WRITE_C1_WE_HIGH;                                      //varState <= STATE_WRITE_C1_WE_HIGH;
        end
        STATE_WRITE_C1_WE_HIGH: begin
             lb_top = 1'b1;
             ub_top = 1'b1;
             rw = 1'b1;
             varState <= STATE_WRITE_C1_SET_ADDR;
        end
        STATE_WRITE_C1_SET_ADDR: begin
             addr_bus <= 21'b100000000000000000001;
             data_f2s_bus <= 16'b0101010111111111;
             varState <= STATE_WRITE_C1_SET_WE;
        end
        STATE_WRITE_C1_SET_WE: begin
             rw = 1'b0;
             lb_top = 1'b0;
             ub_top = 1'b0;
             varState <= STATE_IDLE2;
        end
        STATE_IDLE2: begin
             rw = 1'b1;
             addr_bus <= 21'b000000000000000000011;
             data_f2s_bus <= 16'b0000000000000000;
             varState <= STATE_READ2_SET_ADDRESS;
        end
        STATE_READ2_SET_ADDRESS: begin           
             addr_bus <= 21'b100000000000000000001;
             varState <= STATE_READ2_GET_VALUE;
        end
        STATE_READ2_GET_VALUE: begin         
             data_s2f_r_bus_reg <= data_s2f_r_bus;
             varState <=  STATE_SEND_UART;         
        end
       STATE_SEND_UART : begin           
             trig2 = 1'b0;
             varState <= STATE_IDLE;
        end
    endcase      
end


endmodule

Jest w nim zaimplementaowana prosta maszyna stanowa (FSM) która dokonuje najpierw zapisu 16-to bitowego słowa do pamięci SRAM, a potem odczytuje tą komórkę i za pomocą UART'a wyswietla odczytane dane.

Tutaj kod sterownika pamięci SRAM "sram_ctrl2.v:

module sram_ctrl2(

  input wire clk,                        //  Clock signal
  input wire reset,                      //  Reset signal

  input wire rw,                         //  With this signal, we select reading or writing operation
  input wire [20:0] addr,                //  Address bus
  input wire [15:0] data_f2s,             //  Data to be writteb in the SRAM
  input wire lb_in,
  input wire ub_in,
  output reg  [15:0] data_s2f_r,           //  It is the 8-bit registered data retrieved from the SRAM (the -s2f suffix stands for SRAM to FPGA)
  output wire [20:0] ad,                 //  Address bus
  output wire we_n,                      //  Write enable (active-low)
  output wire oe_n,                      //  Output enable (active-low)
  output wire lb_n,                        //data bus low byte
  output wire ub_n,                         //data bus high byte

  inout wire [15:0] dio_a,                //  Data bus
  output wire ce_a_n                     //  Chip enable (active-low). Disables or enables the chip.
  );

  assign ce_a_n = 1'b0;
  assign oe_n = 1'b0;  //READ and WRITE
  assign we_n = rw;
  assign ad = addr;
  //----------------
  assign lb_n = lb_in; //READ LOW both
  assign ub_n = ub_in;
  
  assign dio_a = (rw == 1'b1)? 16'hZZ : data_f2s;
  
  always @(posedge clk) begin
    if (rw == 1'b1)
      data_s2f_r <= dio_a;
  end

endmodule

Kod jest trochę zmodyfikowany przeze mnie aby obsługiwał ten konkretny wybrany typ pamięci.

W module 'uart.v" jest implementacja lini Tx UART'a do wysyłania danych do komputera PC:

`default_nettype none

module uart
#(
    parameter DELAY_FRAMES = 208, // 24,000,000 (24Mhz) / 115200 Baud rate - 234 was for 27 MHz
    parameter NCH = 8             // Number of bits in data
)
(
    input wire clk,
    output wire uart_tx,
    input wire btn1,
    //--------------------
    input wire [7:0] data_byte_low, //low byte of data
    input wire [7:0] data_byte_high //low byte of data
);

localparam HALF_DELAY_WAIT = (DELAY_FRAMES / 2);

reg [3:0] txState = 0;
reg [24:0] txCounter = 0;
reg [7:0] dataOut = 0;
reg txPinRegister = 1;
reg [2:0] txBitNumber = 0;
reg [8:0] txByteCounter = 0;
reg [29:0] bigCounter = 0;

assign uart_tx = txPinRegister;

reg [8:0] txCharCounter = 0;
localparam MEMORY_LENGTH = 39;
reg [7:0] testMemory [MEMORY_LENGTH-1:0];
localparam BIG_DELAY = 24000000;
//---------------------------------
reg [7:0] testMemory1 [8:0];
reg [7:0] testMemory2 [8:0];
reg [7:0] testMemory3 [1:0];

integer i,i2,i3,i4,i5,i6 = 0;
integer addr = 0;
integer lock = 0;
reg [8:0] loopCounter = 0;

initial begin
    testMemory[0] = "D";
    testMemory[1] = "a";
    testMemory[2] = "t";
    testMemory[3] = "a";
    testMemory[4] = " ";
    testMemory[5] = "H";
    testMemory[6] = "i";   
    testMemory[7] = "g";
    testMemory[8] = "h";
    testMemory[9] = ":";

//    testMemory[10] = "1";
//    testMemory[11] = "1";
//    testMemory[12] = "1";
//    testMemory[13] = "1";
//    testMemory[14] = "1";
//    testMemory[15] = "1";
//    testMemory[16] = "1";   
//    testMemory[17] = "1";

    testMemory[18] = 8'h0D;
    testMemory[19] = "\n";

    testMemory[20] = "D";
    testMemory[21] = "a";
    testMemory[22] = "t";
    testMemory[23] = "a";
    testMemory[24] = " ";
    testMemory[25] = "L";
    testMemory[26] = "o";   
    testMemory[27] = "w";
    testMemory[28] = ":";

//    testMemory[29] = "1";
//    testMemory[30] = "1";
//    testMemory[31] = "1";
//    testMemory[32] = "1";
//    testMemory[33] = "1";
//    testMemory[34] = "1";
//    testMemory[35] = "1";   
//    testMemory[36] = "1";

    testMemory[37] = 8'h0D;;
    testMemory[38] = "\n";

    loopCounter = 10;

end



always @(posedge clk) begin 
     addr = 10;
     for ( i = 0; i < NCH; i=i+1) 
     begin
       testMemory[addr+i] = (data_byte_high[NCH-1-i]) ? "1" : "0";
     end

     addr = 29;
     for ( i = 0; i < NCH; i=i+1)
     begin
       testMemory[addr+i] = (data_byte_low[NCH-1-i]) ? "1" : "0";
     end
end


localparam TX_STATE_IDLE = 0;
localparam TX_STATE_START_BIT = 1;
localparam TX_STATE_WRITE = 2;
localparam TX_STATE_STOP_BIT = 3;
localparam TX_STATE_DEBOUNCE = 4;

always @(posedge clk) begin
    case (txState)
        TX_STATE_IDLE: begin
            if (btn1 == 0) begin
                txState <= TX_STATE_START_BIT;
                txCounter <= 0;
                txByteCounter <= 0;
            end
            else begin
                txPinRegister <= 1;
            end
        end 
        TX_STATE_START_BIT: begin
            txPinRegister <= 0;
            if ((txCounter + 1) == DELAY_FRAMES) begin
                txState <= TX_STATE_WRITE;
                dataOut <= testMemory[txByteCounter];
                txBitNumber <= 0;
                txCounter <= 0;
            end else 
                txCounter <= txCounter + 1;
        end
        TX_STATE_WRITE: begin
            txPinRegister <= dataOut[txBitNumber];
            if ((txCounter + 1) == DELAY_FRAMES) begin
                if (txBitNumber == 3'b111) begin
                    txState <= TX_STATE_STOP_BIT;
                end else begin
                    txState <= TX_STATE_WRITE;
                    txBitNumber <= txBitNumber + 1;
                end
                txCounter <= 0;
            end else 
                txCounter <= txCounter + 1;
        end
        TX_STATE_STOP_BIT: begin
            txPinRegister <= 1;
            if ((txCounter + 1) == DELAY_FRAMES) begin
                if (txByteCounter == MEMORY_LENGTH - 1) begin
                    txState <= TX_STATE_DEBOUNCE;
                end else begin
                    txByteCounter <= txByteCounter + 1;
                    txState <= TX_STATE_START_BIT;
                end
                txCounter <= 0;
            end else 
                txCounter <= txCounter + 1;
        end
        TX_STATE_DEBOUNCE: begin
            if (txCounter == 23'b111111111111111111) begin
                if (btn1 == 1) 
                    txState <= TX_STATE_IDLE;
            end else
                txCounter <= txCounter + 1;
        end
    endcase      
 
end

endmodule

Jak można wywnioskować z lini kodu modułu top:

      STATE_WRITE_C1_SET_ADDR: begin
             addr_bus <= 21'b100000000000000000001;
             data_f2s_bus <= 16'b0101010111111111;
             varState <= STATE_WRITE_C1_SET_WE;
        end

Wartość binarna słowa 16-to bitowego "101010111111111" jest zapisywana w kpmórce pamięci. Ta sama wartośc powinna byc wyświetlona po odczycie tej komórki przez UARTi tak się dzaieje - patrz zrut ekranu z terminala (PUtty):

 

Terminal.thumb.png.6589b9dff29bab3764a6f1c46eaa23f7.png

Nie wiem czemu output z terminal trochę się rozjeżdza, ale dane są wyświetlane poprawnie. Aby wygenerować timing dla operacji odczytu i zapisu pamięci SRAM (tak jak jest to podane w datasheet) musiałem za pomoć petli PLL (IP Core Gowina) wygenerować zegar 100 MHz dla sterownika z zegara 24 MHz, który ma ta płytka.

W pilku zip spakowany projekt dla "Gowin EDA".SRAM_2Mx16_Ctrl01.zip

Pozdrawiam

 

Edytowano przez FlyingDutch
  • Lubię! 1
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.