mirror of
https://github.com/aolofsson/oh.git
synced 2025-01-17 20:02:53 +08:00
Fixing spi controller
- Manually merging work from @olajep in PR #85 (too far out of sync) - Fixing issue with lsbfirst logic - Adding logic for manual control of slave select - Fixing status register for polling reads - Still a timing/glitch issue on mosi, fix it later...
This commit is contained in:
parent
f4a74b462f
commit
f7ce7b800c
@ -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
|
||||
//###############
|
||||
|
@ -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),
|
||||
|
@ -12,8 +12,10 @@ module spi_master_io
|
||||
input cpol, // cpol
|
||||
input cpha, // cpha
|
||||
input lsbfirst, // send lsbfirst
|
||||
input manual_mode,// sets automatic ss mode
|
||||
input send_data, // controls ss in manual ss mode
|
||||
input [7:0] clkdiv_reg, // baudrate
|
||||
output reg [1:0] spi_state, // current spi tx state
|
||||
output reg [2:0] spi_state, // current spi tx state
|
||||
// data to transmit
|
||||
input [7:0] fifo_dout, // data payload
|
||||
input fifo_empty, //
|
||||
@ -33,6 +35,8 @@ module spi_master_io
|
||||
//###############
|
||||
reg fifo_empty_reg;
|
||||
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
|
||||
@ -102,9 +109,6 @@ 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;
|
||||
@ -113,18 +117,23 @@ 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,12 +155,8 @@ 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))
|
||||
@ -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:
|
||||
|
@ -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,6 +116,8 @@ 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
|
||||
|
@ -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,13 +45,22 @@ 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])
|
||||
|
||||
@ -78,16 +88,19 @@ module spi_slave_io #( parameter PW = 104 // packet width
|
||||
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);
|
||||
|
||||
|
@ -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]
|
||||
//#####################################
|
||||
@ -127,13 +135,6 @@ module spi_slave_regs #( parameter UREGS = 13, // # of user regs (max 48)
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user