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 6 to Rev 7
- ↔ Reverse comparison
Rev 6 → Rev 7
/attiny_atmega_xmega_core/trunk/io/twi_s.v
0,0 → 1,333
/* |
* 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 |