mtaciano
Newbie level 4
Hello,
I'm trying to create a "messaging interface" between two FPGA using the UART protocol to communicate between one another, the goal is to type some text into a keyboard connected via PS/2 to one FPGA and have the message appear in the other FPGA's LCD. So far I have the PS/2 implementation, so I can type something and it shows in the LCD of the same FPGA, and I also have the UART protocol too where I can send 8 bits of data whenever I want, the problem is that I can't seem to connect the two components together.
When I type in the keyboard the text shows fine in the FPGA that it's connected to, but it behaves strangely in the other FPGA, like the UART is generating a lot of garbage, the LCD goes crazy and shows a lot of garbage text, even when the TX Active bit is set to low.
Below is the important part of the code:
and the shared code between them:
The other "less important" files are in the attachments.
Currently what I'm doing is pass the four important data (LCD_E, LCD_RS, LCD_RW, LCD_DATA) through one UART channel each, but I think this is causing some synchronization problem, the thing is that I don't know how to fix this problem and the garbage problem, my idea is either some kind of state machine for what data is the receiver receiving at the moment, or make the UART send 11 bits instead of 8 (8 for the data and 3 for the flags), could someone tell me where is the problem, and how can I fix it?
I'm trying to create a "messaging interface" between two FPGA using the UART protocol to communicate between one another, the goal is to type some text into a keyboard connected via PS/2 to one FPGA and have the message appear in the other FPGA's LCD. So far I have the PS/2 implementation, so I can type something and it shows in the LCD of the same FPGA, and I also have the UART protocol too where I can send 8 bits of data whenever I want, the problem is that I can't seem to connect the two components together.
When I type in the keyboard the text shows fine in the FPGA that it's connected to, but it behaves strangely in the other FPGA, like the UART is generating a lot of garbage, the LCD goes crazy and shows a lot of garbage text, even when the TX Active bit is set to low.
Below is the important part of the code:
Code:
module ProjetoTeclado(CLK50MHz, data_ps2, clk_ps2, hex1, hex0, end_scan, LCD_RS, LCD_E, LCD_RW, LCD_DATA,
LCD_ON, LCD_BLON, espera, tx, tx2, tx3, tx4, i_Tx_DV, o_Tx_Active);
input CLK50MHz;
output tx, tx2, tx3, tx4;
// PS2
input data_ps2, clk_ps2;
output [6:0] hex1, hex0;
output end_scan;
// LCD
output LCD_RS, LCD_E, LCD_RW, LCD_ON, LCD_BLON;
output [7:0] LCD_DATA;
output espera;
assign LCD_BLON = 1'b1;
assign LCD_ON = 1'b1;
wire [7:0] scan;
wire finish_ps2;
wire [7:0] comando;
wire num_comando;
assign end_scan = finish_ps2;
leitorPS2(.clk_ps2(clk_ps2), .data(data_ps2), .scan_code(scan), .end_scan(finish_ps2));
PS2_to_LCD(.scancode(scan), .finish_ps2(finish_ps2), .comando(comando), .num_comando(num_comando));
hexto7segment display1(.bin(scan[7:4]), .hex(hex1));
hexto7segment display0(.bin(scan[3:0]), .hex(hex0));
displayLCD(.CLK50MHz(CLK50MHz), .num_comando(num_comando), .comando(comando), .LCD_RS(LCD_RS), .LCD_E(LCD_E), .LCD_RW(LCD_RW), .LCD_DATA(LCD_DATA), .espera(espera));
input i_Tx_DV;
output o_Tx_Active;
wire o_Tx_Active2, o_Tx_Active3, o_Tx_Active4;
wire o_Tx_Done, o_Tx_Done2, o_Tx_Done3, o_Tx_Done4;
uart_tx utx_cmd
(
.i_Clock(CLK50MHz),
.i_Tx_DV(i_Tx_DV),
.i_Tx_Byte(LCD_DATA),
.o_Tx_Active(o_Tx_Active),
.o_Tx_Serial(tx),
.o_Tx_Done(o_Tx_Done)
);
uart_tx utx_2
(
.i_Clock(CLK50MHz),
.i_Tx_DV(i_Tx_DV),
.i_Tx_Byte(LCD_RS),
.o_Tx_Active(o_Tx_Active2),
.o_Tx_Serial(tx2),
.o_Tx_Done(o_Tx_Done2)
);
uart_tx utx_3
(
.i_Clock(CLK50MHz),
.i_Tx_DV(i_Tx_DV),
.i_Tx_Byte(LCD_E),
.o_Tx_Active(o_Tx_Active3),
.o_Tx_Serial(tx3),
.o_Tx_Done(o_Tx_Done3)
);
uart_tx utx_4
(
.i_Clock(CLK50MHz),
.i_Tx_DV(i_Tx_DV),
.i_Tx_Byte(LCD_RW),
.o_Tx_Active(o_Tx_Active4),
.o_Tx_Serial(tx4),
.o_Tx_Done(o_Tx_Done4)
);
endmodule
Code:
module ProjetoTeclado(CLK50MHz, data_ps2, clk_ps2, hex1, hex0, end_scan, LCD_RS, LCD_E, LCD_RW, LCD_DATA,
LCD_ON, LCD_BLON, espera, rx, rx2, rx3, rx4);
input CLK50MHz;
input rx, rx2, rx3, rx4;
// PS2
input data_ps2, clk_ps2;
output [6:0] hex1, hex0;
output end_scan;
// LCD
output LCD_RS, LCD_E, LCD_RW, LCD_ON, LCD_BLON;
output [7:0] LCD_DATA;
output espera;
assign LCD_BLON = 1'b1;
assign LCD_ON = 1'b1;
wire [7:0] scan;
wire finish_ps2;
wire [7:0] comando;
wire num_comando;
assign end_scan = finish_ps2;
leitorPS2(.clk_ps2(clk_ps2), .data(data_ps2), .scan_code(scan), .end_scan(finish_ps2));
PS2_to_LCD(.scancode(scan), .finish_ps2(finish_ps2), .comando(comando), .num_comando(num_comando));
hexto7segment display1(.bin(LCD_DATA[7:4]), .hex(hex1));
hexto7segment display0(.bin(LCD_DATA[3:0]), .hex(hex0));
// displayLCD(.CLK50MHz(CLK50MHz), .num_comando(num_comando), .comando(comando), .LCD_RS(LCD_RS), .LCD_E(LCD_E), .LCD_RW(LCD_RW), .LCD_DATA(LCD_DATA), .espera(espera));
// reg num_comando_r;
// reg o_Rx_DV_r;
//
// initial begin
// num_comando_r = 1'b0;
// count <= 1'b0;
// o_Rx_DV_r <= 1'b0;
// end
//
// always @(posedge CLK50Hz) begin
// if (num_comando != num_comando_r) begin
// num_comando_r <= num_comando;
// end
// end
wire o_Rx_DV, o_Rx_DV2, o_Rx_DV3, o_Rx_DV4;
uart_rx urx
(
.i_Clock(CLK50MHz),
.i_Rx_Serial(rx),
.o_Rx_DV(o_Rx_DV),
.o_Rx_Byte(LCD_DATA)
);
uart_rx urx2
(
.i_Clock(CLK50MHz),
.i_Rx_Serial(rx2),
.o_Rx_DV(o_Rx_DV2),
.o_Rx_Byte(LCD_RS)
);
uart_rx urx3
(
.i_Clock(CLK50MHz),
.i_Rx_Serial(rx3),
.o_Rx_DV(o_Rx_DV3),
.o_Rx_Byte(LCD_E)
);
uart_rx urx4
(
.i_Clock(CLK50MHz),
.i_Rx_Serial(rx4),
.o_Rx_DV(o_Rx_DV4),
.o_Rx_Byte(LCD_RW)
);
endmodule
and the shared code between them:
Code:
//////////////////////////////////////////////////////////////////////
// File Downloaded from http://www.nandland.com
//////////////////////////////////////////////////////////////////////
// This file contains the UART Transmitter. This transmitter is able
// to transmit 8 bits of serial data, one start bit, one stop bit,
// and no parity bit. When transmit is complete o_Tx_done will be
// driven high for one clock cycle.
//
// Set Parameter CLKS_PER_BIT as follows:
// CLKS_PER_BIT = (Frequency of i_Clock)/(Frequency of UART)
// Example: 10 MHz Clock, 115200 baud UART
// (10000000)/(115200) = 87
module uart_tx
#(parameter CLKS_PER_BIT = 87)
(
input i_Clock,
input i_Tx_DV,
input [7:0] i_Tx_Byte,
output o_Tx_Active,
output reg o_Tx_Serial,
output o_Tx_Done
);
parameter s_IDLE = 3'b000;
parameter s_TX_START_BIT = 3'b001;
parameter s_TX_DATA_BITS = 3'b010;
parameter s_TX_STOP_BIT = 3'b011;
parameter s_CLEANUP = 3'b100;
reg [2:0] r_SM_Main = 0;
reg [7:0] r_Clock_Count = 0;
reg [2:0] r_Bit_Index = 0;
reg [7:0] r_Tx_Data = 0;
reg r_Tx_Done = 0;
reg r_Tx_Active = 0;
always @(posedge i_Clock)
begin
case (r_SM_Main)
s_IDLE :
begin
o_Tx_Serial <= 1'b1; // Drive Line High for Idle
r_Tx_Done <= 1'b0;
r_Clock_Count <= 0;
r_Bit_Index <= 0;
if (i_Tx_DV == 1'b1)
begin
r_Tx_Active <= 1'b1;
r_Tx_Data <= i_Tx_Byte;
r_SM_Main <= s_TX_START_BIT;
end
else
r_SM_Main <= s_IDLE;
end // case: s_IDLE
// Send out Start Bit. Start bit = 0
s_TX_START_BIT :
begin
o_Tx_Serial <= 1'b0;
// Wait CLKS_PER_BIT-1 clock cycles for start bit to finish
if (r_Clock_Count < CLKS_PER_BIT-1)
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_TX_START_BIT;
end
else
begin
r_Clock_Count <= 0;
r_SM_Main <= s_TX_DATA_BITS;
end
end // case: s_TX_START_BIT
// Wait CLKS_PER_BIT-1 clock cycles for data bits to finish
s_TX_DATA_BITS :
begin
o_Tx_Serial <= r_Tx_Data[r_Bit_Index];
if (r_Clock_Count < CLKS_PER_BIT-1)
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_TX_DATA_BITS;
end
else
begin
r_Clock_Count <= 0;
// Check if we have sent out all bits
if (r_Bit_Index < 7)
begin
r_Bit_Index <= r_Bit_Index + 1;
r_SM_Main <= s_TX_DATA_BITS;
end
else
begin
r_Bit_Index <= 0;
r_SM_Main <= s_TX_STOP_BIT;
end
end
end // case: s_TX_DATA_BITS
// Send out Stop bit. Stop bit = 1
s_TX_STOP_BIT :
begin
o_Tx_Serial <= 1'b1;
// Wait CLKS_PER_BIT-1 clock cycles for Stop bit to finish
if (r_Clock_Count < CLKS_PER_BIT-1)
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_TX_STOP_BIT;
end
else
begin
r_Tx_Done <= 1'b1;
r_Clock_Count <= 0;
r_SM_Main <= s_CLEANUP;
r_Tx_Active <= 1'b0;
end
end // case: s_Tx_STOP_BIT
// Stay here 1 clock
s_CLEANUP :
begin
r_Tx_Done <= 1'b1;
r_SM_Main <= s_IDLE;
end
default :
r_SM_Main <= s_IDLE;
endcase
end
assign o_Tx_Active = r_Tx_Active;
assign o_Tx_Done = r_Tx_Done;
endmodule
Code:
//////////////////////////////////////////////////////////////////////
// File Downloaded from http://www.nandland.com
//////////////////////////////////////////////////////////////////////
// This file contains the UART Receiver. This receiver is able to
// receive 8 bits of serial data, one start bit, one stop bit,
// and no parity bit. When receive is complete o_rx_dv will be
// driven high for one clock cycle.
//
// Set Parameter CLKS_PER_BIT as follows:
// CLKS_PER_BIT = (Frequency of i_Clock)/(Frequency of UART)
// Example: 10 MHz Clock, 115200 baud UART
// (10000000)/(115200) = 87
module uart_rx
#(parameter CLKS_PER_BIT = 87)
(
input i_Clock,
input i_Rx_Serial,
output o_Rx_DV,
output [7:0] o_Rx_Byte
);
parameter s_IDLE = 3'b000;
parameter s_RX_START_BIT = 3'b001;
parameter s_RX_DATA_BITS = 3'b010;
parameter s_RX_STOP_BIT = 3'b011;
parameter s_CLEANUP = 3'b100;
reg r_Rx_Data_R = 1'b1;
reg r_Rx_Data = 1'b1;
reg [7:0] r_Clock_Count = 0;
reg [2:0] r_Bit_Index = 0; //8 bits total
reg [7:0] r_Rx_Byte = 0;
reg r_Rx_DV = 0;
reg [2:0] r_SM_Main = 0;
// Purpose: Double-register the incoming data.
// This allows it to be used in the UART RX Clock Domain.
// (It removes problems caused by metastability)
always @(posedge i_Clock)
begin
r_Rx_Data_R <= i_Rx_Serial;
r_Rx_Data <= r_Rx_Data_R;
end
// Purpose: Control RX state machine
always @(posedge i_Clock)
begin
case (r_SM_Main)
s_IDLE :
begin
r_Rx_DV <= 1'b0;
r_Clock_Count <= 0;
r_Bit_Index <= 0;
if (r_Rx_Data == 1'b0) // Start bit detected
r_SM_Main <= s_RX_START_BIT;
else
r_SM_Main <= s_IDLE;
end
// Check middle of start bit to make sure it's still low
s_RX_START_BIT :
begin
if (r_Clock_Count == (CLKS_PER_BIT-1)/2)
begin
if (r_Rx_Data == 1'b0)
begin
r_Clock_Count <= 0; // reset counter, found the middle
r_SM_Main <= s_RX_DATA_BITS;
end
else
r_SM_Main <= s_IDLE;
end
else
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_RX_START_BIT;
end
end // case: s_RX_START_BIT
// Wait CLKS_PER_BIT-1 clock cycles to sample serial data
s_RX_DATA_BITS :
begin
if (r_Clock_Count < CLKS_PER_BIT-1)
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_RX_DATA_BITS;
end
else
begin
r_Clock_Count <= 0;
r_Rx_Byte[r_Bit_Index] <= r_Rx_Data;
// Check if we have received all bits
if (r_Bit_Index < 7)
begin
r_Bit_Index <= r_Bit_Index + 1;
r_SM_Main <= s_RX_DATA_BITS;
end
else
begin
r_Bit_Index <= 0;
r_SM_Main <= s_RX_STOP_BIT;
end
end
end // case: s_RX_DATA_BITS
// Receive Stop bit. Stop bit = 1
s_RX_STOP_BIT :
begin
// Wait CLKS_PER_BIT-1 clock cycles for Stop bit to finish
if (r_Clock_Count < CLKS_PER_BIT-1)
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_RX_STOP_BIT;
end
else
begin
r_Rx_DV <= 1'b1;
r_Clock_Count <= 0;
r_SM_Main <= s_CLEANUP;
end
end // case: s_RX_STOP_BIT
// Stay here 1 clock
s_CLEANUP :
begin
r_SM_Main <= s_IDLE;
r_Rx_DV <= 1'b0;
end
default :
r_SM_Main <= s_IDLE;
endcase
end
assign o_Rx_DV = r_Rx_DV;
assign o_Rx_Byte = r_Rx_Byte;
endmodule // uart_rx
The other "less important" files are in the attachments.
Currently what I'm doing is pass the four important data (LCD_E, LCD_RS, LCD_RW, LCD_DATA) through one UART channel each, but I think this is causing some synchronization problem, the thing is that I don't know how to fix this problem and the garbage problem, my idea is either some kind of state machine for what data is the receiver receiving at the moment, or make the UART send 11 bits instead of 8 (8 for the data and 3 for the flags), could someone tell me where is the problem, and how can I fix it?