OpenCores
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.