Below is a stripped down version (with some macros also partially expanded) of the ISR function used for USCI_A0 in UART mode. While running this through a BACnet MS/TP protocol, I'm seeing a few overrun errors, but I'm also seeing a larger number of interrupts where the IV value is 0 and falling to the default case. Our BACnet stack is occasionally failing received frames where there are a few bytes missing (generating an eventual CRC error), but I haven't been able to confirm if these failures are exclusively from the overrun errors.
- How is it possible to trigger an interrupt with the IV register value at 0?
- Is it possible that some received bytes are generating an interrupt without setting the USCI_UART_UCRXIFG flag (resulting in lost data)?
- Is there a potential race condition scenario that I should be avoiding when enabling/disabling the interrupts in the UCA0IE register and clearing the flags in the UCA0IFG register?
void _uartISR(void) { uint16_t err; switch(_even_in_range(HWREG16((0x05C0) + OFS_UCAxIV), USCI_UART_UCTXCPTIFG)) { case USCI_UART_UCRXIFG: // Read the error status before unloading the rx buffer. err = HWREG16((0x05C0) + OFS_UCAxSTATW); *m_rx.pHead = HWREG16((0x05C0) + OFS_UCAxRXBUF); if(err & (UCFE | UCOE | UCPE)) { if(err & UCFE) g_nRxErrors.framing++; else if(err & UCOE) g_nRxErrors.overrun++; else if(err & UCPE) g_nRxErrors.parity++; else g_nRxErrors.undefined++; } break; case USCI_UART_UCTXCPTIFG: if(!(HWREG16((0x05C0) + OFS_UCAxSTATW) & UCBUSY)) { // Disable UART tx complete interrupt. do {HWREG16((0x05C0) + OFS_UCAxIE) &= ~((0x0008)); _nop();} while(0); do {HWREG16((0x05C0) + OFS_UCAxIFG) &= ~((0x0008)); _nop();} while(0); // Enable rx interrupt. do {HWREG16((0x05C0) + OFS_UCAxIFG) &= ~((0x0002)); _nop();} while(0); do {HWREG16((0x05C0) + OFS_UCAxIE) |= ((0x0001));} while(0); } break; default: g_nRxErrors.ivZero++; break; } }