1
\$\begingroup\$

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++;
    }
}
\$\endgroup\$
  • \$\begingroup\$ "In normal mode, the interrupt handler waits for message notifications from the GSM, and ignores everything else." -- an interrupt handler should not be waiting for anything. \$\endgroup\$ – Scott Seidman Jan 7 '16 at 17:18
  • 1
    \$\begingroup\$ scanf & printf in an interrupt handler ... seems like asking for trouble imo ... \$\endgroup\$ – brhans Jan 7 '16 at 17:19
  • \$\begingroup\$ I know that the UARTIntHandler1 (and possibly the other as well) is too big for an interrupt routine. can you elaborate as to why you think this? \$\endgroup\$ – Funkyguy Jan 7 '16 at 17:23
  • \$\begingroup\$ What other processing is happening, and what else needs to be done? A reasonable judgement about the interrupt handlers needs to also have some idea about what else is happening (which may cause a problem), and what else needs to happen (to suggest reasonable technical approaches). Usually, and interrupt handler gets characters from a peripheral interface, and puts them into a buffer (array), and actual processing happens outside the handler, in the main body of the program. However, if there is nothing else to do, and the data rates are low-enough, you have lots of flexibility. \$\endgroup\$ – gbulmer Jan 7 '16 at 18:10
1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ Is a circular buffer something I would need to write from scratch, or would it likely be included in some driver/function by the hardware manufacturer? I'm working with Tiva/Stellaris TM4C. \$\endgroup\$ – LShaver Jan 8 '16 at 2:50
  • \$\begingroup\$ Something you write fro,m scratch, but it takes something on the order of 50 lines to implement and IMO is really easy. And works well. Of the buffer mentioned in my reply only one is actually circular - other don't need to. \$\endgroup\$ – Jan Dorniak Jan 8 '16 at 15:58
0
\$\begingroup\$

how much should I expect it to do in this situation, and how much should I hand off to a different function

Doing the instructions in your interrupt service routine over passing the handling to a different function makes absolutely no difference. What happens when the interrupt comes in is the CPUs current "thread" is halted and priority is given to the interrupt service. Handing the handling of the interrupt to another function within that interrupt routine is pointless

\$\endgroup\$
  • \$\begingroup\$ I edited to clarify. I meant: how much should be processed by setting a flag for the main program to deal with in a separate function? \$\endgroup\$ – LShaver Jan 8 '16 at 2:34
0
\$\begingroup\$

One thing you can do is set different priorities for each interruption. For example, you can set highest priority for your timers, then lower priorities for the uarts. The TivaC microcontroller has 8 different levels. 0 is the highest and 7 is the lowest. This is one example from page 354 of the TivaWare™ Peripheral Driver Library User's Guide.pdf

// // Set the UART 0 interrupt priority to the lowest priority. // IntPrioritySet(INT_UART0, 0xE0);

I am also having the same problem, but it is with xbee in order of gsm module.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.