Electronic – Basys 3 FPGA sequential circuit reset remotely

resetsequential-logicverilogvivado

Since the COVID-19 pandemic, I'm teaching Verilog lab online. I let each student remotely connect to a computer having Xilinx Vivado installed, a Basys 3 board connected and powered on, and a camera that see the board so they can see the results on LEDs and the seven-segment display.

I'm preparing a lab about Counters, but I've an issue with how to remotely handle the reset signal. Do you have any thoughts that can help here, instead of relying on a physical toggle button due to remote access?

Best Answer

I found a workaround that allows me use a remote keyboard button that acts as a remote reset button press. For that I relied on the Basys 3 board shared UART/JTAG USB port, in other words I relied on the UART in the FTDI chip in the board.

I wrote a simple UART reciever module (the code is below) that detects the input received from the Windows COM port commands (I used Tera Term tool enter link description here). Once the ASCII value of a specific keyboard key is received ('a' in my code below), the module gives a short output pulse. Other modules can instantiate that module, and use that pulse generated remotely through keyboard as a reset signal.

The following picture shows how AnyDesk is used to remote access a lab machine for development and to see the connected Basys 3 board via camera, and Tera Term tool and the designed UART receiver are used to simulate board buttons presses remotely from my machine: enter image description here

This is the code:

module UART_receiver_for_reset( // UART (Asynchronous) receiver, that gives pulse on output_level when 'a' keyboard key ascii value is received
    input clk, // input clock
    //input reset, // reset should be normally an input wire that is used to initialize some registers to 0, but in our remote case we don't have access to any GPIOs to use for reset, so we specify reg initial values directly to 0 instead of waiting for a reset signal to do so (for example reg state = 0;), take care that a wire doesn't have storage so an initial value to it doesn't make sense.
    input RxD, // input receiving data line
    output [7:0] RxData, // output for 8 bits data
    output output_level // output level
    );

    //internal variables
    reg [3:0] bitcounter = 0; // 4 bits counter to count if 10 bits data transmission complete or not
    reg [1:0] samplecounter = 0; // 2 bits sample counter to count up to 4 for oversampling
    reg clear_bitcounter, inc_bitcounter, inc_samplecounter, clear_samplecounter; // clear or increment the counter

    reg [13:0] counter = 0; // 14 bits counter to count the baud rate (symbol rate) for UART receiving
    reg state = 0;  // initial state variable (mealy finite state machine)
    reg nextstate; // next state variable (mealy finite state machine)
    reg shift; // signal to indicate shifting data is ready
    reg [9:0] rxshiftreg; // 10 bits data needed to be shifted in during transmission. For storing the serial package and sending its bits one by one. The least significant bit is initialized with the binary value “0” (a start bit) A binary value “1” is introduced in the most significant bit

    reg output_reset = 0; // our output reset
    reg [31:0] time_counter = 0; // needed for our output reset


    // Constants (a parameter infers its type from its value)
    parameter clk_freq = 100_000_000;  // system clock frequency
    parameter baud_rate = 9_600; // baud rate (should be agreed upon with the transmitter)
    parameter oversamples = 4; // oversampling
    parameter reset_counter = clk_freq/(baud_rate*oversamples);  // counter upper bound
    // <------------ 100M clock cycles ----------->
    // <------------ 9,600 bits ------------------>
    // <------------ 9,600x4 samples ------------->
    // reset_counter = 2604, means counter goes from 0 to 2604 (during that time I should take 1 sample)
    parameter counter_mid_sample = (oversamples/2);  // this is the middle point of a bit where you want to sample it
    parameter num_bit = 10; // 1 start, 8 data, 1 stop

    parameter reset_key = 8'b01100001; // 8'b01100001; is the binary value of the ASCII character of small 'a' keyboard button
    parameter reset_high_seconds = 1;
    parameter reset_time_counter = clk_freq*reset_high_seconds;


    assign RxData = rxshiftreg [8:1]; // assign the RxData from the shiftregister
    assign output_level = output_reset;

    // UART receiver logic
    always @ (posedge clk) begin 
        counter <= counter +1; // start count in the counter
        if (counter >= reset_counter-1) begin // if counter reach the baud rate with sampling 
            counter <=0; //reset the counter
            state <= nextstate; // assign the state to nextstate
            if (shift)rxshiftreg <= {RxD,rxshiftreg[9:1]}; //if shift asserted, load the receiving data
            if (clear_samplecounter) samplecounter <=0; // if clear sampl counter asserted, reset sample counter
            if (inc_samplecounter) samplecounter <= samplecounter +1; //if increment counter asserted, start sample count
            if (clear_bitcounter) bitcounter <=0; // if clear bit counter asserted, reset bit counter
            if (inc_bitcounter)bitcounter <= bitcounter +1; // if increment bit counter asserted, start count bit counter
        end

        // Handle our desired reset output
        if (output_reset == 0 && rxshiftreg[8:1] == reset_key)
           output_reset <= 1;
        if (output_reset == 1)
            if (time_counter >= reset_time_counter) begin
                time_counter <= 0;
                output_reset <= 0;
                rxshiftreg[8:1] <= 0;
            end
            else time_counter <= time_counter +1;
    end

    // Finite state machine
    always @ (posedge clk) begin //trigger by clock 
        shift <= 0; // set shift to 0 to avoid any shifting 
        clear_samplecounter <=0; // set clear sample counter to 0 to avoid reset
        inc_samplecounter <=0; // set increment sample counter to 0 to avoid any increment
        clear_bitcounter <=0; // set clear bit counter to 0 to avoid claring
        inc_bitcounter <=0; // set increment bit counter to avoid any count
        nextstate <=0; // set next state to be idle state
        case (state)
            0: begin // idle state
                if (RxD) // if input RxD data line asserted
                  nextstate <=0; // back to idle state because RxD needs to be low to start transmission    
                else begin // if input RxD data line is not asserted
                    nextstate <=1; // jump to receiving state 
                    clear_bitcounter <=1; // trigger to clear bit counter
                    clear_samplecounter <=1; // trigger to clear sample counter
                end
            end
            1: begin // receiving state
                nextstate <= 1; // DEFAULT 
                if (samplecounter == counter_mid_sample - 1) shift <= 1; // if sample counter is 1, trigger shift 
                if (samplecounter == oversamples - 1) begin // if sample counter is 3 as the sample rate used is 3
                    if (bitcounter == num_bit - 1) // check if bit counter if 9 or not
                        nextstate <= 0; // back to idle state if bit counter is 9 as receving is complete
                    inc_bitcounter <=1; // trigger the increment bit counter if bit counter is not 9
                    clear_samplecounter <=1; //trigger the sample counter to reset the sample counter
                end
                else inc_samplecounter <=1; // if sample is not equal to 3, keep counting
            end
           default: nextstate <=0; //default idle state
         endcase
    end
endmodule


module my_module(input clk, RxD); // also add your other inputs and outputs here
    wire reset;
    UART_receiver_for_reset (.clk(clk), .RxD(RxD), .RxData(), .output_level(reset))

    //...your module code...

endmodule