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

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%)]

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.

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.

http://www.uploadarchief.net/files/download/xilinx%20rs232%20fout.jpg

[Bericht gewijzigd door Stefanh001 op (24%)]

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.