This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

UART 0 interrupt service routine called repeatedly

Other Parts Discussed in Thread: EK-TM4C123GXL

Hi all.

I am using a Tiva Launchpad EK-TM4C123GXL.and was trying to get console activity on UART0 and UART1. I haven't done anything with UART 1 yet so I don't know if the same problem will occur on that UART also. If its important then you can know that the part is configured to operate at 80MHz.

What I did was take the uartstdio.c file and hack it by essentially duplicating all the functions and making them uart specific (one for UART0 and the other set for UART1). The code is identical and I haven't change the functionality. The problem I am experiencing also occurs if I just attach UART0 to the <unmodified> uartstdio.c directly and not use my modified variant.

UART0 is in fact working fine - it transmits characters [if you can get them into the buffer] and echoes received characters without any problems (since this is done from within the ISR). This functionality distracted me from the true source of the problem since I thought that the UART interrupt was working fine.

In the application ADC0 interrupts and SYSTick interrupts are enabled and working perfectly. I have a UART0printf() call every 1 second from within the SYSTick ISR which prints out ADC and time information and it scrolls up the console screen perfectly. However what does seem to happen is after whatever is in the initial transmit buffer is sent out the serial port (transmitted) the interrupt is repeatedly called. I have put GPIO toggles around the entry and exit of the UART0 handler and it runs for about 900ns then is back 700ns later [except when there is something to transmit or so...] I have copied the UARTStatus register value to an external location and printed that value out. When masked the status register is 0x0000, and the unmasked value is 0x000F indicating that the modem control signals need attention (but the UART is working without any handshaking).

Whatever is happening out of interrupt service land can occur up until the end of whatever is first sent, thereafter only interrupt service land exists and I can't do anything useful. If anyone can suggest how normal service might be resumed, I would be very grateful.

 

So, the configuration is like this :

-----

  // Enable the peripherals used

  SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

  // UART0 is on peripheral A

  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

  // Set GPIO A0 and A1 as UART pins.

  GPIOPinConfigure(GPIO_PA0_U0RX);

  GPIOPinConfigure(GPIO_PA1_U0TX);

  GPIOPinTypeUART (GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

 /* console on UART0            */

  UART0StdioConfig();

 

---------------------

 

The further configuration

 

---------------------

void UART0StdioConfig(void) {

  /* Enable the UART peripheral for use       */

  SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

 /* Configure the UART for 115200, 8N1       */

  UARTConfigSetExpClk(UART0_BASE,       SysCtlClockGet(),       115200,       (UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE | UART_CONFIG_WLEN_8));

 /* Set the UART to interrupt   * - whenever the TX FIFO is almost empty   * - whenever any character is received   */

UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);

 // UARTFlowControlSet(UART0_BASE, UART_FLOWCONTROL_NONE);

  UARTIntClear(UART0_BASE, UARTIntStatus(UART0_BASE, false));

 /* Flush both the buffers          */

  UART0FlushRx();

  UART0FlushTx(true);

 /* enable interrrupts           */

  UARTIntDisable (UART0_BASE, 0xFFFFFFFF);

  UARTIntEnable (UART0_BASE, UART_INT_RX | UART_INT_RT);

  IntEnable  (INT_UART0);

  /* enable the UART            */

  UARTEnable  (UART0_BASE);

 }

 

----------------------------------------------

 

And the ISR

 

-------------------------------------------------

void UART0intHandler(void) {

  unsigned long interrupts;

  char   data;

  unsigned long value;

  static bool  lastCR = false;

  /* Get and clear the current interrupt source(s)    */

  interrupts  = UARTIntStatus(UART0_BASE, true);

  temporary  = UARTIntStatus(UART0_BASE, false);

  UARTIntClear(UART0_BASE, interrupts);

 /* Handle transmit FIFO draining        */

  if (interrupts & UART_INT_TX) {

   /* fill it up            */

   UART0Tx();

  /* turn off the transmit interrupt?       */

   if (TX0_BUFFER_EMPTY)

   UARTIntDisable(UART0_BASE, UART_INT_TX);

 }

 /* Handle receive interrupts         */

  if (interrupts & (UART_INT_RX | UART_INT_RT)) {

   /* transfer to the buffer         */

   while (UARTCharsAvail(UART0_BASE)) {

    value  = UARTCharGetNonBlocking(UART0_BASE);

    data  = (char)(value & 0xFF);

   /* convert "\r\n" to "\r" only       */

    if((data == '\n') && lastCR) {     lastCR  = false;     continue;    }

   /* make '\n' the only line terminator     */

    if ((data == '\r') || (data == '\n') || (data == 0x1B)) {

     /* isolated CR was received       */

     if (data == '\r')

      lastCR  = true;

    data  = '\n';

    }

   /* handling echoes          */

    if (!DisableEcho0) {

     if (data == '\b') {

      /* delete the last character     */

      if (!RX0_BUFFER_EMPTY) {

       // Rub out the previous character on the users

       // terminal.

       UART0write("\b \b", 3);

       /* strip the character      */

       if (UART0RxWriteIndex == 0) {

        UART0RxWriteIndex = UART_RX_BUFFER_SIZE - 1;

       } else {

        UART0RxWriteIndex--;

       }

      }

      /* read the next character      */

      continue;

     }

    }

   /* buffer the character or throw it away    */

    if (!RX0_BUFFER_FULL) {

     UART0RxBuffer[UART0RxWriteIndex] = data;

     RX_BUFFER_ADVANCE(UART0RxWriteIndex);

    /* echo the character to the transmit buffer  */

     if (!DisableEcho0)

      UART0write(&data, 1);

    }

   }

  }

 }

 

 

 

 

 

 

 

 

 

 

  • jonathan pratt said:
    When masked the status register is 0x0000

    This makes me think that maybe you have accidentally configured your UART0intHandler to handle something else than UART0 interrupts, too - UART1 perhaps?

  • OMG!  a genius!

     

    Cut and paste error in startup_gcc.c  not sure why there was a UART1 interrupt some time after the UART0 was active but that was the cause.

     

    much gratitude!

  • It looks like Veikko beat me to an answer! A couple of other things come to mind that will probably save you some headaches later.

    1. Calling UARTprintf from within the Systick handler can be a bad idea unless you are careful to use the buffered (interrupt-driven) option for uartstdio or you reduce the Systick exception priority. By default. Systick is higher priority than the peripheral interrupts so anything long you do in your Systick handler will hold off all other interrupts. Generally, this is a bad thing because you can start losing data. Rather than performing the time-consuming output function in the handler, I would suggest you set a flag in the handler and have the main loop look for the flag, clear it then perform the output option out of interrupt context.

    2. Copying all the UARTstdio functions is an easy solution but poses a maintenance problem because you need to remember to modify 2 functions any time there is a change. I would recommend changing the module to add an extra ui32Base or ui32Index parameter to each function so that you only have one copy of the code and it uses either UART0 or UART1 depending upon the new parameter. If you don't like the idea of having to modify all calls to include this new parameter, just define some macros for UART0printf and UART1printf that add the parameter for you. This also has the distinct benefit that your final application image with be rather smaller - UARTprintf, for example, isn't a small function!