OpenCores
URL https://opencores.org/ocsvn/attiny_atmega_xmega_core/attiny_atmega_xmega_core/trunk

Subversion Repositories attiny_atmega_xmega_core

[/] [attiny_atmega_xmega_core/] [trunk/] [rtl/] [io/] [spi_s.v] - Rev 15

Compare with Previous | Blame | View Log

/*
 * 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
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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