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

两个VHDL进程是否同步?如何生成无门控50%占空比慢时钟

从12MHz时钟生成1MHz 50%占空比时钟的设计疑问与优化方案

核心问题解答

1. 50%占空比慢时钟的生成方法

要从12MHz时钟生成1MHz、50%占空比的慢时钟且不使用门控时钟,核心逻辑是通过计数器跟踪快时钟周期,每经过固定数量的快时钟周期翻转慢时钟电平:

  • 1MHz时钟周期为1μs,对应12MHz快时钟的12个周期(12*(1/12μs)=1μs)。
  • 要实现50%占空比,慢时钟高低电平需各占6个快时钟周期,因此计数器计数到5(从0开始)时翻转电平,完成半周期;再计数6次后再次翻转,形成完整周期。原代码中SCLK_COUNTER_MAX := 5的设计完全符合这个逻辑。

2. 原代码的时钟域疑问

原代码中sm_proc以slow_clk_q作为敏感信号,确实会创建新的时钟域:

  • 尽管slow_clk_q由12MHz时钟同步生成,但FPGA/ASIC工具会将所有用作触发信号的信号视为独立时钟。这会导致sm_proc所在逻辑被归类到slow_clk_q时钟域,而slow_clk_proc属于12MHz时钟域,两者构成跨时钟域设计。
  • 即便理论上两个时钟完全同步,实际综合、布局布线时仍可能出现时序违规(如建立/保持时间不满足),增加设计风险,因此这种方式不适合用于状态机这类同步逻辑。

优化方案:单时钟域+时钟使能设计

修改后的代码采用**时钟使能(clk_en)**方案,将所有逻辑统一到12MHz时钟域,彻底规避跨时钟域问题,同时满足功能需求:

设计思路

  • 用clk_en脉冲替代慢时钟触发:每12个12MHz时钟周期生成一个高电平脉冲,状态机仅在clk_en='1'时更新状态,等效于1MHz的运行频率。
  • 独立生成给DAC的1MHz 50%占空比spi_clk,逻辑与原慢时钟生成一致,通过计数器每6个快时钟周期翻转一次电平。
  • 可选优化:clk_en_proc和spi_clk_proc可合并为一个进程,共享计数器资源——当计数器到5时翻转spi_clk,到11时置位clk_en,减少逻辑资源占用。

初始代码

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity spi_dac is
    port ( 
        clk : in std_logic;
        slow_clk : out std_logic;
        data_out : out std_logic := '0'
        );
end spi_dac;

architecture behavioral of spi_dac is

    signal slow_clk_q : std_logic := '0';
    constant SCLK_COUNTER_MAX : positive := 5;
    signal sclk_counter : natural range 0 to SCLK_COUNTER_MAX := 0;
    
begin

    sm_proc: process(slow_clk_q)
    begin        
        if rising_edge(slow_clk_q) then        
            -- State machine (hopefully) synchronous to 'clk'             
        end if;
    end process;   
    
    slow_clk_proc: process(clk)
    begin
        if rising_edge(clk) then
 
            if sclk_counter < SCLK_COUNTER_MAX then
                sclk_counter <= sclk_counter + 1;
            else
                sclk_counter <= 0;
                slow_clk_q <= not slow_clk_q;
            end if;
            
        end if;       
    end process;
    
    slow_clk <= slow_clk_q;

end behavioral;

修改后代码

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity spi_dac is
    port ( 
        clk : in std_logic;
        spi_clk : out std_logic;
        data_out : out std_logic := '0'
        );
end spi_dac;

architecture behavioral of spi_dac is

    signal clk_en : std_logic := '0';
    constant EN_COUNT_MAX : positive := 11;
    signal en_counter : natural range 0 to EN_COUNT_MAX := 0;

    type state_type is (STATE_0, STATE_1);
    signal sm_state : state_type := STATE_0;

    constant SPI_CLK_COUNT_MAX : positive := 5;
    signal spi_clk_counter : natural range 0 to SPI_CLK_COUNT_MAX := 0;
    signal spi_clk_q : std_logic := '0';

begin

    sm_proc: process(clk)
    begin        
        if rising_edge(clk) then                    
            if clk_en = '1' then    -- Update state machine at 1/12 the speed of 'clk'
            
                case sm_state is
                    when STATE_0 =>
                        data_out <= '1';
                        sm_state <= STATE_1;
                    
                    when STATE_1 =>
                        data_out <= '0';
                        sm_state <= STATE_0;
                    
                end case;
            end if;                         
        end if;
    end process;    


    clk_en_proc: process(clk)
    begin
        if rising_edge(clk) then 
            clk_en <= '0';
            if en_counter < EN_COUNT_MAX then
                en_counter <= en_counter + 1;
            else
                en_counter <= 0;
                clk_en <= '1';      -- Pulse 'clk_en' high for one clock cycle
            end if;            
        end if;       
    end process;


    spi_clk_proc: process(clk)      -- Toggle 'spi_clk' at 1 MHz and 50% duty cycle 
    begin                            
        if rising_edge(clk) then        
            if spi_clk_counter < SPI_CLK_COUNT_MAX then
                spi_clk_counter <= spi_clk_counter + 1;
            else
                spi_clk_counter <= 0;
                spi_clk_q <= not spi_clk_q;
            end if;        
        end if;    
    end process;


    spi_clk <= spi_clk_q;

end behavioral;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 17:23:18