Electrical – How to simplify UART interrupt handlers on Tiva TM4C with SIMcom 900

cinterruptssim900stellarisuart

UARTIntHandler0 interfaces to the USB UART for debugging.

UARTIntHandler1 interfaces to the SIM900 GSM module.

The purpose of UARTIntHandler0 is very simple – grab an incoming character and push it to UART1 (the GSM module).

UARTIntHandler1 is more complicated. In "talk mode," it should allow the user to talk directly to the GSM module – that is, any characters coming on the UART are simply pushed to the other UART so the user can see them via terminal connection.

In normal mode, the interrupt is triggered by any input from the GSM, and does some processing if this input is a message notification. Any other input is ignored by the interrupt handler (but still populates the buffer, where other portions of the code can access it).

I know that the UARTIntHandler1 (and possibly the other as well) is too big for an interrupt routine: When the program is done, there will be at least seven interrupt sources (GSM UART, console UART, ADC, three timers, and hardware interrupt from keypad) so I want to keep them short.

My question is, how much should I expect it to do in this situation, and how much should I hand off to a different function by setting flags for the main program? Please note this code is working most of the time, but it's when it doesn't work (poor cell signal, long messages, etc) that it really hurts. I am suspicious that my interrupt handling is the problem.

In my main program, I have a superloop running which periodically checks if the message count has been incremented.

Some global stuff:

// Used by UART interrupt handlers
unsigned char var;                  // Incoming UART character
unsigned char ptr[10000];           // Array for storing incoming UART characters
unsigned long i;                    // UART character pointer.
unsigned long ulStatus0,ulStatus1;  // To hold the interrupt status  

The console UART:

void
UARTIntHandler0(void)
{
    // Get the interrupt status.
    ulStatus0 = ROM_UARTIntStatus(UART0_BASE, true);

    // Clear the asserted interrupts
    ROM_UARTIntClear(UART0_BASE, ulStatus0);

    // Loop while there are characters in the receive FIFO.
    while(ROM_UARTCharsAvail(UART0_BASE))
    {
        // Grab a character
        var = (unsigned char)ROM_UARTCharGetNonBlocking(UART0_BASE);

        // Hold it
        ptr[i] = var;

        // Mirror it to GSM
        ROM_UARTCharPutNonBlocking(UART1_BASE, ptr[i]);

        // Proceed to next character
        i++;
    }
}

The GSM UART:

void
UARTIntHandler1(void)
{
    char *msgCountStr;                  // Number of new messages
    static char g_cInput[128];          // String input to a UART

    // Get the interrupt status.
    ulStatus1 = ROM_UARTIntStatus(UART1_BASE, true);

    // Clear the asserted interrupts.
    ROM_UARTIntClear(UART1_BASE, ulStatus1);

    // Interrupt trigger means GSM is on
    if ( GSMoff ) { GSMoff = false; }

    // Loop while there are characters in the receive FIFO.
    while(ROM_UARTCharsAvail(UART1_BASE))
    {
        // Grab a character
        var = (unsigned char)ROM_UARTCharGetNonBlocking(UART1_BASE);

        // Hold it
        ptr[i] = var;

        // In talk mode mirror to console...
        if (talkMode) { ROM_UARTCharPutNonBlocking(UART0_BASE, ptr[i]); }

        // ...or else see if it's a message notification (like +CMTI: "SM",12):
        else 
        {
            if(ptr[i-3] == 'C' && ptr[i-2] == 'M' && ptr[i-1] == 'T'&& ptr[i] == 'I')
            {
                // Grab everything
                UART1gets(g_cInput,sizeof(g_cInput));

                // Stop after newline character
                msgCountStr = strtok(g_cInput,"\n");

                // Parse out the message count (terminate with null to store)
                strncpy(msgCountStr,msgCountStr+7,3);
                msgCountStr[3]='\0';

                // Convert to integer
                sscanf(msgCountStr, "%d", &msgCount);

                // Tell the user
                UART0printf("\n\r>>> %u NEW MESSAGE(S)",msgCount);
            }
        }
        // Proceed to next character
        i++;
    }
}

Best Answer

Usually the idea is that you grab the character, put them in a circular buffer and handle the data in a function called from the superloop. You do them it seemds, all you need is properly handling the circularity. In fact in your UART1 handler I don't see any kind of condition to check for buffer overflow on incoming data - i should wrap around the size of whatever it is prt points to.

In a similar application I actually have 3 buffers - one to handle data coming in from the PC (I have to parse it somewhat), one to handle data incoming from radio and one temporary for parsing.