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/] [twi_s.v] - Rev 15

Compare with Previous | Blame | View Log

/*
 * This IP is a TWI 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 twi_s #(
	parameter DINAMIC_BAUDRATE = "TRUE",
	parameter BAUDRATE_DIVIDER = 255,
	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_tx_cmpl,
	output int_rx_cmpl,
	input int_tx_rst,
	input int_rx_rst,
 
	inout scl,
	inout sda
    );
 
reg [7:0]CTRLA;
reg [7:0]CTRLB;
reg [7:0]CTRLC;
reg [7:0]STATUS;
reg [7:0]BAUD;
reg [7:0]DATA;
 
wire cs_int = addr >= ADDRESS && addr < (ADDRESS + 16);
wire rd_int = cs_int && rd;
wire wr_int = cs_int && wr;
 
reg [7:0]baud_cnt;
reg [1:0]cmd;
reg tx_mode;
reg start_sent;
reg rcv_ack;
reg send_ack;
reg send_ack_st2;
reg [1:0]stage;
reg [2:0]bit_count;
reg scl_int;
reg sda_int;
reg send_ack_int;
 
localparam [2:0]CMD_NOP = {1'b1, 2'b00};
localparam [2:0]CMD_RESTART = {1'b0, 2'b01};
localparam [2:0]CMD_RECEIVE = {1'b0, 2'b10};
localparam [2:0]CMD_STOP = {1'b0, 2'b11};
 
always @ (*)
begin
	bus_out <= 'hz;
	if(rd_int)
	begin
		case(addr[3:0])
		`TWI_MASTER_CTRLA: bus_out <= CTRLA;
		`TWI_MASTER_CTRLB: bus_out <= CTRLB;
		`TWI_MASTER_CTRLC: bus_out <= CTRLC;
		`TWI_MASTER_STATUS: bus_out <= STATUS;
		`TWI_MASTER_BAUD: bus_out <= BAUD;
		`TWI_MASTER_DATA: bus_out <= DATA;
		endcase
	end
end
 
always @ (posedge clk or posedge rst)
begin
	if(rst)
	begin
		CTRLA <= 'h0;
		CTRLB <= 'h0;
		CTRLC <= 'h0;
		STATUS <= 'h0;
		BAUD <= 'h0;
		DATA <= 'h0;
		baud_cnt <= 'h00;
		cmd <= 'h00;
		tx_mode <= 1'b0;
		start_sent <= 1'b0;
		scl_int <= 1'b1;
		sda_int <= 1'b1;
		rcv_ack <= 1'b0;
		send_ack <= 1'b0;
		send_ack_st2 <= 1'b0;
		stage <= 'h00;
		send_ack_int <= 1'b1;
	end
	else
	begin
		if(DINAMIC_BAUDRATE == "TRUE" ? baud_cnt == BAUD : baud_cnt == {BAUDRATE_DIVIDER})
		begin
			baud_cnt <= 'h00;
			if(CTRLA[`TWI_MASTER_ENABLE_bp])
			begin
				case({tx_mode, cmd})
				CMD_NOP:
				begin
					if(~start_sent)
					begin/* Send the start sequence */
						stage <= stage + 1;
						case(stage)
						'h0:
						begin
							scl_int <= 1'b1;
							sda_int <= 1'b0;
						end
						'h1:
						begin
							scl_int <= 1'b0;
							bit_count <= 'hF;
							start_sent <= 1'b1;
							stage <= 'h0;
						end
						endcase
					end
					else
					begin/* Send bits */
						stage <= stage + 1;
						case(stage)
						'h0:
						begin
							case(rcv_ack)
							1'b0:
							begin
								sda_int <= DATA[bit_count];
							end
							1'b1:
								sda_int <= 1'b1;
							endcase
						end
						'h1:
						begin
							scl_int <= 1'b1;
						end
						'h2:
						begin
							if(rcv_ack)
								STATUS[`TWI_MASTER_RXACK_bp] <= sda;
						end
						'h3:
						begin
							stage <= 'h0;
							scl_int <= 1'b0;
							case(rcv_ack)
							1'b0:
							begin
								if(~|bit_count)
									rcv_ack <= 1'b1;
								bit_count <= bit_count - 1;
							end
							1'b1:
							begin
								tx_mode <= 1'b0;
								STATUS[`TWI_MASTER_WIF_bp] <= 1'b1;
								rcv_ack <= 1'b0;
							end
							endcase
						end
						endcase
					end
				end
				CMD_RESTART:
				begin/* Send restart */
					stage <= stage + 1;
					case(stage)
					'h0:
					begin
						sda_int <= 1'b1;
					end
					'h1:
					begin
						scl_int <= 1'b1;
					end
					'h2:
					begin
						sda_int <= 1'b0;
					end
					'h3:
					begin
						scl_int <= 1'b0;
						bit_count <= 'hF;
						start_sent <= 1'b1;
						stage <= 'h0;
						cmd <= 'h0;
						CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp] <= 'h0;
					end
					endcase
				end
				CMD_RECEIVE:
				begin/* Receive bits */
					stage <= stage + 1;
					case(stage)
					'h0:
					begin
						if(send_ack && ~send_ack_st2)
							sda_int <= send_ack_int;
						else if(send_ack_st2)
						begin
							STATUS[`TWI_MASTER_RIF_bp] <= 1'b1;
							cmd <= 'h0;
							CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp] <= 'h0;
							sda_int <= 1'b1;
						end
					end
					'h1:
					begin
						scl_int <= 1'b1;
					end
					'h2:
					begin
						if(~send_ack)
							DATA[bit_count] <= sda;
					end
					'h3:
					begin
						scl_int <= 1'b0;
						stage <= 'h0;
						case(send_ack)
						1'b0:
						begin
							if(~|bit_count)
								send_ack <= 1'b1;
							bit_count <= bit_count - 1;
						end
						1'b1: send_ack_st2 <= 1'b1;
						endcase
					end
					endcase
				end
				CMD_STOP:
				begin/* Send stop */
					stage <= stage + 1;
					case(stage)
					'h0: sda_int <= 1'b0;
					'h1: scl_int <= 1'b1;
					'h2:
					begin
						sda_int <= 1'b1;
						start_sent <= 1'b0;
						stage <= 'h0;
						cmd <= 'h0;
						CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp] <= 'h0;
					end
					endcase
				end
			endcase
			end
		end
		else
		begin
			baud_cnt <= baud_cnt + 1;
		end
		if(CTRLA[`TWI_MASTER_ENABLE_bp])
		begin
			if(CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp] && ~|cmd && ~tx_mode)
			begin
				cmd <= CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp];
				stage <= 'h0;
				send_ack <= 1'b0;
				send_ack_st2 <= 1'b0;
				send_ack_int <= CTRLC[`TWI_SLAVE_ACKACT_bp];
			end
		end
		if(wr_int)
		begin
			case(addr[3:0])
			`TWI_MASTER_CTRLA: CTRLA <= bus_in;
			`TWI_MASTER_CTRLB: CTRLB <= bus_in;
			`TWI_MASTER_CTRLC: CTRLC <= bus_in;
			`TWI_MASTER_STATUS: STATUS <= STATUS ^ bus_in;
			`TWI_MASTER_BAUD: BAUD <= bus_in;
			//`TWI_MASTER_ADDR: ADDR <= bus_in;
			`TWI_MASTER_DATA: 
			begin
				if(~|CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp])
				begin
					DATA <= bus_in;
					tx_mode <= 1'b1;
					STATUS[`TWI_MASTER_WIF_bp] <= 1'b0;
				end
			end
			endcase
		end
		if(rd_int)
		begin
			case(addr[3:0])
			`TWI_MASTER_DATA: 
			begin
				STATUS[`TWI_MASTER_RIF_bp] <= 1'b0;
			end
			endcase
		end
	end
end
 
PULLUP PULLUP_scl_inst (
	.O(scl)  // 1-bit output: Pullup output (connect directly to top-level port)
);
PULLUP PULLUP_sda_inst (
	.O(sda)  // 1-bit output: Pullup output (connect directly to top-level port)
);
 
 
assign scl = scl_int ? 1'bz : scl_int;
assign sda = sda_int ? 1'bz : sda_int;
 
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.