Hallo mensen,
Ik heb rechtstreeks van de site van Digilent een UART, beschreven in VHDL, gehaalt.
Nu zit ik met een probleempje, ik snap geen drol van het ding. Een byte naar de uart sturen is niet zo lastig. Gewoon doen, dan gooit ie de waarde vanzelf uit DBOUT.
Maar het verzenden, ik heb wat met een testbench lopen rommelen, maar ik krijg niet uitgevogeld hoe ik een byte moet zenden.
Hieronder de code:
------------------------------------------------------------------------
-- uartcomponent.vhd
------------------------------------------------------------------------
-- Author: Dan Pederson
-- Copyright 2004 Digilent, Inc.
------------------------------------------------------------------------
-- Description: This file defines a UART which tranfers data from
-- serial form to parallel form and vice versa.
------------------------------------------------------------------------
-- Revision History:
-- 07/15/04 (Created) DanP
------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following lines to use the declarations that are
-- provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;
entity UARTcomponent is
Port ( TXD : out std_logic := '1';
RXD : in std_logic;
CLK : in std_logic; --Master Clock
DBIN : in std_logic_vector (7 downto 0); --Data Bus in
DBOUT : out std_logic_vector (7 downto 0); --Data Bus out
RDA : inout std_logic; --Read Data Available
TBE : inout std_logic := '1'; --Transfer Bus Empty
RD : in std_logic; --Read Strobe
WR : in std_logic; --Write Strobe
PE : out std_logic; --Parity Error Flag
FE : out std_logic; --Frame Error Flag
OE : out std_logic; --Overwrite Error Flag
RST : in std_logic := '0'); --Master Reset
end UARTcomponent;
architecture Behavioral of UARTcomponent is
------------------------------------------------------------------------
-- Component Declarations
------------------------------------------------------------------------
------------------------------------------------------------------------
-- Local Type Declarations
------------------------------------------------------------------------
--Receive state machine
type rstate is (
strIdle, --Idle state
strEightDelay, --Delays for 8 clock cycles
strGetData, --Shifts in the 8 data bits, and checks parity
strCheckStop --Sets framing error flag if Stop bit is wrong
);
type tstate is (
sttIdle, --Idle state
sttTransfer, --Move data into shift register
sttShift --Shift out data
);
type TBEstate is (
stbeIdle,
stbeSetTBE,
stbeWaitLoad,
stbeWaitWrite
);
------------------------------------------------------------------------
-- Signal Declarations
------------------------------------------------------------------------
constant baudDivide : std_logic_vector(7 downto 0) := "10100011"; --Baud Rate dividor, set now for a rate of 9600.
--Found by dividing 50MHz by 9600 and 16.
signal rdReg : std_logic_vector(7 downto 0) := "00000000"; --Receive holding register
signal rdSReg : std_logic_vector(9 downto 0) := "1111111111"; --Receive shift rigister
signal tfReg : std_logic_vector(7 downto 0); --Transfer holding register
signal tfSReg : std_logic_vector(10 downto 0) := "11111111111"; --Transfer shift register
signal clkDiv : std_logic_vector(8 downto 0) := "000000000"; --used for rClk
signal rClkDiv : std_logic_vector(3 downto 0) := "0000"; --used for tClk
signal ctr : std_logic_vector(3 downto 0) := "0000"; --used for delay times
signal tfCtr : std_logic_vector(3 downto 0) := "0000"; --used to delay in transfer
signal rClk : std_logic := '0'; --Receiving Clock
signal tClk : std_logic; --Transfering Clock
signal dataCtr : std_logic_vector(3 downto 0) := "0000"; --Counts the number of read data bits
signal parError: std_logic; --Parity error bit
signal frameError: std_logic; --Frame error bit
signal CE : std_logic; --Clock enable for the latch
signal ctRst : std_logic := '0';
signal load : std_logic := '0';
signal shift : std_logic := '0';
signal par : std_logic;
signal tClkRST : std_logic := '0';
signal rShift : std_logic := '0';
signal dataRST : std_logic := '0';
signal dataIncr: std_logic := '0';
signal strCur : rstate := strIdle; --Current state in the Receive state machine
signal strNext : rstate; --Next state in the Receive state machine
signal sttCur : tstate := sttIdle; --Current state in the Transfer state machine
signal sttNext : tstate; --Next state in the Transfer state machine
signal stbeCur : TBEstate := stbeIdle;
signal stbeNext: TBEstate;
------------------------------------------------------------------------
-- Module Implementation
------------------------------------------------------------------------
begin
frameError <= not rdSReg(9);
parError <= not ( rdSReg(8) xor (((rdSReg(0) xor rdSReg(1)) xor (rdSReg(2) xor rdSReg(3))) xor ((rdSReg(4) xor rdSReg(5)) xor (rdSReg(6) xor rdSReg(7)))) );
DBOUT <= rdReg;
tfReg <= DBIN;
par <= not ( ((tfReg(0) xor tfReg(1)) xor (tfReg(2) xor tfReg(3))) xor ((tfReg(4) xor tfReg(5)) xor (tfReg(6) xor tfReg(7))) );
--Clock Dividing Functions--
process (CLK, clkDiv) --set up clock divide for rClk
begin
if (Clk = '1' and Clk'event) then
if (clkDiv = baudDivide) then
clkDiv <= "000000000";
else
clkDiv <= clkDiv +1;
end if;
end if;
end process;
process (clkDiv, rClk, CLK) --Define rClk
begin
if CLK = '1' and CLK'Event then
if clkDiv = "10100011" then
rClk <= not rClk;
else
rClk <= rClk;
end if;
end if;
end process;
process (rClk) --set up clock divide for tClk
begin
if (rClk = '1' and rClk'event) then
rClkDiv <= rClkDiv +1;
end if;
end process;
tClk <= rClkDiv(3); --define tClk
process (rClk, ctRst) --set up a counter based on rClk
begin
if rClk = '1' and rClk'Event then
if ctRst = '1' then
ctr <= "0000";
else
ctr <= ctr +1;
end if;
end if;
end process;
process (tClk, tClkRST) --set up a counter based on tClk
begin
if (tClk = '1' and tClk'event) then
if tClkRST = '1' then
tfCtr <= "0000";
else
tfCtr <= tfCtr +1;
end if;
end if;
end process;
--This process controls the error flags--
process (rClk, RST, RD, CE)
begin
if RD = '1' or RST = '1' then
FE <= '0';
OE <= '0';
RDA <= '0';
PE <= '0';
elsif rClk = '1' and rClk'event then
if CE = '1' then
FE <= frameError;
OE <= RDA;
RDA <= '1';
PE <= parError;
rdReg(7 downto 0) <= rdSReg (7 downto 0);
end if;
end if;
end process;
--This process controls the receiving shift register--
process (rClk, rShift)
begin
if rClk = '1' and rClk'Event then
if rShift = '1' then
rdSReg <= (RXD & rdSReg(9 downto 1));
end if;
end if;
end process;
--This process controls the dataCtr to keep track of shifted values--
process (rClk, dataRST)
begin
if (rClk = '1' and rClk'event) then
if dataRST = '1' then
dataCtr <= "0000";
elsif dataIncr = '1' then
dataCtr <= dataCtr +1;
end if;
end if;
end process;
--Receiving State Machine--
process (rClk, RST)
begin
if rClk = '1' and rClk'Event then
if RST = '1' then
strCur <= strIdle;
else
strCur <= strNext;
end if;
end if;
end process;
-- This process generates the sequence of steps needed receive the data
process (strCur, ctr, RXD, dataCtr, rdSReg, rdReg, RDA)
begin
case strCur is
when strIdle =>
dataIncr <= '0';
rShift <= '0';
dataRst <= '0';
CE <= '0';
if RXD = '0' then
ctRst <= '1';
strNext <= strEightDelay;
else
ctRst <= '0';
strNext <= strIdle;
end if;
when strEightDelay =>
dataIncr <= '0';
rShift <= '0';
CE <= '0';
if ctr(2 downto 0) = "111" then
ctRst <= '1';
dataRST <= '1';
strNext <= strGetData;
else
ctRst <= '0';
dataRST <= '0';
strNext <= strEightDelay;
end if;
when strGetData =>
CE <= '0';
dataRst <= '0';
if ctr(3 downto 0) = "1111" then
ctRst <= '1';
dataIncr <= '1';
rShift <= '1';
else
ctRst <= '0';
dataIncr <= '0';
rShift <= '0';
end if;
if dataCtr = "1010" then
strNext <= strCheckStop;
else
strNext <= strGetData;
end if;
when strCheckStop =>
dataIncr <= '0';
rShift <= '0';
dataRst <= '0';
ctRst <= '0';
CE <= '1';
strNext <= strIdle;
end case;
end process;
--TBE State Machine--
process (CLK, RST)
begin
if CLK = '1' and CLK'Event then
if RST = '1' then
stbeCur <= stbeIdle;
else
stbeCur <= stbeNext;
end if;
end if;
end process;
--This process gererates the sequence of events needed to control the TBE flag--
process (stbeCur, CLK, WR, DBIN, load)
begin
case stbeCur is
when stbeIdle =>
TBE <= '1';
if WR = '1' then
stbeNext <= stbeSetTBE;
else
stbeNext <= stbeIdle;
end if;
when stbeSetTBE =>
TBE <= '0';
if load = '1' then
stbeNext <= stbeWaitLoad;
else
stbeNext <= stbeSetTBE;
end if;
when stbeWaitLoad =>
if load = '0' then
TBE <= '1';
stbeNext <= stbeWaitWrite;
else
TBE <= '0';
stbeNext <= stbeWaitLoad;
end if;
when stbeWaitWrite =>
TBE <= '1';
if WR = '0' then
stbeNext <= stbeIdle;
else
stbeNext <= stbeWaitWrite;
end if;
end case;
end process;
--This process loads and shifts out the transfer shift register--
process (load, shift, tClk, tfSReg)
begin
TXD <= tfsReg(0);
if tClk = '1' and tClk'Event then
if load = '1' then
tfSReg (10 downto 0) <= ('1' & par & tfReg(7 downto 0) &'0');
end if;
if shift = '1' then
tfSReg (10 downto 0) <= ('1' & tfSReg(10 downto 1));
end if;
end if;
end process;
-- Transfer State Machine--
process (tClk, RST)
begin
if (tClk = '1' and tClk'Event) then
if RST = '1' then
sttCur <= sttIdle;
else
sttCur <= sttNext;
end if;
end if;
end process;
-- This process generates the sequence of steps needed transfer the data--
process (sttCur, tfCtr, tfReg, TBE, tclk)
begin
case sttCur is
when sttIdle =>
tClkRST <= '0';
shift <= '0';
load <= '0';
if TBE = '1' then
sttNext <= sttIdle;
else
sttNext <= sttTransfer;
end if;
when sttTransfer =>
shift <= '0';
load <= '1';
tClkRST <= '1';
sttNext <= sttShift;
when sttShift =>
shift <= '1';
load <= '0';
tClkRST <= '0';
if tfCtr = "1100" then
sttNext <= sttIdle;
else
sttNext <= sttShift;
end if;
end case;
end process;
end Behavioral;Kan iemand misschien hieruit halen hoe ik een byte terug naar de pc kan zenden?? Ik denk dat ik maar eens een boek over VHDL programmeren ga kopen.! Dan hoef ik niet zoveel meer over die zeik het VHDL gebeuren te vragen.!
Mvg Stefan
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Je zult moeten uitvogelen wat de user interface van UARTcomponent is. Ik kan wel wat gokken, maar je moet dan al snel in de code duiken om het echt goed te snappen.
Echter, bij IP hoort altijd een beschrijving. Zat dat niet bij het pakket wat je ge-download hebt? Een readme file of zo, of een echte spec?
Je had toch wel begrepen dat DBIN en DBOUT de in- en uitgangen voor data is? Nu de control nog.
PS, welke zeik bedoel je?
DBIN en DBOUT snap ik nog wel. Alleen ik kan dus echt niet echt volgen wat er in de code gebeurt. Ik snap dus niet waar die Write Strobe (WR) en Read Strobe (RD) voor dienen. Je kunt ze beide hoog en laag maken, maar er gebeurt geen flikker in de simulatie.
Als ik die UART implementeer, en ik geef mijn Spartan kit een byte te vreten, dan komt die waarde netjes op de ledjes. WR of RD zijn niet bediend.
ik heb de file hiervandaan
Hier kon ik de losse VHDL file downloaden. Voor de rest heb ik nergens info gevonden erover. Ze gaan er denk ik vanuit dat mensen met meer ervaring die dingen downloaden/kopen.
Van de andere kant kun je ervaring hebben, maar zonder timing diagram ben je nog nergens. Ik hoef alleen een timing diagram erbij, dat wilde ik uitvogelen met de testbench. Door middel van Trial and Error, maar er gebeurt niks op de uitgangen.
[Bericht gewijzigd door Stefanh001 op (15%)]
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Ik zou een beetje voorzichtiger zijn met je taalgebruik. Komt nogal horkerig over zo.
Die WR wordt wel degelijk gebruikt. Zie regel 320. Het lijkt me dat je WR tegelijk met DBIN actief moet maken, al vindt ik nog niet zo snel terug waar DBIN nou heen gaat.
Dat je op DBOUT al data zie zonder een RD kan best kloppen. Ontvangen data komt blijkbaar gelijk beschikbaar, echter het volgende byte komt pas als je het huidige gelezen hebt, door RD dus.
Ach, en anders schrijf je toch even een eigen UART. Weet je gelijk hoe die werkt.
RD heb ik nooit bedient, ik heb gewoon via een snel in elkaar geknutseld C# programmatje een aantal bytes verstuurt. In een Textbox geef ik de decimale waarde, dan op SEND duwen, en daarna gooit ie de byte naar de spartan. Komt allemaal direct beschikbaar.
Eigen UART bouwen, makkelijker gezegd als gedaan. Zenden is het probleem niet echt, maar het ontvangen in VHDL. Zou je me ermee kunnen helpen dan.?
Ik heb wel eens een poging gewaagd, maar het probleem waar ik op blijf steken is hoe ik het startbit opvang, of de baudrate in VHDL goed kan instellen.
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Stefan,
De RD en WR signalen zijn waarschijnlijk strobes. Dus die moet je hoog en weer laag maken willen ze doen waar ze voor bedoeld zijn.
Dus je zet je data op "DBIN" en doet "WR" hoog en weer laag en dan zou ie moeten gaan zenden.... Dat is wat ik verwacht zonder de handleiding en zonder de code te hebben gelezen.
Hmm, rare UART heb ik dan. TxD blijft in de simulatie (testbench) toch statisch '1'.
Ik zal er zo even een screenshot van maken.

[Bericht gewijzigd door Stefanh001 op (24%)]
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Als je begint te zoeken naar het process waar txd assigned wordt, dan zie je dat het load signaal hier iets doet. Als je dan verder terug zoekt, dan zie je wanneer load actief wordt. Dan zie je ook wat je moet doen om load actief te krijgen, en daarna txd te activeren.
Als het niet gebeurt zoals je het verwacht, dan zet je de betrokken signalen erbij in je waveform. Of liever nog, zet alles er maar bij, dan zie je vanzelf waar het misgaat. WR is wel degelijk essentieel volgens mij.