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] - Diff between revs 8 and 15

Show entire file | Details | Blame | View Log

Rev 8 Rev 15
Line 1... Line 1...
 
/*
 
 * 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
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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