假设您有一些数据传输外设,如UART,只要它准备好传输更多数据就会发出中断信号。我们从循环缓冲区发送数据,其中tail
是数据从中删除的位置,head
是添加数据的位置,而tail == head
表示没有更多数据要传输。
我们还假设外围设备没有任何缓冲,并且当它忙于发送当前值时,您无法将下一个值传递给它。如果你需要一个具体的,如果是一个例子,可以考虑一个直接连接到CPU并行I / O端口的移位寄存器。
为了使发送器尽可能忙,您可能希望在输入发送中断处理程序后立即发送。当没有数据要传输时,中断被屏蔽掉,即使中断已经布防,也不会调用处理程序。系统启动时中断屏蔽。
我将使用C来说明事情,尽管问题不是特定于C的。中断处理程序和缓冲区的设置如下:
char buf[...];
char * head = buf; ///< write pointer
char * tail = buf; ///< read pointer
char * const first = buf; ///< first byte of the buffer
char * const last = buf+sizeof(buf)-1; ///< last byte of the buffer
/// Sends one byte out. The interrupt handler will be invoked as soon
/// as another byte can be sent.
void transmit(char);
void handler() {
transmit(*tail);
if (tail == last)
tail = first;
else
tail++;
if (tail == head)
mask_interrupt();
}
到目前为止,这么好。现在让我们看看如何实现putch()
。我们可以比设备能够发送数据更快地以突发方式调用putch()
。让我们假设调用者知道不要溢出缓冲区。
void putch(char c) {
*head = c;
if (head == last)
head = first;
else
head++;
/***/
unmask_interrupt();
}
现在假设发生了这些事情:
putch
时,正在发送一个字节。putch
位于上方标有/***/
的地点时,传输即将结束。 handler()
恰好在那里执行。 handler()
碰巧发送缓冲区中数据的最后一个字节 - 我们刚刚在putch()
中的前一行中加载的字节。处理程序屏蔽了中断,因为没有更多数据要发送,但putch
在handler()
返回后错误地取消屏蔽。因此handler
将有另一个通过缓冲区,并将发送缓冲区的过时数据,直到tail
再次等于head
。
我的问题是:在发送handler
之前,唯一的解决方法是增加延迟并检查空缓冲区吗?固定代码如下所示:
void fixed_handler() {
if (head == tail) {
mask_interrupt();
arm_interrupt(); // so that next time we unmask it, we get invoked
return;
}
transmit(*tail);
if (tail == last)
tail = first;
else
tail++;
}
此修补程序增加了一些延迟,并且还添加了一个额外的操作(arm_interrupt
),当没有更多数据要发送时,该操作会执行一次。
对于可能的其他方法,请随意假设至少存在以下操作:
/// Is the interrupt armed and will the handler fire once unmasked?
bool is_armed();
/// Is the interrupt unmasked?
bool is_unmasked();
答案 0 :(得分:2)
我总是使用双缓冲完成此操作,因此在任何时间点程序和UART都“拥有”不同的缓冲区。
当UART完成发送缓冲区时,可能会发生交换,中断被屏蔽。 这样,它就不必掩盖每个角色的中断。
答案 1 :(得分:0)
一种解决方法是阻止中断处理程序在putch
中运行:
void putch(char c) {
*head = c;
mask_interrupt();
if (head == last)
head = first;
else
head++;
unmask_interrupt();
}
这让我们可以使用原始的发送优先中断处理程序。问题在于它总体上增加了每个发送字节执行的操作数。它也会增加峰值延迟,因为现在有时handler()
根本无法运行,即使硬件已准备好接收更多数据和也要发送数据。
使发送器再次忙碌的平均延迟由中断处理程序决定。最重要的峰值延迟由延迟执行中断处理程序的代码决定。