0
\$\begingroup\$

I'm working on a UART transmit process (uart_transmit) in VHDL (115200 baud, 8 data bits, 1 stop bit and no parity). I need the transmit line (tx_line) in the process to go idle whenever the carriage return (CARR_RET) in the message buffer is detected.

The buffer is part of another process but it shifts each character into char_byte when the transmission of the last byte has finished. It is clocked by the TX_DONE signal.

The issue I'm having, however, is that the FPGA transmits the entire message as required except for the carriage return. I know it's because the process uart_ready detects the carriage return and changes the state of TX_READY accordingly but I don't know how to workaround the instantaneous change, I thought about delaying the TX_READY signal with an FDC but that didn't work. Are there any suggestions as to how I can detect the carriage return, transmit the carriage return and still send the transmit line to idle?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD;

entity uart_tx is
        Port (clk               : in std_logic;
                    reset           : in std_logic;
                    tx_line         : out std_logic;
                    switch          : in std_logic;
                    TX_DONE         : out std_logic;
                    char_byte       : in std_logic_vector(7 downto 0));
end uart_tx;

architecture Behavioral of uart_tx is

constant stop_bit       : std_logic :='1';
constant start_bit      : std_logic :='0';
constant idle           : std_logic :='1';
constant CARR_RET       : std_logic_vector(7 downto 0) :="00001010";

signal  TX_READY    : std_logic :='0';
signal  TX_MESSAGE  : std_logic_vector(9 downto 0) :=(others => '0');

begin
uart_ready: process (clk,reset)
 begin
    if(reset='1') then
        TX_READY<='0';
    elsif rising_edge(clk)then 
        if(switch = '1')then
            if(char_byte = CARR_RET)then
                TX_READY<='0';
            else
                TX_READY<='1';
            end if;
        end if;
    end if;
 end process;

uart_transmit: process (clk,reset)
 variable bit_count: integer range 0 to 9:=0;
 begin
    if(reset='1') then
        tx_line<=idle;
        bit_count:=0;
        TX_DONE<='0';
        TX_MESSAGE<="0000000000";
        elsif rising_edge(clk)then 
            if(switch = '1')then
                TX_MESSAGE(9 downto 0) <= stop_bit &char_byte &start_bit;

                if(TX_READY = '1')then
                 if(bit_count=9)then
                    TX_MESSAGE<="0000000000";
                    TX_DONE<='1';
                    tx_line<=idle;
                    bit_count:=0;
                 else 
                    tx_line<=TX_MESSAGE(bit_count);
                    bit_count:= bit_count+1;
                    TX_DONE<='0';
                 end if;
                elsif(TX_READY = '0')then
                 tx_line<=idle;
                end if;
          end if;
        end if;
 end process;
end Behavioral;
\$\endgroup\$
1
\$\begingroup\$

the process to go idle whenever the carriage return (CARR_RET) in the message buffer is detected.

If you look at the above carefully your should notice that your specification is already wrong. The correct specification would be: "the process to go idle after the carriage return (CARR_RET) has been sent."

That means detect a CR has been loaded in the the transmitter and the transmitter has sent it.

Next you try to solve this by adapting your existing logic. I would not do that. Instead I would keep that functionality separated from the other functions and add a small FSM to specifically deal with the issue:

  1. Idle state, goto 2 if a CR has been loaded in the transmit register.
  2. Goto 3 if the transmit register has started shifting out.
  3. Goto 4 if the transmitter finishes. set line to not-ready.
  4. Wait for a 'goto idle' signal, set line to ready.

In state 4 you need some condition on which the FSM is reset again, but you did not talk about that part of the protocol in your question.


Your comment:

Is there any particular reason why you wouldn't adapt the existing logic?

is a good one so I'll answer it here:

Experience has shown me code is easier to understand, debug and maintain if you keep functionality separated. In fact you are doing that already as you have a separate process for the READY.
Now all you need to do is make that process a bit more intelligent by keeping better track of what is happening, which is like the sort of FSM I suggested.

Also, the FSM would be reset when the message buffer has a new message loaded into it

That is not the right way. A reset is there to set an initial state. Sending the next character should not require you to use the reset. I consider that sloppy and the easy-way out.

In a real chip the reset goes everywhere on start-up and now you are going to have to add some 'or' functionality to reset the block also when a character needs to be sent. Your company's Design-For-Test engineer will give you a firm talk-to for that as it will play havoc with his scan-chains.

Furthermore you reset is asynchronous which can cause glitches in all logic down the chain. If you really want to use a reset use at least a synchronous one.

\$\endgroup\$
  • \$\begingroup\$ Is there any particular reason why you wouldn't adapt the existing logic? Also, the FSM would be reset when the message buffer has a new message loaded into it. \$\endgroup\$ – Simeon R Jan 18 at 10:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.