【问题标题】:Beginner - While() - Optimization初学者 - While() - 优化
【发布时间】:2017-03-02 17:48:33
【问题描述】:

我是嵌入式开发的新手,前几次我刷了一些关于 PIC24xxxx 的代码。

void i2c_Write(char data) {
    while (I2C2STATbits.TBF) {};

    IFS3bits.MI2C2IF = 0;

    I2C2TRN = data;

    while (I2C2STATbits.TRSTAT) {};

    Nop();
    Nop();
}

您如何看待 while 条件?微芯片不会为此使用大量 CPU 吗?

我问了自己这个问题,惊讶地在网上看到很多类似的代码。

没有更好的方法吗?


Nop() 呢,为什么是两个?

【问题讨论】:

  • 如果您无事可做并且必须等待事情完成,那么您必须等待,以及如何等待您投票...如果您还有其他事情要做然后你可以在做其他事情的时候经常轮询,或者你可以使用中断。
  • 这两个 nop 可能是为了在事务之间消磨 i2c 总线上的时间,以防您背靠背地执行它们。他们可能有一个问题违反了公共汽车的时间安排,并且为了解决它而延误了一些时间,这又是相当典型的。你正在用软件实现一个硬件状态机,所以你必须做一些事情,比如等待这个,等待那个,延迟 N 个时间段,等等......

标签: c embedded pic


【解决方案1】:

一般来说,为了与硬件进行交互,有两种方式:

  • 忙等
  • 中断基础

在您的情况下,为了与 I2C 设备交互,您的软件首先等待 TBF 位被清除,这意味着 I2C 设备已准备好接受要发送的字节。 然后您的软件实际上正在将字节写入设备并等待 TRSTAT 位被清除,这意味着您的 I2C 设备已正确处理数据。

您显示的代码是用繁忙的等待循环编写的,这意味着 CPU 正在积极等待硬件。这确实是浪费资源,但在某些情况下(例如,您的 I2C 中断线未连接或不可用)这是唯一的方法。

如果您要使用中断,您会要求硬件在给定事件发生时通知您。例如,TBF 位被清除,等等...... 这样做的好处是,当硬件在做它的事情时,你可以继续做其他事情。或者只是休眠以节省电池电量。

我不是 I2C 方面的专家,所以我描述的中断事件很可能不准确,但这让您知道为什么会出现 2 个 while 循环。

现在关于基于中断的实现和忙等待实现的优缺点,我想说基于中断的实现更高效但更难编写,因为您必须处理来自硬件的异步事件。忙等待实现容易写,但速度较慢;但这对您来说可能仍然足够快。

最终,我不知道为什么需要 2 NoP。很可能需要进行调整,因为不知何故,CPU 仍然会运行得太快。

【讨论】:

  • 您很少看到的第三个选项是硬件会等待您,这与轮询非常匹配。您执行写入以执行操作或读取以读取状态,该读取保持处理器总线直到操作完成。我见过它,但我亲眼见过的次数还不到五个手指。通常是轮询或中断。
  • 另一个实现实际上是硬件的工作方式。写入是或可能是触发并忘记例如,内存控制器可以获取地址和数据并释放处理器然后关闭并花时间进行写入,但它们只能缓冲这么多。如果您进行过多的写入(可能少至 2 次,具体取决于设计),他们可能不得不推迟处理器,直到他们的写入缓冲区中有空间来存储另一个。也可以用这种方式构建外围设备,但您通常看不到。
  • 很有趣!我希望在我的嵌入式系统工程师职业生涯中看到这一点:D
  • 写缓冲在很多缓存的后面,甚至没有缓存,这是相当普遍的。至于另一个,作为系统工程师,如果/当您处于该位置时,您可以要求/告诉芯片/fpga 设计师这样做。和/或学习verilog,然后自己动手。它有粗糙的副作用,像这样阻止处理器,但一些 dma 引擎也会阻止处理器。
  • 在这种情况下,中断实现的效率会低得多,因为进入和退出中断上下文所花费的所有时间(更不用说通过不必要的缓冲区在应用程序和中断代码之间进行协调)永远无法弥补用于旋转的几条指令。
【解决方案2】:

在执行此类事务 (i2c/spi) 时,您会发现自己处于以下两种情况之一:bit bang 或某种形式的硬件辅助。 bit bang 更容易实现、读取和调试,并且通常可以从一个芯片/系列移植到下一个芯片/系列。但是会烧很多cpu。但微控制器大多是定制硬件,如更容易编程的 cpld 或 fpga。他们在那里假装是硬件设计来消耗 CPU 周期。使用 i2c 或 spi,您试图在设备上的一些 I/O 引脚上创建特定波形,并且有时会锁存输入。总线有一个规范,有时比你的 cpu 慢。有时不需要,有时当您添加软件和编译器开销时,您可能最终不需要用于延迟的计时器,您可能只是够慢了。但理想情况下,您查看波形并简单地创建它,提高引脚 X 延迟 n ms,提高引脚 Y 延迟 n ms,降低引脚 Y 延迟 2*n ms,依此类推。这些延迟可能来自调谐循环(从 0 到 1341 计数)或轮询计时器,直到它达到某个时钟的 Z 个滴答数。大量的 cpu 浪费,但关键是你实际上只是可编程硬件,硬件也会浪费时间等待。

当您的 mcu 中有一个外围设备可以帮助您完成大部分时间但可能不是全部时间时,也许您必须断言/取消断言芯片选择,然后 spi 逻辑处理时钟和数据为您计时。而且这些外围设备通常非常特定于一个芯片供应商的一个家族,可能在芯片供应商中很常见,但从来没有供应商之间的供应商,因此非常不便携,并且有一个学习曲线。也许在您的情况下,如果 cpu 足够快,您可能会以违反总线时序的方式执行下一件事,因此您将不得不消磨更多时间(也许为什么您有那些 Nops()) .

将单片机视为软件可编程 CPLD 或 FPGA,这种浪费就更有意义了。不幸的是,与 CPLD 或 FPGA 不同,您是单线程的,因此您不能在时钟精确时序的同时做几件琐碎的事情(正是这么多时钟任务切换状态并更改输出)。中断有帮助,但不完全相同,更改一行代码,您的时间就会改变。

在这种情况下,尤其是带有 nops 的情况下,您可能无论如何都应该使用示波器来查看 i2c 总线,并且因为/当您将它放在示波器上时,您可以尝试使用和不使用这些调用来查看它如何影响波形.这也可能是外围设备中的错误或功能可能您不能太快地点击某些寄存器,否则外围设备会中断。或者它可能是 5 年前芯片中的一个错误,并且代码是为该错误早已消失而编写的,但他们只是不断重复使用代码,您会在供应商库中看到很多。

【讨论】:

  • 请注意,遗憾的是,clang/llvm 在无限循环中存在问题,我已经看到它破坏了与此类似的操作,而且编译器损坏似乎也没有问题。不会一直中断,但已经看到它在尝试在微控制器上使用它来轮询某些东西时会中断(等待 uart tx 缓冲区为空)。
  • 你不能真正责怪编译器。该代码不严格符合 C 标准。如何让编译器通过硬件交互做正确的事情总是需要特定于平台和编译器的工作。
  • 如此易变的int a; while(1) if (a!=0) 中断;不合法吗?如果是这样,那么就足够公平了...然后需要调用 asm 编码的函数...
  • 绝对合法。但它意味着是特定于平台的。对于某些特定的硬件应用程序来说,它可能不够,也可能不够。例如,想象一个 CPU 需要发出显式指令来查看对某些硬件寄存器的更改,但看不到其他寄存器的更改。这当然是可能的。该代码是否应该在循环中发出该指令? C标准没有说。如果仅此硬件设备需要它并且编译器编写者甚至不知道该硬件存在怎么办?
  • 在 llvm 案例中,我调用了一个单独的优化域中的函数,一个他们无法看到或预测的汇编函数,并且 while 循环对返回值进行操作,所以它甚至不是一个案例volatile 是什么意思等等。它在这个循环中调用了这个函数并查看它的返回值,无法想象这是多么模糊或特定于平台。
【解决方案3】:

您如何看待 while 条件?微芯片不会为此使用大量 CPU 吗?

不,因为传输缓冲区不会长时间保持满。

我问了自己这个问题,惊讶地在网上看到很多类似的代码。

你会建议什么?

没有更好的方法吗? (我讨厌疯狂的循环:D)

我、你或其他任何人都不知道。你认为它在什么方面会更好?传输缓冲区不会保持足够长的时间来重新分配 CPU 任务。

Nop() 也一样,为什么是两个?

Nop 确保信号保持足够长的时间稳定。这使得该代码在所有条件下都可以安全调用。没有它,如果您在调用它后没有立即弄乱 i2c 总线,那么调用此代码才是安全的。但在大多数情况下,这段代码无论如何都会在循环中调用,因此使其具有内在安全性更有意义。

【讨论】:

  • 我不同意所说的大部分内容,抱歉。如果需要 CPU 执行其他工作,那么繁忙的轮询循环确实是个坏主意,并且相对于 CPU 速度,传输缓冲区将保持满的时间过长,因为通信速度非常慢。更好的方法是使用中断驱动或 DMA(如果可用)传输。
  • @EugeneSh。 CPU不能做其他工作,循环只运行几条指令。没有办法利用这么少的时间。
  • 感谢您回答我的问题。我可以看到对于 CPU 在寄存器写入和读取之间可以执行多少工作存在分歧。是否存在可以证明某人是正确的基准或测试或数学演示?
  • 您可以在旋转循环中添加一个计数器来查看它旋转了多少次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-14
  • 1970-01-01
  • 2013-09-26
  • 1970-01-01
  • 2017-04-12
  • 2012-01-20
  • 1970-01-01
相关资源
最近更新 更多