1// 2// Copyright 2012 Ettus Research LLC 3// 4// This program is free software: you can redistribute it and/or modify 5// it under the terms of the GNU General Public License as published by 6// the Free Software Foundation, either version 3 of the License, or 7// (at your option) any later version. 8// 9// This program is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU General Public License for more details. 13// 14// You should have received a copy of the GNU General Public License 15// along with this program. If not, see <http://www.gnu.org/licenses/>. 16// 17 18// Simple SPI core, the simplest, yet complete spi core I can think of 19 20// Settings register controlled. 21// 2 settings regs, control and data 22// 1 32-bit readback and status signal 23 24// Settings reg map: 25// 26// BASE+0 divider setting 27// bits [15:0] spi clock divider 28// 29// BASE+1 configuration input 30// bits [23:0] slave select, bit0 = slave0 enabled 31// bits [29:24] num bits (1 through 32) 32// bit [30] data input edge = in data bit latched on rising edge of clock 33// bit [31] data output edge = out data bit latched on rising edge of clock 34// 35// BASE+2 input data 36// Writing this register begins a spi transaction. 37// Bits are latched out from bit 0. 38// Therefore, load this register in reverse. 39// 40// Readback 41// Bits are latched into bit 0. 42// Therefore, data will be in-order. 43 44module simple_spi_core 45 #( 46 //settings register base address 47 parameter BASE = 0, 48 49 //width of serial enables (up to 24 is possible) 50 parameter WIDTH = 8, 51 52 //idle state of the spi clock 53 parameter CLK_IDLE = 0, 54 55 //idle state of the serial enables 56 parameter SEN_IDLE = 24'hffffff 57 ) 58 ( 59 //clock and synchronous reset 60 input clock, input reset, 61 62 //32-bit settings bus inputs 63 input set_stb, input [7:0] set_addr, input [31:0] set_data, 64 65 //32-bit data readback 66 output [31:0] readback, 67 68 //read is high when spi core can begin another transaction 69 output ready, 70 71 //spi interface, slave selects, clock, data in, data out 72 output [WIDTH-1:0] sen, 73 output sclk, 74 output mosi, 75 input miso, 76 77 //optional debug output 78 output [31:0] debug 79 ); 80 81 wire [15:0] sclk_divider; 82 setting_reg #(.my_addr(BASE+0),.width(16)) divider_sr( 83 .clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data), 84 .out(sclk_divider),.changed()); 85 86 wire [23:0] slave_select; 87 wire [5:0] num_bits; 88 wire datain_edge, dataout_edge; 89 setting_reg #(.my_addr(BASE+1),.width(32)) config_sr( 90 .clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data), 91 .out({dataout_edge, datain_edge, num_bits, slave_select}),.changed()); 92 93 wire [31:0] mosi_data; 94 wire trigger_spi; 95 setting_reg #(.my_addr(BASE+2),.width(32)) data_sr( 96 .clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data), 97 .out(mosi_data),.changed(trigger_spi)); 98 99 localparam WAIT_TRIG = 0; 100 localparam PRE_IDLE = 1; 101 localparam CLK_REG = 2; 102 localparam CLK_INV = 3; 103 localparam POST_IDLE = 4; 104 localparam IDLE_SEN = 5; 105 106 reg [2:0] state; 107 108 reg ready_reg; 109 assign ready = ready_reg && ~trigger_spi; 110 111 //serial clock either idles or is in one of two clock states 112 reg sclk_reg; 113 assign sclk = sclk_reg; 114 115 //serial enables either idle or enabled based on state 116 wire sen_is_idle = (state == WAIT_TRIG) || (state == IDLE_SEN); 117 wire [23:0] sen24 = (sen_is_idle)? SEN_IDLE : (SEN_IDLE ^ slave_select); 118 reg [WIDTH-1:0] sen_reg; 119 always @(posedge clock) sen_reg <= sen24[WIDTH-1:0]; 120 assign sen = sen_reg; 121 122 //data output shift register 123 reg [31:0] dataout_reg; 124 wire [31:0] dataout_next = {dataout_reg[30:0], 1'b0}; 125 assign mosi = dataout_reg[31]; 126 127 //data input shift register 128 reg [31:0] datain_reg; 129 wire [31:0] datain_next = {datain_reg[30:0], miso}; 130 assign readback = datain_reg; 131 132 //counter for spi clock 133 reg [15:0] sclk_counter; 134 wire sclk_counter_done = (sclk_counter == sclk_divider); 135 wire [15:0] sclk_counter_next = (sclk_counter_done)? 0 : sclk_counter + 1; 136 137 //counter for latching bits miso/mosi 138 reg [6:0] bit_counter; 139 wire [6:0] bit_counter_next = bit_counter + 1; 140 wire bit_counter_done = (bit_counter_next == num_bits); 141 142 always @(posedge clock) begin 143 if (reset) begin 144 state <= WAIT_TRIG; 145 sclk_reg <= CLK_IDLE; 146 ready_reg <= 0; 147 end 148 else begin 149 case (state) 150 151 WAIT_TRIG: begin 152 if (trigger_spi) state <= PRE_IDLE; 153 ready_reg <= ~trigger_spi; 154 dataout_reg <= mosi_data; 155 sclk_counter <= 0; 156 bit_counter <= 0; 157 sclk_reg <= CLK_IDLE; 158 end 159 160 PRE_IDLE: begin 161 if (sclk_counter_done) state <= CLK_REG; 162 sclk_counter <= sclk_counter_next; 163 sclk_reg <= CLK_IDLE; 164 end 165 166 CLK_REG: begin 167 if (sclk_counter_done) begin 168 state <= CLK_INV; 169 if (datain_edge != CLK_IDLE) datain_reg <= datain_next; 170 if (dataout_edge != CLK_IDLE && bit_counter != 0) dataout_reg <= dataout_next; 171 sclk_reg <= ~CLK_IDLE; //transition to rising when CLK_IDLE == 0 172 end 173 sclk_counter <= sclk_counter_next; 174 end 175 176 CLK_INV: begin 177 if (sclk_counter_done) begin 178 state <= (bit_counter_done)? POST_IDLE : CLK_REG; 179 bit_counter <= bit_counter_next; 180 if (datain_edge == CLK_IDLE) datain_reg <= datain_next; 181 if (dataout_edge == CLK_IDLE && ~bit_counter_done) dataout_reg <= dataout_next; 182 sclk_reg <= CLK_IDLE; //transition to falling when CLK_IDLE == 0 183 end 184 sclk_counter <= sclk_counter_next; 185 end 186 187 POST_IDLE: begin 188 if (sclk_counter_done) state <= IDLE_SEN; 189 sclk_counter <= sclk_counter_next; 190 sclk_reg <= CLK_IDLE; 191 end 192 193 IDLE_SEN: begin 194 if (sclk_counter_done) state <= WAIT_TRIG; 195 sclk_counter <= sclk_counter_next; 196 sclk_reg <= CLK_IDLE; 197 end 198 199 default: state <= WAIT_TRIG; 200 201 endcase //state 202 end 203 end 204 205 assign debug = { 206 trigger_spi, state, //4 207 sclk, mosi, miso, ready, //4 208 sen[7:0], //8 209 1'b0, bit_counter[6:0], //8 210 sclk_counter_done, bit_counter_done, //2 211 sclk_counter[5:0] //6 212 }; 213 214endmodule //simple_spi_core 215