首页 > 解决方案 > VHDL在顺序CASE语句列表中需要时间延迟

问题描述

我有一个 8051 内核作为我的 FPGA 中的顶级主模块运行。然后我在这里也实例化了一个 I2C 例程(我在这里只做 8051 主到 LED 显示从属)。8051 将并行 I2C 地址和数据发送到 I2C 例程,并将 I2C 数据输出到我的 Salela 示波器。它有效,但是,我遇到了问题,我需要时间延迟,只是不明白如何实现这一点。这不适用于测试台或模型模拟,这是真实的。当 I2C 例程忙时,它使“忙”位变高,8051 轮询这个,当忙位变低时,8051 然后将接下来的 8 位并行数据发送到 I2C 例程。问题是 I2C 例程切换这个“忙碌”位的速度太快,8051 无法及时将其数据发送到 I2C 例程。在忙位变低后,我需要 I2C 例程坐等一会儿。这是我需要它的地方。

WHEN slv_ack2 =>                  
            IF(ena = '1') THEN                  
              busy <= '0';     -- I2C routine sets busy bit to low for 8051 to send data

              I need to wait here for 1 full second all the time when at this step

              
              addr_rw <= addr & rw;          
              data_tx <= data_wr;            
              IF(addr_rw = addr & rw) THEN   
                sda_int <= data_wr(bit_cnt); 
                state <= wr;                 
              ELSE                           
                state <= stop;              
              END IF;
              
WHEN wr =>                         -
            busy <= '1';                     
            IF(bit_cnt = 0) THEN             
              sda_int <= '1';                
              bit_cnt <= 7;                  
              state <= slv_ack2;             
            ELSE                             
              bit_cnt <= bit_cnt - 1;        
              sda_int <= data_tx(bit_cnt-1); 
              state <= wr;                   
            END IF;           
 

是的,我找到了一个漂亮的柜台,我可以清楚地看到它的作用,但是我在哪里插入它以及如何使用它?好的,我是 VHDL/FPGA 的新手,但现在大约 4 周,所以仍在学习,语法和布局是我迄今为止最大的难题。


      PROCESS (timer)
BEGIN
IF (clk12'EVENT AND clk12 = '1') THEN
    counter <= counter + '1';
    if( counter = 2 ) then
        SIGNAL_COUNTED <= '1';
        counter <= "0";
    else
        SIGNAL_COUNTER <= '0';
    end if;
END IF;
END PROCESS;

所以我想做的是这个,但我知道它不会那样工作。我应该把它放在哪里让它工作?


WHEN slv_ack2 =>                  
            IF(ena = '1') THEN               
              busy <= '0';
              
              

                  PROCESS (timer)
BEGIN
IF (clk12'EVENT AND clk12 = '1') THEN
    counter <= counter + '1';
    if( counter = 1 ) then
        SIGNAL_COUNTED <= '1';
        counter <= "0";
    else
        SIGNAL_COUNTER <= '0';
    end if;
END IF;
END PROCESS;


              
              addr_rw <= addr & rw;          
              data_tx <= data_wr;            
              IF(addr_rw = addr & rw) THEN   
                sda_int <= data_wr(bit_cnt); 
                state <= wr;                 
              ELSE                           
                state <= stop;              
              END IF;
              
WHEN wr =>                         -
            busy <= '1';                     
            IF(bit_cnt = 0) THEN             
              sda_int <= '1';                
              bit_cnt <= 7;                  
              state <= slv_ack2;             
            ELSE                             
              bit_cnt <= bit_cnt - 1;        
              sda_int <= data_tx(bit_cnt-1); 
              state <= wr;                   
            END IF;           

标签: vhdlfpga

解决方案


当您编写 VHDL 时,您需要记住您是在描述硬件,因此考虑底层电路是什么会很有帮助。在这种情况下,您正在尝试实现睡眠类型功能,因此您基本上希望您的 FSM 坐在那里什么都不做,直到计数器超时。

为此,您需要添加另一个等待计数器达到 0 的状态(假设您使用递减计数器来实现计数器)。例如:

WHEN slv_ack2 =>                  
    IF(ena = '1') THEN                  
         busy  <= '0';
         state <= sleep;
    END IF;

WHEN sleep =>
    IF (timer = 0) THEN
        state        <= setup_write;
        enable_timer <= '0';
    ELSE
        enable_timer <= '1';
    END IF;

WHEN setup_write =>
    addr_rw <= addr & rw;          
    data_tx <= data_wr;            
    IF(addr_rw = addr & rw) THEN   
        sda_int <= data_wr(bit_cnt); 
        state <= wr;                 
    ELSE                           
        state <= stop;              
    END IF;

对于计数器代码,您不能将一个进程块放在另一个进程块内。所以你需要把它移到case语句之外。您也只希望它在您实际处于睡眠状态时主动计数,因此您需要为其添加一个启用信号。


推荐阅读