SPI 정리

 

[Verilog] 16. SPI(Serial Peripheral Interface)

SPI(Serial Peripheral Interface)는 Controller(Master)와 Peripheral(Slave) 간의 동기식 직렬 데이터 링크를 제공하는 통신버스입니다.Controller(Master) 장치가 CLK 신호를 제공하고 Peripheral(Slave)와 Data를 주고 받습니

chanfifo77.tistory.com

 


SPI Diagram

 

Block Diagram Of SPI

앞단입니다. FSM을 통해 구성할 생각이고, 뒷단은 SPI slave와 RAM으로 구성하겠습니다.

먼저 FIFO module 입니다.

 


FIFO

FIFO는 하나의 Module로 만들어 놓고 Top Module에서 TX, RX로 나누어 사용할 것입니다.

 

 


FIFO

`timescale 1ns / 1ps

module my_fifo(
    input RST,
    input CLK,
    input [7:0] DIN,
    input WR_EN,
    output FULL,
    output reg [7:0] DOUT,
    input RD_EN,
    output EMPTY
    );

reg [7:0] ram [0:31]; 
reg [4:0] wr_addr, rd_addr;
wire    addr_pos;      // full, empty check

// Data write 
always @(posedge CLK)
begin
    if (RST)
        wr_addr <= 5'd0;
    else if(WR_EN && !FULL)
        wr_addr <= wr_addr + 1;        
end // always 

always @(posedge CLK)
    if(WR_EN && !FULL)
        ram[wr_addr] <= DIN;

//data read
always @(posedge CLK)
begin
    if (RST) begin 
        rd_addr <= 5'd0;
        DOUT <= 8'd0;
    end else if(RD_EN && !EMPTY) begin 
        rd_addr <= rd_addr + 1;
        DOUT = ram[rd_addr];
    end        
end  //always

//assign DOUT = ram[rd_addr-1];

wire addr_equ = wr_addr[3:0] == rd_addr[3:0];     // check address equal
assign addr_pos = wr_addr[4] ^ rd_addr[4];

assign FULL = addr_equ & (addr_pos);
assign EMPTY = addr_equ & ~addr_pos;
                   
endmodule

 


SPI Master

 

1) nCS Part
nCS는 state가 idle이면 nCS는 1

2) SCLK gen Part
SCLK는 기존 CLK의 1/10 으로 지정하고, state가 idle, start, cmd_chk일 때 0 아니면 sclk_clk와 동일한 클럭을 생성합니다.
원래 CLK마다 clk_cnt를 1씩 올려서 9가 될 때(CLK_DIV - 1이 될 때), 다시 clk를 0으로 초기화하여 0~9까지 10번의 CLK을 마다 변화하도록 기존 125MHz의 1/10 로 설정하였습니다.

3) FSM Part

FSM of SPI Master

FSM 은 7개의 State로 구성하였습니다.

 


`timescale 1ns / 1ps

module spi_master(
    input RST,
    input CLK,
    input EMPTY,
    output reg RD,
    input [7:0] DIN,
    input FULL,
    output reg WR,
    output [7:0] DOUT,
    output NCS ,
    output SCLK,
    output reg  MOSI,
    input MISO
    );
parameter   [2:0]   sidle = 3'd0,
                    scmd_rd = 3'd1,
                    scmd = 3'd2,
                    scmd_chk = 3'd3,
                    sdata_rd = 3'd4,
                    swrite = 3'd5,
                    sread = 3'd6;
//                    sstop = 3'd5;
parameter   CLK_DIV = 10;                    

reg [2:0] state;
reg [3:0] clk_cnt;
wire       sclk_clk;
reg [7:0] rdata;
wire     cmd; 
wire    bit_en;
reg [2:0]   bit_cnt;
reg [7:0]   sdata;
reg rd_d;


assign NCS = state == sidle || state == scmd_chk; // | state == sstart;
assign SCLK = ((state == sidle) || (state == scmd_chk)|| (state == scmd_rd)) ? 1'b0 : sclk_clk;
assign DOUT = sdata;

assign cmd = rdata[7];

//  spi master FSM
always @(posedge CLK, posedge RST)
begin
    if(RST) begin
        state <= sidle;
        RD <= 1'b0;
        WR <= 1'b0;
        bit_cnt <= 3'd7;
    end        
//    else if(bit_en) begin
    else begin            
        RD <= 1'b0;
        WR <= 1'b0;
        case (state)
            sidle : begin
                bit_cnt <= 3'd7;
                if(~EMPTY && bit_en) begin
                    state <= scmd_rd;
                    RD <= 1'b1;
                end else
                    state <= sidle;
            end
            scmd_rd :
                if(rd_d) 
                    state <= scmd;
                else
                    state <= scmd_rd;                    
            scmd : begin
                if(bit_en) begin
                    bit_cnt <= bit_cnt - 1;
                    if(bit_cnt == 3'd0)
                        state <= scmd_chk;
                    else
                        state <= scmd;                     
                end 
            end                
            scmd_chk : begin
                bit_cnt <= 3'd7;
                if(bit_en) begin
                    if(cmd)
                        state <= sread;
                    else begin
                        state <= sdata_rd;
                        RD <= 1'b1;
                    end
                end                                
            end
            sdata_rd :
                if(rd_d) 
                    state <= swrite;
                else
                    state <= sdata_rd;                    
            swrite : begin
                if(bit_en) begin
                    bit_cnt <= bit_cnt - 1;
                    if(bit_cnt == 3'd0)
                        state <= sidle;
                    else
                        state <= swrite;
                end                                            
            end
            sread : begin
                if(bit_en) begin
                    bit_cnt <= bit_cnt - 1;
                    if(bit_cnt == 3'd0) begin
                        state <= sidle;
                        WR <= ~FULL;
                    end else
                        state <= sread;
                end                                                            
            end
            default : state <= sidle;
        endcase
    end     //if(RST)    
end     //always fsm        

//SCLK gen
always @(posedge CLK)
begin
    if(RST)
        clk_cnt <= 4'd0;
    else if(clk_cnt == (CLK_DIV -1))
        clk_cnt <= 4'd0;
    else
        clk_cnt <= clk_cnt + 1;
end

assign sclk_clk = ( clk_cnt < CLK_DIV/2);
assign bit_en = clk_cnt == 3'd6;

// Parallel to serial MOSI
always @(state, bit_cnt)
begin
    if (state == swrite || state == scmd)
        MOSI = rdata[bit_cnt];
    else
        MOSI = 1'b0;        
end 

//Serial to parallel MISO
always @(negedge sclk_clk)
begin
    if(state == sidle)
        sdata <= 8'd0;
    else if(state == sread)
        sdata[bit_cnt] <= MISO;
end

always @(posedge CLK)
    rd_d <= RD;

always @(posedge CLK)
    if(state == sidle)
        rdata <= 8'd0;
    else if(rd_d)
        rdata <= DIN;        
    
endmodule

 

이번 포스팅은 여기까지 하고 다음 포스팅에서 SPI Slave와 RAM까지 연결해보도록 하겠습니다.

 

'Circuit Design > 🔥HDL' 카테고리의 다른 글

[Verilog] 19. AXI Lite(AXI - Light weight)  (1) 2024.07.14
[Verilog] 18. SPI Slave + RAM 설계  (0) 2024.07.09
[Verilog] 16. SPI(Serial Peripheral Interface)  (0) 2024.06.27
[Vitis] 1. AXI  (0) 2024.06.27
[Verilog] 15. AXI Write  (0) 2024.06.27