Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
13 years ago

UART Transmitter Sends Bytes Out of Order

Hello,

I have the following Verilog code which sends 8 bytes to the serial port successively after a button is pressed.

The problem is, the bytes are sent out of order as to what I would expect.

For example, if I send out the bytes 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef - the PC gets 0xef, 0xad, 0xef, 0xad and sometimes does not receive the rest and will hang-up.

I've looked at this code many times, and can't seem to figure out why this might be. Am I using the part-select incorrectly? I don't think so, but I don't know what else could be the issue.

I've attached a second version of this code that does work(meaning all the bytes are received and in the correct order), but it takes an extra clock cycle because it updates the data in the shift register after each transmission. If you can see any reason why the first version posted does not work, but the second does - please let me know!

Any suggestions are greatly appreciated.

Kristin


module transmission_test_2(sysclk, rxd, txd, LED, button);
input sysclk, rxd, button;
output txd;
output reg LED;
wire receiving_complete, isReceiving, isTransmitting, isError;
reg begin_transmit;
reg  tbyte;
wire  rbyte;
reg  state;
reg  plain_text;
integer byteN;
parameter IDLE = 0, BEGIN_TRANSMISSION = 1, UPDATE_DATA = 2, SEND_BYTES = 3;
uart uart1(
    .clk(sysclk),
    .rx(rxd),
    .tx(txd),
    .transmit(begin_transmit),
    .tx_byte(tbyte),
    .received(receiving_complete),
    .rx_byte(rbyte),
    .is_receiving(isReceiving), 
    .is_transmitting(isTransmitting),
    .recv_error(isError)
    );
always @(posedge sysclk)
    begin
        begin_transmit = 1'b0;
        case(state)
        IDLE: begin
            if(button==1'b0) begin
                LED = 1'b1;
                plain_text = 64'hDEADBEEFDEADBEEF;
                state = BEGIN_TRANSMISSION;
            end else begin
                LED <= 1'b0;
            end
        end
        BEGIN_TRANSMISSION: begin
            tbyte = plain_text;
            begin_transmit = 1'b1;
            byteN = 1;
            state = SEND_BYTES;
        end
        SEND_BYTES: begin
            if(!isTransmitting) begin
                tbyte = plain_text;
                begin_transmit = 1'b1;
                byteN = byteN + 1;
                if(byteN == 8) begin
                    state = IDLE;
                end
            end
        end
        endcase
    end
endmodule


module transmission_test(sysclk, rxd, txd, LED, button);
input sysclk, rxd, button;
output txd;
output reg LED;
wire receiving_complete, isReceiving, isTransmitting, isError;
reg begin_transmit;
reg  tbyte;
wire  rbyte;
reg  state;
reg  plain_text;
integer bytes_remaining;
parameter IDLE = 0, BEGIN_TRANSMISSION = 1, UPDATE_DATA = 2, SEND_BYTES = 3, DONE = 4;
uart uart1(
    .clk(sysclk),
    .rx(rxd),
    .tx(txd),
    .transmit(begin_transmit),
    .tx_byte(tbyte),
    .received(receiving_complete),
    .rx_byte(rbyte),
    .is_receiving(isReceiving), 
    .is_transmitting(isTransmitting),
    .recv_error(isError)
    );
always @(posedge sysclk)
    begin
        begin_transmit = 1'b0;
        case(state)
        IDLE: begin
            if(button==1'b0) begin
                LED = 1'b1;
                plain_text = 64'hDEADBEEFDEADBEEF;
                state = BEGIN_TRANSMISSION;
            end else begin
                LED <= 1'b0;
            end
        end
        BEGIN_TRANSMISSION: begin
            tbyte = plain_text;
            begin_transmit = 1'b1;
            bytes_remaining = 7;
            state = UPDATE_DATA;
        end
        UPDATE_DATA: begin
            plain_text = plain_text >> 8;
            state = SEND_BYTES;
        end
        SEND_BYTES: begin
            if(!isTransmitting) begin
                tbyte = plain_text;
                begin_transmit = 1'b1;
                bytes_remaining = bytes_remaining - 1;
                if(bytes_remaining == 0) begin
                    state = IDLE;
                end else begin
                    state = UPDATE_DATA;
                end
            end
        end
        endcase
    end
endmodule

9 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    There isn't quite enough here to go on, but I'll hazard a guess. The code for uart1 is critical.

    If the isTransmitting signal is generated using a clocked process, (sorry for the terminology, I'm a VHDL guy) the isTransmitting signal will go high at least 1 clock after begin_transmit is set high. This will cause if(!isTransmitting) to be true.

    A Verilog simulator would probably show you exactly what is going on. If you are still stuck on this, post the uart code. It will help fill in the gaps.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I'd test without repeated byte values - might make it slightly more obvious what is going on.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    In the first piece of code (the not working one) in SEND_BYTES state you wrote:

    tbyte = plain_text[byteN*8 +: 8];

    What does that mean?

    I have never seen such a syntax. Is this a typo?

    I'd rather used:

    tbyte = plain_text[(byteN+1)*8: byteN*8];
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    In the first piece of code (the not working one) in SEND_BYTES state you wrote:

    tbyte = plain_text[byteN*8 +: 8];

    What does that mean?

    I have never seen such a syntax. Is this a typo?

    I'd rather used:

    tbyte = plain_text[(byteN+1)*8: byteN*8];

    --- Quote End ---

    Check section 4.2.1 of the 1364-2001 spec, Vector bit-select and part-select addressing

    fe, if you declare a reg as:

    reg [15:0] d,

    then d[0 +: 8] is equivalent to d[7:0]

    if you declare it as:

    reg [0:15] d,

    then d[0 +: 8] is equivalent to d[0:7]

    there is also a -: operator that works similarly

    As for the question in hand, you should get a simulator (there are free ones), and check your timing constraints
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    @Cris72: No, it's not a typo - it's called part-select - added to the language in Verilog 2001. Your version would be simpler, except that it isn't allowed. One of the indices in the part-select must be a constant/literal and the other may be a variable - but they can't both contain variables.

    @kosh271: Here is the code for uart1:

    
    module uart(
        input clk, // The master clock for this module
        input rst, // Synchronous reset.
        input rx, // Incoming serial line
        output tx, // Outgoing serial line
        input transmit, // Signal to transmit
        input  tx_byte, // Byte to transmit
        output received, // Indicated that a byte has been received.
        output  rx_byte, // Byte received
        output is_receiving, // Low when receive line is idle.
        output is_transmitting, // Low when transmit line is idle.
        output recv_error // Indicates error in receiving packet.
        );
    parameter CLOCK_DIVIDE = 1302; // clock rate (50Mhz) / (baud rate (9600) * 4)
    // States for the receiving state machine.
    // These are just constants, not parameters to override.
    parameter RX_IDLE = 0;
    parameter RX_CHECK_START = 1;
    parameter RX_READ_BITS = 2;
    parameter RX_CHECK_STOP = 3;
    parameter RX_DELAY_RESTART = 4;
    parameter RX_ERROR = 5;
    parameter RX_RECEIVED = 6;
    // States for the transmitting state machine.
    // Constants - do not override.
    parameter TX_IDLE = 0;
    parameter TX_SENDING = 1;
    parameter TX_DELAY_RESTART = 2;
    reg  rx_clk_divider = CLOCK_DIVIDE;
    reg  tx_clk_divider = CLOCK_DIVIDE;
    reg  recv_state = RX_IDLE;
    reg  rx_countdown;
    reg  rx_bits_remaining;
    reg  rx_data;
    reg tx_out = 1'b1;
    reg  tx_state = TX_IDLE;
    reg  tx_countdown;
    reg  tx_bits_remaining;
    reg  tx_data;
    assign received = recv_state == RX_RECEIVED;
    assign recv_error = recv_state == RX_ERROR;
    assign is_receiving = recv_state != RX_IDLE;
    assign rx_byte = rx_data;
    assign tx = tx_out;
    assign is_transmitting = tx_state != TX_IDLE;
    always @(posedge clk) begin
        if (rst) begin
            recv_state = RX_IDLE;
            tx_state = TX_IDLE;
        end
        
        // The clk_divider counter counts down from
        // the CLOCK_DIVIDE constant. Whenever it
        // reaches 0, 1/16 of the bit period has elapsed.
       // Countdown timers for the receiving and transmitting
        // state machines are decremented.
        rx_clk_divider = rx_clk_divider - 1;
        if (!rx_clk_divider) begin
            rx_clk_divider = CLOCK_DIVIDE;
            rx_countdown = rx_countdown - 1;
        end
        tx_clk_divider = tx_clk_divider - 1;
        if (!tx_clk_divider) begin
            tx_clk_divider = CLOCK_DIVIDE;
            tx_countdown = tx_countdown - 1;
        end
        
        // Receive state machine
        case (recv_state)
            RX_IDLE: begin
                // A low pulse on the receive line indicates the
                // start of data.
                if (!rx) begin
                    // Wait half the period - should resume in the
                    // middle of this first pulse.
                    rx_clk_divider = CLOCK_DIVIDE;
                    rx_countdown = 2;
                    recv_state = RX_CHECK_START;
                end
            end
            RX_CHECK_START: begin
                if (!rx_countdown) begin
                    // Check the pulse is still there
                    if (!rx) begin
                        // Pulse still there - good
                        // Wait the bit period to resume half-way
                        // through the first bit.
                        rx_countdown = 4;
                        rx_bits_remaining = 8;
                        recv_state = RX_READ_BITS;
                    end else begin
                        // Pulse lasted less than half the period -
                        // not a valid transmission.
                        recv_state = RX_ERROR;
                    end
                end
            end
            RX_READ_BITS: begin
                if (!rx_countdown) begin
                    // Should be half-way through a bit pulse here.
                    // Read this bit in, wait for the next if we
                    // have more to get.
                    rx_data = {rx, rx_data};
                    rx_countdown = 4;
                    rx_bits_remaining = rx_bits_remaining - 1;
                    recv_state = rx_bits_remaining ? RX_READ_BITS : RX_CHECK_STOP;
                end
            end
            RX_CHECK_STOP: begin
                if (!rx_countdown) begin
                    // Should resume half-way through the stop bit
                    // This should be high - if not, reject the
                    // transmission and signal an error.
                    recv_state = rx ? RX_RECEIVED : RX_ERROR;
                end
            end
            RX_DELAY_RESTART: begin
                // Waits a set number of cycles before accepting
                // another transmission.
                recv_state = rx_countdown ? RX_DELAY_RESTART : RX_IDLE;
            end
            RX_ERROR: begin
                // There was an error receiving.
                // Raises the recv_error flag for one clock
                // cycle while in this state and then waits
                // 2 bit periods before accepting another
                // transmission.
                rx_countdown = 8;
                recv_state = RX_DELAY_RESTART;
            end
            RX_RECEIVED: begin
                // Successfully received a byte.
                // Raises the received flag for one clock
                // cycle while in this state.
                recv_state = RX_IDLE;
            end
        endcase
        
        // Transmit state machine
        case (tx_state)
            TX_IDLE: begin
                if (transmit) begin
                    // If the transmit flag is raised in the idle
                    // state, start transmitting the current content
                    // of the tx_byte input.
                    tx_data = tx_byte;
                    // Send the initial, low pulse of 1 bit period
                    // to signal the start, followed by the data
                    tx_clk_divider = CLOCK_DIVIDE;
                    tx_countdown = 4;
                    tx_out = 0;
                    tx_bits_remaining = 8;
                    tx_state = TX_SENDING;
                end
            end
            TX_SENDING: begin
                if (!tx_countdown) begin
                    if (tx_bits_remaining) begin
                        tx_bits_remaining = tx_bits_remaining - 1;
                        tx_out = tx_data;
                        tx_data = {1'b0, tx_data};
                        tx_countdown = 4;
                        tx_state = TX_SENDING;
                    end else begin
                        // Set delay to send out 2 stop bits.
                        tx_out = 1;
                        tx_countdown = 8;
                        tx_state = TX_DELAY_RESTART;
                    end
                end
            end
            TX_DELAY_RESTART: begin
                // Wait until tx_countdown reaches the end before
                // we send another transmission. This covers the
                // "stop bit" delay.
                tx_state = tx_countdown ? TX_DELAY_RESTART : TX_IDLE;
            end
        endcase
    end
    endmodule
    

    I've also attached an image of the simulation for all relevant signals:

    https://docs.google.com/open?id=0b4wyejzmihtnadbib1njtzrymta

    Looking at the output, it's obvious that byteN is increasing by two instead of one - and that's why I'm getting every other byte.

    However, I still don't see why this is happening. Is it because I sample the value of byteN and update its value in the same clock cycle? I didn't think this would be a problem - since I'm using blocking assignments and also because I'm following a similar convention in the version of the code that is working.

    Any insights? :)
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    As an alternative, I also tried removing the "catch-all" state for sending all 8 bytes and created a separate state for each byte that needed to be sent.

    However, the result is still the same. I receive every other byte. What gives?

    Any ideas?

    Below is the code:

    
    module transmission_test_3(sysclk, rxd, txd, LED, button);
    input sysclk, rxd, button;
    output txd;
    output reg LED;
    wire receiving_complete, isReceiving, isTransmitting, isError, reset;
    reg begin_transmit;
    reg  tbyte;
    wire  rbyte;
    reg  state = 4'b0;
    reg  plain_text = 64'h0;
    uart uart1(
        .clk(sysclk),
        .rst(reset),
        .rx(rxd),
        .tx(txd),
        .transmit(begin_transmit),
        .tx_byte(tbyte),
        .received(receiving_complete),
        .rx_byte(rbyte),
        .is_receiving(isReceiving), 
        .is_transmitting(isTransmitting),
        .recv_error(isError)
        );
    always @(posedge sysclk)
        begin
            begin_transmit = 1'b0;
            case(state)
            4'b0000: begin
                if(button==1'b0) begin
                    LED = 1'b1;
                    plain_text = 64'hDEADBEEFAAABACAD;
                    state = 4'b0001;
                end else begin
                    LED = 1'b0;
                end
            end
            4'b0001: begin
                tbyte = plain_text;
                begin_transmit = 1'b1;
                state = 4'b0010;
            end
            4'b0010: begin
                if(!isTransmitting) begin
                    tbyte = plain_text;
                    begin_transmit = 1'b1;
                    state = 4'b0011;
                end
            end
            4'b0011: begin
                    if(!isTransmitting) begin
                        tbyte = plain_text;
                        begin_transmit = 1'b1;
                        state = 4'b0100;
                    end
                end
            4'b0100: begin
                if(!isTransmitting) begin
                    tbyte = plain_text;
                    begin_transmit = 1'b1;
                    state = 4'b0101;
                end
            end
            4'b0101: begin
                if(!isTransmitting) begin
                    tbyte = plain_text;
                    begin_transmit = 1'b1;
                    state = 4'b0110;
                end
            end
            4'b0110: begin
                if(!isTransmitting) begin
                    tbyte = plain_text;
                    begin_transmit = 1'b1;
                    state = 4'b0111;
                end
            end
            4'b0111: begin
                if(!isTransmitting) begin
                    tbyte = plain_text;
                    begin_transmit = 1'b1;
                    state = 4'b1000;
                end
            end
            4'b1000: begin
                if(!isTransmitting) begin
                    tbyte = plain_text;
                    begin_transmit = 1'b1;
                    state = 4'b0000;
                end
            end
            endcase
        end
    endmodule
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Quite cleary isTransmitting is active for 2 clocks.

    It won't be seen inactive until the clock after the uart sees begin_transmit active.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Here is a version of your code that I modified somewhat and it works quite well. I'm using HyperTerm at 9600 8-N-2 to display the xmitted chars. Note the order in which 'plain_text' is read. For valid printing chars to be displayed you cannot send 0xDEADBEEF but rather its ASCII equivalent. There are some additional little changes, for example, tbyte = plain_text[(byteN*8)-1 -: 8] and the state machine runs at 4-KHz. No changes to uart.v except for some cosmetics.

    rgs
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    FWIW HyperTerm is a bad choice of program, it is designed(?) to talk to modems and can get confused if the modem signal lines are incorrect.

    Its UI is also painful.

    putty (free download) works a lot better on serial lines (as well as for ssh etc).