diff options
Diffstat (limited to 'fpga/xilinx/digilent/spartan_3e/remote_access.v')
-rw-r--r-- | fpga/xilinx/digilent/spartan_3e/remote_access.v | 1184 |
1 files changed, 1184 insertions, 0 deletions
diff --git a/fpga/xilinx/digilent/spartan_3e/remote_access.v b/fpga/xilinx/digilent/spartan_3e/remote_access.v new file mode 100644 index 0000000..154478e --- /dev/null +++ b/fpga/xilinx/digilent/spartan_3e/remote_access.v @@ -0,0 +1,1184 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: Pearson Computing +// Engineer: Timothy Pearson +// +// Create Date: 11:58:21 07/07/2007 +// Design Name: Remote Access Driver +// Module Name: remote_access +// Project Name: Remote Access Driver +// Target Devices: Digilent Spartan 3E Development Board +// Tool versions: Xilinx ISE v9.1 SP3 +// Description: Serial remote access driver and LCD display driver +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: Released into the Public Domain +// +////////////////////////////////////////////////////////////////////////////////// +module remote_access( + input main_fifty_clock, // 50MHz clock in + 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 + 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, + 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, + input sram_wren_in, + input sram_clock_in, + input [7:0] sram_data_in, + input [13:0] sram_address_in, + output [7:0] sram_data_out, + output sram_available, + input sram_processing_done, + input [7:0] led_segment_bus, + input [3:0] led_digit_select); + + 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 remote_access_4_bit_input = remote_access_4_bit_input_reg; + 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_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 @(posedge clk_div_by_two) 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 [4:0] digit_blanker_1 = 0; + reg [4:0] digit_blanker_2 = 0; + reg [4:0] digit_blanker_3 = 0; + reg [4:0] digit_blanker_4 = 0; + + always @(negedge clk_div_by_eight) begin + if (led_digit_select[0] == 0) begin + led_display_bytes[0] = led_segment_bus; + digit_blanker_1 = 0; + end + + if (led_digit_select[1] == 0) begin + led_display_bytes[1] = led_segment_bus; + digit_blanker_2 = 0; + end + + if (led_digit_select[2] == 0) begin + led_display_bytes[2] = led_segment_bus; + digit_blanker_3 = 0; + end + + if (led_digit_select[3] == 0) begin + led_display_bytes[3] = led_segment_bus; + digit_blanker_4 = 0; + end + + if (digit_blanker_1 > 30) begin + led_display_bytes[0] = 255; + end + + if (digit_blanker_2 > 30) begin + led_display_bytes[1] = 255; + end + + if (digit_blanker_3 > 30) begin + led_display_bytes[2] = 255; + end + + if (digit_blanker_4 > 30) 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 [13:0] data_storage_addra; + wire data_storage_write_enable; + wire [7:0] data_storage_data_out; + + reg [7:0] data_storage_dina_reg; + reg [13:0] data_storage_addra_reg; + reg data_storage_write_enable_reg; + + data_storage 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; + + // ----------------------------------------------------------------------------------------------- + // + // 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_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 prev_was_carriage_return = 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 [15: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; + + // 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_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_status == 1) && (transmit_dsp_status_done == 0)) begin + if (transmit_dsp_status_holdoff == 0) begin + transmit_dsp_status_holdoff = 1; + data_storage_write_enable_reg = 0; + data_storage_addra_reg = 0; // Initial data value + end else begin + data_storage_write_enable_reg = 0; + TxD_data = data_storage_data_out; + + TxD_start = 1; + tx_toggle = 1; + + transmit_dsp_status_counter = transmit_dsp_status_counter + 1; + data_storage_addra_reg = transmit_dsp_status_counter; + if (transmit_dsp_status_counter > 16384) begin + transmit_dsp_status_done = 1; + data_storage_write_enable_reg = 1'bz; + data_storage_addra_reg = 14'bz; + 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_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_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 [15: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_main_status_done == 1) begin + transmit_main_status = 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 + data_storage_write_enable_reg = 0; + 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 + 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 + // Parse the command and see what it is + serial_character_received = 1; + if (RxD_data == 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 + 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 + + // DSP input data + if (next_byte_is_command_prev_command == 77) begin + if (dsp_update_counter < 16384) begin + data_storage_remote_enable = 1; + data_storage_addra_reg = dsp_update_counter; + data_storage_dina_reg = serial_command_buffer; + data_storage_write_enable_reg = 1; + 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 + end else begin + next_byte_is_command = 0; + data_storage_write_enable_reg = 0; + data_storage_remote_enable = 0; + sram_available_reg = 1; + data_storage_write_enable_reg = 1'bz; + data_storage_addra_reg = 14'bz; + waiting_on_dsp_processing = 1; + + // TESTING ONLY!!! + //transmit_dsp_status = 1; + end + end + end + end + end + end + + //if (RxD_data != 10) begin // Ignore linefeeds + serial_command_buffer = RxD_data; + //end + + if (RxD_data == 13) begin + prev_was_carriage_return = 1; + end else begin + prev_was_carriage_return = 0; + 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; // <blank> + lcd_display_string[15] = 32; // <blank> + lcd_display_string[16] = 79; // O + lcd_display_string[17] = 75; // k + lcd_display_string[18] = 32; // <blank> + lcd_display_string[19] = 32; // <blank> + lcd_display_string[20] = 32; // <blank> + lcd_display_string[21] = 32; // <blank> + lcd_display_string[22] = 32; // <blank> + lcd_display_string[23] = 32; // <blank> + lcd_display_string[24] = 32; // <blank> + lcd_display_string[25] = 32; // <blank> + lcd_display_string[26] = 32; // <blank> + lcd_display_string[27] = 32; // <blank> + lcd_display_string[28] = 32; // <blank> + lcd_display_string[29] = 32; // <blank> + lcd_display_string[30] = 32; // <blank> + lcd_display_string[31] = 32; // <blank> + + 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 |