You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Crosslink-NX FPGA中UART-TX单脉冲触发仅首次生效问题求助

问题:FPGA UART-TX单脉冲触发逻辑硬件失效分析与解决

我基于Lattice Crosslink-NX系列8MG289C FPGA实现了FPGA到PC的UART-TX功能。为避免按键按住时重复发送UART数据包,设计了单脉冲触发逻辑:利用防抖后的按键信号start_deb生成短脉冲i_TX_DV触发UART-TX,该逻辑仿真正常,但下载到FPGA硬件后,i_TX_DV仅首次按键时置1,后续按键无法触发(通过板载LED验证),现求助该问题的原因与解决方法。

核心代码(注释已翻译)

-- start_deb 是经过防抖处理的按键触发信号(来自按键开关)

i_TX_DV_gen: process(start_deb, clk) is
variable counter: natural := 0;
begin
if rising_edge(start_deb) then
    i_TX_DV <= '1';
end if;
if i_TX_DV = '1' and rising_edge(clk) then
    counter := counter + 1;
    if counter > 10_000 then
        i_TX_DV <= '0';
        counter := 0;
    end if;
end if;
end process;

信号说明

  • clk:系统时钟
  • start_n:按键信号(低电平有效)
  • start:start_n的取反信号
  • shift_input_n:切换待发送字节的按键信号
  • o_TX_serial:UART-TX串行输出信号
  • packet:待发送字节
  • i_TX_DV:UART-TX触发信号
  • start_deb:经过防抖处理后的start信号

问题原因

  1. 异步信号处理不规范:start_deb是异步按键信号,直接用rising_edge(start_deb)捕获上升沿,未做时钟域同步,硬件中易出现亚稳态,导致后续按键的上升沿无法被正确采样。
  2. 进程逻辑竞争冲突:进程同时响应start_deb和clk的上升沿,i_TX_DV的赋值存在时序竞争。首次触发后,clk域的拉低逻辑可能覆盖start_deb的触发信号,导致后续按键无法置位i_TX_DV。
  3. 变量初始化的硬件特性问题:仿真中变量counter初始值为0,但FPGA综合时,变量会被映射为寄存器,其初始状态由FPGA配置决定(并非必然为0),可能导致首次触发后counter无法正确复位,i_TX_DV一直保持高电平,屏蔽后续触发。

解决方法

方法一:规范异步信号同步+时钟域内单脉冲逻辑

先将异步的start_deb同步到系统时钟域,再生成单脉冲,全程在时钟域内处理逻辑:

-- 两级寄存器同步异步信号,消除亚稳态
signal start_deb_sync1, start_deb_sync2, start_deb_pulse : std_logic := '0';

-- 同步进程
sync_process: process(clk)
begin
    if rising_edge(clk) then
        start_deb_sync1 <= start_deb;
        start_deb_sync2 <= start_deb_sync1;
        -- 生成时钟域内的单脉冲(捕获上升沿)
        start_deb_pulse <= start_deb_sync1 and not start_deb_sync2;
    end if;
end process;

-- 生成i_TX_DV的进程
i_TX_DV_gen: process(clk)
-- 限定变量范围,提升综合稳定性
variable counter: natural range 0 to 10_000 := 0;
begin
    if rising_edge(clk) then
        -- 捕获同步后的单脉冲,置位i_TX_DV并重置计数器
        if start_deb_pulse = '1' then
            i_TX_DV <= '1';
            counter := 0;
        -- 保持i_TX_DV高电平直到计数器达到阈值,再拉低
        elsif i_TX_DV = '1' then
            counter := counter + 1;
            if counter >= 10_000 then
                i_TX_DV <= '0';
                counter := 0;
            end if;
        end if;
    end if;
end process;

方法二:修复原进程逻辑缺陷

如果保留原结构,需将异步信号同步后再处理,调整赋值顺序避免竞争:

i_TX_DV_gen: process(clk)
variable counter: natural range 0 to 10_000 := 0;
-- 用寄存器同步start_deb到时钟域
signal start_deb_reg : std_logic := '0';
begin
    if rising_edge(clk) then
        start_deb_reg <= start_deb;
        -- 捕获同步后的start_deb上升沿
        if start_deb = '1' and start_deb_reg = '0' then
            i_TX_DV <= '1';
            counter := 0;
        elsif i_TX_DV = '1' then
            counter := counter + 1;
            if counter >= 10_000 then
                i_TX_DV <= '0';
                counter := 0;
            end if;
        end if;
    end if;
end process;

关键优化点

  • 所有异步信号必须经过两级寄存器同步,消除亚稳态影响;
  • 单脉冲触发逻辑必须在系统时钟域内完成,禁止直接用异步信号触发;
  • 变量建议限定范围,或改用信号存储跨周期数据,避免综合歧义;
  • 确保i_TX_DV每次触发后能被可靠拉低,避免后续触发被屏蔽。

内容的提问来源于stack exchange,提问作者acefrrag

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 13:10:57