无线电爱好网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

无线电爱好网 首页 技术应用 初学入门 查看内容

裸机系统上的模拟调试

2022-6-14 10:52| 发布者: 闪电| 查看: 3| 评论: 0

摘要: 我承认“模拟调试”这个标题有点神秘。阅读后,嵌入式固件开发人员可能会遭受认知失调的困扰,但相信我,以后会说得通的。标题暗示的是处理在微控制器中处理的信号的任务。许多涉及较小微型设备的任务都与处理来自传 ...

我承认“模拟调试”这个标题有点神秘。阅读后,嵌入式固件开发人员可能会遭受认知失调的困扰,但相信我,以后会说得通的。标题暗示的是处理在微控制器中处理的信号的任务。 

许多涉及较小微型设备的任务都与处理来自传感器(如麦克风、水听器、压力传感器等)的原始信号有关。其中一些信号需要清理或以其他方式处理。该处理可以使用多种数字信号处理 (DSP) 固件技术,例如 FIR 和 IIR 滤波器、混频器、FFT 等。  

随着信号通过微传输,我们希望通过调试验证的数据可能很广泛。例如,信号通过滤波器后会看到什么,或者当信号通过相关器时,相关器的输出是什么。这就是模拟调试的用武之地。它允许您实时观察信号。较小的微控制器可能缺少较大处理器所具有的一些强大的调试工具(例如BDMJ-TagSWD)。 

较小的微也可以作为基础金属运行,而不使用操作系统,这意味着操作系统中可用的任何调试工具都丢失了。这种工具的缺乏和实时信号处理的复杂性会使调试代码出现问题。但是,调试需要深入了解微处理器内部的数据发生了什么,并且在处理流模拟信号时,您可能希望查看这些在模拟域中的实际情况。 

通常,在调试固件时,工程师会使用微控制器上的串行端口(如果存在)打印出正在执行的代码的变量值或指示符。这里有很多问题:

  • 首先,在小型微型计算机中,可能没有足够的空间用于打印例程,因为内存可能是稀缺的。
  • 其次,速度可能是一个问题。在 DSP 类型的处理中,我们通常一个接一个地对输入信号进行实时处理,我们不能停下来处理相当长的打印调用。 
  • 第三,打印例程通常会使用中断,这可能会导致实时系统出现问题。
  • 最后,将数据转储到串行端口不会为您提供正在处理的数据的直接模拟视图。

例如,假设您使用模数转换器 (ADC) 从传感器接收信号。您可以在传感器的输出上挂一个示波器,并在模拟视图中查看信号和噪声,但是,如果您通过串行端口查看相同的信号,在微控制器读取 ADC 并发送此串行端口后,您会看到一堆数字。现在您可以将这些数字放入电子表格并绘制图表,或者设置另一台带有数字和模拟转换器和显示器的设备来再次查看数据,但这似乎有点慢和乏味,而且肯定不是实时的。

现在,如果串行端口不可用或不适合调试,工程师可以使用连接到微控制器的 LED,该 LED 可以根据被调试程序中的各种条件打开或关闭。示波器可以连接到 LED 或可用的 I/O 线,以查看状态或通过切换固件中的 LED 或 I/O 线来测量状态变化之间的时间。这非常有效,但不符合获得信号模拟视图的想法,因为它正在由滤波器、相关器、切片器、混频器等的各个阶段进行处理。

一个连接示波器探头的地方会很好,我们可以在固件中快速转储处理过的样本。那么,我们可以使用什么?第一个想法是将 DAC 连接到微控制器,或者更好的是,使用可用作微控制器上的外围设备的 DAC。为了尝试这种技术,我将一个 Analog Devices AD7801、8 位 DAC 连接到我正在研究的 Arduino Nano 设计中。Nano 的核心是 Microchip ATmega328,它没有板载 DAC。AD7801 使用 8 条数据线的并行输入,这些数据线由另一条线同步;写入速度非常快而且非常简单。(请注意,我们可以使用此设置查看 8 位数据,但 10 位、12 位或其他大小可以与其他 DAC 一起使用,或者可以缩放以适应 8 位 DAC。)我将八根数据线连接到Arduino 上的端口 D 和WR线连接到 Arduino 的 D13,如图 1 所示

图 1 Analog Devices AD7801、8 位 DAC 与 Arduino Nano 设计的连接。

现在,要将数据发送到 DAC,只需要 3 行 Arduino IDE C 代码:

PORTD = 数据;// 将数据字节放在 D0 到 D7 上
PORTB = PORTB & B11011111; // 将 D13 拉低以将数据锁存到 AD7801
PORTB = PORTB | B00100000; // 拉高 D13

在 16-MHz Arduino 上,此代码需要大约 5 个周期或大约 312 ns,DAC 的建立时间为 1.2 us。所以,你可以看到这种数据显示的方法可以比较快的完成,不需要中断,也不需要太多的代码。可以将此代码插入固件的适当位置以查看感兴趣的数据。将 3 行代码放入宏或函数中可能会更简洁。如果为此创建函数,则应使用“always_inline”编译指示对其进行编译,以确保其快速运行。

现在连接了 DAC,让我们看几个调试示例。看一下图2

图 2传入传感器信号的示波器快照。

这是传入传感器信号的示波器快照(为清楚起见,删除了格线)。底部迹线(粉红色/紫色)是原始信号,因为它正在进入 ATmega328 上的 ADC 引脚。您可以在这条线上看到明显的噪音。上面的迹线(黄色)是在微固件中进行一些过滤和其他处理后的相同信号。我们的 DAC 写入调试代码已插入此流程中,因此 DAC 中的采样时序与 ADC 相同。如果需要,您还可以对微信号中的信号进行抽取。暂时忽略信号中的“尖峰”,我们看到处理过程已经消除了大部分噪声。我们现在有一个可以评估的干净信号。应该注意的是,DAC 输出是一个连续的信号流,而不仅仅是一些短暂的内存缓冲捕获。 

但什么是“尖峰”?这些是我有意放入代码中的一些调试功能,以查看处理过程是如何进行的。您看到的信号实际上是被信号介质破坏的专有数字信号。代码任务是通过以下方式读取数字数据包:

  • 发现前导码“包开始”符号序列
  • 跟踪采样时间,以便我们可以在适当的时间对样本进行切片
  • 继续采集样本直到数据包结束

让我们看一下图 3

图 3添加了注释的处理信号视图。

图 3 显示了添加了注释的已处理信号的视图。我在代码中所做的是将信号从最小值 50 缩放到最大值 200。这允许在 256 个可用值中留出一些空间来在信号上方和下方添加“尖峰”。我们首先看到的是标有“检测到前导码”的“尖峰”。这是在代码验证已找到前导码 (B00000011) 时创建的,并且可以使用以下 Arduino IDE 代码轻松生成:

端口 = 255;// 将 255 放在 D0 到 D7 上
PORTB = PORTB & B11011111; // 将 D13 拉低以将数据锁存到 AD7801
PORTB = PORTB | B00100000; // 拉高 D13

这会在示波器轨迹上创建一个 312 ns 宽的标记,其幅度等于 DAC 的最大电压。信号迹线内上下的“尖峰”是指示代码确定符号边界的位置的标记。这对于在正确的时间对符号进行切片非常重要,并且在出现长时间运行的 0 或 1 时变得至关重要。这是因为没有发现从 0 到 1 或 1 到 0 的转换。 

在示波器上查看这些“尖峰”非常有用,因为它可以让我们验证实际时序并确认没有遗漏。这些符号边界“尖峰”是通过使用以下 Arduino IDE 代码向 DAC 发送 127 来创建的,该代码插入到符号时序代码的适当位置:

端口 = 127;// 将 127 放在 D0 到 D7 上
PORTB = PORTB & B11011111; // 将 D13 拉低以将数据锁存到 AD7801
PORTB = PORTB | B00100000; // 拉高 D13

符号转换通过使用以下代码向 DAC 发送 0 标记为“尖峰”,该代码插入到符号从 0 到 1 或 1 到 0 转换的代码中:

端口 = 0;// 将 0 放在 D0 到 D7 上
PORTB = PORTB & B11011111; // 将 D13 拉低以将数据锁存到 AD7801
PORTB = PORTB | B00100000; // 拉高 D13

您可以看到,使用 DAC 查看覆盖在实际处理跟踪上的调试信息,可以极大地帮助调试代码的各个部分。它比使用 LED、I/O 线和示波器强大许多倍。由于包含时序信息,它也可能比串行端口发送数据更有用。

有敏锐眼光的人可能已经注意到,在图 3的右边缘,即探头衰减不是 x1 或 x10 而是 x53.5。这是可以在许多较新的示波器上完成的技巧,有时称为自定义衰减设置。将其设置为 53.5 的原因是它允许使用示波器光标直接读取 DAC 的 8 位输入值。也就是说,如果我将光标向上滑动到前导检测“尖峰”的顶部,如果我将光标移动到符号边界“尖峰”的末尾,示波器光标读数为 255 或 127。使用 8 位 DAC 时,此设置的公式为 255/MaxVolts。MaxVolts 是输入最大二进制输入时 DAC 的输出电压;本例中为 255。因此,对于 5v 导轨,自定义设置为 51.0(我的导轨只有 4.77 V,所以我的数字是 53.5)。使用 10:1 探头时,您可能需要将此数字乘以 10,然后再将其输入示波器。

这非常方便,因为您可以直接读取 DAC 设置的数字,或者换句话说,内部变量在调用 DAC 时所具有的值。这点考虑一下吧。本质上,您可以以这种方式“实时”读取变量……几乎与打印语句一样好,但速度更快且非侵入性。请注意,示波器垂直刻度的噪声和分辨率会降低精度,因此您可能只能得到实际值的 ±1 或 ±2 个计数,仍然相当不错。

除了流式传输信号外,使用这种技术,8 位 DAC 还可以同时表示 8 个二进制标志的状态,或程序中 8 位变量的当前值。换句话说,使用 8 位 DAC 提供的信息是监控单个 I/O 线所提供的信息的 8 倍。

好的,如果您没有 DAC 可以使用怎么办?您可以使用微控制器上的脉宽调制器 (PWM) 外围设备执行类似操作。许多小型微型机都有 PWM,当它们有 PWM 时,它们通常有多个……通常是六个。PWM 和 DAC 之间的区别之一是 PWM 输出需要使用低通滤波器进行滤波,以将输出转换为电压电平。因此,当您将信号样本发送到 PWM 时,电压电平会重新创建可以在示波器上显示的信号,就像使用 DAC 所做的那样。这种过滤可以通过一个简单的 RC 过滤器来完成。 

不过这里有一些警告;低通滤波器意味着只能显示具有低频成分的信号,即响应较慢。因此,您应该将 PWM 的频率初始化为可用的最高频率。在 16MHz ATmega328 上,PWM 可以设置为大约 31 kHz 的最大频率,因此低通信号应设计为大约 3-4 kHz 的频率内容。 

使用 PWM 的 Arduino IDE 代码在初始化后甚至比 DAC 代码更简单。将 8 位值写入 PWM 的代码很简单:

类比写入(PinNumber,数据)

其中“data”是一个 8 位采样值,“PinNumber”是 PWM 输出的引脚号。

尽管 PWM 可能不那么准确或无法显示更高频率的信号,但它有一个有趣的功能。由于一些微控制器具有多达 6 个 PWM,这意味着多达 6 个输出可以实时传输数据。您可以有一个四迹示波器同时显示四个变量,留下两个备用 PWM 输出。此外,通过 PWM 或 DAC 两个输出,您可以提供 I & Q 数据,这些数据通常用于 DSP 信号处理(并允许您探索负频率)。请注意,就像 DAC 代码一样,PWM 代码也不需要中断。

另一个可用于 DAC 或 PWM 传递的信号的强大工具是频谱。图 4中的示波器屏幕截图显示了一个示例。

图 4对 DAC 或 PWM 传递的信号使用频谱的示例。

上面的迹线显示了在微系统中生成的波形。该信号实际上是两个频率(f1 = 165 Hz 和 f2 = 135 Hz)被逐个采样混合或相乘,然后在生成时发送到 DAC。在频率混合中,结果是频率之和和频率差的频率。原始生成频率被混频操作抑制,在示波器迹线下半部分的 FFT 中可以清楚地看到。大多数示波器——甚至是业余爱好者——都提供 FFT 作为数学运算之一。

如果您的系统没有 DAC 或 PWM,您仍然可以使用一些东西来获取有关正在运行的固件中的信号的一些信息。例如,您可以编写代码来对 PWM 信号进行 bit-bang,尽管这可能仅对低频信号或缓慢变化的变量有用。 

希望模拟调试的想法现在更清楚了。从固件流式传输数据并将其显示在示波器上的主要概念是一个强大的工具,可以加快您的信号处理固件调试。如果可行,选择带有 DAC 外设的微控制器或在您的第一个原型 PCB 中加入 DAC 可能会很有用。它总是可以在以后删除或在 BOM 中制作为 NO-POP。


路过

雷人

握手

鲜花

鸡蛋

相关阅读

QQ|关于本站|小黑屋|Archiver|手机版|无线电爱好网 ( 粤ICP备15040352号 ) 无线电爱好技术交流5 无线电爱好技术交流1无线电爱好技术交流9开关电源讨论群LED照明应用、电源无线电爱好技术交流4无线电爱好技术交流8无线电爱好技术交流10无线电爱好技术交流11

粤公网安备 44030702001224号

GMT+8, 2022-7-29 15:39 , Processed in 0.124801 second(s), 18 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

返回顶部