我正在尝试在 GPIO 引脚(ARM 平台,mach-davinci,内核 2.6.27)上生成时钟信号,该信号的频率为 100kHz。使用具有高优先级的 tasklet 来做到这一点。原理很简单,设置gpio高,udelay为5us,设置gpio低,再等5us,但是出现了奇怪的问题。首先,不能得到这个 5us 的 dalay,但没关系,看起来像硬件性能问题,所以我移到 period = 40us(给出 ~25kHz)。第二个问题是最糟糕的。每约 10 毫秒一次,udelay 的等待时间比平时长 3 倍。我认为这次是心跳,但从协议(将在此之上实现)的角度来看,这是不可接受的。有什么方法可以暂时禁用心跳程序,比如说,500ms?或者也许我从一开始就做错了?任何意见?
3 回答
您不能将 tasklet 用于此类工作。小任务可以被中断抢占。在某些情况下,您的 tasklet 甚至可以在流程上下文中执行!
如果您绝对必须这样做,请使用中断处理程序 - 进入,禁用中断,做任何您必须做的事情并尽快离开。
在软件中异步生成时钟不是正确的做法。我可以想到两种效果更好的替代方案:
您的处理器可能有一个内核或其他驱动程序尚未使用的内置时钟发生器外围设备。当你设置其中之一时,你告诉它运行时钟的速度有多快,它就会开始耗尽脉冲。
获取处理器的数据表并进行研究。
您可能找不到本身称为“时钟”的外围设备,但可能会找到类似的东西,您可以将其投入使用,例如 PWM 外围设备。
您正在与之交谈的其他设备实际上可能不需要常规时钟。一些需要“时钟”线的芯片只需要一条在有要读取的位时变高的线,然后在数据线发生变化时变低。如果是这种情况,您正在读取的 100 kHz 的内容对于恰好具有该频率的时钟并不是硬性要求,它只是时钟线(以及数据线)多快的上限被允许过渡。
CPU 比时钟快得多,你想把它分成两半:
“上半部分”正确设置数据线状态,然后将时钟线拉起。然后它使用中断或内核定时器安排下半部分在 5 μs 后运行。
在由中断或定时器调用的“下半部分”中,将时钟线拉回,然后安排上半部分在 5 μs 后再次运行。
除非您可以以比内核计时器更高的优先级运行计时器 tasklet,否则您将始终容易受到这种抖动的影响。你真的必须通过bit-ganging来做到这一点吗?使用硬件定时器或 PWM 发生器会容易得多。将定时器配置为以您想要的速率运行,将引脚设置为输出,您就完成了。
如果您需要对每个位周期进行软件控制,您可以尝试通过将 tasklet 设置为在短时间内运行来解决其他任务,例如 40 us 延迟的四分之三。在 tasklet 中,禁用中断并轮询时钟,直到到达正确的 40 us 时隙,设置 I/O 状态,重新启用中断,然后退出。但这有效地占用了系统 25% 的时间来观看时钟。