Как исправить фазовый сдвиг, используя делитель часов в VHDL? - PullRequest
0 голосов
/ 27 октября 2018

Я хочу создать приемник UART, который считывает 8 последовательных битов с битом четности в конце и с простым стоп-битом.Моя FPGA имеет тактовую частоту 100 МГц, а данные, которые передаются на UART, имеют скорость 56700 бод.Коэффициент деления составляет 1736 (56700 * 1736 ≈ 100 МГц).Эти два выхода - это сообщение входа, декодированного UART, и сигнал ошибки, который указывает, правильно ли UART прочитал вход.Вот что у меня есть:

    library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;

entity uart_receiver is
  generic (
    clksPerBit : integer := 1736     -- Needs to be set correctly
    );
  port (
    clk       : in  std_logic;
    clk_en_uart : in std_logic ;
    reset     : in std_logic;
    uart_rx : in  std_logic;
    error     : out std_logic;
    char   : out std_logic_vector(7 downto 0)
    );
end uart_receiver;


architecture uart_receiver_arch of uart_receiver is

  type etat is (init, start_bit, receiving_bits, parity_bit,
                     stop_bit );
  signal current_state : etat := init ;
  signal error_signal : std_logic := '0';
  signal clk_count : integer range 0 to clksPerBit-1 := 0;
  signal bit_index : integer range 0 to 7 := 0;  -- 8 Bits Total
  signal data_byte   : std_logic_vector(7 downto 0) := (others => '0');


begin

process (clk_en_uart)
  begin
    if rising_edge(clk_en_uart) then

    end if;
  end process;


process (clk,reset)
variable  check_parity : integer range 0 to 7 := 0;
   begin
     if (reset = '1') then 
             current_state <= init;
             error_signal <= '0';
             clk_count <= 0;
             bit_index <= 0;

             data_byte <= (others => '0');
     elsif rising_edge(clk) then
       case current_state  is
         when init =>

           clk_count <= 0;
           Bit_Index <= 0;

           if uart_rx = '0' then       -- Start bit detected
             current_state <= start_bit;
           else
             current_state <= init;
           end if;

          when start_bit =>
            if clk_count = (clksPerBit-1)/2 then
                 if uart_rx = '0' then
                   clk_count <= 0;  -- reset counter since we found the middle
                   current_state   <= receiving_bits;
                 else
                   current_state   <= init;
                 end if;
            else
                 clk_count <= clk_count + 1;
                 current_state <= start_bit;
               end if;               

         when receiving_bits =>
                  if clk_count < clksPerBit-1 then
                    clk_count <= clk_count + 1;
                    current_state   <= receiving_bits;
                  else
                    clk_count <= 0;
                    data_byte(bit_index) <= uart_rx;  
                 if bit_index < 7 then
                  bit_index <= bit_index + 1;
                  current_state   <= receiving_bits ;
                else
                  bit_index <= 0;
                  current_state <= parity_bit;
                end if;
              end if;

          when parity_bit =>
                if clk_count < clksPerBit-1 then
                  clk_count <= clk_count + 1;
                  current_state   <= parity_bit;
                else 
                   for k in 0 to 7 loop
                      if ( data_byte(k) = '1' ) then
                         check_parity := check_parity + 1 ;
                      end if;
                      end loop; 
                      if((uart_rx  = '1' and check_parity mod 2 = 0) or (uart_rx = '0' and check_parity mod 2 = 1)) then 
                            error_signal  <= '1' ;
                      else 
                            error_signal  <= '0';
                      end if ;
                  current_state <= stop_bit;
                end if;

               when stop_bit =>
                    if clk_count < clksPerBit-1 then
                      clk_count <= clk_count + 1;
                      current_state   <= stop_bit ;
                    else
                      clk_count <= 0;
                      current_state  <= init;
                    end if;

                when others => 
                     current_state <= init;
               end case;
         end if; 
     char <= data_byte ;    
     error <= error_signal ;  
     end process;                    
 end uart_receiver_arch;

Итак, существует фазовый сдвиг между данными, которые передаются на UART и его часами.Если есть фазовый сдвиг, я не читаю данные в нужное время.Я думаю, что этого кода достаточно, чтобы решить эту проблему.Но я создал clock_divider и не могу найти способ использовать его в этом коде.Это мой делитель тактовых импульсов:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity clock_divider is
    generic (divfactor : positive := 1736);
    Port (clk,clk2, reset : in STD_LOGIC ;
          clkdiv, activationsig : out STD_LOGIC );
end clock_divider;

architecture clock_divider_arch of clock_divider is

begin
    process(clk,reset)
    variable  clksigv : std_logic := '0' ;
    variable  activationsigv : std_logic := '0' ;
    variable  count : integer := 0 ;
        begin
            if (reset = '1') then 
              clksigv := '0' ;
              activationsigv := '0' ;
              count := 0 ;
            elsif ( rising_edge(clk) ) then 
                count := count + 2 ;
                if (activationsigv = '1') then
                    activationsigv := '0';
                end if;
                if ( count >= divfactor - 1 ) then 
                    clksigv := not(clksigv) ;
                     if ( clksigv = '1' ) then 
                        activationsigv := '1' ;
                      end if;
                    count := 0 ;
                end if ;

            end if ;
            clkdiv <= clksigv ;
            activationsig <= activationsigv;
        end process ;           
end clock_divider_arch;

Выходными данными этого делителя тактовых импульсов являются разделенные тактовые импульсы и сигнал активации, который, когда он равен «1», должен считывать данные в UART.Таким образом, два выхода также должны быть входами UART.В uart_recevier clk_en_uart - это фактически разделенные часы, но я им не пользуюсь, потому что не знаю как.

Я думаю, что решение состоит в том, чтобы «активировать» эти разделенные часы, когда я вхожу в случае start_bit, чтобы у меня было два часа с одинаковой фазой и одинаковой частотой, но я также думаю, что установить невозможнофаза для часов.

Я не уверен, что четко обозначил свою проблему.Если есть что-то, чего вы не понимаете в моем коде или в моем объяснении, не стесняйтесь задавать вопросы.

Спасибо за вашу помощь, надеясь, что я найду решение.

1 Ответ

0 голосов
/ 27 октября 2018

Похоже, что предлагаемое решение является сложным для этой проблемы.

Обычный подход заключается в том, что приемник просто ищет задний фронт начального бита, затем считает половину бита (1736/2 цикла в вашем случае), затем производит выборку значения начального бита и затем дискретизирует значения данных, четности и стоп-бита после каждого полного бита (1736 циклов в вашем случае). После этого начните заново, ища новый спадающий бит стартового бита.

Разница между частотами передатчика и приемника тогда (обычно) настолько мала, что время выборки будет практически в середине для сообщений, состоящих только из 11 битов с относительно низкой скоростью передачи битов, и перезапуск счетчика с падающего фронта стартового бита обеспечивает что любое влияние длительной разности частот устранено.

...