Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Problem with PS/2 communication over UART

mtaciano

Newbie level 4
Joined
Jan 1, 2023
Messages
6
Helped
0
Reputation
0
Reaction score
1
Trophy points
3
Activity points
78
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:
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?
 

Attachments

  • displayLCD.txt
    19.8 KB · Views: 66
  • leitorPS2.txt
    1.5 KB · Views: 64
  • PS2_to_LCD.txt
    13.4 KB · Views: 62
  • registradorDesloc.txt
    702 bytes · Views: 61
Currently what I'm doing is pass the four important data (LCD_E, LCD_RS, LCD_RW, LCD_DATA) through one UART channel each,
Why are you making it complicated?
You need to send out only the data received from the keyboard to the other FPGA via UART.
At the receiving FPGA use this data to display on the LCD. Since you already know how to do this, just implement this functionality on the receiving FPGA. In this way things will be much simple.

PS2 -->FIFO --> UART Tx ----> UART Rx --> FIFO --> LCD Display logic
 
Last edited:
Why are you making it complicated?
You need to send out only the data received from the keyboard to the other FPGA via UART.
At the receiving FPGA use this data to display on the LCD. Since you already know how to do this, just implement this functionality on the receiving FPGA. In this way things will be much simple.

PS2 -->FIFO --> UART Tx ----> UART Rx --> FIFO --> LCD Display logic
This worked, thank you! It really was easier than what I was trying to do.
 
Hello,

Recently I made a verilog project that uses two Altera DE2-115 FPGA to communicate with each other, when I type in a keyboard connected to the "A" FPGA it shows on the LCD of the "B" FPGA.
My problem is that the code was working just fine, but for some reason when I tested it today it goes fine and then, after some interaction, just stops working, no matter what I type, nothing changes on the LCD, like if the keyboard was disconnected.

Could someone tell me if there are any problems with my current implementation that could cause it, or if it was some kind of problem with a defective board.

The "can_call" variable is assigned to a switch.

Code:
module UART_Phone(
    input CLK50MHz,

    // PS/2
    input data_ps2,
    input clk_ps2,

    // LCD & 7-segment
    output [6:0] hex0,
    output [6:0] hex1,
    output end_scan,
    output LCD_RS,
    output LCD_E,
    output LCD_RW,
    output [7:0] LCD_DATA,
    output LCD_ON,
    output LCD_BLON,
    output espera, // Not used

    // UART
    input rx,
    output tx,
     input can_call
);

// Keep the LCD on
assign LCD_BLON = 1'b1;
assign LCD_ON = 1'b1;

// PS/2 transmission data
wire [7:0] scan;
wire finish_ps2;
assign end_scan = finish_ps2;

// LCD commands from PS/2
wire [7:0] comando;
wire num_comando;

// UART Rx
wire o_Rx_DV;
wire [7:0] rx_message;

// UART Tx
wire i_Tx_DV;
wire o_Tx_Active; // Not used
wire o_Tx_Done; // Not used
wire [7:0] tx_message;
assign tx_message = scan;
assign i_Tx_DV = finish_ps2 & can_call;

leitorPS2 lps2 (
    .clk_ps2(clk_ps2),
    .data(data_ps2),
    .scan_code(scan),
    .end_scan(finish_ps2)
);

PS2_to_LCD ps2tolcd (
    .scancode(rx_message),
    .finish_ps2(o_Rx_DV),
    .comando(comando),
    .num_comando(num_comando)
);

hexto7segment display0 (
    .bin(LCD_DATA[3:0]),
    .hex(hex0)
);

hexto7segment display1 (
    .bin(LCD_DATA[7:4]),
    .hex(hex1)
);

displayLCD dlcd (
    .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)
);

uart_rx urx (
   .i_Clock(CLK50MHz),
   .i_Rx_Serial(rx),
   .o_Rx_DV(o_Rx_DV),
   .o_Rx_Byte(rx_message)
);

uart_tx utx (
   .i_Clock(CLK50MHz),
   .i_Tx_DV(i_Tx_DV),
   .i_Tx_Byte(tx_message),
   .o_Tx_Active(o_Tx_Active),
   .o_Tx_Serial(tx),
   .o_Tx_Done(o_Tx_Done)
);

endmodule

Other files are attached.
 

Attachments

  • displayLCD.txt
    19.8 KB · Views: 65
  • hexto7segment.txt
    1.2 KB · Views: 60
  • leitorPS2.txt
    1.5 KB · Views: 68
  • PS2_to_LCD.txt
    13.4 KB · Views: 62
  • registradorDesloc.txt
    702 bytes · Views: 60
  • uart_rx.txt
    4.5 KB · Views: 60
  • uart_tx.txt
    4.4 KB · Views: 55
Did you simulate your design?
Not the LCD display module but the UART Rx and Tx.
Although UART is trivial but it is nice to do design verification using simulation.
 
Did you simulate your design?
Not the LCD display module but the UART Rx and Tx.
Although UART is trivial but it is nice to do design verification using simulation.
I found the problem, in the line
Code:
assign i_Tx_DV = finish_ps2 & can_call;
This causes some kind of bug, when I change it to
Code:
assign i_Tx_DV = finish_ps2;
It works! can_call is a physical switch located on the board.
 

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top