fpga: created axi stream controled spi core

This commit is contained in:
Josh Blum
2015-07-28 16:31:29 -07:00
parent 80e65f35cf
commit 2727f62ab8
2 changed files with 244 additions and 0 deletions

View File

@@ -58,5 +58,6 @@ gpio_atr.v \
user_settings.v \
settings_fifo_ctrl.v \
simple_spi_core.v \
axis_spi_core.v \
simple_i2c_core.v \
))

View File

@@ -0,0 +1,243 @@
//
// Copyright 2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Simple SPI core, the simplest, yet complete spi core I can think of
// Settings register controlled.
// 2 settings regs, control and data
// 1 32-bit readback and status signal
// Settings reg map:
//
// BASE+0 divider setting
// bits [15:0] spi clock divider
//
// BASE+1 configuration input
// bits [23:0] slave select, bit0 = slave0 enabled
// bits [29:24] num bits (1 through 32)
// bit [30] data input edge = in data bit latched on rising edge of clock
// bit [31] data output edge = out data bit latched on rising edge of clock
//
// BASE+2 input data
// Writing this register begins a spi transaction.
// Bits are latched out from bit 0.
// Therefore, load this register in reverse.
//
// Readback
// Bits are latched into bit 0.
// Therefore, data will be in-order.
module axis_spi_core
#(
//set to 1 for ILA
parameter DEBUG = 0,
//tdest width for number of core users
parameter DESTW = 1,
//width of serial enables (up to 24 is possible)
parameter WIDTH = 8,
//idle state of the spi clock
parameter CLK_IDLE = 0,
//idle state of the serial enables
parameter SEN_IDLE = 24'hffffff
)
(
//clock and synchronous reset
input clock, input reset,
//configuration settings bus
input [DESTW-1:0] CONFIG_tdest,
input [79:0] CONFIG_tdata,
input CONFIG_tvalid,
output CONFIG_tready,
//32-bit data readback
output reg [DESTW-1:0] READBACK_tdest,
output [31:0] READBACK_tdata,
output READBACK_tvalid,
input READBACK_tready,
//spi interface, slave selects, clock, data in, data out
output [WIDTH-1:0] sen,
output sclk,
output mosi,
input miso
);
//state
localparam WAIT_CONFIG = 0;
localparam PRE_IDLE = 1;
localparam CLK_REG = 2;
localparam CLK_INV = 3;
localparam POST_IDLE = 4;
localparam IDLE_SEN = 5;
localparam WAIT_READBACK = 6;
reg [2:0] state;
//configuration settings
reg [15:0] sclk_divider;
reg [23:0] slave_select;
reg [5:0] num_bits;
reg datain_edge, dataout_edge;
//output ready/valid signals
assign CONFIG_tready = (state == WAIT_CONFIG);
assign READBACK_tvalid = (state == WAIT_READBACK);
//serial clock either idles or is in one of two clock states
reg sclk_reg;
assign sclk = sclk_reg;
//serial enables either idle or enabled based on state
wire sen_is_idle = (state == WAIT_CONFIG) || (state == IDLE_SEN);
wire [23:0] sen24 = (sen_is_idle)? SEN_IDLE : (SEN_IDLE ^ slave_select);
reg [WIDTH-1:0] sen_reg;
always @(posedge clock) sen_reg <= sen24[WIDTH-1:0];
assign sen = sen_reg;
//data output shift register
reg [31:0] dataout_reg;
wire [31:0] dataout_next = {dataout_reg[30:0], 1'b0};
assign mosi = dataout_reg[31];
//data input shift register
reg [31:0] datain_reg;
wire [31:0] datain_next = {datain_reg[30:0], miso};
assign READBACK_tdata = datain_reg;
//counter for spi clock
reg [15:0] sclk_counter;
wire sclk_counter_done = (sclk_counter == sclk_divider);
wire [15:0] sclk_counter_next = (sclk_counter_done)? 0 : sclk_counter + 1;
//counter for latching bits miso/mosi
reg [6:0] bit_counter;
wire [6:0] bit_counter_next = bit_counter + 1;
wire bit_counter_done = (bit_counter_next == num_bits);
always @(posedge clock) begin
if (reset) begin
state <= WAIT_CONFIG;
sclk_reg <= CLK_IDLE;
end
else begin
case (state)
WAIT_CONFIG: begin
if (CONFIG_tvalid && CONFIG_tready) begin
state <= PRE_IDLE;
end
{sclk_divider, dataout_edge, datain_edge, num_bits, slave_select, dataout_reg} <= CONFIG_tdata;
READBACK_tdest <= CONFIG_tdest;
sclk_counter <= 0;
bit_counter <= 0;
sclk_reg <= CLK_IDLE;
end
PRE_IDLE: begin
if (sclk_counter_done) state <= CLK_REG;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
CLK_REG: begin
if (sclk_counter_done) begin
state <= CLK_INV;
if (datain_edge != CLK_IDLE) datain_reg <= datain_next;
if (dataout_edge != CLK_IDLE && bit_counter != 0) dataout_reg <= dataout_next;
sclk_reg <= ~CLK_IDLE; //transition to rising when CLK_IDLE == 0
end
sclk_counter <= sclk_counter_next;
end
CLK_INV: begin
if (sclk_counter_done) begin
state <= (bit_counter_done)? POST_IDLE : CLK_REG;
bit_counter <= bit_counter_next;
if (datain_edge == CLK_IDLE) datain_reg <= datain_next;
if (dataout_edge == CLK_IDLE && ~bit_counter_done) dataout_reg <= dataout_next;
sclk_reg <= CLK_IDLE; //transition to falling when CLK_IDLE == 0
end
sclk_counter <= sclk_counter_next;
end
POST_IDLE: begin
if (sclk_counter_done) state <= IDLE_SEN;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
IDLE_SEN: begin
if (sclk_counter_done) state <= WAIT_READBACK;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
WAIT_READBACK: begin
if (READBACK_tready && READBACK_tvalid) begin
state <= WAIT_CONFIG;
end
end
default: state <= WAIT_CONFIG;
endcase //state
end
end
/*******************************************************************
* Debug
******************************************************************/
generate
if (DEBUG == 1) begin
wire [35:0] CONTROL0;
chipscope_icon chipscope_icon
(
.CONTROL0(CONTROL0)
);
wire [255:0] DATA;
wire [7:0] TRIG0;
chipscope_ila chipscope_ila
(
.CONTROL(CONTROL0),
.CLK(clock),
.DATA(DATA),
.TRIG0(TRIG0)
);
assign TRIG0 =
{
4'b0,
CONFIG_tvalid, CONFIG_tready,
READBACK_tvalid, READBACK_tready
};
assign DATA[79:0] = CONFIG_tdata;
assign DATA[111:80] = READBACK_tdata;
assign DATA[112] = CONFIG_tvalid;
assign DATA[113] = CONFIG_tready;
assign DATA[114] = READBACK_tvalid;
assign DATA[115] = READBACK_tready;
assign DATA[127:120] = state;
end
endgenerate
endmodule //axis_spi_core