我需要为 linux 内核实现 PWM 模块,它应该是高分辨率的(在我的 400MHz ARM cpu 上会超过 10kHz)任何人都可以给我一个建议,我可以用什么来实现这个目的?内核版本为 2.6.28.9。设备没有硬件 PWM 驱动程序。现在我使用一个内核定时器,其频率由 CONFIG_HZ 设置。这个配置的默认值是100HZ,但对我来说太小了,最大值是4kHZ,但这仍然不够
2 回答
脉冲宽度调制在软件中非常非常难以实现。理论上,您所要做的就是在您的 CPU 中找到一个具有足够分辨率的计时器,附加一个 IRQ 处理程序并启动它。
如果你看一下时钟,你会觉得你不能在 400 MHz CPU 上执行 10 kHz PWM 感觉很疯狂——你每个脉冲会有 400000/10 = 40000 个 CPU 周期,这肯定够了吗?
也许不吧。linux内核使用中断本身来进行内核调用。然后你有其他中断(DMA,NMI,其他计时器,...)。根据定时器中断的优先级,其中一些可以阻止它。这意味着网络操作或其他事情可能会延迟您的 IRQ 处理程序。如果您使用 Linux 内核 API 来处理中断,那么您会遇到更多问题:内核不会调用您的处理程序。相反,真正的 IRQ 处理程序将收集有关中断的一些信息并将其作为任务附加到链中。
最终,内核将查看该链并处理其中的任务。
另一个问题是 CPU 也不会立即响应 IRQ。有些操作码是您无法中断的。
这会导致很多抖动。
如果您想尝试它,那么您应该在汇编程序中编写自己的 IRQ 处理程序,该处理程序执行所有处理 - 获取 IRQ 并写入新的输出值。不要使用标准的 linux 中断 API。然后你必须禁用这个定时器的中断 API(或者内核可能会删除你的处理程序)。
你必须使用一个在你的 CPU 中具有非常非常高优先级的计时器——任何可以延迟它的东西都会毁了你的一天。
即使你有 40K CPU 周期要花费:总有其他软件也想咬一口。所以你可能无法运行其他任何东西。
“如果你想要一些精确的时序,请使用硬件 PWM。软件会有太多的偏差、抖动等。即使付出巨大的努力,它也远非好(更不用说完美)。”
上面的答案并不完全正确,尽管它显示了 PWM 的一些问题:
问题是,无论输出信号是来自硬件 PWM 发生器还是来自软件控制的 GPIO,应用程序都必须在单个 PWM 周期内执行所有计算。否则,抖动将被观察为不正确的平均 PWM 值或不正确的平均信号相移。
换句话说,使用硬件 PWM 的唯一好处是计算可以与 PWM 脉冲边沿异步完成,但它们必须与 PWM 周期的开始/结束同步。