Как исправить фазовый сдвиг с помощью тактового делителя в VHDL?

Я хочу сделать приемник 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, чтобы у меня было два тактовых генератора с одинаковой фазой и одинаковой частотой, но я также считаю, что невозможно установить фазу для часов.

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

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

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
787
1

Ответы 1

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

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

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

Другие вопросы по теме