diff --git a/src/spi/hdl/spi.v b/src/spi/hdl/spi.v index 356faa4..46ed2d3 100644 --- a/src/spi/hdl/spi.v +++ b/src/spi/hdl/spi.v @@ -34,6 +34,11 @@ module spi #( parameter AW = 32, // address width output s_miso // slave output ); +//1. set manual_CS mode +//2. assert ss (0000) +//4. write to tx fifo +//6. deassert ss (1111) + //############### //# LOCAL WIRES //############### diff --git a/src/spi/hdl/spi_master.v b/src/spi/hdl/spi_master.v index 36a3b83..7f24394 100644 --- a/src/spi/hdl/spi_master.v +++ b/src/spi/hdl/spi_master.v @@ -47,10 +47,12 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth wire fifo_read; // From spi_master_io of spi_master_io.v wire fifo_wait; // From spi_master_fifo of spi_master_fifo.v wire lsbfirst; // From spi_master_regs of spi_master_regs.v + wire manual_mode; // From spi_master_regs of spi_master_regs.v wire rx_access; // From spi_master_io of spi_master_io.v wire [63:0] rx_data; // From spi_master_io of spi_master_io.v + wire send_data; // From spi_master_regs of spi_master_regs.v wire spi_en; // From spi_master_regs of spi_master_regs.v - wire [1:0] spi_state; // From spi_master_io of spi_master_io.v + wire [2:0] spi_state; // From spi_master_io of spi_master_io.v // End of automatics //##################################################### @@ -65,6 +67,8 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth .cpha (cpha), .lsbfirst (lsbfirst), .spi_en (spi_en), + .manual_mode (manual_mode), + .send_data (send_data), .clkdiv_reg (clkdiv_reg[7:0]), .wait_out (wait_out), .access_out (access_out), @@ -75,7 +79,7 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth .hw_en (hw_en), .rx_data (rx_data[63:0]), .rx_access (rx_access), - .spi_state (spi_state[1:0]), + .spi_state (spi_state[2:0]), .fifo_prog_full (fifo_prog_full), .fifo_wait (fifo_wait), .access_in (access_in), @@ -116,7 +120,7 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth spi_master_io spi_master_io (/*AUTOINST*/ // Outputs - .spi_state (spi_state[1:0]), + .spi_state (spi_state[2:0]), .fifo_read (fifo_read), .rx_data (rx_data[63:0]), .rx_access (rx_access), @@ -129,6 +133,8 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth .cpol (cpol), .cpha (cpha), .lsbfirst (lsbfirst), + .manual_mode (manual_mode), + .send_data (send_data), .clkdiv_reg (clkdiv_reg[7:0]), .fifo_dout (fifo_dout[7:0]), .fifo_empty (fifo_empty), diff --git a/src/spi/hdl/spi_master_io.v b/src/spi/hdl/spi_master_io.v index b96ce07..e3529ad 100644 --- a/src/spi/hdl/spi_master_io.v +++ b/src/spi/hdl/spi_master_io.v @@ -12,8 +12,10 @@ module spi_master_io input cpol, // cpol input cpha, // cpha input lsbfirst, // send lsbfirst - input [7:0] clkdiv_reg, // baudrate - output reg [1:0] spi_state, // current spi tx state + input manual_mode,// sets automatic ss mode + input send_data, // controls ss in manual ss mode + input [7:0] clkdiv_reg, // baudrate + output reg [2:0] spi_state, // current spi tx state // data to transmit input [7:0] fifo_dout, // data payload input fifo_empty, // @@ -32,7 +34,9 @@ module spi_master_io //# LOCAL WIRES //############### reg fifo_empty_reg; - reg load_byte; + reg load_byte; + wire rx_access; + reg ss_reg; wire [7:0] data_out; wire [15:0] clkphase0; wire period_match; @@ -42,7 +46,7 @@ module spi_master_io wire data_done; wire spi_wait; wire shift; - + wire spi_active; /*AUTOWIRE*/ @@ -76,24 +80,27 @@ module spi_master_io //# STATE MACHINE //################################# -`define SPI_IDLE 2'b00 // set ss to 1 -`define SPI_SETUP 2'b01 // setup time -`define SPI_DATA 2'b10 // send data -`define SPI_HOLD 2'b11 // hold time +`define SPI_IDLE 3'b000 // set ss to 1 +`define SPI_SETUP 3'b001 // setup time +`define SPI_DATA 3'b010 // send data +`define SPI_HOLD 3'b011 // hold time +`define SPI_MARGIN 3'b100 // pause always @ (posedge clk or negedge nreset) if(!nreset) - spi_state[1:0] <= `SPI_IDLE; + spi_state[2:0] <= `SPI_IDLE; else - case (spi_state[1:0]) + case (spi_state[2:0]) `SPI_IDLE : - spi_state[1:0] <= fifo_read ? `SPI_SETUP : `SPI_IDLE; + spi_state[2:0] <= fifo_read ? `SPI_SETUP : `SPI_IDLE; `SPI_SETUP : - spi_state[1:0] <= phase_match ? `SPI_DATA : `SPI_SETUP; + spi_state[2:0] <= phase_match ? `SPI_DATA : `SPI_SETUP; `SPI_DATA : - spi_state[1:0] <= data_done ? `SPI_HOLD : `SPI_DATA; + spi_state[2:0] <= data_done ? `SPI_HOLD : `SPI_DATA; `SPI_HOLD : - spi_state[1:0] <= phase_match ? `SPI_IDLE : `SPI_HOLD; + spi_state[2:0] <= phase_match ? `SPI_MARGIN : `SPI_HOLD; + `SPI_MARGIN : + spi_state[2:0] <= phase_match ? `SPI_IDLE : `SPI_MARGIN; endcase // case (spi_state[1:0]) //read fifo on phase match (due to one cycle pipeline latency @@ -101,10 +108,7 @@ module spi_master_io //data done whne assign data_done = fifo_empty & ~spi_wait & phase_match; - - //shift on every clock cycle while in datamode - assign shift = phase_match & (spi_state[1:0]==`SPI_DATA);//period_match - + //load is the result of the fifo_read always @ (posedge clk) load_byte <= fifo_read; @@ -112,19 +116,24 @@ module spi_master_io //################################# //# CHIP SELECT //################################# - - assign ss = (spi_state[1:0]==`SPI_IDLE); + + assign spi_active = ~(spi_state[2:0]==`SPI_IDLE | spi_state[2:0]==`SPI_MARGIN); + + assign ss = ~((spi_active & ~manual_mode) | (send_data & manual_mode)); //################################# //# DRIVE OUTPUT CLOCK //################################# - assign sclk = clkout & (spi_state[1:0]==`SPI_DATA); + assign sclk = clkout & (spi_state[2:0]==`SPI_DATA); //################################# //# TX SHIFT REGISTER //################################# - + + //shift on falling edge + assign tx_shift = phase_match & (spi_state[2:0]==`SPI_DATA); + oh_par2ser #(.PW(8), .SW(1)) par2ser (// Outputs @@ -135,7 +144,7 @@ module spi_master_io .clk (clk), .nreset (nreset), // async active low reset .din (fifo_dout[7:0]), // 8 bit data from fifo - .shift (shift), // shift on neg edge + .shift (tx_shift), // shift on neg edge .datasize (8'd7), // 8 bits at a time (0..7-->8) .load (load_byte), // load data from fifo .lsbfirst (lsbfirst), // serializer direction @@ -146,13 +155,9 @@ module spi_master_io //# RX SHIFT REGISTER //################################# - //generate access pulse at rise of ss - oh_rise2pulse - pulse (.out (rx_access), - .nreset (nreset), - .clk (clk), - .in (ss)); - + //shift in rising edge + assign rx_shift = (spi_state[2:0] == `SPI_DATA) & period_match; + oh_ser2par #(.PW(64), .SW(1)) ser2par (//output @@ -161,7 +166,17 @@ module spi_master_io .din (miso), // serial data in .clk (clk), // shift clk .lsbfirst (lsbfirst), // shift direction - .shift (shift)); // shift data + .shift (rx_shift)); // shift data + + //generate access pulse at rise of ss + always @ (posedge clk or negedge nreset) + if(!nreset) + ss_reg <= 1'b1; + else + ss_reg <= ss; + + assign rx_access = ss & ~ss_reg; + endmodule // spi_master_io // Local Variables: diff --git a/src/spi/hdl/spi_master_regs.v b/src/spi/hdl/spi_master_regs.v index 5ff9a15..0a8bf55 100644 --- a/src/spi/hdl/spi_master_regs.v +++ b/src/spi/hdl/spi_master_regs.v @@ -6,6 +6,7 @@ //############################################################################# `include "spi_regmap.vh" + module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv parameter AW = 32, // addresss width parameter PW = 104 // packet width @@ -14,7 +15,7 @@ module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv //clk,reset, cfg input clk, // core clock input nreset, // async active low reset - input hw_en, // block enable pin + input hw_en, // block enable //io interface input [63:0] rx_data, // rx data input rx_access, // rx access pulse @@ -23,8 +24,10 @@ module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv output cpha, // clk phase shift (default is 0) output lsbfirst, // send lsbfirst output spi_en, // enable transmitter + output manual_mode,// sets manual ss control + output send_data, // controls ss in manual ss mode output reg [7:0] clkdiv_reg, // baud rate setting - input [1:0] spi_state, // transmit state + input [2:0] spi_state, // transmit state input fifo_prog_full, // fifo reached half/full input fifo_wait, // tx transfer wait //packet to transmit @@ -113,7 +116,9 @@ module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv assign cpol = config_reg[2]; // cpol assign cpha = config_reg[3]; // cpha assign lsbfirst = config_reg[4]; // send lsb first - + assign manual_mode = config_reg[5]; // manual control of ss bit + assign send_data = config_reg[6]; // ss bit + //#################################### //# STATUS //#################################### @@ -124,10 +129,10 @@ module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv else if(status_write) status_reg[7:0] <= reg_wdata[7:0]; else - status_reg[7:0] <= {5'b0, //7:3 - fifo_prog_full, //2 - |spi_state[1:0], //1 - (rx_access | status_reg[0])};//0 + status_reg[7:0] <= {5'b0, //7:4 + fifo_prog_full, //3 + 1'b0, //reserved + (rx_access | (~tx_write & status_reg[0]))};//0 //#################################### //# CLKDIV diff --git a/src/spi/hdl/spi_slave_io.v b/src/spi/hdl/spi_slave_io.v index a90c452..e5e371e 100644 --- a/src/spi/hdl/spi_slave_io.v +++ b/src/spi/hdl/spi_slave_io.v @@ -1,5 +1,6 @@ //############################################################################# //# Purpose: SPI slave IO state-machine # +//# NOTE: only cpol=0, cpha=0 supported for now!! # //############################################################################# //# Author: Andreas Olofsson # //# License: MIT (see LICENSE file in OH! repository) # @@ -44,14 +45,23 @@ module spi_slave_io #( parameter PW = 104 // packet width wire [63:0] tx_data; wire rx_shift; wire tx_load; - wire tx_shift; wire tx_wait; wire ss_sync; wire ss_pulse; wire spi_fetch; wire byte_done; + + //################################# + //# MODES: TODO! + //################################# - + //cpol=0,cpha=0 + //(launch on negedge, capture on posedge) + assign shift = ~ss & spi_en; + assign rx_clk = sclk; + assign tx_clk = ~sclk; + assign tx_load = next_byte; + //################################# //# STATE MACHINE //################################# @@ -67,7 +77,7 @@ module spi_slave_io #( parameter PW = 104 // packet width else case (spi_state[1:0]) `SPI_IDLE_STATE : spi_state[1:0] <= `SPI_CMD_STATE; - `SPI_CMD_STATE : spi_state[1:0] <= byte_done ? `SPI_DATA_STATE : `SPI_CMD_STATE; + `SPI_CMD_STATE : spi_state[1:0] <= next_byte ? `SPI_DATA_STATE : `SPI_CMD_STATE; `SPI_DATA_STATE : spi_state[1:0] <= `SPI_DATA_STATE; endcase // case (spi_state[1:0]) @@ -77,17 +87,20 @@ module spi_slave_io #( parameter PW = 104 // packet width bit_count[7:0] <= 'b0; else bit_count[7:0] <= bit_count[7:0] + 1'b1; + + assign next_byte = (spi_state[1:0]!=`SPI_IDLE_STATE) & + (bit_count[2:0]==3'b000); assign byte_done = (spi_state[1:0]!=`SPI_IDLE_STATE) & - (bit_count[2:0]==3'b000); + (bit_count[2:0]==3'b111); // command/address register // auto increment for every byte - always @ (negedge sclk or negedge nreset) + always @ (posedge sclk or negedge nreset) if(!nreset) command_reg[7:0] <= 'b0; else if((spi_state[1:0]==`SPI_CMD_STATE) & byte_done) - command_reg[7:0] <= rx_data[7:0]; + command_reg[7:0] <= spi_wdata[7:0]; else if(byte_done) command_reg[7:0] <= {command_reg[7:6], command_reg[5:0] + 1'b1}; @@ -96,17 +109,17 @@ module spi_slave_io #( parameter PW = 104 // packet width //# SPI RX SHIFT REGISTER //################################# - assign rx_shift = ~ss & spi_en; + assign shift = ~ss & spi_en; oh_ser2par #(.PW(8), .SW(1)) rx_ser2par (// Outputs .dout (rx_data[7:0]), // Inputs - .clk (sclk), + .clk (rx_clk), .din (mosi), .lsbfirst (lsbfirst), //msb first - .shift (rx_shift)); + .shift (shift)); //#################################### //# REMOTE TRANSAXTION SHIFT REGISTER @@ -117,27 +130,24 @@ module spi_slave_io #( parameter PW = 104 // packet width e_ser2par (// Outputs .dout (packet_out[PW-1:0]), // Inputs - .clk (sclk), + .clk (rx_clk), .din (mosi), .lsbfirst (lsbfirst), //msb first - .shift (rx_shift));//rx_shift + .shift (shift));//rx_shift //################################# //# TX SHIFT REGISTER //################################# - assign tx_load = byte_done; // & (spi_state[1:0]==`SPI_CMD_STATE); - assign tx_shift = ~ss & spi_en; - oh_par2ser #(.PW(8), .SW(1)) tx_par2ser (.dout (miso), .access_out (), .wait_out (tx_wait), - .clk (sclk), // shift out on positive edge + .clk (tx_clk), // shift out on positive edge .nreset (~ss), .din (spi_rdata[7:0]), - .shift (tx_shift), + .shift (shift), .lsbfirst (lsbfirst), .load (tx_load), .datasize (8'd7), @@ -148,7 +158,7 @@ module spi_slave_io #( parameter PW = 104 // packet width //# REGISTER FILE INTERFACE //################################# - assign spi_clk = sclk; + assign spi_clk = rx_clk; assign spi_addr[5:0] = command_reg[5:0]; @@ -158,24 +168,24 @@ module spi_slave_io #( parameter PW = 104 // packet width (command_reg[7:6]==`SPI_WR) & (spi_state[1:0]==`SPI_DATA_STATE); - assign spi_wdata[7:0] = rx_data[7:0]; + assign spi_wdata[7:0] = lsbfirst ? {mosi, rx_data[7:1]} + : {rx_data[6:0], mosi}; //################################### //# REMOTE FETCH LOGIC //################################### //sync the ss to free running clk - //look for rising edge - oh_dsync dsync (.dout (ss_sync), .clk (clk), .nreset(nreset), .din (ss)); //create single cycle pulse - oh_rise2pulse r2p (.out (ss_pulse), - .clk (clk), - .in (ss_sync)); + oh_rise2pulse r2p (.nreset (nreset), + .out (ss_pulse), + .clk (clk), + .in (ss_sync)); assign spi_fetch = ss_pulse & (command_reg[7:6]==`SPI_FETCH); @@ -185,7 +195,7 @@ module spi_slave_io #( parameter PW = 104 // packet width access_out <= 1'b0; else if(~wait_in) access_out <= spi_fetch; - + endmodule // spi_slave_io // Local Variables: // verilog-library-directories:("." "../../common/hdl") diff --git a/src/spi/hdl/spi_slave_regs.v b/src/spi/hdl/spi_slave_regs.v index 34684e0..3e873fd 100644 --- a/src/spi/hdl/spi_slave_regs.v +++ b/src/spi/hdl/spi_slave_regs.v @@ -108,6 +108,14 @@ module spi_slave_regs #( parameter UREGS = 13, // # of user regs (max 48) assign lsbfirst = spi_config[4]; // lsb shifted in first assign valid = spi_config[5]; // user regs enable + //##################################### + //# USER SPACE REGISTERS + //##################################### + + always @ (negedge spi_clk) + if(user_write) + user_regs[spi_addr[4:0]] <= spi_wdata[7:0]; + //##################################### //# STATUS [1] //##################################### @@ -117,7 +125,7 @@ module spi_slave_regs #( parameter UREGS = 13, // # of user regs (max 48) spi_status[7:0] <= 8'b0; // clears previous data ready else if(access_in) spi_status[7:0] <= 8'd1; // data ready - + //##################################### //# RX DATA FOR FETCH //##################################### @@ -126,15 +134,8 @@ module spi_slave_regs #( parameter UREGS = 13, // # of user regs (max 48) always @ (posedge clk) if(access_in) core_regs[63:0] <= core_data[63:0]; - - //##################################### - //# USER SPACE REGISTERS - //##################################### - - always @ (negedge spi_clk) - if(user_write) - user_regs[spi_addr[4:0]] <= spi_wdata[7:0]; + //##################################### //# REGISTER VECTOR (FOR FLEXIBILITY) //#####################################