广告

裸机系统上的模拟调试

2022-11-18 10:13:41 Damian Bonicatto和Phoenix Bonicatto 阅读:
我承认“模拟调试”这个标题有点神秘。阅读本文后,嵌入式固件开发人员可能会遭受认知失调的困扰,但相信我,这以后会说得通的。本标题暗示的是处理MCU中被处理信号的任务。

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

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

随着信号通过MCU传输,我们希望通过调试验证的数据可能会很广泛。例如,信号通过滤波器后会看到什么,或者当信号通过相关器时,相关器的输出是什么。这就是模拟调试的用武之地,我们可以用它来实时观察信号。较小的MCU可能缺少较大的处理器所具有的一些强大的调试工具,例如BDM、JTAG和SWD。sQFednc

较小的MCU也可以不使用操作系统而作为裸机运行,但这样的话,操作系统中任何可用的调试工具都无法使用。这种工具的缺乏和实时信号处理的复杂性,会使调试代码出现问题。但是,调试需要深入了解MCU内部的数据在发生什么,并且在处理流式模拟信号时,我们可能希望查看其在模拟域中的实际情况。sQFednc

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

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

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

现在,如果没有可用的串行端口或者其不适合调试,工程师可以用一个LED连接到MCU,然后根据被调试程序中的各种条件控制其亮灭。可以将示波器连接到该LED或可用的I/O线,从而查看其状态,或通过翻转固件中的LED或I/O线来测量状态变化之间的时序。这非常有效,但不符合我们想要获得信号的模拟视图的想法,因为它会受到滤波器、相关器、切片器和混频器等各级处理。sQFednc

如果有某个地方能够连接示波器探头,并可以在此在固件中快速打印输出已处理样本,那就会很好。那么,我们可以使用什么呢?第一个想法是将DAC连接到MCU,或者更好的是,如果MCU本身带有DAC外设,那就直接使用它。为了尝试这种技术,我将ADI公司的8位DAC AD7801连接到我正在研究的Arduino Nano设计中。Nano的核心是Microchip的ATmega328,其上不带有DAC。AD7801使用8根数据线的并行输入,并通过另一根线同步;其写入速度非常快而且非常简单。(请注意,可以使用此设置查看8位数据,但对于其他DAC也可以使用10位、12位或其他大小,或者可以对其进行缩放来适应8位DAC。)我将八根数据线连接到Arduino上的端口D并将WR线连接到Arduino的D13,如图1所示。sQFednc

sQFednc

图1:将ADI的8位DAC AD7801连接到Arduino Nano设计。sQFednc

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

PORTD = data; // 将数据字节放到D0至D7上sQFednc

PORTB=PORTB & B11011111; // 将D13拉低以将数据锁存到AD7801sQFednc

PORTB = PORTB | B00100000; // 拉高D13sQFednc

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

现在连接了DAC,下面来看一些调试示例。看一下2sQFednc

sQFednc

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

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

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

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

下面来看一下3sQFednc

sQFednc

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

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

PORTD = 255; // 将255放到D0至D7上sQFednc

PORTB = PORTB & B11011111; // 将D13拉低以将数据锁存到AD7801sQFednc

PORTB = PORTB | B00100000; // 拉高D13sQFednc

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

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

PORTD = 127; // 将127放到D0至D7上sQFednc

PORTB = PORTB & B11011111; // 将D13拉低以将数据锁存到AD7801sQFednc

PORTB = PORTB | B00100000; // 拉高D13sQFednc

可通过使用以下代码(插入到监视从0到1或从1到0的符号转换的代码)向DAC发送0,将符号转换标记为“尖峰”:sQFednc

PORTD = 0; // 将0放到D0至D7上sQFednc

PORTB = PORTB & B11011111; // 将D13拉低以将数据锁存到AD7801sQFednc

PORTB = PORTB | B00100000; // 拉高D13sQFednc

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

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

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

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

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

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

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

analogWrite(PinNumber, data)sQFednc

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

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

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

sQFednc

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

上面的迹线显示了在MCU中所生成的波形。该信号实际上是对两个频率(f1=165Hz和f2=135Hz)逐个采样混合或相乘,然后在生成时将其发送到DAC。在频率混合中,所得到的频率是频率之和与频率之差。原始生成的频率受到混频操作抑制,这在示波器迹线下半部分的FFT中可以清楚地看到。大多数示波器——甚至是业余水平的示波器——都将FFT作为数学运算之一进行了提供。sQFednc

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

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

(原文刊登于EDN美国版,参考链接:Analog debugging on bare-metal systems,由Franklin Zhao编译。)sQFednc

本文为《电子技术设计》2022年11月刊杂志文章,版权所有,禁止转载。免费杂志订阅申请点击这里sQFednc

责编:Franklin
本文为电子技术设计原创文章,未经授权禁止转载。请尊重知识产权,违者本司保留追究责任的权利。
  • 微信扫一扫
    一键转发
  • 最前沿的电子设计资讯
    请关注“电子技术设计微信公众号”
  • 手机信号强弱跟什么有关,手机信号放大器真的有用吗? 现代生活的各个方面都离不开手机,无论是衣食住行,还是社交娱乐,手机都极大的方便了我们的日常生活,而手机信号则会极大的影响我们的使用体验。不知道大家有没有这样的体验,明明手机信号显示的满格,甚至还是5G信号满格,但就是加载不出页面,那这到底是怎么一回事呢?EDN小编带您一起了解。
  • 寄生峰值:使原本稳定的反馈回路不稳定的寄生反馈通路 我一直坚信电子比人更加聪明。即使是最优秀的工程师,也可能深受不易察觉的电子作用之害,尤其是在存在寄生反馈通路对原本稳定的反馈回路造成破坏而需要找到它时。本文就带大家看一个案例研究。
  • 有助于低压测量的精密同步检波放大器设计 本设计实例提出了一种实用电路,借此就可实现同步检测,进而以高线性度和出色的抗噪性对小直流电压进行放大。在涉及电流分流器、称重传感器和热电偶等的测量中需要使用这种电路。
  • 高通5G毫米波独立组网在我国取得重要突破 近日高通技术公司宣布,在中国完成的多项技术验证中实现了稳健的毫米波性能,实现5G毫米波独立组网 (SA) 性能突破,可满足未来中国毫米波商用部署需求,为进一步推动毫米波商用部署奠定了基础。
  • 智能控制如何降低能耗 全球超过 65% 的电力用于为工业环境、商业建筑和个人住宅中的电机和电源供电。据 Our World in Data 资料显示,60% 的电力来自燃烧煤炭和天然气,只有不到 10%的电力来自可再生能源。智能变频数字电机控制则可降低 25% 以上的能耗。智能数字电源控制可以更大限度地提高太阳能和风能的生产效率,并更大限度地减少超高能耗设备的电源功耗。在本文中,我们将探讨智能控制应用的一些趋势,以及分享智能控制如何降低能耗和提高可再生能源效率的示例。
  • 如何打造韧性供应链中兴通讯这样说 未来的三到五年,是供应链在各组织乃至世界范围内占据核心位置的关键时刻,我们要敢于针对性的进行自我改造或者说“重塑”,供应链应该更好的改变去拥抱环境的变化。
  • Bosch Sensortec:通过嵌入式AI和MEMS传感器感知未来 11月10日,由全球电子技术领域知名媒体集团AspenCore主办的国际集成电路展览会暨研讨会(IIC Shenzhen 2022)的全球CEO峰会上,Bosch Sensortec的CEO Stefan Finkbeiner发表了“安全、健康和可持续:通过嵌入式AI和MEMS传感器感知未来”主题演讲。
  • 机器人航位推算:深入研究里程计测试与分析 我保证会深入研究这个话题,但首先得从如何进行算法测试开始。我们之前在基于国际规范的模拟居家环境中收集了数据。但是,为了记录更多与航位推算精度直接相关的测试数据,我们在一个更简单、更小环境中对更多的方向变化进行了测试。
  • 英伟达为中国“特供”A800芯片,数据传输速率比A100低 英伟达周一表示,已为中国开发了一种新的先进芯片,该芯片遵守美国旨在限制该国获得人工智能技术的新出口管制规则。该芯片被称为A800,是第三季度投入生产的A100芯片的替代品。
  • Google AI在3个变革性领域的新成果 Google AI在3个变革性领域取得的成果。
  • 如何使用示波器或数字化仪进行更好的测量 现代示波器和数字化仪正变得越来越好——更高的带宽、更好的垂直分辨率和更长的采集内存,更不用说有更多的固件工具可用于特定应用的测量了。有了所有这些高级分析功能,我们对一些简单而又非常古老的可提高测量准确性和精度的规则,有时就很难记住。本文希望通过一些好的实例来为大家提供帮助。
  • 整合ADC的一种简易测试方法 基于Hein van den Heuvel的电路,构建了一个经典的、三运放、状态变量振荡器,并用一小粒小麦灯泡作为振幅稳定电路。对电路中运算放大器的各级负载进行了一天的摆弄,成功地将谐波失真产物降至-95 dBc以下,满足了当时的需求。
广告
热门推荐
广告
广告
EE直播间
在线研讨会
广告
广告
面包芯语
广告
向右滑动:上一篇 向左滑动:下一篇 我知道了