vhdl - 如何使用 VHDL 中的时钟分频器校正相移?
问题描述
我想制作一个 UART 接收器,它可以读取 8 个连续位,最后有一个奇偶校验位和一个简单的停止位。我的 FPGA 有一个 100Mhz 的时钟,传输到 uart 的数据的速率为 56700 波特。分频系数为 1736(56700 * 1736 ≈ 100Mhz)。两个输出是由 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 情况时“激活”这个分频时钟,这样我就有两个具有相同相位和相同频率的时钟,但我也认为不可能为时钟设置相位。
我不确定我是否清楚地解决了我的问题。如果您在我的代码或我的解释中有不明白的地方,请随时提出问题。
谢谢你的帮助,希望我能找到解决办法。
解决方案
听起来建议的解决方案对于这个问题很复杂。
通常的方法是接收器只是寻找起始位的下降沿,然后计数半位时间(在您的情况下为 1736 / 2 个周期),然后对起始位值进行采样,然后对数据进行采样,奇偶校验并在每个完整位时间后停止位值(在您的情况下为 1736 个周期)。之后重新开始寻找起始位的新下降沿。
发射器和接收器频率之间的差异(通常)非常小,以至于对于只有 11 位的消息在相对较低的比特率下采样时间实际上处于中间,并且计数器在起始位的下降沿重新启动确保任何影响去除了长时间的频差。
推荐阅读
- python - 如何总结包含混合数字和字符串的 DataFrame 中的数字
- python - 在 json 中保存 PIL 图像的最佳方法是什么
- r - 如何使用数据集的特定行顺序?
- c# - 获取当前控制台字体信息
- bash - Bash脚本逐行遍历文件的所有行并计算新行与前一行不同的次数
- python - 如何使用 PySpark 获取父 XML 节点
- xtext - 如何将导入(importURI)限制为某些文件类型
- c# - 检查协方差时是否忽略约束?
- kubernetes - 为什么 kube-dns 在 kubernetes 中找不到 API 服务器?
- java - 如何在 json 对象的列表视图中搜索?