Russell Russell - 8 days ago 5
C Question

MSP430 UART TX Interrupt Enabling/Disabling

I have RX interrupts working just fine, but I wanted to add TX interrupts. I respond to long commands over the UART and don't want to waste cycles waiting for the TX to complete before sending along the next byte. I am trying to enable interrupts, transmit the data that needs to be transmitted, then disable the interrupts until the next TX packet comes along.

This works fine for the FIRST payload that I send out. I see it go out just fine. However as soon as I disable TX Interrupts once, I am never able to enter the ISR again. How on the MSP430 does one enable TX Interrupts on the UART and have it ever get into the ISR again?

Below where you see EUSCI_A_UART_enableInterrupt call, shouldn't this line trigger my ISR every time the interrupt gets enabled? If not, HOW DO I GET BACK INTO THE ISR AGAIN?

Here's the Transmit code:

void UartSendChar(uint8_t tx_char)
{
ring_buffer_put(_rbdTx, &tx_char);
EUSCI_A_UART_enableInterrupt(EUSCI_A1_BASE, EUSCI_A_UART_TRANSMIT_INTERRUPT); // Enable interrupt
}


Here's my ISR:

void EUSCI_A1_ISR(void)
{
int c=-1;
switch(__even_in_range(UCA1IV,USCI_UART_UCTXCPTIFG))
{
case USCI_NONE: break;
case USCI_UART_UCRXIFG:
...
case USCI_UART_UCTXIFG:
// If there's something in the Ring Buffer, transmit it
// If not, then disable TX interrupts until new data gets written.
if (ring_buffer_get(_rbdTx, &c) == 0)
{
EUSCI_A_UART_transmitData(EUSCI_A1_BASE, (uint8_t)c);
}
else
{
EUSCI_A_UART_disableInterrupt(EUSCI_A1_BASE, EUSCI_A_UART_TRANSMIT_INTERRUPT);
}

Answer

I figured out the problem. In this particular MSP430, when the interrupt vector is read and it shows a TX interrupt, the TXIFG bit automatically gets cleared by the micro. (How nice of it)

In order to get this ISR to fire again after re-enabling TX interrupts, the TXIFG bit must be manually set back to 1 again, which shows an interrupt pending. That way, when interrupts are enabled after data is shoved into the queue, the TXIFG bit is set, so the ISR executes and ships the data off.

Now my ISR looks like this:

void EUSCI_A1_ISR(void)
{
    int c=-1;
    switch(__even_in_range(UCA1IV,USCI_UART_UCTXCPTIFG))
    {
    case USCI_NONE: break;
    case USCI_UART_UCRXIFG:
       ...
    case USCI_UART_UCTXIFG:
        // If there's something in the Ring Buffer, transmit it
        // If not, then disable TX interrupts until new data gets written.
        if (ring_buffer_get(_rbdTx, &c) == 0)
        {
            EUSCI_A_UART_transmitData(EUSCI_A1_BASE, (uint8_t)c);
        }
        else
        {
            EUSCI_A_UART_disableInterrupt(EUSCI_A1_BASE, EUSCI_A_UART_TRANSMIT_INTERRUPT);

            // Set TXIFG manually back to 1 for next time.
            HWREG16(EUSCI_A1_BASE + OFS_UCAxIFG) |= EUSCI_A_UART_TRANSMIT_INTERRUPT;

        }
Comments