URL
https://opencores.org/ocsvn/attiny_atmega_xmega_core/attiny_atmega_xmega_core/trunk
Subversion Repositories attiny_atmega_xmega_core
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 7 to Rev 8
- ↔ Reverse comparison
Rev 7 → Rev 8
/attiny_atmega_xmega_core/trunk/io/spi_s.v
0,0 → 1,292
/* |
* This IP is a SPI IO adapter implementation. |
* |
* Copyright (C) 2018 Iulian Gheorghiu |
* |
* 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 2 |
* 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, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
*/ |
|
`timescale 1ns / 1ps |
|
`include "io_s_h.v" |
|
module spi_s #( |
parameter DINAMIC_BAUDRATE = "TRUE", |
parameter BAUDRATE_DIVIDER = 3, |
parameter ADDRESS = 0, |
parameter BUS_ADDR_DATA_LEN = 16 |
)( |
input rst, |
input clk, |
input [BUS_ADDR_DATA_LEN-1:0]addr, |
input wr, |
input rd, |
input [7:0]bus_in, |
output reg[7:0]bus_out, |
output int, |
|
output sck,/* SPI 'sck' signal (output) */ |
output mosi,/* SPI 'mosi' signal (output) */ |
input miso,/* SPI 'miso' signal (input) */ |
output reg ss/* SPI 'ss' signal (if send buffer is maintained full the ss signal will not go high between between transmit chars)(output) */ |
); |
|
//reg [7:0]CTRL; |
//reg [7:0]BAUD; |
|
wire cs_int = addr >= ADDRESS && addr < (ADDRESS + 8); |
wire rd_int = cs_int && rd; |
wire wr_int = cs_int && wr; |
|
reg [7:0]baud_cnt; |
|
wire buffempty; |
|
reg [7:0]CTRL; |
reg [7:0]INTCTRL; |
reg [7:0]STATUS; |
|
|
localparam WORD_LEN = 8; |
localparam PRESCALLER_SIZE = 8; |
|
reg _mosi; |
|
reg charreceivedp; |
reg charreceivedn; |
|
reg inbufffullp = 1'b0; |
reg inbufffulln = 1'b0; |
|
reg [WORD_LEN - 1:0]input_buffer; |
reg [WORD_LEN - 1:0]output_buffer; |
|
assign buffempty = ~(inbufffullp ^ inbufffulln); |
reg [2:0]prescallerbuff; |
|
always @ (posedge clk or posedge rst) |
begin |
if(rst) |
begin |
inbufffullp <= 1'b0; |
prescallerbuff <= 3'b000; |
CTRL <= 0; |
INTCTRL <= 0; |
input_buffer <= 0; |
end |
else |
begin |
if(wr_int) |
begin |
case(addr[2:0]) |
`SPI_CTRL: CTRL <= bus_in; |
`SPI_INTCTRL: INTCTRL <= bus_in; |
`SPI_DATA: |
begin |
if(inbufffullp == inbufffulln && buffempty && CTRL[`SPI_ENABLE_bp]) |
begin |
inbufffullp <= ~inbufffullp; |
prescallerbuff <= {CTRL[`SPI_CLK2X_bp], CTRL[`SPI_PRESCALER_gp + 1:`SPI_PRESCALER_gp]}; |
input_buffer <= bus_in; |
end |
end |
endcase |
end |
end |
end |
|
always @ (posedge clk or posedge rst) |
begin |
if(rst) |
begin |
STATUS <= 8'h00; |
charreceivedn <= 1'b0; |
end |
else if(rd_int) |
begin |
case(addr[2:0]) |
`SPI_DATA: STATUS[`SPI_IF_bp] <= 1'b0; |
endcase |
end |
else if(charreceivedp != charreceivedn) |
begin |
STATUS[`SPI_IF_bp] <= 1'b1; |
charreceivedn <= ~charreceivedn; |
end |
|
end |
|
always @ (*) |
begin |
bus_out <= 8'bz; |
if(rd_int) |
begin |
case(addr[2:0]) |
`SPI_CTRL: bus_out <= CTRL; |
`SPI_INTCTRL: bus_out <= INTCTRL; |
`SPI_STATUS: bus_out <= STATUS; |
`SPI_DATA: bus_out <= output_buffer; |
endcase |
end |
end |
|
assign int = INTCTRL[`SPI_INTLVL_gp + 1: `SPI_INTLVL_gp] ? STATUS[`SPI_IF_bp] : 1'b0; |
|
/***********************************************/ |
/************ !Asynchronus send ****************/ |
/***********************************************/ |
localparam state_idle = 1'b0; |
localparam state_busy = 1'b1; |
reg state; |
|
|
reg [PRESCALLER_SIZE - 1:0]prescaller_cnt; |
reg [WORD_LEN - 1:0]shift_reg_out; |
reg [WORD_LEN - 1:0]shift_reg_in; |
reg [4:0]sckint; |
//reg sckintn; |
reg [2:0]prescallerint; |
reg [7:0]prescdemux; |
|
|
always @ (*) |
begin |
case(prescallerint) |
3'b000: prescdemux <= 3; |
3'b001: prescdemux <= 15; |
3'b010: prescdemux <= 63; |
3'b011: prescdemux <= 127; |
3'b100: prescdemux <= 1; |
3'b101: prescdemux <= 7; |
3'b110: prescdemux <= 31; |
3'b111: prescdemux <= 63; |
endcase |
end |
|
reg lsbfirstint; |
reg [1:0]modeint; |
|
|
always @ (posedge clk or posedge rst) |
begin |
if(rst) |
begin |
baud_cnt = 'h00; |
inbufffulln <= 1'b0; |
ss <= 1'b1; |
state <= state_idle; |
prescaller_cnt <= {PRESCALLER_SIZE{1'b0}}; |
prescallerint <= {PRESCALLER_SIZE{3'b0}}; |
shift_reg_out <= {WORD_LEN{1'b0}}; |
shift_reg_in <= {WORD_LEN{1'b0}}; |
sckint <= {5{1'b0}}; |
_mosi <= 1'b1; |
output_buffer <= {WORD_LEN{1'b0}}; |
charreceivedp <= 1'b0; |
lsbfirstint <= 1'b0; |
modeint <= 2'b00; |
end |
else |
begin |
if(CTRL[`SPI_ENABLE_bp]) |
begin |
if(DINAMIC_BAUDRATE == "TRUE" ? baud_cnt == prescdemux : baud_cnt == {BAUDRATE_DIVIDER}) |
begin |
baud_cnt <= 'h00; |
case(state) |
state_idle: |
begin |
if(inbufffullp != inbufffulln) |
begin |
inbufffulln <= ~inbufffulln; |
ss <= 1'b0; |
prescaller_cnt <= {PRESCALLER_SIZE{1'b0}}; |
prescallerint <= prescallerbuff; |
lsbfirstint <= CTRL[`SPI_DORD_bp]; |
modeint <= CTRL[`SPI_MODE_gp + 1:`SPI_MODE_gp]; |
shift_reg_out <= input_buffer; |
state <= state_busy; |
if(!CTRL[`SPI_MODE_gp]) |
begin |
if(!CTRL[`SPI_DORD_bp]) |
_mosi <= input_buffer[WORD_LEN - 1]; |
else |
_mosi <= input_buffer[0]; |
end |
end |
end |
state_busy: |
begin |
if(prescaller_cnt != prescdemux) |
begin |
prescaller_cnt <= prescaller_cnt + 1; |
end |
else |
begin |
prescaller_cnt <= {PRESCALLER_SIZE{1'b0}}; |
sckint <= sckint + 1; |
if(sckint[0] == modeint[0]) |
begin |
if(!lsbfirstint) |
begin |
shift_reg_in <= {miso, shift_reg_in[7:1]}; |
shift_reg_out <= {shift_reg_out[6:0], 1'b1}; |
end |
else |
begin |
shift_reg_in <= {shift_reg_in[6:0], miso}; |
shift_reg_out <= {1'b1, shift_reg_out[7:1]}; |
end |
end |
else |
begin |
if(sckint[4:1] == WORD_LEN - 1) |
begin |
sckint <= {5{1'b0}}; |
if(inbufffullp == inbufffulln) |
begin |
ss <= 1'b1; |
end |
output_buffer <= shift_reg_in; |
if(charreceivedp == charreceivedn) |
begin |
charreceivedp <= ~charreceivedp; |
end |
state <= state_idle; |
end |
else |
begin |
if(!lsbfirstint) |
_mosi <= shift_reg_out[WORD_LEN - 1]; |
else |
_mosi <= shift_reg_out[0]; |
end |
end |
end |
end |
endcase |
end |
else |
begin |
baud_cnt <= baud_cnt + 1; |
end |
end |
end |
end |
|
assign sck = (modeint[1])? ~sckint : sckint; |
assign mosi = (ss) ? 1'b1:_mosi; |
|
endmodule |