In and email Jonathan Leslie said:
> > TX_DATA_IN( 7 DOWNTO 0 ) <=3D x"55";
> What is wrong with the way you have it written above?
>
> JL:: - nothing if all I want is a single character on the outbound, but t=
he idea is to get to a point where I can put message strings on the outboun=
d uart. My app will need message packets sent out, and making long strings=
of hex code makes for a maintenance nightmare.
>
> having a string of
> TX_DATA_IN( 7 DOWNTO 0 ) <=3D x"55";
> -- send char
> TX_DATA_IN( 7 DOWNTO 0 ) <=3D x"45";
> -- send char
> TX_DATA_IN( 7 DOWNTO 0 ) <=3D x"62";
> -- send char
>
> is gonna get real annoying I'm building up to making a
> communication package where I can send out on my uart
>
> send_to_uart("UUT:init");
>
> or
>
> send_to_uart("UUT:shutdown");
>
>
>
> 1) Instead of using a test for the clock being 1 and an event, you
> should use rising_edge(clock). This is a standard form and will make
> the simulation match the synthesis better.
> JL:: - check. thanks for semantic correction.
>
>
>
>
> 2) The above should be a single process and not combined with
> anything else.
> JL:: Quite right, I think I misspoke. I mean that the routine needs to b=
e able to handle a "parameter" (using a c term) in
> place of the x"55" where some other routine establishes what exactly is g=
oing to be sent on the TX line.
>
>
> It will check for the trigger just as you have it
> written. When found, it will use the character currently pointed to
> by the index and increment the index. Remember that HDL describes
> hardware and this is a description of the transmit holding register
> and the logic controlling its timing. BTW, is this a holding
> register or the transmitter data register (the one that shifts the
> data out)? If the latter, you need to describe both the loading and
> the shifting in one process.
>
> JL:: not sure what your getting at here. I don't see anything to increme=
nt an index. Now as far as how the tx_data_in is used,
> either as a register or transmitter data register, well that's a good que=
stion. I'm gonna have to dig a little on that one.
You need to *add* a counter. The only way you can access the
individual characters in the string is to use an index. Thinking of
this in hardware, there will be a tx shift register, a tx holding
register and a character source which does not need to be a register,
but can be.
The two registers need to define their controls and actions in the
same or different clocked processes. The character source is
controlled by a counter which also needs to be defined in a clocked
process. The character source can be defined in an unclocked process
or in a concurrent statement. In the process it would be a case
statement. In a concurrent statement it would be a selected
statement, IIRC (the one that uses "with").
I can tell that you are still trying to code in C. When you refer to
this as 'the routine needs to be able to handle a "parameter"' that
says to me that you are thinking of a subroutine that is called by a
higher routine. VHDL does not work like that really. A process is
*not* a subroutine. A process defines hardware that runs separately
from the other hardware in the design.
Here is a way to visualize the difference. When you program in C, you
would normally use a flowchart. That shows sequences of operations.
When you program in an HDL, you would instead use a data flow
diagram. That shows different operations on data that happen at the
same time. In a flowchart, blocks can be used that represent
subroutines that can be separately charted in levels. In a data flow
diagram, each block is a process that runs all the time and acts on
whatever data is presented to it.
> The way I'm thinking is that I'm gonna need a fifo buffer where the trans=
mit characters are placed and as long as that buffer is not empty the P7 pr=
ocess will take a character, load it into the tx_data_in register, and send=
it on its way. the fifo buffer handler will then move its pointer to the =
next character in the fifo.
You would only need a FIFO if you can't control the rate that
characters are sent to the Xmitter. Since you are producing the
characters, you can control that. Actually, the same is true for a Tx
Holding register. It is only there so that a CPU can have a full
character time to send the next character to the xmitter. The xmitter
has timing to control the character shifting. When it is complete,
the next data is loaded into the TxData register. A TxRdy signal is
asserted at this time and the counter is incremented so the next
character is presented.
Having a poor memory for detail, I always have to use templates or
look at existing code in order to write HDL. So I'll use pseudo code
here, meaning don't trust my details...
constant TstData : string(0 to 15) :=3D "Testing 1, 2, 3!";
signal TxCntr : integer range 0 to 15;
TxNxtData <=3D TstData (TxCntr);
-- Data source control, provide string data to the UART, repeat every
16 chars
process SelectCntr ( clk, reset ) is
begin
if (reset =3D '1') then
TxCntr <=3D 0;
elsif ( rising_edge (clk) ) then
if ( TxRdy =3D '0' ) then
TxWrite <=3D '0';
else
if ( TxWrite =3D '0' ) then
TxWrite <=3D '1';
if ( TxCntr =3D 15 ) then
TxCntr <=3D 0;
else
TxCntr <=3D TxCntr + 1;
end if;
end if;
end if;
end if;
end process;
-- This code should be replaced with your UART code
process UART_Tx ( clk, reset ) is
begin
if (reset =3D '1') then
TxCntr <=3D 0;
elsif ( rising_edge (clk) ) then
if ( TxBitCnt =3D 9 ) then
if ( TxWrite =3D '1' ) then
TxData <=3D '0' & TxNxtData;
TxRdy <=3D '0';
TxBitCnt <=3D 0;
elsif ( TxBitTiming =3D '1' ) then
TxRdy <=3D '1';
end if;
elsif ( TxBitTiming =3D '1' ) then
TxData <=3D TxData ( TxData'high - 1 downto 0 ) & '1';
TxBitCnt <=3D TxBitCnt + 1;
end if;
end if;
end process;
Does this make sense? Do you see how this is different from writing C
code?
Rick
> --- On Mon, 1/26/09, Rick Collins <gnuarm.2006@arius.com> wrote:
>
>
> From: Rick Collins <gnuarm.2006@arius.com>
> Subject: Re: RS232 Uart is working!! now to get it cleaned up.
> To: jon@jonathanleslie.com
> Date: Monday, January 26, 2009, 2:16 PM
>
>
> At 01:34 PM 1/26/2009, you wrote:
> > Ok finally,
> >
> > I've got a working UART. I initially had it monitor the receive line
> > and echo back out the character that it received.
> >
> > I then changed it so that just sent the the letter 'U' by stuffing the
> > hex code in the TX_DATA_IN buffer:
> >
> > TX_DATA_IN( 7 DOWNTO 0 ) <=3D x"55";
> >
> > so
> >
> > 1) instead of manually converting 'U' to x'55', how do I use a
> > string literal to do the job.
> > for instance in C, I would simply write:
> >
> > tx_data_in =3D 'U';
> >
> > which is the same as the c code:
> >
> > tx_data_in =3D 0x55;
> >
> > my point is, I want to be able to use the ascii character instead of
> > the hexidecimal code.
>
> What is wrong with the way you have it written above? Although the
> above is a character literal and not a string. A string would be
> "abcd". To send that you would need a loop that sends each character
> in turn. You can either put a check for TxRdy explicity in the loop
> code or you can make a function that waits for TxRdy and sends one
> character. Then call this function in the loop.
>
> Opps, I guess I was thinking of C code. You can do something
> similiar in VHDL using an index to address the string.
>
> > 2) I want a scheduler so that I can put out whole messages. I want to
> > be able to write on the uart, "I got it\n"
> >
> > I can see a language element in VHDL called string:
> >
> > constant char_sequence : string :=3D "I got it";
> >
> > but I'm not sure if that is the right way to do it. in addition, I
> > don't now how to send the characters of char_sequence out
> > sequentially.
> >
> > here is my transmit process:
> >
> > -----------------------------------------------------------------------=
--------------------------
> > -- LATCHING NEW TRANSMIT DATA FROM RECEIVE UART ( TX_DATA_IN
> > [ 7-0 ] )
> > -----------------------------------------------------------------------=
--------------------------
> > P7: PROCESS ( CLK_16_6MHZ, UART_RESET_BUFFER, RX_READ_BUFFER_STB,
> > RX_DATA_OUT( 7 DOWNTO 0 ) )
> > BEGIN
> > IF ( CLK_16_6MHZ =3D '1' AND CLK_16_6MHZ'EVENT ) THEN
> > IF ( UART_RESET_BUFFER =3D '0' ) THEN
> > IF ( RX_READ_BUFFER_STB =3D '1' ) THEN
> > TX_DATA_IN( 7 DOWNTO 0 ) <=3D x"55";
> > END IF;
> > END IF;
> > END IF;
> > END PROCESS P7;
> >
> > now the x"55"; is gonna have to change, but I imagine that this
> > process will need
> > to be an entity in another process that is aware of the characters "I g=
ot
> > it" and schedule the
> > 8 characters (I, ,g,o,t, ,i,t) to go out.
>
> 1) Instead of using a test for the clock being 1 and an event, you
> should use rising_edge(clock). This is a standard form and will make
> the simulation match the synthesis better.
>
> 2) The above should be a single process and not combined with
> anything else. It will check for the trigger just as you have it
> written. When found, it will use the character currently pointed to
> by the index and increment the index. Remember that HDL describes
> hardware and this is a description of the transmit holding register
> and the logic controlling its timing. BTW, is this a holding
> register or the transmitter data register (the one that shifts the
> data out)? If the latter, you need to describe both the loading and
> the shifting in one process.
>
> Rick