`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: Raptor Engineering // Engineer: Timothy Pearson // // Design Name: Remote Access Driver // Module Name: remote_access // Project Name: Remote Access Driver // Target Devices: Any // Description: Serial remote access driver and LCD display driver // // Dependencies: // // (c) 2007-2019 Timothy Pearson, Raptor Engineering, LLC // Licensed under the terms of the AGPL v3 // // For commercial licensing options, please contact: // sales@raptorengineering.com // ////////////////////////////////////////////////////////////////////////////////// `include "remote_access_defines.v" module remote_access( input main_fifty_clock, // 50MHz clock in output user_logic_reset, // Active high user logic reset out input [3:0] remote_access_4_bit_output, // 4 bit output from the user program to remote access client output [3:0] remote_access_4_bit_input, // 4 bit input from the remote access client to user program input [7:0] remote_access_8_bit_output, // 8 bit output from the user program to remote access client output [7:0] remote_access_8_bit_input, // 8 bit input from the remote access client to user program input [15:0] remote_access_16_bit_output, // 16 bit output from the user program to the remote access client output [15:0] remote_access_16_bit_input, // 16 bit input from the remote access client to the user program input serial_port_receiver, output serial_port_transmitter, input remote_access_input_enable, input [7:0] local_input, input seize_serial_tx, input [7:0] serial_tx_data, input serial_tx_strobe, output [7:0] serial_rx_data, output serial_rx_strobe, input [5:0] lcd_data_in_address, input [7:0] lcd_data_in_data, input lcd_data_in_enable, `ifdef SYSTEM_HAS_SRAM input sram_wren_in, input sram_clock_in, input [7:0] sram_data_in, input [(RAM_ADDR_BITS-1):0] sram_address_in, output [7:0] sram_data_out, `endif output sram_available, `ifdef SYSTEM_HAS_SRAM input sram_processing_done, `endif input [7:0] led_segment_bus, input [3:0] led_digit_select, // For use on Digilent Spartan 3E or compatible board only output [3:0] remote_access_lcd_data_out, output remote_access_lcd_rs_out, output remote_access_lcd_rw_out, output remote_access_lcd_enable_out); parameter RAM_ADDR_BITS = 14; `ifndef SYSTEM_HAS_SRAM reg sram_processing_done = 1'b1; `endif reg user_logic_reset_reg = 1'b0; reg [7:0] remote_access_4_bit_input_reg; reg [7:0] remote_access_8_bit_input_reg; reg [15:0] remote_access_16_bit_input_reg; reg [3:0] remote_access_lcd_data_out_reg; reg remote_access_lcd_rs_out_reg; reg remote_access_lcd_rw_out_reg; reg remote_access_lcd_enable_out_reg; reg [7:0] serial_rx_data_reg; reg serial_rx_strobe_reg; reg sram_available_reg; reg startup_needed = 1; assign user_logic_reset = user_logic_reset_reg; assign remote_access_4_bit_input = remote_access_4_bit_input_reg[3:0]; assign remote_access_8_bit_input = remote_access_8_bit_input_reg; assign remote_access_16_bit_input = remote_access_16_bit_input_reg; assign remote_access_lcd_data_out = remote_access_lcd_data_out_reg; assign remote_access_lcd_rs_out = remote_access_lcd_rs_out_reg; assign remote_access_lcd_rw_out = remote_access_lcd_rw_out_reg; assign remote_access_lcd_enable_out = remote_access_lcd_enable_out_reg; assign serial_rx_data = serial_rx_data_reg; assign serial_rx_strobe = serial_rx_strobe_reg; assign sram_available = sram_available_reg; //----------------------------------------------------------------------------------- // // Create a 4.16MHz clock for the LCD display driver and a 25MHz clock // for the serial receiver. // //----------------------------------------------------------------------------------- reg four_mhz_clk; reg clk_div_by_two; reg clk_div_by_two_oneeighty; reg clk_div_by_four; reg clk_div_by_eight; reg [3:0] fifty_clock_divider = 0; always @(posedge main_fifty_clock) begin fifty_clock_divider = fifty_clock_divider + 1; if (fifty_clock_divider > 12) begin four_mhz_clk = !four_mhz_clk; fifty_clock_divider = 0; end end always @(posedge main_fifty_clock) begin clk_div_by_two = !clk_div_by_two; end always @(negedge main_fifty_clock) begin clk_div_by_two_oneeighty = !clk_div_by_two_oneeighty; end always @(posedge clk_div_by_two_oneeighty) begin clk_div_by_four = !clk_div_by_four; end always @(posedge clk_div_by_four) begin clk_div_by_eight = !clk_div_by_eight; end //----------------------------------------------------------------------------------- // // Keep track of what is on the LED display // //----------------------------------------------------------------------------------- reg [7:0] led_display_bytes [3:0]; reg [17:0] digit_blanker_1 = 0; reg [17:0] digit_blanker_2 = 0; reg [17:0] digit_blanker_3 = 0; reg [17:0] digit_blanker_4 = 0; reg [7:0] led_segment_bus_latch; reg [3:0] led_digit_select_latch; always @(negedge clk_div_by_eight) begin led_segment_bus_latch = led_segment_bus; led_digit_select_latch = led_digit_select; if (led_digit_select_latch[0] == 1) begin digit_blanker_1 = digit_blanker_1 + 1; end if (led_digit_select_latch[1] == 1) begin digit_blanker_2 = digit_blanker_2 + 1; end if (led_digit_select_latch[2] == 1) begin digit_blanker_3 = digit_blanker_3 + 1; end if (led_digit_select_latch[3] == 1) begin digit_blanker_4 = digit_blanker_4 + 1; end if (led_digit_select_latch[0] == 0) begin led_display_bytes[0] = led_segment_bus_latch; digit_blanker_1 = 0; end if (led_digit_select_latch[1] == 0) begin led_display_bytes[1] = led_segment_bus_latch; digit_blanker_2 = 0; end if (led_digit_select_latch[2] == 0) begin led_display_bytes[2] = led_segment_bus_latch; digit_blanker_3 = 0; end if (led_digit_select_latch[3] == 0) begin led_display_bytes[3] = led_segment_bus_latch; digit_blanker_4 = 0; end if (digit_blanker_1 > 128000) begin led_display_bytes[0] = 255; end if (digit_blanker_2 > 128000) begin led_display_bytes[1] = 255; end if (digit_blanker_3 > 128000) begin led_display_bytes[2] = 255; end if (digit_blanker_4 > 128000) begin led_display_bytes[3] = 255; end end //----------------------------------------------------------------------------------- // // Instantiate the data storage RAM for signal processing // //----------------------------------------------------------------------------------- reg data_storage_remote_enable = 0; wire data_storage_clka; wire [7:0] data_storage_dina; wire [(RAM_ADDR_BITS-1):0] data_storage_addra; wire data_storage_write_enable; wire [7:0] data_storage_data_out; reg [7:0] data_storage_dina_reg; reg [(RAM_ADDR_BITS-1):0] data_storage_addra_reg; reg data_storage_write_enable_reg; `ifdef SYSTEM_HAS_SRAM data_storage #(RAM_ADDR_BITS) data_storage(.clka(data_storage_clka), .dina(data_storage_dina), .addra(data_storage_addra), .wea(data_storage_write_enable), .douta(data_storage_data_out)); assign data_storage_clka = (data_storage_remote_enable) ? main_fifty_clock : sram_clock_in; assign data_storage_dina = (data_storage_remote_enable) ? data_storage_dina_reg : sram_data_in; assign data_storage_addra = (data_storage_remote_enable) ? data_storage_addra_reg : sram_address_in; assign data_storage_write_enable = (data_storage_remote_enable) ? data_storage_write_enable_reg : sram_wren_in; assign sram_data_out = data_storage_data_out; `endif // ----------------------------------------------------------------------------------------------- // // Here is the serial receiver and transmitter // // ----------------------------------------------------------------------------------------------- reg [7:0] transmit_all_data_state = 0; wire RxD_data_ready; wire [7:0] RxD_data; wire RxD_endofpacket; wire RxD_idle; reg TxD_start; reg [7:0] TxD_data; wire TxD_busy; wire [4:0] state; reg [7:0] transmitter_4_bit_state = 0; reg [7:0] transmitter_8_bit_state = 0; reg [15:0] transmitter_16_bit_state = 0; reg [7:0] transmitter_main_state = 0; reg [7:0] transmitter_input_state = 0; async_transmit asyncTX(.clk(clk_div_by_two), .TxD_start(TxD_start), .TxD_data(TxD_data), .TxD(serial_port_transmitter), .TxD_busy(TxD_busy), .state(state)); async_receiver asyncRX(.clk(clk_div_by_two), .RxD(serial_port_receiver), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data), .RxD_endofpacket(RxD_endofpacket), .RxD_idle(RxD_idle)); reg tx_toggle = 0; reg transmit_4_bit_status = 0; reg transmit_4_bit_status_done = 0; reg transmit_8_bit_status = 0; reg transmit_8_bit_status_done = 0; reg transmit_16_bit_status = 0; reg transmit_16_bit_pass_two = 0; reg transmit_16_bit_status_done = 0; reg transmit_main_status = 0; reg transmit_main_status_done = 0; reg transmit_dsp_ram_size = 0; reg transmit_dsp_ram_size_done = 0; reg transmit_input_status = 0; reg transmit_input_status_done = 0; reg transmit_lcd_status = 0; reg transmit_lcd_status_done = 0; reg [7:0] transmit_lcd_status_counter = 0; reg enable_remote_access_input = 1; reg remote_access_input_enable_prev = 0; reg [7:0] lcd_display_string [31:0]; reg transmit_dsp_status = 0; reg transmit_dsp_status_done = 0; reg transmit_dsp_status_holdoff = 0; reg [RAM_ADDR_BITS:0] transmit_dsp_status_counter = 0; reg transmit_led_status = 0; reg transmit_led_status_done = 0; reg [7:0] transmit_led_status_counter = 0; reg transmit_dsp_rx_complete = 0; reg transmit_dsp_rx_complete_done = 0; // Transmit! always @(posedge clk_div_by_two) begin transmitter_4_bit_state = remote_access_4_bit_output; transmitter_8_bit_state = remote_access_8_bit_output; transmitter_16_bit_state = remote_access_16_bit_output; transmitter_main_state = 0; transmitter_main_state[0] = enable_remote_access_input; transmitter_input_state = local_input; if (seize_serial_tx == 1) begin TxD_start = serial_tx_strobe; TxD_data = serial_tx_data; end else begin if (tx_toggle == 0) begin if ((transmit_4_bit_status == 1) && (transmit_4_bit_status_done == 0)) begin TxD_data = transmitter_4_bit_state; TxD_start = 1; tx_toggle = 1; transmit_4_bit_status_done = 1; end if ((transmit_8_bit_status == 1) && (transmit_8_bit_status_done == 0)) begin TxD_data = transmitter_8_bit_state; TxD_start = 1; tx_toggle = 1; transmit_8_bit_status_done = 1; end if ((transmit_16_bit_status == 1) && (transmit_16_bit_status_done == 0)) begin if (transmit_16_bit_pass_two == 0) begin TxD_data = transmitter_16_bit_state[15:8]; TxD_start = 1; tx_toggle = 1; transmit_16_bit_pass_two = 1; end else begin TxD_data = transmitter_16_bit_state[7:0]; TxD_start = 1; tx_toggle = 1; transmit_16_bit_status_done = 1; end end if ((transmit_main_status == 1) && (transmit_main_status_done == 0)) begin TxD_data = transmitter_main_state; TxD_start = 1; tx_toggle = 1; transmit_main_status_done = 1; end if ((transmit_dsp_ram_size == 1) && (transmit_dsp_ram_size_done == 0)) begin TxD_data = RAM_ADDR_BITS; TxD_start = 1; tx_toggle = 1; transmit_dsp_ram_size_done = 1; end if ((transmit_input_status == 1) && (transmit_input_status_done == 0)) begin TxD_data = transmitter_input_state; TxD_start = 1; tx_toggle = 1; transmit_input_status_done = 1; end if ((transmit_lcd_status == 1) && (transmit_lcd_status_done == 0)) begin TxD_data = lcd_display_string[transmit_lcd_status_counter]; TxD_start = 1; tx_toggle = 1; transmit_lcd_status_counter = transmit_lcd_status_counter + 1; if (transmit_lcd_status_counter > 31) begin transmit_lcd_status_done = 1; end end if ((transmit_led_status == 1) && (transmit_led_status_done == 0)) begin TxD_data = led_display_bytes[transmit_led_status_counter]; TxD_start = 1; tx_toggle = 1; transmit_led_status_counter = transmit_led_status_counter + 1; if (transmit_led_status_counter > 3) begin transmit_led_status_done = 1; end end if ((transmit_dsp_rx_complete == 1) && (transmit_dsp_rx_complete_done == 0)) begin TxD_data = 77; TxD_start = 1; tx_toggle = 1; transmit_dsp_rx_complete_done = 1; end if ((transmit_dsp_status == 1) && (transmit_dsp_rx_complete == 0) && (transmit_dsp_status_done == 0)) begin if (transmit_dsp_status_holdoff == 0) begin transmit_dsp_status_holdoff = 1; `ifdef SYSTEM_HAS_SRAM data_storage_write_enable_reg = 0; data_storage_addra_reg = 0; // Initial data value `endif end else begin `ifdef SYSTEM_HAS_SRAM data_storage_write_enable_reg = 0; TxD_data = data_storage_data_out; `else TxD_data = 0; `endif TxD_start = 1; tx_toggle = 1; transmit_dsp_status_counter = transmit_dsp_status_counter + 1; data_storage_addra_reg = transmit_dsp_status_counter[(RAM_ADDR_BITS-1):0]; if (transmit_dsp_status_counter >= (2**RAM_ADDR_BITS)) begin transmit_dsp_status_done = 1; `ifdef SYSTEM_HAS_SRAM data_storage_write_enable_reg = 1'bz; data_storage_addra_reg = {(RAM_ADDR_BITS){1'bz}}; `endif end end end end else begin if (state == 5'b10000) begin // Wait for transmission of byte to complete TxD_start = 0; tx_toggle = 0; end end end if (transmit_4_bit_status == 0) begin transmit_4_bit_status_done = 0; end if (transmit_8_bit_status == 0) begin transmit_8_bit_status_done = 0; end if (transmit_16_bit_status == 0) begin transmit_16_bit_pass_two = 0; transmit_16_bit_status_done = 0; end if (transmit_main_status == 0) begin transmit_main_status_done = 0; end if (transmit_dsp_ram_size == 0) begin transmit_dsp_ram_size_done = 0; end if (transmit_input_status == 0) begin transmit_input_status_done = 0; end if (transmit_lcd_status == 0) begin transmit_lcd_status_done = 0; transmit_lcd_status_counter = 0; end if (transmit_led_status == 0) begin transmit_led_status_done = 0; transmit_led_status_counter = 0; end if (transmit_dsp_rx_complete == 0) begin transmit_dsp_rx_complete_done = 0; end if (transmit_dsp_status == 0) begin transmit_dsp_status_done = 0; transmit_dsp_status_holdoff = 0; transmit_dsp_status_counter = 0; end end reg [7:0] lcd_display_initialization_state = 0; reg serial_character_received = 0; reg [7:0] serial_receiver_toggler = 0; reg [7:0] serial_command_buffer = 0; reg [2:0] next_byte_is_command = 0; reg [7:0] next_byte_is_command_prev_command = 0; reg [7:0] serial_command_timer = 0; reg update_lcd_display = 0; reg [7:0] serial_update_counter = 0; reg [RAM_ADDR_BITS:0] dsp_update_counter = 0; reg [7:0] received_lcd_display_string [31:0]; reg data_write_timer = 0; reg waiting_on_dsp_processing = 0; // Receive serial commands always @(posedge clk_div_by_two) begin if (startup_needed == 1) begin startup_needed = 0; transmit_dsp_status = 1; end if (lcd_data_in_enable == 1) begin received_lcd_display_string[lcd_data_in_address] = lcd_data_in_data; update_lcd_display = 1; serial_command_timer = 255; end if ((remote_access_input_enable == 1) && (remote_access_input_enable_prev == 0)) begin enable_remote_access_input = !enable_remote_access_input; end remote_access_input_enable_prev = remote_access_input_enable; if (enable_remote_access_input == 0) begin // Enable local input remote_access_8_bit_input_reg = local_input; end if (serial_command_timer > 0) begin serial_command_timer = serial_command_timer - 1; end else begin update_lcd_display = 0; end if (transmit_4_bit_status_done == 1) begin transmit_4_bit_status = 0; if (transmit_all_data_state == 1) begin transmit_8_bit_status = 1; end end if (transmit_8_bit_status_done == 1) begin transmit_8_bit_status = 0; if (transmit_all_data_state == 1) begin transmit_16_bit_status = 1; end end if (transmit_16_bit_status_done == 1) begin transmit_16_bit_status = 0; if (transmit_all_data_state == 1) begin transmit_led_status = 1; end end if (transmit_led_status_done == 1) begin transmit_led_status = 0; if (transmit_all_data_state == 1) begin transmit_all_data_state = 0; end end if (transmit_dsp_rx_complete_done == 1) begin transmit_dsp_rx_complete = 0; end if (transmit_main_status_done == 1) begin transmit_main_status = 0; if (transmit_all_data_state == 1) begin transmit_dsp_ram_size = 1; end end if (transmit_dsp_ram_size_done == 1) begin transmit_dsp_ram_size = 0; if (transmit_all_data_state == 1) begin transmit_4_bit_status = 1; end end if (transmit_input_status_done == 1) begin transmit_input_status = 0; end if (transmit_lcd_status_done == 1) begin transmit_lcd_status = 0; if (transmit_all_data_state == 1) begin transmit_main_status = 1; end end if (transmit_dsp_status_done == 1) begin transmit_dsp_status = 0; data_storage_remote_enable = 0; end if (transmit_dsp_status == 1) begin data_storage_remote_enable = 1; end if (data_write_timer > 1) begin data_write_timer = data_write_timer - 1; end else begin if (data_write_timer == 1) begin `ifdef SYSTEM_HAS_SRAM data_storage_write_enable_reg = 0; `endif data_write_timer = 0; end end if ((waiting_on_dsp_processing == 1) && (sram_processing_done == 1)) begin waiting_on_dsp_processing = 0; transmit_dsp_status = 1; end serial_rx_strobe_reg = 0; // Make sure that this get reset! if ((sram_processing_done == 1) && (sram_available_reg == 1)) begin sram_available_reg = 0; transmit_dsp_status = 1; end if (RxD_data_ready == 1) begin // Release user logic reset if set on previous serial receive cycle user_logic_reset_reg = 1'b0; if (serial_character_received == 0) begin serial_rx_data_reg = RxD_data; serial_rx_strobe_reg = 1; // Signal new data... if (seize_serial_tx == 0) begin if (next_byte_is_command_prev_command == 77) begin // DSP input data if (dsp_update_counter < (2**RAM_ADDR_BITS)) begin data_storage_remote_enable = 1; `ifdef SYSTEM_HAS_SRAM data_storage_addra_reg = dsp_update_counter[(RAM_ADDR_BITS-1):0]; data_storage_dina_reg = serial_rx_data_reg; data_storage_write_enable_reg = 1; `endif data_write_timer = 3; dsp_update_counter = dsp_update_counter + 1; // TESTING ONLY!!! //if (dsp_update_counter < 17) begin // received_lcd_display_string[dsp_update_counter - 1] = serial_command_buffer; //end if (dsp_update_counter >= (2**RAM_ADDR_BITS)) begin next_byte_is_command = 0; `ifdef SYSTEM_HAS_SRAM data_storage_write_enable_reg = 0; `endif data_storage_remote_enable = 0; sram_available_reg = 1; `ifdef SYSTEM_HAS_SRAM data_storage_write_enable_reg = 1'bz; data_storage_addra_reg = {(RAM_ADDR_BITS){1'bz}}; `endif waiting_on_dsp_processing = 1; transmit_dsp_rx_complete = 1; next_byte_is_command_prev_command = 0; // TESTING ONLY!!! //transmit_dsp_status = 1; end end end else begin // Parse the command and see what it is serial_character_received = 1; if (serial_rx_data_reg == 13) begin // Carriage Return! The serial_command_buffer holds the command! Parse it! if (next_byte_is_command == 0) begin if (serial_command_buffer == 65) begin // Display update requested next_byte_is_command = 1; serial_update_counter = 0; next_byte_is_command_prev_command = 65; end if (serial_command_buffer == 66) begin // 8 bit input update if (enable_remote_access_input == 1) begin next_byte_is_command = 1; serial_update_counter = 0; next_byte_is_command_prev_command = 66; end end if (serial_command_buffer == 67) begin // 16 bit input update next_byte_is_command = 1; serial_update_counter = 0; next_byte_is_command_prev_command = 67; end if (serial_command_buffer == 68) begin // 8 bit output status transmit_8_bit_status = 1; end if (serial_command_buffer == 69) begin // 16 bit output status transmit_16_bit_status = 1; end if (serial_command_buffer == 70) begin // System status transmit_main_status = 1; end if (serial_command_buffer == 71) begin // Simulate center button press enable_remote_access_input = !enable_remote_access_input; end if (serial_command_buffer == 72) begin // Local input status transmit_input_status = 1; end if (serial_command_buffer == 73) begin // 4 bit input update if (enable_remote_access_input == 1) begin next_byte_is_command = 1; serial_update_counter = 0; next_byte_is_command_prev_command = 73; end end if (serial_command_buffer == 74) begin // 4 bit output status transmit_4_bit_status = 1; end if (serial_command_buffer == 75) begin // Transmit the contents of the LCD... transmit_lcd_status = 1; end if (serial_command_buffer == 76) begin // Transmit the contents of the LCD... transmit_all_data_state = 1; transmit_lcd_status = 1; end if (serial_command_buffer == 77) begin // Receive offline DSP data next_byte_is_command = 1; dsp_update_counter = 0; next_byte_is_command_prev_command = 77; end if (serial_command_buffer == 78) begin // Transmit the contents of RAM... transmit_dsp_status = 1; end if (serial_command_buffer == 79) begin // Transmit the DSP RAM size transmit_dsp_ram_size = 1; end if (serial_command_buffer == 82) begin // Strobe user logic reset user_logic_reset_reg = 1'b1; end end else begin if (next_byte_is_command == 1) begin // The previous byte was the command--now load in the data! if (next_byte_is_command_prev_command == 65) begin if (serial_update_counter < 32) begin received_lcd_display_string[serial_update_counter] = serial_command_buffer; serial_update_counter = serial_update_counter + 1; end else begin update_lcd_display = 1; serial_command_timer = 255; next_byte_is_command = 0; end end // 4 bit input update if (next_byte_is_command_prev_command == 73) begin remote_access_4_bit_input_reg = serial_command_buffer; next_byte_is_command = 0; end // 8 bit input update if (next_byte_is_command_prev_command == 66) begin remote_access_8_bit_input_reg = serial_command_buffer; next_byte_is_command = 0; end // 16 bit input update if (next_byte_is_command_prev_command == 67) begin if (serial_update_counter == 0) begin remote_access_16_bit_input_reg[15:8] = serial_command_buffer; serial_update_counter = 1; end else begin remote_access_16_bit_input_reg[7:0] = serial_command_buffer; next_byte_is_command = 0; end end end end end end end //if (RxD_data != 10) begin // Ignore linefeeds serial_command_buffer = RxD_data; //end serial_receiver_toggler = serial_receiver_toggler + 1; end end if (RxD_data_ready == 0) begin serial_character_received = 0; end end //----------------------------------------------------------------------------------- // // This routine will display the contents of lcd_display_string on the LCD display // //----------------------------------------------------------------------------------- reg [15:0] lcd_display_wait_counter = 0; reg [7:0] lcd_display_current_character = 0; reg lcd_display_line_two = 0; // Are we trying to write to line two? always @(posedge four_mhz_clk) begin case (lcd_display_initialization_state) // Initialize the display according to the reference manual 0:begin // Set up the default display... lcd_display_string[0] = 73; // I lcd_display_string[1] = 110; // n lcd_display_string[2] = 105; // i lcd_display_string[3] = 116; // t lcd_display_string[4] = 105; // i lcd_display_string[5] = 97; // a lcd_display_string[6] = 108; // l lcd_display_string[7] = 105; // i lcd_display_string[8] = 122; // z lcd_display_string[9] = 97; // a lcd_display_string[10] = 116; // t lcd_display_string[11] = 105; // i lcd_display_string[12] = 111; // o lcd_display_string[13] = 110; // n lcd_display_string[14] = 32; // lcd_display_string[15] = 32; // lcd_display_string[16] = 79; // O lcd_display_string[17] = 75; // k lcd_display_string[18] = 32; // lcd_display_string[19] = 32; // lcd_display_string[20] = 32; // lcd_display_string[21] = 32; // lcd_display_string[22] = 32; // lcd_display_string[23] = 32; // lcd_display_string[24] = 32; // lcd_display_string[25] = 32; // lcd_display_string[26] = 32; // lcd_display_string[27] = 32; // lcd_display_string[28] = 32; // lcd_display_string[29] = 32; // lcd_display_string[30] = 32; // lcd_display_string[31] = 32; // lcd_display_current_character = 0; lcd_display_line_two = 0; remote_access_lcd_data_out_reg = 3; remote_access_lcd_enable_out_reg = 1; remote_access_lcd_rs_out_reg = 0; remote_access_lcd_rw_out_reg = 0; lcd_display_wait_counter = 17083; // Wait 15mS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 1:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 2:begin remote_access_lcd_data_out_reg = 3; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 417; // Wait 100uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 3:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 4:begin remote_access_lcd_data_out_reg = 3; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 167; // Wait 40uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 5:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 6:begin remote_access_lcd_data_out_reg = 2; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 167; // Wait 40uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 7:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end // Display is now initialized // Send Function Set command 8:begin remote_access_lcd_data_out_reg = 2; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 5; // Wait 1uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 9:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 10:begin remote_access_lcd_data_out_reg = 8; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 167; // Wait 40uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 11:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end // Send Entry Mode Set command 12:begin remote_access_lcd_data_out_reg = 0; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 5; // Wait 1uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 13:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 14:begin remote_access_lcd_data_out_reg = 6; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 167; // Wait 40uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 15:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end // Send Display On command and disable cursors and blinking 16:begin remote_access_lcd_data_out_reg = 0; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 5; // Wait 1uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 17:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 18:begin remote_access_lcd_data_out_reg = 12; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 167; // Wait 40uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 19:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end // Send Clear Display command 20:begin remote_access_lcd_data_out_reg = 0; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 5; // Wait 1uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 21:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 22:begin remote_access_lcd_data_out_reg = 1; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 6833; // Wait 1.64uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 23:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end // Set DD RAM Address to 0 if lcd_display_line_two is 0, or 0x40 if it is 1 24:begin remote_access_lcd_rs_out_reg = 0; if (lcd_display_line_two == 0) begin remote_access_lcd_data_out_reg = 8; end if (lcd_display_line_two == 1) begin remote_access_lcd_data_out_reg = 12; end remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 5; // Wait 1uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 25:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 26:begin remote_access_lcd_data_out_reg = 0; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 167; // Wait 40uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 27:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end // Display the characters 28:begin remote_access_lcd_data_out_reg = lcd_display_string[lcd_display_current_character][7:4]; remote_access_lcd_rs_out_reg = 1; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 5; // Wait 1uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 29:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 30:begin remote_access_lcd_data_out_reg = lcd_display_string[lcd_display_current_character][3:0]; remote_access_lcd_enable_out_reg = 1; lcd_display_wait_counter = 167; // Wait 40uS lcd_display_initialization_state = lcd_display_initialization_state + 1; end 31:begin remote_access_lcd_enable_out_reg = 0; lcd_display_wait_counter = lcd_display_wait_counter - 1; if (lcd_display_wait_counter == 0) lcd_display_initialization_state = lcd_display_initialization_state + 1; end 32:begin lcd_display_current_character = lcd_display_current_character + 1; lcd_display_initialization_state = lcd_display_initialization_state + 1; if (lcd_display_current_character < 32) begin lcd_display_initialization_state = 28; end if (lcd_display_current_character == 16) begin if (lcd_display_line_two == 0) begin lcd_display_line_two = 1; lcd_display_initialization_state = 24; end end end 33:begin // End! remote_access_lcd_rs_out_reg = 0; remote_access_lcd_enable_out_reg = 0; lcd_display_line_two = 0; lcd_display_current_character = 0; if (update_lcd_display == 1) begin lcd_display_line_two = 0; lcd_display_current_character = 0; lcd_display_initialization_state = 24; lcd_display_string[0] = received_lcd_display_string[0]; lcd_display_string[1] = received_lcd_display_string[1]; lcd_display_string[2] = received_lcd_display_string[2]; lcd_display_string[3] = received_lcd_display_string[3]; lcd_display_string[4] = received_lcd_display_string[4]; lcd_display_string[5] = received_lcd_display_string[5]; lcd_display_string[6] = received_lcd_display_string[6]; lcd_display_string[7] = received_lcd_display_string[7]; lcd_display_string[8] = received_lcd_display_string[8]; lcd_display_string[9] = received_lcd_display_string[9]; lcd_display_string[10] = received_lcd_display_string[10]; lcd_display_string[11] = received_lcd_display_string[11]; lcd_display_string[12] = received_lcd_display_string[12]; lcd_display_string[13] = received_lcd_display_string[13]; lcd_display_string[14] = received_lcd_display_string[14]; lcd_display_string[15] = received_lcd_display_string[15]; lcd_display_string[16] = received_lcd_display_string[16]; lcd_display_string[17] = received_lcd_display_string[17]; lcd_display_string[18] = received_lcd_display_string[18]; lcd_display_string[19] = received_lcd_display_string[19]; lcd_display_string[20] = received_lcd_display_string[20]; lcd_display_string[21] = received_lcd_display_string[21]; lcd_display_string[22] = received_lcd_display_string[22]; lcd_display_string[23] = received_lcd_display_string[23]; lcd_display_string[24] = received_lcd_display_string[24]; lcd_display_string[25] = received_lcd_display_string[25]; lcd_display_string[26] = received_lcd_display_string[26]; lcd_display_string[27] = received_lcd_display_string[27]; lcd_display_string[28] = received_lcd_display_string[28]; lcd_display_string[29] = received_lcd_display_string[29]; lcd_display_string[30] = received_lcd_display_string[30]; lcd_display_string[31] = received_lcd_display_string[31]; end end endcase end endmodule module async_receiver(clk, RxD, RxD_data_ready, RxD_data, RxD_endofpacket, RxD_idle); input clk, RxD; output RxD_data_ready; // onc clock pulse when RxD_data is valid output [7:0] RxD_data; parameter ClkFrequency = 25000000; // 25MHz parameter Baud = 115200; // We also detect if a gap occurs in the received stream of characters // That can be useful if multiple characters are sent in burst // so that multiple characters can be treated as a "packet" output RxD_endofpacket; // one clock pulse, when no more data is received (RxD_idle is going high) output RxD_idle; // no data is being received // Baud generator (we use 8 times oversampling) parameter Baud8 = Baud*8; parameter Baud8GeneratorAccWidth = 16; wire [Baud8GeneratorAccWidth:0] Baud8GeneratorInc = ((Baud8<<(Baud8GeneratorAccWidth-7))+(ClkFrequency>>8))/(ClkFrequency>>7); reg [Baud8GeneratorAccWidth:0] Baud8GeneratorAcc; always @(posedge clk) Baud8GeneratorAcc <= Baud8GeneratorAcc[Baud8GeneratorAccWidth-1:0] + Baud8GeneratorInc; wire Baud8Tick = Baud8GeneratorAcc[Baud8GeneratorAccWidth]; //////////////////////////// reg [1:0] RxD_sync_inv; always @(posedge clk) if(Baud8Tick) RxD_sync_inv <= {RxD_sync_inv[0], ~RxD}; // we invert RxD, so that the idle becomes "0", to prevent a phantom character to be received at startup reg [1:0] RxD_cnt_inv; reg RxD_bit_inv; always @(posedge clk) if(Baud8Tick) begin if( RxD_sync_inv[1] && RxD_cnt_inv!=2'b11) RxD_cnt_inv <= RxD_cnt_inv + 2'h1; else if(~RxD_sync_inv[1] && RxD_cnt_inv!=2'b00) RxD_cnt_inv <= RxD_cnt_inv - 2'h1; if(RxD_cnt_inv==2'b00) RxD_bit_inv <= 1'b0; else if(RxD_cnt_inv==2'b11) RxD_bit_inv <= 1'b1; end reg [3:0] state; reg [3:0] bit_spacing; // "next_bit" controls when the data sampling occurs // depending on how noisy the RxD is, different values might work better // with a clean connection, values from 8 to 11 work wire next_bit = (bit_spacing==4'd10); always @(posedge clk) if(state==0) bit_spacing <= 4'b0000; else if(Baud8Tick) bit_spacing <= {bit_spacing[2:0] + 4'b0001} | {bit_spacing[3], 3'b000}; always @(posedge clk) if(Baud8Tick) case(state) 4'b0000: if(RxD_bit_inv) state <= 4'b1000; // start bit found? 4'b1000: if(next_bit) state <= 4'b1001; // bit 0 4'b1001: if(next_bit) state <= 4'b1010; // bit 1 4'b1010: if(next_bit) state <= 4'b1011; // bit 2 4'b1011: if(next_bit) state <= 4'b1100; // bit 3 4'b1100: if(next_bit) state <= 4'b1101; // bit 4 4'b1101: if(next_bit) state <= 4'b1110; // bit 5 4'b1110: if(next_bit) state <= 4'b1111; // bit 6 4'b1111: if(next_bit) state <= 4'b0001; // bit 7 4'b0001: if(next_bit) state <= 4'b0000; // stop bit default: state <= 4'b0000; endcase reg [7:0] RxD_data; always @(posedge clk) if(Baud8Tick && next_bit && state[3]) RxD_data <= {~RxD_bit_inv, RxD_data[7:1]}; reg RxD_data_ready; always @(posedge clk) begin RxD_data_ready <= (Baud8Tick && next_bit && state==4'b0001 && ~RxD_bit_inv); // ready only if the stop bit is received end reg [4:0] gap_count; always @(posedge clk) if (state!=0) gap_count<=5'h00; else if(Baud8Tick & ~gap_count[4]) gap_count <= gap_count + 5'h01; assign RxD_idle = gap_count[4]; reg RxD_endofpacket; always @(posedge clk) RxD_endofpacket <= Baud8Tick & (gap_count==5'h0F); endmodule module async_transmit(clk, TxD_start, TxD_data, TxD, TxD_busy, state); input clk, TxD_start; input [7:0] TxD_data; output TxD, TxD_busy; output [4:0] state; parameter ClkFrequency = 25000000; // 25MHz //parameter ClkFrequency = 50000000; // 50MHz parameter Baud = 115200; parameter RegisterInputData = 1; // in RegisterInputData mode, the input doesn't have to stay valid while the character is been transmitted // Baud generator parameter BaudGeneratorAccWidth = 16; reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc; `ifdef DEBUG wire [BaudGeneratorAccWidth:0] BaudGeneratorInc = 17'h10000; `else wire [BaudGeneratorAccWidth:0] BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4); `endif wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth]; wire TxD_busy; always @(posedge clk) if(TxD_busy) BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc; // Transmitter state machine reg [4:0] state; wire TxD_ready = (state==0); assign TxD_busy = ~TxD_ready; reg [7:0] TxD_dataReg; always @(posedge clk) if(TxD_ready & TxD_start) TxD_dataReg <= TxD_data; wire [7:0] TxD_dataD = RegisterInputData ? TxD_dataReg : TxD_data; always @(posedge clk) begin if (TxD_start == 0) state <= 5'b00000; case(state) 5'b00000: if(TxD_start) state <= 5'b00001; 5'b00001: if(BaudTick) state <= 5'b00100; 5'b00100: if(BaudTick) state <= 5'b01000; // start 5'b01000: if(BaudTick) state <= 5'b01001; // bit 0 5'b01001: if(BaudTick) state <= 5'b01010; // bit 1 5'b01010: if(BaudTick) state <= 5'b01011; // bit 2 5'b01011: if(BaudTick) state <= 5'b01100; // bit 3 5'b01100: if(BaudTick) state <= 5'b01101; // bit 4 5'b01101: if(BaudTick) state <= 5'b01110; // bit 5 5'b01110: if(BaudTick) state <= 5'b01111; // bit 6 5'b01111: if(BaudTick) state <= 5'b00010; // bit 7 5'b00010: if(BaudTick) state <= 5'b00011; // stop1 //4'b0011: if(BaudTick) state <= 4'b0000; // stop2 5'b00011: if(BaudTick) state <= 5'b10000; // stop2 //default: if(BaudTick) state <= 4'b0000; endcase end // Output mux reg muxbit; always @( * ) case(state[2:0]) 3'd0: muxbit <= TxD_dataD[0]; 3'd1: muxbit <= TxD_dataD[1]; 3'd2: muxbit <= TxD_dataD[2]; 3'd3: muxbit <= TxD_dataD[3]; 3'd4: muxbit <= TxD_dataD[4]; 3'd5: muxbit <= TxD_dataD[5]; 3'd6: muxbit <= TxD_dataD[6]; 3'd7: muxbit <= TxD_dataD[7]; endcase // Put together the start, data and stop bits reg TxD; always @(posedge clk) TxD <= (state<4) | (state[3] & muxbit) | state[4]; // register the output to make it glitch free endmodule