📄 spi_burst.v
字号:
///////////////////////////////////////////////////////////////////////////////
// //
// FileName: "spi_burst.v" //
// //
// Description: This is SPI control logic. One/Two Byte Data is transmitted //
// and one byte data is received by 8051 from SPI. Burst data is transmitted //
// and received from/to buffer by hardware. //
// The main function are: //
// a. one/burst Read //
// b. one/burst Write //
// c. Two bytes Write //
// //
// Author : Well.yu //
// //
// //
// Revision History //
// //
// //
///////////////////////////////////////////////////////////////////////////////
//CTRL Configure
//1.CLOCK: ctrl[7]
// a. mck==mcu_clk : XBYTE[0x03f1] |= 0x80 ;
// b. mck==1/2*(N+1)*mcu_clk : XBYTE[0x03f1] &= 0x7f ;
//2.Sample edge selection: ctrl[6]
// a. Sample Data from mdi at mck rising edge : XBYTE[0x03f1] &= 0xbf ;
// b. Sample Data from mdi at mck falling edge : XBYTE[0x03f1] |= 0x40 ;
//3.Clock divide Frequency Counter: ctrl[5:0]
// mck==1/2*(N+1)*mcu_clk : XBYTE[0x03f1] = data ;(data<64,data==N)
//Five Types Operation
//1:One byte Write -> XBYTE[0x03fb] = data ;
//2:Burst Write -> XBYTE[0x03fe] = 0x01 ;
//3:One byte Read -> XBYTE[0x03fe] = 0x0E ;
//4:Burst Read -> XBYTE[0x03fe] = 0x0A ;
//5:Two bytes Wriet -> 1.XBYTE[0x03fd] = 0x0F ;
// 2.XBYTE[0x03fc] = data2;
// 3.XBYTE[0x03fb] = data1;
//Reg Map : 0x03f0~0x03ff
`define SPI_TEST_SEL 8'h60
`define SPI_CTL 8'h61
`define XMIT_LEN_L 8'h62
`define XMIT_LEN_H 8'h63
`define RECV_LEN_L 8'h64
`define RECV_LEN_H 8'h65
`define SPI_S_RST 8'h69
`define SPI_STAT_M 8'h6a
`define XMIT_ONE_D 8'h6b
`define XMIT_TWO_D 8'h6c
`define XMIT_BIT_L 8'h6d
`define SPI_CMD_WR 8'h6e
`define SPI_STATUS 8'h6f
`timescale 1ns/10ps
module spi(
///////spi bus//////////
mdi,
mdo,
mck,
///////ctrl block//////
mcu_clk,
reset_n,
//reset_s,
spi_en,
//////burst read ctrl///
spidat,
spidat_vld,
//////mcu interface//////
wr_8051,
rd_8051,
addr,
data_in,
data_out,
//////burst write ctrl///
buf_rd_mcu,
buf_dat,
//////test bus//////////
spi_test_bus
);
//////////////////////// Ports ///////////////////////////////////////////////////
input mdi; // master data in, connect to flash pin 'sdo'
output mdo; // master data out, connect to flash pin 'sdi'
output mck; // master clock, connect to flash pin 'clk'
input mcu_clk; // system clock, 30Mhz
input reset_n; // system reset:'0'
//input reset_s; // soft reset :'0'
input spi_en; // enable SPI block : '1'-enable;'0'-disable
output [7:0] spidat; // 8051 control transfer data, e.x, spi command is transfered
// by this regsiter. The second function is receiving data
// serially from SPI flash
output spidat_vld; // valid signal for spidat when transfer data from SPI to buf
input [7:0] addr; // 8051 write/read address
input [7:0] data_in; // from 8051 data
output [7:0] data_out; // to 8051 data
input wr_8051; // 8051 write enable
input rd_8051; // 8051 read enable
output buf_rd_mcu; // read enable to read data from buf1 or buf2
input [7:0] buf_dat; // data which will be xmitted from buffer to SPI
//output [7:0] spictrl ; // SPI Ctrl Register : default 8'h84 -> 1000,0100
//output [7:0] bufwl ; // from Buffer Write data Length Low :default 8'hff - 256Bytes
//output [7:0] bufwh ; // from Buffer Write data Length High :default 8'h00
//output [7:0] bufrl ; // to Buffer Read data Length Low :default 8'hff - 256Bytes
//output [7:0] bufrh ; // to Buffer Read data Length High :default 8'h00
output [15:0] spi_test_bus ;
////////////////////// Signals //////////////////////////////////////////////////////
wire mcu_clk_sel; // '1' selects MCU CLK for SPI :30MHz
//wire mcu_clk_h_sel; // '1' selects Half of MCU CLK for SPI :15MHz
// {mcu_clk_sel,mcu_clk_h_sel}== 2'b00, then select 7.5Mhz
wire rd_one_byte ;
wire rcv_edge_sel;
wire spi_dir ;
//wire [7:0] spictrl ;
//wire [7:0] bufwl ;
//wire [7:0] bufwh ;
//wire [7:0] bufrl ;
//wire [7:0] bufrh ;
wire [7:0] addr ;
wire [7:0] data_in ;
reg [7:0] data_out;
reg [3:0] state, state_nxt;
wire cmd_lat;
reg cmd_lat_d1;
wire xmit_done;
reg [7:0] xmit_cnt;
reg [7:0] dat_out,dat_out2;
reg [7:0] buf_dat_lch;
reg mck_en;
wire mck;
reg mdo;
wire xmit_nxt;
wire spi_cmd_sent;
reg [15:0] buf_rd_cnt;
reg [3:0] sta_d, sta_d_nxt;
reg [2:0] cnt7;
reg buf_rd /* synthesis syn_keep = 1 */;
reg buf_rd_d1;
wire buf_rd_mcu;
reg xmit_nxt_dat;
reg [7:0] spidat;
reg rd_en;
reg xmit_nxt_dat_d1;
reg xmit_done_d1;
reg spidat_vld_reg, spidat_vld_pre_d1;
wire spidat_vld_pre;
wire spidat_vld;
reg [12:0] cnt7_for_rd;
reg spi_work; // '1':mck is working '0': mck is idle
wire spi_busy; // Burst write Busy ->'1':Idle->'0'
wire mck_jump;
reg cmd_lat_24, ctrl_3_24m;
reg [1:0] bus_sel;
reg [7:0] ctrl ; // SPI control register:
// ctrl[7] -> mcu_clk_sel R/W
// ctrl[6] -> Sample received data clock edge select R/W
// ctrl[5:0] -> Divide Frequency Coefficient R/W
reg [7:0] bwdl ; // Burst Write Data Length Low , default 8'hff - 256Bytes
reg [7:0] bwdh ; // Burst Write Data Length High, default 8'h00
reg [7:0] brdl ; // Burst Read Data Length Low , default 8'hff - 256Bytes
reg [7:0] brdh ; // Burst Read Data Length High, default 8'h00
reg [7:0] bitl ; // Bit Write Data Length Low , default 8'h07 - 8Bits
reg [7:0] cmd ; // cmd[3] -> SPI direction :'1'->Read '0'->Write R/W
// cmd[2] -> Read One Byte Data R/W
// cmd[1] -> Start SPI Read operation '1' W
// cmd[0] -> Start SPI Burst Write operation W
reg [7:0] sbdw ; // the Second Byte in Double Bytes Write
reg soft_rst;//soft reset :'0' active
reg [15:0] spi_test_bus ;// Inside SPI Signal Bus for Test
wire reset_s;
wire clk ; // spi clk : 30MHz,15MHz,7.5MHz
//reg [1:0] spi_divcnt ;
reg [6:0] spi_clk_cnt;
reg clk_conv_zero;
reg clk_conv_one ;
wire [5:0] clkdiv;
wire [6:0] clk_divx2;
wire [6:0] clkdiv_add1;
wire spi_clk_trig;
reg spi_div_clk;
reg spi_divclk_ok;//SPI Clock is OK : '1' -> OK ; '0' -> NOT
parameter IDLE = 4'h0, // idle state, this machine controls command sending
START = 4'h1, // start to xmit command
XMIT = 4'h2; // xmitting command
parameter IDLE_D = 4'h0, // idle state, this machinen controls data sending
BEGIN = 4'h1, // begin to xmit data
BUF_RD = 4'h2, // reading data from buf1
wait = 4'h3, // waiting next buffer, if there are more data
wire [15:0] bwdt = {1'b0,bwdh[6:0],bwdl}+1'b1;
assign reset_s = soft_rst && spi_en ;
assign spi_busy = (sta_d == BUF1_RD) ? 1'b1 : 1'b0;
assign mcu_clk_sel = ctrl[7] ;
assign rcv_edge_sel = ctrl[6] ;
assign spi_dir = cmd[3] ;
assign rd_one_byte = cmd[2] ;
assign spi_cmd_sent = cmd[0] ;
///////////////////////////////////// CLK GEN ///////////////////////////////////
assign clk = mcu_clk_sel ? mcu_clk : spi_div_clk ;
assign clkdiv = ctrl[5:0] ;
assign clk_divx2 = {clkdiv,1'b1} ;
assign clkdiv_add1 = clkdiv + 1'b1 ;
always @(posedge mcu_clk or negedge reset_n)
begin
if(!reset_n)
spi_clk_cnt <= #1 7'h00 ;
else if(!reset_s)
spi_clk_cnt <= #1 7'h00 ;
else if(spi_clk_cnt == clk_divx2)
spi_clk_cnt <= #1 7'h00 ;
else
spi_clk_cnt <= #1 spi_clk_cnt + 1'b1 ;
end
always @(posedge mcu_clk or negedge reset_n)
begin
if(!reset_n)
clk_conv_one <= #1 1'b0 ;
else if(!reset_s)
clk_conv_one <= #1 1'b0 ;
else if(spi_clk_cnt == clkdiv_add1)
clk_conv_one <= #1 1'b1 ;
else
clk_conv_one <= #1 1'b0 ;
end
always @(posedge mcu_clk or negedge reset_n)
begin
if(!reset_n)
clk_conv_zero <= #1 1'b0 ;
else if(!reset_s)
clk_conv_zero <= #1 1'b0 ;
else if(spi_clk_cnt == 7'h00)
clk_conv_zero <= #1 1'b1 ;
else
clk_conv_zero <= #1 1'b0 ;
end
always @(posedge mcu_clk or negedge reset_n)
begin
if(!reset_n)
spi_div_clk <= #1 1'b0 ;
else if(!reset_s)
spi_div_clk <= #1 1'b0 ;
else if(clk_conv_one)
spi_div_clk <= #1 1'b1 ;
else if(clk_conv_zero)
spi_div_clk <= #1 1'b0 ;
end
assign spi_clk_trig = mcu_clk_sel ? 1'b1 : clk_conv_one ;
///////////////////////////////////////// state machine for byte data sending //////////////////////////////
always @(posedge mcu_clk or negedge reset_n)
begin
if (!reset_n)
state <= #1 4'h0;
else if (!reset_s)
state <= #1 4'h0;
else if (spi_clk_trig)
state <= #1 state_nxt;
end
always @(state or cmd_lat_24 or xmit_done)
begin
case (state)
IDLE :
if (cmd_lat_24)
state_nxt = START;
else
state_nxt = IDLE;
START:
state_nxt = XMIT;
XMIT :
if (xmit_done)
state_nxt = IDLE;
else
state_nxt = XMIT;
default:
state_nxt = IDLE;
endcase
end
// state machine for data burst sending
always @(posedge mcu_clk or negedge reset_n)
begin
if (!reset_n)
sta_d <= #1 4'h0;
else if (!reset_s)
sta_d <= #1 4'h0;
else if (spi_clk_trig)
sta_d <= #1 sta_d_nxt;
end
always @(sta_d or buf_rd_cnt or
bwdl or bwdh or spi_cmd_sent or bwdt or cnt7)
begin
case (sta_d)
IDLE:
if (spi_cmd_sent)
sta_d_nxt = BEGIN;
else
sta_d_nxt = IDLE;
BEGIN:
sta_d_nxt = BUF_RD;
BUF_RD:
if ((buf_rd_cnt == bwdt)&&(cnt7==8'h07))
sta_d_nxt = WAIT;
else
sta_d_nxt = BUF_RD;
WAIT:
sta_d_nxt = IDLE ;
default:
sta_d_nxt = IDLE;
endcase
end
always @(posedge mcu_clk or negedge reset_n)
begin
if (!reset_n)
buf_rd_cnt <= #1 16'h0000;
else if (!reset_s)
buf_rd_cnt <= #1 16'h0000;
else if (spi_clk_trig && buf_rd)
buf_rd_cnt <= #1 buf_rd_cnt + 1'b1;
else if (spi_clk_trig && (sta_d == WAIT))
buf_rd_cnt <= #1 16'h0000;
end
assign xmit_done = (xmit_cnt == bitl) ;
always @(posedge mcu_clk or negedge reset_n)
begin
if (!reset_n)
xmit_done_d1 <= #1 1'b0;
else if (!reset_s)
xmit_done_d1 <= #1 1'b0;
else if (spi_clk_trig)
xmit_done_d1 <= #1 xmit_done;
end
always @(posedge mcu_clk or negedge reset_n)
begin
if (!reset_n)
xmit_cnt <= #1 8'h00;
else if ((spi_clk_trig && xmit_done) || !reset_s)
xmit_cnt <= #1 8'h00;
else if (spi_clk_trig && (state == XMIT))
xmit_cnt <= #1 xmit_cnt + 1'b1;
end
assign xmit_nxt = xmit_nxt_dat;
always @(posedge mcu_clk or negedge reset_n)
begin
if (!reset_n)
xmit_nxt_dat <= #1 1'b0;
else if (!reset_s)
xmit_nxt_dat <= #1 1'b0;
else if (spi_clk_trig && (buf_rd_cnt == bwdt) && (cnt7 == 8'h7))
xmit_nxt_dat <= #1 1'b0;
else if (spi_clk_trig && buf_rd)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -