每个触发器都有两个我们在风险方面违反的关键规格。“建立时间”是时钟到来之前输入数据必须稳定的最小纳秒数。“保持时间”告诉我们在时钟转换后保持数据存在多长时间。
这些规格因逻辑设备而异。有些可能需要数十纳秒的设置和/或保持时间;其他人则需要少一个数量级。
图9.1:建立和保持时间
如果我们倾向于编织,我们将尊重这些参数,并且触发器将始终是完全可预测的。但是,当区域同步时(例如,腕部以其自己的速度旋转,并且只要需要数据,该软件便会读取数据),这很可能会违反设置或保持时间。
假设触发器需要3纳秒的设置时间。我们的数据在该窗口内发生变化,可能在时钟转换之前翻转状态一纳秒。该设备将进入稳态,其输出确实变得非常奇怪。
通过违反规范,设备实际上不知道我们表示的是零还是一。它的输出不是逻辑状态,而是半电平(在数字规范之间),或者会振荡,在状态之间疯狂地切换。触发器是亚稳态的。
图9.2:亚稳态
这种疯狂不会持续很长时间。通常在几秒到50纳秒后,振荡衰减或半态消失,使输出保持有效的1或0。但是是哪一个?这是一个数字系统,我们期望一个为1,并将零为零。
输出是随机的。 那个,那个 您无法预测它将采用的级别。这肯定使设计可预测的数字系统变得困难!
硬件人员认为随机输出不是问题。由于输入几乎在时钟选通的同一时间发生变化,因此零或一是合理的。无论如何,如果我们只是在先发制人或落后,我们将获得不同的价值。从哲学上讲,谁知道我们测量的状态?这真的很重要吗?也许不影响EE,但这将在很大程度上影响我们的软件,我们将很快看到。
仅当时钟和数据几乎同时到达时才发生亚稳态。随着时钟频率的飙升,赔率增加。同样重要的因素是所使用的逻辑组件的类型:较慢的逻辑(如74HCxx)比较快的器件(例如74FCTxx)具有更宽的亚稳态窗口。
显然,以适当的速率,两个异步信号及时到位足以引起亚稳态的可能性很低,可测量,是的,很重要。在使用10 MHz时钟和10KHz数据速率的情况下,使用典型但并非十分快速的逻辑,亚稳态错误大约每分钟发生一次。尽管很少见,但没有可靠的系统可以承受该故障率。
经典的亚稳态修正使用串联的两个触发器。它的输出馈入第二个的数据输入。两者都使用相同的时钟输入。两个时钟后,第二个触发器的输出将是“正确的”,因为两个背对背发生的亚稳态事件的几率几乎为零。使用两个触发器,合理的数据速率误差相隔数百万甚至数十亿年,对于大多数系统来说已经足够了。
但是,“正确”意味着第二阶段的输出将无可挑剔:它没有振荡,也没有处于非法电压电平。该值处于两种法律状态的机会仍然相等。
固件,而不是硬件
据我所知,没有关于亚稳性如何影响软件的文献,但它对构建可靠的系统却构成了真正的威胁。
嵌入式开发工程师使用所述的两阶段触发器自鸣得意地解决了他们的亚稳性问题。它们的域是单个位的域,其输入几乎在时钟转换的同一时间改变。用这么狭义的思想思考,接受触发器产生的固有随机输出确实是合理的。
但是,我们的嵌入式开发工程师正在读取并行的I / O端口,每个端口可能都是8位宽。这意味着输入捕捉寄存器中有8个触发器,它们均由相同的时钟脉冲驱动。
让我们看看会发生什么。编码器从0xff变为0x100。这种小的差异可能只是角度的微小变化。我们要求在数据改变的几乎同一时间读取数据,我们的输入操作会选通捕捉寄存器的时钟,从而会破坏建立时间或保持时间。
每个输入位都会变化,寄存器中的每个触发器都将变为亚稳态。短时间后,振荡消失,但寄存器中的每个位都是随机的。尽管硬件人员可能耸耸肩并抱怨没有人知道正确的值,但是由于时钟的到来,一切都发生了变化,实际上数据大约是0xf表示0x100。例如,0x12的随机结果是荒谬的,是完全不可接受的,并且可能导致疯狂的系统行为。
数据从0xff变为0x100的情况是病理性的,因为每个位都立即更改。每当许多位更改时,系统都会面临相同的风险。0x0f至0x10。0x1f至0x20。不变的高位数据始终会正确锁存,但每个变化位都有风险。
为什么不使用多重触发器解决方案?串联连接两个输入捕捉寄存器,它们均由同一时钟驱动。尽管这将消除非法的逻辑状态和振荡,但第二级的输出也将是随机的。
一种选择是忽略亚稳态,并希望获得最好的结果。或使用建立时间/保持时间窗口非常窄的快速逻辑来减少故障几率。如果代码很少在输入中进行采样,则有可能将亚稳定性降低到几百万甚至数十亿的机会。建立安全关键系统?感觉很幸运?
可以构建一个同步器电路,该电路接收从处理器读取的请求,并将其与I / O设备的可用数据位组合在一起,并以数据OK信号响应返回到CPU,这是不平凡的,并且容易出错。
一种替代方法是对I / O设备使用不同的编码方案。例如,购买带有格雷码输出的编码器(如果可以找到的话)。格雷码是一种计数方案,其中数字之间只有一个位更改,如下所示:
0 000
1 001
2 011
3 010
4 110
5 111
6 101
7 100
只有当您的代码读取设备的速度比可能更改的速度快,并且更改以相当可预测的方式发生(例如递增计数)时,格雷码才有意义。那么,如果输入变为亚稳态,那么只有一位是错误的,那么读取之间的变化就不会超过一个位。结果仍然是合理的。
另一种解决方案是在捕获寄存器之前计算输入数据的奇偶校验或校验和。也将其锁存到寄存器中。如果有错误,请执行代码计算奇偶校验并将其与该读取进行比较,然后再进行一次读取。
尽管我已经讨论过添加输入捕获寄存器,但是请不要以为这是问题的根本原因。没有那个寄存器-如果您仅将异步输入直接输入到CPU中-很有可能会违反处理器的固有设置/保持时间。
没有免费的午餐,所有逻辑都有我们必须遵守的身体限制。有些设计永远不会出现亚稳性问题。它总是防止违反设置或保持时间,而这又源于不良的设计或异步输入。
当时钟和数据在时间上不相关时,到目前为止,所有讨论都围绕异步输入展开。警惕任何不属于处理器时钟的东西。中断是问题的根源。
如果是由某人按下按钮引起的,请确保中断本身以及矢量生成逻辑不会违反处理器的建立和保持时间。
但是,在计算机系统中,大多数事情确实是同步发生的。如果您正在读取一个以CPU时钟为基础的计时器,则它与代码本身是同步的。从亚稳定性的角度来看,这是完全安全的。
但是,不良的设计会困扰任何电子系统。每个逻辑组件都需要花费时间来传播数据。当信号经过许多设备时,延迟可能会显着增加。如果数据随后进行分配,则延迟很可能导致输入与时钟同时转换。即时亚稳。
但是,嵌入式开发工程师非常小心,避免出现这些情况。请注意FPGA和其他组件的延迟,延迟取决于软件如何路由设备。此外,当锁存数据或为计数器计时时,通过使用错误的时钟沿不难引起亚稳性问题。拾取使设备有时间在读取之前稳定的边缘。
那模拟输入呢?将一个12位A / D转换器连接到两个8位端口,我们似乎会遇到类似的问题:模拟数据会遍历整个状态,在读取两个端口的过程中会发生变化。
但是,不需要输入捕获寄存器,因为转换器本身通常包括一个“采样和保持”模块,该模块在A / D数字化时存储模拟信号。然后,大多数A / D都会存储数字值,直到我们开始下一次转换为止。
我们所有使用的其他输入都会遇到这个问题。假设机器人使用10位编码器监视腕关节的角度位置,当腕部旋转时,编码器会发回10位宽的二进制代码,以表示关节的当前位置。一个8位处理器需要两个不同的I / O指令(两个字节宽的读取)才能获取数据。无论计算机速度有多快,读取之间的时间间隔都是有限的,在此期间编码器数据可能会更改。
手腕在旋转。“ get_position”例程从位置数据的下部读取0xff。然后,在下一条指令之前,编码器将翻转到0x100。“ get_position”读取数据的大部分(现在为0x1)并返回0x1ff的位置,显然是错误的,甚至可能是不可能的。
这是一个常见的问题,需要处理两轴控制器的输入,如果在读取过程中硬件继续移动,则X和Ydata会略有不相关,可能无法得到结果。
一位朋友追踪了一种罕见的自动驾驶仪故障,该故障是代码读取磁通门罗盘的方式,该罗盘的输出是一对相关的正交信号。在船只继续移动的同时,在不同的时间读取它们,无法获得航向数据。嵌入式开发工程师