Jump to content
Sign in to follow this  
Lessberg

Реализация Uart На Плис

Recommended Posts

Добрый день!

Извиняюсь, начну сразу с вопроса: Как можно код в спойлер убрать ?

Мне была поставлена задача реализовать UART приемопередатчик через com port RS-232 для обмена данными между ПЛИС и ПК.

ПЛИС -> Altera DE2 Board Cyclone II EP2C 35F 672C6 (Вложен файл для визуального понимания работы проекта)

ПК -----> Com Port Toolkit 4.0

Проект делаю в стандартной программе Алтеры: Quartus II v 12.1

post-167913-0-43936200-1359640199_thumb.jpg

Необходимо передать число от 0 до FF из ПК на ПЛИС и так же задав входные данных на ПЛИС передать на ПК.

Я взял готовый проект:

----------------------------------------------------
-- UART RS232
-- Ver. 1.0 - 10.07.2003
---------------------------------------------------
library ieee;
use IEEE.STD_LOGIC_1164.all;
USE IEEE.numeric_std.all;
entity UART is
generic (UART_Speed : integer := 115200 ; -- UART Speed
	 System_CLK : integer := 50000000 -- System CLK in Hz
 );
port (
 CLK	 : in std_logic;	 -- system clk
 RST_N : in std_logic;	 -- system reset#
 DATA_IN : in std_logic_vector(7 downto 0); -- Transmit data
 DATA_OUT : out std_logic_vector(7 downto 0); --Recieved data
 RX_VALID : out std_logic; -- RX buffer data ready
 TX_VALID : in std_logic;		 -- Data for TX avaible
 RXD	 : in std_logic;		 -- RX pin
 TXD	 : out std_logic ;	 -- TX pin
 TX_BUSY : out std_logic; -- TX pin
 RX_BUSY : out std_logic
);
end UART;
---------------------------------------------------
-- Architecture for UART
---------------------------------------------------
architecture rtl of UART is
signal TxBuf : Std_Logic_Vector(7 downto 0); -- transmit buffer
signal RxBuf : Std_Logic_Vector(7 downto 0); -- recieve buffer
signal prevRXD : Std_Logic;		 -- RXD buffer register
signal RxReady : Std_Logic;
signal TXRead : Std_Logic;
signal TxBitCnt : integer range 0 to 9;
signal TxReady : Std_Logic;
signal CntRX : integer range 0 to System_CLK/(UART_Speed);
signal CntTX : integer range 0 to System_CLK/(UART_Speed);
signal RxBitCnt: integer range 0 to 10;
begin
UART_Tx: process(CLK, RST_N)
begin
if RST_N='0' then
TXD <= '1';
TxBitCnt <= 0;
TxBuf <= (others => '0');
CntTX <= 0;
TxReady <= '1';
elsif (rising_edge(CLK)) then
if (TX_VALID = '1' and TxReady = '1') then
 TxBuf(7 downto 0) <= DATA_IN(7 downto 0);
 TxReady <= '0';
 TxBitCnt <= 0;
 CntTX <= 0;
end if;
if (TxReady = '0') then
 if CntTX=(System_CLK/(UART_Speed)) then
 CntTX <= 0;
 case TxBitCnt is
	 when 0 = >
	 TXD <= '0';	 -- start bit
	 TxBitCnt <= TxBitCnt+1;
	 when 1|2|3|4|5|6|7|8 =>
	 TXD	 <= TxBuf(0);
	 TxBuf <= '0' & TxBuf(7 downto 1);
	 TxBitCnt <= TxBitCnt+1;
	 when 9 =>
	 TXD	 <= '1'; -- stop bit
	 TxBuf <= (others => '0');
	 TxBitCnt <= 0;
	 TxReady <= '1';	
 end case;
 else
 CntTX <= CntTX+1;
 end if;
end if;
end if;
end process UART_Tx;
TX_BUSY <= not (TxReady);
UART_Rx: process(CLK, RST_N)
begin
if RST_N='0' then
RxBitCnt <=0;
RxBuf <= (others => '0');
RxReady <= '1';
prevRXD <= '1';
CntRX <= 0;
elsif (rising_edge(CLK)) then
if (RxReady = '1') then
 prevRXD <= RXD;
 if (RXD='0' and prevRXD='1') then -- Start bit,
 RxBitCnt <= 0;			 -- RX Bit counter
 RxReady <= '0'; -- Start receiving
 RxBuf <= (others => '0');
 CntRX <= 0;
 end if;
else
 if CntRX=(System_CLK/(UART_Speed*2)) then
 case RxBitCnt is
	 when 0 =>
	 if (RXD='1') then -- start bit failed
		 RxReady <= '1';
	 end if;
	 when 1|2|3|4|5|6|7|8 =>
	 RxBuf <= RXD & RxBuf(7 downto 1);
	 RxReady <= '0';
	 when 9 =>
	 RxReady <= '1';
	 when others => RxReady <= '0';
 end case;
 CntRX <= CntRX+1;
 RxBitCnt <= RxBitCnt+1;
 elsif (CntRX=(System_CLK/(UART_Speed))) then
 CntRX <= 0;
 else
 CntRX <= CntRX+1;
 end if;
end if;
end if;
end process UART_Rx;
DATA_OUT(7 downto 0) <= RxBuf(7 downto 0) when RxReady='1'
	 else (others => '0');
RX_VALID <= RxReady;
RX_BUSY <= not (RxReady);
end rtl;

Доработав его под свои нужды получил следующие:

1. Вывод принятых данных с ПК на 2 семисегментных индикатора в формате от 00 до FF

2. Так же вывод дублируется на 8 светодиодов, дабы видеть соответствие двоичному коду. (более для удобства в отладке программы чем необходимость)

3. Данные для передачи с ПЛИС на ПК задаю 8 тумблерами. Данные для передачи так же выводятся на семисегментные индикаторы (HEX0 HEX1). По нажатию кнопки КЕЙ 0 данные передаются на ПК.

Вот мой код:

-- UART RS232
-- Ver. 1.0 - 10.07.2003
---------------------------------------------------
library ieee;
use IEEE.STD_LOGIC_1164.all;
USE IEEE.numeric_std.all;
entity uart is
generic (UART_Speed : integer := 9600 ; -- скорость UART
	 System_CLK : integer := 50000000 -- частота в герцах (Гц)
 );
port (
--============================ ВХОД ==============================
CLK	 : in std_logic;		 -- частота
RST	 : in std_logic;		 -- сброс
DATA_IN : in std_logic_vector (7 downto 0); -- Ввод данных в виде двоичного кода через тумблеры SW[0...7]
TX_VALID : in std_logic;		 -- Data for TX avaible / Данные для передачи доступны
UART_RXD : in std_logic;		 -- RX линия приема
--============================ ВЫХОД =============================
HEX4 : out std_logic_vector(7 downto 0); -- Вывод переданных данных с ПК на семисегментный индикатор
HEX5 : out std_logic_vector(7 downto 0); -- Вывод переданных данных с ПК на семисегментный индикатор
LEDG	 : out std_logic_vector(7 downto 0); -- Вывод данных в виде двоичного кода на светодиоды
RX_VALID : out std_logic;		 -- RX buffer data ready / Буферизация данных приема готова
UART_TXD : out std_logic;		 -- TX линия передачи
 TX_BUSY : out std_logic;		 -- Флаг - линия передачи занята
RX_BUSY : out std_logic;	 -- Флаг - линия приема занята
HEX0 : out std_logic_vector(7 downto 0); -- Вывод передаваемых данных с ПЛИС на семисегментный индикатор
HEX1 : out std_logic_vector(7 downto 0); -- Вывод передаваемых данных с ПЛИС на семисегментный индикатор
--== Выключение незадействованных семисегментных индикаторов =====
HEX2 : out std_logic_vector(6 downto 0);
HEX3 : out std_logic_vector(6 downto 0);
HEX6 : out std_logic_vector(6 downto 0);
HEX7 : out std_logic_vector(6 downto 0)
);
end uart;
--========= Архитектура для UART ===========
architecture rtl of UART is

signal DATA_OUT : std_logic_vector(7 downto 0); --Вспомогательный сигнал вывода данных
signal TxBuf : Std_Logic_Vector(7 downto 0); -- буфер передатчик
signal RxBuf : Std_Logic_Vector(7 downto 0); -- буфер приеманика
signal prevRXD : Std_Logic;		 -- RXD buffer register / Буферный регистрт линии приема
signal RxReady : Std_Logic;
signal TXRead : Std_Logic;
signal TxBitCnt : integer range 0 to 9;
signal TxReady : Std_Logic;
signal CntRX : integer range 0 to System_CLK/(UART_Speed); -- счет принятых битов
signal CntTX : integer range 0 to System_CLK/(UART_Speed); -- счет отправленных битов
signal RxBitCnt : integer range 0 to 10;
begin
HEX2 <= "1111111";
HEX3 <= "1111111";
HEX6 <= "1111111";
HEX7 <= "1111111";
-- Вывод передаваемых данных с ПЛИС на семисегментные индикаторы
UART_HEX:process(DATA_IN)
begin
case DATA_IN (3 downto 0) is
when "0000" => HEX0 <= "11000000"; --"0"
when "0001" => HEX0 <= "11111001"; --"1"
when "0010" => HEX0 <= "10100100"; --"2"
when "0011" => HEX0 <= "10110000"; --"3"
when "0100" => HEX0 <= "10011001"; --"4"
when "0101" => HEX0 <= "10010010"; --"5"
when "0110" => HEX0 <= "10000010"; --"6"
when "0111" => HEX0 <= "11111000"; --"7"
when "1000" => HEX0 <= "10000000"; --"8"
when "1001" => HEX0 <= "10010000"; --"9"
when "1010" => HEX0 <= "10001000"; --"A"
when "1011" => HEX0 <= "10000011"; --"b"
when "1100" => HEX0 <= "11000110"; --"C"
when "1101" => HEX0 <= "10100001"; --"d"
when "1110" => HEX0 <= "10000110"; --"E"
when "1111" => HEX0 <= "10001110"; --"F"
when others => HEX0 <= "11111111";
end case;
case DATA_IN (7 downto 4) is
when "0000" => HEX1 <= "11000000"; --"0"
when "0001" => HEX1 <= "11111001"; --"1"
when "0010" => HEX1 <= "10100100"; --"2"
when "0011" => HEX1 <= "10110000"; --"3"
when "0100" => HEX1 <= "10011001"; --"4"
when "0101" => HEX1 <= "10010010"; --"5"
when "0110" => HEX1 <= "10000010"; --"6"
when "0111" => HEX1 <= "11111000"; --"7"
when "1000" => HEX1 <= "10000000"; --"8"
when "1001" => HEX1 <= "10010000"; --"9"
when "1010" => HEX1 <= "10001000"; --"A"
when "1011" => HEX1 <= "10000011"; --"b"
when "1100" => HEX1 <= "11000110"; --"C"
when "1101" => HEX1 <= "10100001"; --"d"
when "1110" => HEX1 <= "10000110"; --"E"
when "1111" => HEX1 <= "10001110"; --"F"
when others => HEX1 <= "11111111";
end case;
end process;
--========= Передатчик =========
UART_Tx: process(CLK, RST)
begin
if RST='0' then
UART_TXD <= '1';
TxBitCnt <= 0;
TxBuf <= (others => '0');
CntTX <= 0;
TxReady <= '1';
elsif (rising_edge(CLK)) then
if (TX_VALID = '0' and TxReady = '1') then
 TxBuf(7 downto 0) <= DATA_IN (7 downto 0);
 TxReady <= '0';
 TxBitCnt <= 0;
 CntTX <= 0;
end if;
if (TxReady = '0') then
 if CntTX=(System_CLK/(UART_Speed)) then
 CntTX <= 0;
 case TxBitCnt is
	 when 0 =>
	 UART_TXD <= '0';	 -- старт бит
	 TxBitCnt <= TxBitCnt+1;
	 when 1|2|3|4|5|6|7|8 =>
	 UART_TXD	 <= TxBuf(0);
	 TxBuf <= '0' & TxBuf(7 downto 1);
	 TxBitCnt <= TxBitCnt+1;
	 when 9 =>
	 UART_TXD	 <= '1'; -- стоп бит
	 TxBuf <= (others => '0');
	 TxBitCnt <= 0;
	 TxReady <= '1';	
 end case;
 else
 CntTX <= CntTX+1;
 end if;
end if;
end if;
end process UART_Tx;
TX_BUSY <= not (TxReady);
--=========== Приемник =============
UART_Rx: process(CLK, RST)
begin
if RST='0' then
HEX4 <= "11111111";
HEX5 <= "11111111";
RxBitCnt <=0;
RxBuf <= (others => '0');
RxReady <= '1';
prevRXD <= '1';
CntRX <= 0;
elsif (rising_edge(CLK)) then
if (RxReady = '1') then -- Если на момент фронта сигнала CLK RxReady = 1 тогда
 prevRXD <= UART_RXD; -- после прохождения фронта CLK prevRXD будет равно RXD
 if (UART_RXD='0' and prevRXD='1') then -- Старт бит /если на момент фронта CLK RXD='0' и prevRXD='1' мы словили старт бит
 RxBitCnt <= 0;				 -- Счетчик битов приема
 RxReady <= '0';		 -- Начало приема
 RxBuf <= (others => '0');
 CntRX <= 0;
 end if;
else
 if CntRX=(System_CLK/(UART_Speed*2)) then
 case RxBitCnt is
	 when 0 =>
	 if (UART_RXD='1') then -- Условие необнаружения стартового бита
		 RxReady <= '1';
	 end if;
	 when 1|2|3|4|5|6|7|8 =>
	 RxBuf <= UART_RXD & RxBuf(7 downto 1);
	 RxReady <= '0';
	 when 9 =>
	 RxReady <= '1';
	 when others => RxReady <= '0';
 end case;

 case RxBuf (3 downto 0) is
when "0000" => HEX4 <= "11000000"; --"0"
when "0001" => HEX4 <= "11111001"; --"1"
when "0010" => HEX4 <= "10100100"; --"2"
when "0011" => HEX4 <= "10110000"; --"3"
when "0100" => HEX4 <= "10011001"; --"4"
when "0101" => HEX4 <= "10010010"; --"5"
when "0110" => HEX4 <= "10000010"; --"6"
when "0111" => HEX4 <= "11111000"; --"7"
when "1000" => HEX4 <= "10000000"; --"8"
when "1001" => HEX4 <= "10010000"; --"9"
when "1010" => HEX4 <= "10001000"; --"A"
when "1011" => HEX4 <= "10000011"; --"b"
when "1100" => HEX4 <= "11000110"; --"C"
when "1101" => HEX4 <= "10100001"; --"d"
when "1110" => HEX4 <= "10000110"; --"E"
when "1111" => HEX4 <= "10001110"; --"F"
when others => HEX4 <= "11111111";
end case;

case RxBuf (7 downto 4) is
when "0000" => HEX5 <= "11000000"; --"0"
when "0001" => HEX5 <= "11111001"; --"1"
when "0010" => HEX5 <= "10100100"; --"2"
when "0011" => HEX5 <= "10110000"; --"3"
when "0100" => HEX5 <= "10011001"; --"4"
when "0101" => HEX5 <= "10010010"; --"5"
when "0110" => HEX5 <= "10000010"; --"6"
when "0111" => HEX5 <= "11111000"; --"7"
when "1000" => HEX5 <= "10000000"; --"8"
when "1001" => HEX5 <= "10010000"; --"9"
when "1010" => HEX5 <= "10001000"; --"A"
when "1011" => HEX5 <= "10000011"; --"b"
when "1100" => HEX5 <= "11000110"; --"C"
when "1101" => HEX5 <= "10100001"; --"d"
when "1110" => HEX5 <= "10000110"; --"E"
when "1111" => HEX5 <= "10001110"; --"F"
when others => HEX5 <= "11111111";
end case;

 CntRX <= CntRX+1;
 RxBitCnt <= RxBitCnt+1;
 elsif (CntRX=(System_CLK/(UART_Speed))) then
 CntRX <= 0;
 else
 CntRX <= CntRX+1;
 end if;
end if;
end if;
end process UART_Rx;
DATA_OUT(7 downto 0) <= RxBuf(7 downto 0) when RxReady='1'
	 else (others => '0');
LEDG <= DATA_OUT;

RX_VALID <= RxReady;
RX_BUSY <= not (RxReady);
end rtl;

Что хотелось бы еще реализовать, но не получается в связи с недолгим изучением VHDL.

1. Самая важная ошибка, точнее недороботка заключается в том что с ПЛИС на ПК передается не 1 БАЙТ (8 бит) а целая пачка. Зависит конечно от времени нажатия на кнопку КЕЙ0 (передать данные). Стандартная скорость в проекте была 115200. Я пробовал уменьшить и минимальная скорость при которой проект работает верно это 300-600 БОД.

К примеру при скорости 115200 передается примерно 100 Байт информации. При 300 БОД 9-10 байт. Если уж сильно постарать быстро нажать и отпустить кнопку передачи у меня выходило 4 байта )))

Пробовал ставить задержку из ряда Триггеров.. не особо помогло.

Бьюсь уже не первый день не могу додуматься как в код внести условие чтобы передавал 8 Бит то есть 1 раз ,, данные которые введены на ПЛИС (тумблерами)по нажатию кнопки передачи.

​2. Вторая проблема она не так существенна, но хотелось бы что в проекте присутствовал бит четности.

Логика работы его понятна, сложить все 8 бито по модулю 2 (xor). Далее сумму 8 бит сложить по модулю 2 с битом четности (пусть будет 1 (проверка на четность)) и уже результат их добавить как 9-ый бит к фрейму. Или как 0 - ой ?

ЗЫ. Постарался разжевать смысл проекта. Надеюсь на Вашу помощь и буду рад любым замечаниям и комментариям.

post-167913-0-43936200-1359640199_thumb.jpg

Edited by Lessberg

Share this post


Link to post
Share on other sites

По п.1. Сделайте счетчик с периодом переполнения 0,1 с. Далее по его переполнению заносите в сдвиговый регистр состояние кнопки. Реистр достаточно иметь на 3-4 разряда. Далее выделяете по своему усмотрению передний или задний фронт от нажатия и запускаете передачу. Делаю таким образом:

variable shift:std_logic_vector(2 downto 0);

variable flag:std_logic;

.........

begin

if(rising_edge(clk))then

shift(2 downto 1):=shift(1 downto 0);--Сдвиг состояния кнопки

shift(0):=key;

if(shift="001")then

flag:='1';--Разрешаем работу передатчика

end if;

end if;

По п.2 бит четности надо добавлять после передачи информационных битов, т.е. сначала старт-бит, затем Х0, Х1,...Х7, бит-четности, 1 или 2 стоп-бита.

Share this post


Link to post
Share on other sites

Конденсаторы Panasonic. Часть 4. Полимеры – номенклатура

В заключительной, четвертой статье из цикла «Конденсаторы Panasonic» рассматриваются основные достоинства и особенности использования конденсаторов этого японского производителя на основе полимерной технологии. Главной конструктивной особенностью таких конденсаторов является полимерный материал, используемый в качестве проводящего слоя. Полимер обеспечивает конденсаторам высокую электрическую проводимость и пониженное эквивалентное сопротивление (ESR). Номинальная емкость и ESR отличается в данном случае высокой стабильностью во всем рабочем диапазоне температур. А повышенная емкость при низком ESR идеальна для решения задач шумоподавления и ограничения токовых паразитных импульсов в широком частотном диапазоне.

Читать статью

В догонку, признак Флаг, необходимо обнулять по окончанию передачи (байта или строки, в зависимости от задачи). Так же можно принудительно его ставить в нуль по второму (незадействованному) фронту - для надежности

Edited by Meteor77

Share this post


Link to post
Share on other sites

пока чтото не получается....

Вот компонент передатчик. При компиляции выдает ошибки...

UART_Tx: process(CLK, RST)
variable shift:std_logic_vector(2 downto 0);
variable flag:std_logic;
begin
if RST='0' then
UART_TXD <= '1';
TxBitCnt <= 0;
TxBuf <= (others => '0');
CntTX <= 0;
TxReady <= '1';
elsif (rising_edge(CLK)) then
 shift(2 downto 1):=shift(1 downto 0);--Сдвиг состояния кнопки
shift(0):=TX_VALID;
elsif (shift="001")then
flag:='1';--Разрешаем работу передатчика
if (TX_VALID = '0' and TxReady = '1' and flag = '1') then
TxBuf(7 downto 0) <= DATA_IN (7 downto 0);
TxReady <= '0';
TxBitCnt <= 0;
CntTX <= 0;
end if;
if (TxReady = '0') then
 if CntTX=(System_CLK/(UART_Speed)) then
 CntTX <= 0;
 case TxBitCnt is
	 when 0 =>
	 UART_TXD <= '0';	 -- старт бит
	 TxBitCnt <= TxBitCnt+1;
	 when 1|2|3|4|5|6|7|8 =>
	 UART_TXD	 <= TxBuf(0);
	 TxBuf <= '0' & TxBuf(7 downto 1);
	 TxBitCnt <= TxBitCnt+1;
	 when 9 =>
	 UART_TXD	 <= '1'; -- стоп бит
	 TxBuf <= (others => '0');
	 TxBitCnt <= 0;
	 TxReady <= '1';	
flag := '0';
 end case;
 else
 CntTX <= CntTX+1;
 end if;
end if;
end if;
end process UART_Tx;

Лог ошибок

Error (10818): Can't infer register for "TxReady" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[0]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[1]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[2]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[3]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[4]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[5]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[6]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[7]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[8]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[9]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[10]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[11]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "CntTX[12]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "TxBuf[0]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "TxBuf[1]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "TxBuf[2]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "TxBuf[3]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (10818): Can't infer register for "TxBuf[4]" at uart.vhd(125) because it does not hold its value outside the clock edge

Error (12153): Can't elaborate top-level user hierarchy

Error: Quartus II 64-Bit Analysis & Synthesis was unsuccessful. 20 errors, 12 warnings

Error: Peak virtual memory: 490 megabytes

Error: Processing ended: Thu Jan 31 23:04:05 2013

Error: Elapsed time: 00:00:01

Error: Total CPU time (on all processors): 00:00:01

Error (293001): Quartus II Full Compilation was unsuccessful. 22 errors, 12 warnings

Займусь пока проверкой четности, тут мне хоть понятно как должно работать.

А вот с задержкой хоть и выложили пример готовый, но все равно тяжеловато понять :(

Edited by Lessberg

Share this post


Link to post
Share on other sites
                     

STM32G0 - средства противодействия угрозам безопасности

Результатом выполнения требований безопасности всегда является усложнение разрабатываемой системы. Особенно чувствительными эти расходы стали теперь, в процессе массового внедрения IoT. Обладая мощным набором инструментов информационной безопасности, микроконтроллеры STM32G0 производства STMicroelectronics, объединив в себе невысокую цену, энергоэффективность и расширенный арсенал встроенных аппаратных инструментов, способны обеспечить полную безопасность разрабатываемого устройства.

Подробнее...

Опять блок передатчика разбираю...

Выкинул пока мысль о задержках, Добавил бит четности "1". Все работает. Но вот в чем проблема:

Добавил сигнал выхода "error" сигнализировал об ошибке при передачи данных, если такова была, но светодиод всегда горит, тем самым говоря что данные всегда передаются с ошибкой.. хотя это не правда :(



UART_Tx: process(CLK)
begin
 if RST='0' then
   UART_TXD <= '1';
   TxBitCnt <= 0;
   TxBuf <= (others => '0');
   CntTX <= 0;
   TxReady <= '1';
 elsif (rising_edge(CLK)) then
   if (TX_VALID = '0' and TxReady = '1') then
     TxBuf(7 downto 0) <= DATA_IN (7 downto 0);
     TxReady <= '0';
     TxBitCnt <= 0;
     CntTX  <= 0;
   end if;

   if (TxReady = '0') then
     if CntTX=(System_CLK/(UART_Speed)) then
       CntTX <= 0;
       case TxBitCnt is
         when 0 =>
           UART_TXD  <=  '0';       -- старт бит
           TxBitCnt <= TxBitCnt+1;
         when 1|2|3|4|5|6|7|8 =>
           UART_TXD      <= TxBuf(0);
           TxBuf    <= '0' & TxBuf(7 downto 1);
           TxBitCnt <= TxBitCnt+1;
         when 9 =>                  -- бит четности "1"
            a <= TxBuf (7 downto 0);
            b <= a(0) xor a(1) xor a(2) xor a(3) xor a(4) xor a(5) xor a(6) xor a(7);
            c <= parity xor b; -- parity константа равная "1"
            if c = parity then
                TxBuf <= '1' & TxBuf (7 downto 1);
                TxBitCnt <= TxBitCnt+1;
            else 
                error <= '1';
                TxBitCnt <= TxBitCnt+1;
            end if;
         when 10 =>
           UART_TXD      <= '1';    -- стоп бит
           TxBuf    <= (others => '0');
           TxBitCnt <= 0;
           TxReady  <= '1';        
       end case;
     else
       CntTX <= CntTX+1;
     end if;
   end if;
 end if;
end process UART_Tx;

Edited by Lessberg

Share this post


Link to post
Share on other sites

хм.. ну прям чудеса творятся... Дорабатывал проверку на бит четности, и тут взял и стал передавать на ПК по 1 Байту ))).. сейчас еще проверю

Почему так, не понимаю. Но меня это больше чем устраивает )))

Вот часть кода, где описывал бит четности. При такой записи бит четности работает (правда без оповещения об ошибке) и данные на ПК по 1 Байту передаются.

Но все равно есть загвоздка... ЧТобы пердать следующий байт с другой информацией, требуется нажать кнопку сброса, и только потом кнопку передачи данных... Иначе не передаются данные. А т.к. сброс общий, то и пришедшие с ПК данные сбрасываются. Надо тоже доработать.

   when 9 =>				  -- бит четности "1"
   a <= TxBuf (7 downto 0);
   b <= a(0) xor a(1) xor a(2) xor a(3) xor a(4) xor a(5) xor a(6) xor a(7);
   c <= parity xor b; -- parity константа равная "1"
   if c = parity then
 TxBuf <= TxBuf (6 downto 0) & '1';
   end if;

Edited by Lessberg

Share this post


Link to post
Share on other sites

Ох..

Стараюсь делать так:

Процесс передатчика

Процесс приемника

Процесс формирователя синхросигналов (в том числе таймеров для антидребезга)

Все пересылки - через сигналы

Ну например для частоты 50 МГц

Architecture /////////
signal ovf_s:std_logic;
begin
timeout:process(clk)
variable cnt:unsigned(22 downto 0);
variable ovf:std_logic:='0';
constant zero:unsigned(22 downto 0):="00000000000000000000000";
constant step:unsigned(22 downto 0):="00000000000000000000001";
constant max:unsigned(22 downto 0):="10011000100101001000000";
begin
if(rising_edge(clk))then
cnt:=cnt+step;
if(cnt=max-3)then
 ovf:='1';
elsif(cnt=max)then
 ovf:='0';
 cnt:=zero;
end if;
ovf_s<=ovf;
end if;
end process;

key:process(ovf_s)
variable shift:std_logic_vector(2 downto 0);
begin
if(rising_edge(ovf_s))then
 shift(2 downto 0):=shift(1 downto 0);
 shift(0):=key;
 if(shift="001")then
 flag:='1';
 end if;
 flag_s<=flag;
end if;
end process;

UART:process(clk)
if(rising_edge(clk))then
begin
if(flag_s)then
тут надо поместить описание передачи
 end if;
end if;
end process;

Edited by Meteor77

Share this post


Link to post
Share on other sites

не помогает :( Точно так же пачкой передает

signal ovf_s:std_logic;
signal flag_s:std_logic;
.........
timeout:process(clk)
variable cnt: std_LOGIC_vector(22 downto 0);
variable ovf:std_logic:='0';
constant zero: std_LOGIC_vector(22 downto 0):="00000000000000000000000";
constant step: std_LOGIC_vector(22 downto 0):="00000000000000000000001";
constant max: std_LOGIC_vector(22 downto 0):="10011000100101001000000";
begin
if(rising_edge(clk))then
cnt:=cnt+step;
 if(cnt=max-3)then
	 ovf:='1';
 elsif(cnt=max)then
	 ovf:='0';
	 cnt:=zero;
 end if;
ovf_s<=ovf;
end if;
end process;
Key:process(ovf_s)
variable shift:std_logic_vector(2 downto 0);
variable flag : std_Logic;
begin
if(rising_edge(ovf_s))then
	 shift(2 downto 1):=shift(1 downto 0);
	 shift(0):=TX_INT;
	 if(shift="001")then
	 flag:='1';
	 end if;
	 flag_s<=flag;
end if;
end process;
UART_Tx: process(CLK, RST_N, TxClk, TxBufEmpty, TX_INT, TXRead)
variable TxBitCnt: integer range 0 to 9;
begin
 if RST_N='0' then
	 TxD<='1';
	 TxBitCnt:=0;
	 TxBuf<=(others=>'0');
	 TxBufEmpty<='1';
	 TXRead<='0';
 else
	 if (rising_edge(clk) ) then
if(flag_s = '1')then
	 if TXRead='1' then
		 TXRead<='0';
	 end if;
	 if (TxBufEmpty='1' and TX_INT='0') then -- ***
		 TXRead<='1';
		 TxBuf(7 downto 0)<=SW(7 downto 0);
		 TxBufEmpty<='0';
	 end if;
	 if (TxClk='1' and TxBufEmpty='0') then
			 case TxBitCnt is
			 when 0 =>
				 TxD<='0'; -- start bit
				 TxBitCnt:=TxBitCnt+1;
			 when 1|2|3|4|5|6|7|8 =>
				 TxD<= TxBuf(0);	
				 TxBuf<='1' & TxBuf(7 downto 1);
				 TxBitCnt:=TxBitCnt+1;
			 when 9 =>
				 TxD<='1'; -- stop bit
				 TxBuf<='1' & TxBuf(7 downto 1);
				 TxBitCnt:=0;
				 TxBufEmpty<='1';
		 end case;
	 end if;
	 end if;
 end if;
end if;
end process UART_Tx;

Edited by Lessberg

Share this post


Link to post
Share on other sites

Еще предложили приделать разрешающий сигнал для сдвигового регистра.

Вот схема (то что ниже схемы. это просто заметки не относящиеся к этой схеме)

643fcf1d2040t.jpg

Вот моя реализация схемы, для простоты расписал пока отдельными компонентами



-- Сигнали управления кнопкой передачи
signal reset, q1,q2, Q : std_Logic; -- сигналы первого Т триггера
signal en : std_Logic; -- сигналы счетчика
signal enable : std_Logic;
signal count : integer;
.........

Trigger1:process(TxClk,reset,Tx_INT)
begin
if (reset = '1') then
 q1 <= '1';
 elsif (TxClk'event and TxClk = '1') then
	 q1 <= Tx_INT;
 end if;
end process;

Counter:process(TxClk,reset,Tx_INT)
variable cnt : integer range 0 to 10;
begin
en <= q1;
 if (reset = '1') then
	 cnt:= 0;
 elsif (TxClk'event and TxClk = '1') then
	 if (en = '0') then
 if (cnt = 10) then
 cnt:= 0;
else
		 cnt := cnt + 1;
end if;
else cnt := 0;
	 end if;
 end if;
 count <= cnt ;
end process;


Comparator:process(count)
variable V : integer:= 10;
begin
 if count = V then
	 q2 <= '1';
else
 q2 <= '0';
end if;
Q <= q2;
end process;


Trigger2:process(TxClk,reset)
begin
 if (TxClk'event and TxClk = '1') then
 enable <= not(Q);
end if;
reset <= not(enable);
end process;

Сигнал разрешения "enable" подключаю к сдвиговому регистру

UART_Tx: process(CLK, RST, TxClk, TxBufEmpty, TX_INT, TXReady,enable)
variable TxBitCnt: integer range 0 to 10;
begin
 if RST='0' then
	 TxD<='1';
	 TxBitCnt:=0;
	 TxBuf<=(others=>'0');
	 TxBufEmpty<='1';
	 TXReady<='0';
 else
	 if (CLK'event and CLK='1') then
	 if TXReady='1' then
		 TXReady<='0';
	 end if;
	 if (TxBufEmpty='1' and TX_INT='0' and enable = '0') then
		 TXReady<='1';
		 TxBuf(7 downto 0)<= Data_IN(7 downto 0);
		 TxBufEmpty<='0';
--	 enable <= '1';
	 end if;
	 if (TxClk='1' and TxBufEmpty='0' ) then
			 case TxBitCnt is
			 when 0 =>
				 TxD<='0'; -- Старт бит
				 TxBitCnt:=TxBitCnt+1;
			 when 1|2|3|4|5|6|7|8 =>
				 TxD<= TxBuf(0);	
				 TxBuf<='1' & TxBuf(7 downto 1);
				 TxBitCnt:=TxBitCnt+1;
 when 9 =>
		 a <= TxBuf (7 downto 0);
		 b <= a(0) xor a(1) xor a(2) xor a(3) xor a(4) xor a(5) xor a(6) xor a(7);
		 c <= parity xor b; -- parity константа равная "1"
		 if c = parity then

				 TxBitCnt := TxBitCnt+1;
 error_1 <= '0';
 else
	 TxBuf <= parity & TxBuf (6 downto 0);
	 error_1 <= '1'; -- датчик ошибки четности "1" на передаче
				 end if;
			 when 10 =>
				 TxD<='1'; -- стоп бит
				 TxBuf<='1' & TxBuf(7 downto 1);
				 TxBitCnt:=0;
				 TxBufEmpty<='1';
		 end case;
	 end if;
	 end if;
 end if;
end process UART_Tx;

Но в итоге передает все равно пачку :(

Вариантов уже кучу испробовал.. может кто ткнет носом куда надо ?

Edited by Lessberg

Share this post


Link to post
Share on other sites

Вот проект UART, который я использую у себя. Он не совсем оптимален, но гарантированно работает.

Тактовая частота 40 МГц. Отсылается один байт при установке сигнала записи Tx_write в состояние лог 1.

По окончании, выдается сигнал Tx_empty. Данные желательно устанавливать до перехода 1-0 (задний фронт) по линии Tx_write.

Результат работы показан в скане. Частота посылок 115200 б/с. Есть четность, 1 стоп-бит.

library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
Entity UART IS
PORT(
clk40, RxD, Tx_write:in std_logic;
TxD,Rx_empty, Tx_empty, P_error, Rec_error:out std_logic;
RDB: out std_logic_vector(7 downto 0);
TDB:in std_logic_vector(7 downto 0)
);
End UART;
ARCHITECTURE arch OF UART IS

begin
--------------------------------------------------------------
transmite:process(clk40)
variable cnt_dev:unsigned(8 downto 0):="000000000";
variable cnt_bit:unsigned(3 downto 0):="1111";
variable par_t:std_logic;
variable buf_0:std_logic_vector(7 downto 0);
variable buf_1:std_logic_vector(11 downto 0);
variable T_empty:std_logic:='1';
variable TWB:std_logic_vector(3 downto 0):="0000";
constant max:unsigned(8 downto 0):="101011011";
constant step:unsigned(8 downto 0):="000000001";
constant zero:unsigned(8 downto 0):="000000000";
begin
if(rising_edge(clk40))then
TWB(3 downto 1):=TWB(2 downto 0);--Write comand buffer
TWB(0):=Tx_write;
Tx_empty<=T_empty;
if(TWB="1110")then
cnt_dev:="000000000";
cnt_bit:="0000";
elsif(TWB="0001")then
buf_0:=TDB;
buf_1(11 downto 10):="11";
buf_1(0):='0';
elsif(TWB="0011")then
par_t:= buf_0(7) xor buf_0(6) xor buf_0(5) xor buf_0(4) xor buf_0(3) xor buf_0(2) xor buf_0(1) xor buf_0(0);
elsif(TWB="0111")then
buf_1(8 downto 1):=buf_0;
buf_1(9):=par_t;
T_empty:='0';
elsif(TWB="1111")then
if(T_empty='0')then
cnt_dev:=cnt_dev+step;
if(cnt_dev=max)then
 cnt_bit:=cnt_bit+"0001";
 cnt_dev:=zero;
end if;
case cnt_bit IS
 when "0000" => TxD<=buf_1(0);
 when "0001" => TxD<=buf_1(1);
 when "0010" => TxD<=buf_1(2);
 when "0011" => TxD<=buf_1(3);
 when "0100" => TxD<=buf_1(4);
 when "0101" => TxD<=buf_1(5);
 when "0110" => TxD<=buf_1(6);
 when "0111" => TxD<=buf_1(7);
 when "1000" => TxD<=buf_1(8);
 when "1001" => TxD<=buf_1(9);
 when "1010" => TxD<=buf_1(10);
 when others => TxD<='1'; T_empty:='1';cnt_bit:="1111";
end case;
end if;
end if;
end if;
end process;
-----------------------------------------------------------------------------
----------------------------------------------------------------------------
recieve:process(clk40)
variable cnt_dev:unsigned(5 downto 0):="000000";
variable cnt_bit:unsigned(2 downto 0):="000";
variable cnt_sh:unsigned(2 downto 0):="000";
variable cnt_bf:unsigned(3 downto 0):="0000";
variable shift_in:std_logic_vector(7 downto 0):="11111111";
variable shift_dt:std_logic_vector(11 downto 0):="111111111111";
variable takt:std_logic:='0';
variable start:std_logic:='0';
variable det:std_logic_vector(2 downto 0);
variable dbit:std_logic;
variable par:std_logic;
variable buf_out:std_logic_vector(7 downto 0);
constant step_1:unsigned(5 downto 0):="000001";
constant max_dev:unsigned(5 downto 0):="101011";
constant imp_dev:unsigned(5 downto 0):="101010";
begin
if(rising_edge(clk40))then
cnt_dev:=cnt_dev+step_1;
if(cnt_dev=imp_dev)then
takt:='1';
elsif(cnt_dev=max_dev)then
takt:='0';
cnt_dev:="000000";
shift_in(7 downto 1):=shift_in(6 downto 0);
shift_in(0):=RxD;
if((shift_in="11111110")and (start='0'))then
cnt_bit:="000";
cnt_sh:="000";
shift_dt:="111111111111";
Rx_empty<='0';
else
cnt_bit:=cnt_bit+"001";
end if;

if(cnt_bit="111")then
det(0):=shift_in(0);
det(1):=shift_in(4);
det(2):=shift_in(7);
case det IS
 when "000" => dbit:='0';
 when "001" => dbit:='0';
 when "010" => dbit:='0';
 when "100" => dbit:='0';
 when others => dbit:='1';
end case;
end if;
if(cnt_bf="0000")then
if((dbit='0')and(start='0'))then
 start:='1';
 cnt_bf:="0001";
end if;
elsif(cnt_bf="1011")then
START:='0';
cnt_bf:="0000";
buf_out:=shift_dt(10 downto 3);
par:=shift_dt(9) xor shift_dt(8) xor shift_dt(7) xor shift_dt(6) xor shift_dt(5) xor shift_dt(4) xor shift_dt(3) xor shift_dt(2) xor shift_dt(10);-- xor shift_dt(0);
Rec_error<= shift_dt(1)xor shift_dt(0);
cnt_bf:="0000";
Rx_empty<='1';
end if;

end if;
--test1<=start;
--test2<=takt;
if(start='1')then
if(takt='1')then
cnt_sh:=cnt_sh+"001";
if(cnt_sh="111")then
 shift_dt(10 downto 0):=shift_dt(11 downto 1);
 shift_dt(11):=dbit;
 cnt_bf:=cnt_bf+"0001";
end if;
end if;
end if;
P_error<=par;
RDB<=buf_out;
end if;
end process;
----------------------------------------------------------------------------
End arch;

post-95351-0-21855200-1360173940_thumb.jpg

Edited by Meteor77

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...