[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
앞단입니다. 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 은 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 |