在不同的 eUSCI 部件上、定义了一个 IV (中断向量)、它给出了一个数字代码、表示实际向量的不同中断源中的哪一个已发出、已启用、并且是最高优先级。 这很好。
但是、读取该寄存器具有清除与上述四项相关的 IFG 的副作用 这很糟糕。 让我来展示一下原因...
例如、让我们讨论 eUSCI UART 的传输侧。 根据定义、TXIFG 为1 (有效)表示 TXBUF 为空、另一个字节可以写入 TXBUF 进行传输。 这是非常基础的。 如果 TXIFG 为0、则不应写入 TXBUF。
但现在考虑以下 eUSCI UART 的中断驱动发送代码。
首先是发件人:
ERROR_t GPS_SEND_BLOCK (uint8_t * ptr、uint16_t len){ if (!len ||!ptr) 返回失败; 如果(m_TX_Buf) 返回 EBUSY; m_TX_len = len; m_TX_idx = 0; m_TX_Buf = ptr; // *启动时应将 UCTXIFG 置为有效,因此启用 TX 中断 *应导致调用 ISR。 // //调用 USCI.enableTxIntr (); BITBAND_peri (EUSCI_A2->IE、EUSCI_A_IE_TXIE_OFS)= 1 返回成功; }
m_TX_Buf 用于保存指向我们要传输的缓冲区的指针、m_TX_idx 是我们在该缓冲区中的位置(要传输的下一个字节)、而 m_TX_len 是我们要传输的字节数量。
我们使用这样一个事实、即 TXIFG 应该挂起且具有一个空 TXBUF、以便在我们打开中断时立即将我们启动。
这里是中断服务例程。 仅显示 TX 部分。
void EUSCIA2_Handler()@C()@nived()__attribute__((interrupt){
uint8_t data;
uint8_t *buf;
switch (EUSCI_A2->IV){
MSP432U_IV_TXIFG 案例:
if (m_TX_idx >= m_TX_len){
buf = m_TX_Buf;
// USCI.disableTxIntr ();
BITBAND_PERI (EUSCI_A2->IE、EUSCI_A_IE_TXIE_OFS)= 0;
m_TX_Buf =空;
GPS_SEND_BLOCK_DONE (buf、m_TX_len、sucf);
返回;
}
数据= m_TX_Buf[m_TX_idx+];
// Usci.setTxbuf(data);
EUSCI_A2->TXBUF =数据;
返回;
}
现在、在最后一个字节上、我们将中断、m_TX_idx 将为 m_TX_len - 1、我们将最后一个字节填充到 TXBUF 中并从中断返回。 当最后一个字节从 TXBUF 转移到移位寄存器进行传输时、TXIFG 将再次出现、我们将中断。
通过在 switch 语句中读取 IV 寄存器、TXIFG 将被清零。 我们将看到 m_TX_idx >= m_TX_len 并输入终止子句。 我们将禁用 TxInterrupt 并进行标注以指示传输已完成。
但请注意、TXBUF 为空、TXIFG 清零、表示 TXBUF 已满。 这是错误的。 当读取 EUSCI_A2->IV 且 TXIFG 中断具有最高优先级时、清除 TXIFG 会产生副作用、这是直接结果。 如果我们尝试触发另一个 send_block、它将失败、因为当我们打开中断时、TXIFG 会关闭、我们不会进入中断例程来启动新的发送。 TXIFG 永远不会再次出现、因为没有任何东西会使它生效。 我们可以写入 TXBUF、这最终会使事情再次正常工作、但从技术上讲、这是不允许的、因为除非 TXIFG 为1、否则应该写入 TXBUF、表明 TXBUF 为空。
解决方法:
1) 1)将中断例程重新排序为类似的内容:
void EUSCIA2_Handler()@C()@nived()__attribute__((interrupt){
uint8_t data;
uint8_t *buf;
switch (EUSCI_A2->IV){
MSP432U_IV_TXIFG 案例:
数据= m_TX_Buf[m_TX_idx+];
// Usci.setTxbuf(data);
EUSCI_A2->TXBUF =数据;
if (m_TX_idx >= m_TX_len){
buf = m_TX_Buf;
// USCI.disableTxIntr ();
BITBAND_PERI (EUSCI_A2->IE、EUSCI_A_IE_TXIE_OFS)= 0;
m_TX_Buf =空;
GPS_SEND_BLOCK_DONE (buf、m_TX_len、Success);
}
返回;
}
因此、当写入最后一个字节时、我们会检测到这一点并禁用中断。 由于 TXIFG 的中断被禁用、当硬件完成移位寄存器中的字节的发送并将 TXBUF 复制到移位寄存器中时、TXBUF 将变为空、TXIFG 将变为1、并且不会发生中断。 由于不会发生中断、因此不会读取 EUSCI_A2->IV、也不会发生问题。 存在一个有效状态、这意味着 TXBUF 为空并且 TXIFG 被置为有效、这表明了这种情况。
那么、解决这个问题的方法是什么呢? 当我们发出信号完成时、HW 状态为 TXBUF 已满、TXIFG 无效。 信令完成表示当前发送已完成,如果需要,您可以触发另一个发送。 如果立即启动另一个发送、则必须等待发送完成前仍在进行中。 这将是一个字节时间、在低波特率下可能会很重要。
但它可以正常工作、这正是我目前对基于 MSP432的设计所做的工作。
2)将第四条改为"已死亡"的国际金融集团替换为"已死亡"。
在第一个示例中断处理程序中、将 BITBAND_PERI (EUSCI_A2->IFG、EUSCI_A_IFG_TXIFG_OFS)放置为1。 这将使 TXIFG 重新生效。
但是、不清楚这是如何与硬件的其余部分进行交互的。 BITBAND 操作将指示存储器系统对保存 TXIFG 标志的外设寄存器执行原子访问。 但不清楚的是、其余 eUSCI h/w 是如何与该寄存器交互的。 例如、如果一个 RXIFG 需要被置位(或者 STTIFG、START 中断标志)、是否有可能由于与代表 TXIFG 写入的存储器系统置位 IFG 寄存器的交互而丢失这个标志?
换言之、确保不存在硬件竞态条件是有问题的。
总之、使 h/w 中断系统自动清零 TXIFG 标志是有问题的/次优的。 这样做会为导致问题的 h/w 创建一个无效状态。
今后最好不要这样做。