BrunoLevy / learn-fpga

Learning FPGA, yosys, nextpnr, and RISC-V
BSD 3-Clause "New" or "Revised" License
2.44k stars 236 forks source link

Icebreaker FPGA UART communication garbage out #116

Open kir486680 opened 6 months ago

kir486680 commented 6 months ago

I am trying to run step17.v or step18.v and see what kind of output I can get using the ./terminal.sh (picocom -b $BAUDS $DEVICE --imap lfcrlf,crcrlf --omap delbs,crlf --send-cmd "ascii-xfr -s -l 30 -n") after uploading the code into my FPGA with usual BOARDS/run_icebreaker.sh step17.v. However, all I get is continuous flow of garbage ��o�į�����O�������p��o�����O�_x��o�į������O�������p��o�������O_x I have not edited the original code and it seems like the baud rates are matched. What could be causing the problem?

(I have also tried running python3 -m serial.tools.miniterm --dtr=1 $DEVICE $BAUDS or just picocom -b $BAUDS $DEVICE and I still get the same output)

BrunoLevy commented 6 months ago

It really looks like mismatched BAUD rate but can be something else: by default, I have configured it to run at 1000000 (1 million) bauds. Some hw/OS combinations may not support it, so the first thing I'd try is changingit to a more standard 57600 bauds (line 456 of step17.v). Please tell me what it gives, hope that it will work. If it works I will add a "troubleshooting" section.

kir486680 commented 6 months ago

Thanks! I was able to fix that by setting the baud rate to 9600! However, I am running into another issue. I am trying to send two letters consecutively and continuously using this code

    reg [7:0] char_A = 8'h41; // 'A'
    reg [7:0] char_B = 8'h42; // 'B'
    reg [7:0] tx_byte; // Byte to transmit
    reg [4:0] state; // State machine control

    wire uart_valid;
    wire uart_ready;

    // UART module
    corescore_emitter_uart #(
        .clk_freq_hz(`CPU_FREQ*1000000),
        .baud_rate(9600)                
    ) UART (
        .i_clk(clk),
        .i_rst(!resetn),
        .i_data(tx_byte),
        .i_valid(uart_valid),
        .o_ready(uart_ready),
        .o_uart_tx(TXD)                        
    );

// State machine for sending characters
    always @(posedge clk or posedge resetn) begin
        if (resetn) begin
            state <= 0; // Start with state 0 to send 'A'
            uart_valid <= 0;
            tx_byte <= 0;
        end else if (uart_ready && uart_valid) begin
            uart_valid <= 0; // Deassert uart_valid once character is sent
        end else begin
            case (state)
                0: begin
                    tx_byte <= char_A; // Load 'A' to be sent
                    state <= 1;
                    uart_valid <= 1; // Assert uart_valid for 'A'
                end
                1: begin
                    tx_byte <= char_B; // Load 'B' to be sent
                    state <= 0; // Loop back to start
                    uart_valid <= 1; // Assert uart_valid for 'B'
                end
            endcase
        end
    end

Ideally, the output should be ABABAB...but all I get is a non continuous stream of data BAB every time I run the code. Would you happen to know what the issue might be?

BrunoLevy commented 6 months ago

It is because you need to wait for uart_busy to be deasserted before sending the next character (your state machine is much much faster than the UART).

kir486680 commented 6 months ago

Thanks for the suggestion. Do you mean uart_ready be asserted since there is no uart_busy? I changed my code to this, and the output seems to be nothing

always @(posedge clk or posedge resetn) begin
    if (resetn) begin
        state <= 0; // Start with state 0 to send 'A'
        tx_byte <= 0;
        uart_valid <= 0;
    end else if (uart_valid) begin
        uart_valid <= 0; // Deassert uart_valid once character is sent
    end else if (uart_ready) begin
        case (state)
            0: begin
                tx_byte <= char_A; // Load 'A' to be sent
                state <= 1;
                uart_valid <= 1; // Assert uart_valid for 'A'
            end
            1: begin
                tx_byte <= char_B; // Load 'B' to be sent
                state <= 0; // Loop back to start
                uart_valid <= 1; // Assert uart_valid for 'B'
            end
        endcase
    end
end