vhdl - 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;
解决方案
当您编写 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语句之外。您也只希望它在您实际处于睡眠状态时主动计数,因此您需要为其添加一个启用信号。
推荐阅读
- javascript - mapStateToProps 和变量未定义 React-Redux
- php - yii2-redis find() 返回空结果
- ios - ios 图表 - 在轴内部显示标签
- android - 我们可以在不给用户任何奖励的情况下使用 Admob 奖励广告吗?
- python - python HTTPServer return multipart/form-data(返回多个二进制文件)
- c++ - CppAD 中的固定大小特征矩阵
- ruby - 如何使用 RSpec 测试方法是否捕获符号?
- javascript - 在导航中计算过滤的行数
- java - 将 JFoenix JFXDialogLayout 警报通知代码重构为更简单的形式,以便可以将其重用于其他类
- javascript - 哪个会更快?