如何在多仪器模式下使用数字 I/O 引脚
使用Moku:Go数字 I/O 与多仪器模式和Moku云编译
Moku:Go具有 16 个双向引脚,用户可以灵活地将它们用作 16 个独立的信号引脚,也可以将它们组合成单个 16 位总线。本文将介绍如何在Moku:Go多仪器模式下使用数字 I/O 引脚。
1. 独立数字引脚
Moku:Go上的 16 个引脚中的每一个都可以单独设置为数字输入或输出,并可以通过逻辑分析仪中的集成模式生成器进行控制。引脚 1~8 配置为输出引脚,引脚 9~16 配置为输入引脚。引脚 1~8 通过跳线从外部环回到引脚 9~16 。


在此设置中,逻辑分析仪/码型发生器可以同时从某些数字引脚读取信号并向其他数字引脚输出信号。如下图所示,逻辑分析仪通过 DIO 和跳线准确捕获码型发生器 1 生成的信号。请注意,位是基于 0 的,而引脚是基于 1 的。

2. 组合为16位总线
数字引脚可以映射到 16 位信号总线,从最低有效位 (LSB) 到最高有效位 (MSB) 排序。例如,引脚 1 对应于 16 位信号总线中的位 0 (LSB),而引脚 16 与位 15 (MSB) 对齐。在下面屏幕截图中所示的配置中,波形发生器通过 DIO 产生 16 位斜波;同时,逻辑分析仪可视化 16 个引脚上的输出波形。

斜坡波形设置为 100 Hz 重复率和 10 Vpp 振幅。逻辑分析仪上的波形表明高阶位经历的转换较少,而低阶位则表现出更多的转换。这一观察结果与预期行为一致,因为最高有效位 (MSB) 在每个周期内仅改变两次,而最低有效位 (LSB) 几乎每次波形更新都会改变。

3. Moku云编译
通过Moku Cloud Compile (MCC),使用 DIO 创建适应性强且量身定制的算法的范围更广。您可以制作数字信号发生器并通过 DIO 传输信号。例如,考虑这个 MCC 自定义函数:它从引脚 1 读取触发信号并在引脚 6 至 8 上生成三个数字触发器。随后,引脚 6 至 8 环回到引脚 2 至 4 ,可以使用逻辑分析仪进行观察。

例如,附件中的 MCC 代码在收到输入触发信号后会生成三个触发信号,每个相邻触发信号之间间隔 10 个时钟周期。下图显示了非触发(左)和触发(右)的输出结果。在触发图中可以观察到触发信号之间的 320 ns(10 * 1/31.25 MHz)延迟。
此自定义触发功能的 VHDL 代码如下所示,可合成并部署到Moku:Go 。要生成比特流,请点击此链接: Moku Cloud Compile - 入门指南
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- InputA(0): trigger input
-- OutputA(5): regenerated trigger0 output
-- OutputA(6): regenerated trigger1 output
-- OutputA(7): regenerated trigger2 output
architecture TopWrapper of CustomWrapper is
type t_state is (Waiting, Running);
signal state, state_next : t_state;
signal prevTriggerIn : std_logic;
signal count, count_next : unsigned(15 downto 0);
begin
State_Machine: process (prevTriggerIn, InputA(0), count, state)
begin
case state is
when Waiting =>
if(prevTriggerIn /= '1' and InputA(0) = '1') then
state_next <= Running;
else
state_next <= Waiting;
end if;
when Running =>
if(count /= to_unsigned(31,count'length)) then
count_next <= count + to_unsigned(1,count'length);
state_next <= Running;
else
count_next <= to_unsigned(0,count'length);
state_next <= Waiting;
end if;
end case;
end process;
Trigger_Gen: process(clk) is
begin
if reset = '1' then
state <= Waiting;
prevTriggerIn <= '0';
count <= to_unsigned(0,count'length);
OutputA(5) <= '0';
OutputA(6) <= '0';
OutputA(7) <= '0';
elsif rising_edge(Clk) then
prevTriggerIn <= InputA(0);
state <= state_next;
count <= count_next;
case state is
when Waiting =>
OutputA(5) <= '0';
OutputA(6) <= '0';
OutputA(7) <= '0';
when Running =>
if (count = to_unsigned(10,count'length)) then
OutputA(5) <= '1';
OutputA(6) <= '0';
OutputA(7) <= '0';
elsif (count = to_unsigned(20,count'length)) then
OutputA(5) <= '0';
OutputA(6) <= '1';
OutputA(7) <= '0';
elsif (count = to_unsigned(30,count'length)) then
OutputA(5) <= '0';
OutputA(6) <= '0';
OutputA(7) <= '1';
else
OutputA(5) <= '0';
OutputA(6) <= '0';
OutputA(7) <= '0';
end if;
end case;
end if;
end process;
end architecture;