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 RX problem when leaving Deep-Sleep mode

Other Parts Discussed in Thread: TM4C1237H6PZ

Hi,


I am seeing some strange behavior when using the UART of the TM4C1237H6PZ MCU in Deep-Sleep. The module is clocked by the 16 MHz internal oscillator which is also active in Deep-Sleep. When waking up on a UART interrupt, if I immediately read the RX FIFO I always get 0x00. However, if (after checking that data is received with UARTCharsAvail) I wait some microseconds, I get the correct value. Below is the relevant code.

Kind regards
Per

static void init_uart_as_uart_master(void)
{
   // Enable GPIO port
   ROM_SysCtlPeripheralEnable(DEBUG_UART_PORT_PERIPHERAL);
   
   // Enable UART peripheral
   ROM_SysCtlPeripheralEnable(DEBUG_UART_PERIPHERAL);
   
   // Set UART signals
   ROM_GPIOPinTypeUART(DEBUG_UART_PORT_BASE, PIN_DEBUG_URX | PIN_DEBUG_UTX);
   
   // Configure UART
   ROM_UARTClockSourceSet(DEBUG_UART_BASE, UART_CLOCK_PIOSC);
   ROM_UARTConfigSetExpClk(DEBUG_UART_BASE, MCU_PIOSC_HZ, BAUD_RATE,
                           (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                            UART_CONFIG_PAR_NONE));
                            
   // Disable hardware flow control
   UARTFlowControlSet(DEBUG_UART_BASE, UART_FLOWCONTROL_NONE);
}

static void init_uart_interrupts(void)
{
   // Generate UART receive / transmit interrupts when FIFO is more than 1/8 full
   ROM_UARTFIFOLevelSet(DEBUG_UART_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
   
   // Enable UART receive and receive timeout interrupts
   ROM_UARTIntEnable(DEBUG_UART_BASE, UART_INT_RX | UART_INT_RT);
   
   // Clear any pending interrupts
   ROM_UARTIntClear(DEBUG_UART_BASE, UART_INT_RX | UART_INT_RT);
   
   // Gate UART module interrupts to mcu core
   ROM_IntEnable(DEBUG_UART_INT);
}

void debug_uart_isr_handler(void)
{
   uint32_t status = ROM_UARTIntStatus(DEBUG_UART_BASE, true);
   
   if ((UART_INT_RX | UART_INT_RT) & status)
   {
      while (ROM_UARTCharsAvail(DEBUG_UART_BASE))
      {
         char c;
         
         // NB! ~5 microseconds delay is needed to get correct RX FIFO data when
         // leaving deep sleep. Without this, ROM_UARTCharsAvail returns 0x00.
         // This should not be needed since UARTCharsAvail returns true.
         // Question to be answered by TI FAE.
         mcu_wait_us_blocking(10);
         
         c = ROM_UARTCharGetNonBlocking(DEBUG_UART_BASE);
         
         // Send to debug channel parser
         debug_parser_putc(c);
      }
      
      ROM_UARTIntClear(DEBUG_UART_BASE, UART_INT_RX | UART_INT_RT);
   }
}

  • Hello Per,

    Could it be possible that there is no data in the RXFIFO because of which the FIFO sends out 0x00? What is the source of wakeup from deep sleep.

    Regards
    Amit
  • As stated above, ROM_UARTCharsAvail(DEBUG_UART_BASE) returns true. It works without entering sleep mode, and the interrupt criteria are the same.

  • Hello Per

    I would need to run the scenario locally. Can you please share the Deep Sleep Clock/Power Settings and Run Mode Clock Settings? My intent is to reproduce the test with settings and use a Serial COM Terminal to send a byte and read it back with and w/o the WA.

    Regards
    Amit
  • Hi Amit,

    I think this should be enough:

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    ROM_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    ROM_UARTConfigSetExpClk(UART0_BASE, 16000000, 57600,
                            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_PAR_NONE));
    UARTFlowControlSet(DEBUG_UART_BASE, UART_FLOWCONTROL_NONE);
    
    ROM_SysCtlPeripheralClockGating(true);
    SysCtlDeepSleepClockSet(SYSCTL_DSLP_OSC_INT30);
    ROM_SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_UART0);
  • Hello Per

    The Run Mode Clock setting (SysCtlClockSet) definition is missing?

    Regards
    Amit
  • SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_INT | SYSCTL_MAIN_OSC_DIS);

    This is the mode we're using when allowing the MCU to go into deep-sleep. We go to deep-sleep with the following code:

    // Set flash and SRAM into low power mode
    HWREG(SYSCTL_DSLPPWRCFG) = 0x00000023;
    ROM_SysCtlDeepSleep();

    Regards Per

  • Hello Per,

    I ran the code w/o delay (after reconstructing it) and it worked without delay as well. Attached for your reference

    //*****************************************************************************
    //
    // uart_echo.c - Example for reading data from and writing data to the UART in
    //               an interrupt driven fashion.
    //
    // Copyright (c) 2012-2014 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    //
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    //
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    //
    // This is part of revision 2.1.0.12573 of the EK-TM4C123GXL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_sysctl.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>UART Echo (uart_echo)</h1>
    //!
    //! This example application utilizes the UART to echo text.  The first UART
    //! (connected to the USB debug virtual serial port on the evaluation board)
    //! will be configured in 115,200 baud, 8-n-1 mode.  All characters received on
    //! the UART are transmitted back to the UART.
    //
    //*****************************************************************************
    #define DEBUG_UART_PORT_PERIPHERAL	SYSCTL_PERIPH_GPIOA
    #define DEBUG_UART_PERIPHERAL		SYSCTL_PERIPH_UART0
    #define DEBUG_UART_PORT_BASE		GPIO_PORTA_BASE
    #define DEBUG_UART_BASE				UART0_BASE
    #define DEBUG_UART_INT				INT_UART0
    #define PIN_DEBUG_URX				GPIO_PIN_0
    #define PIN_DEBUG_UTX				GPIO_PIN_1
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    unsigned char cUARTSendData = 0;
    
    static void init_uart_as_uart_master(void)
    {
       // Enable GPIO port
       ROM_SysCtlPeripheralEnable(DEBUG_UART_PORT_PERIPHERAL);
    
       // Enable UART peripheral
       ROM_SysCtlPeripheralEnable(DEBUG_UART_PERIPHERAL);
    
       // Set UART signals
       ROM_GPIOPinTypeUART(DEBUG_UART_PORT_BASE, (PIN_DEBUG_URX | PIN_DEBUG_UTX));
    
       // Configure UART
       ROM_UARTClockSourceSet(DEBUG_UART_BASE, UART_CLOCK_PIOSC);
       ROM_UARTConfigSetExpClk(DEBUG_UART_BASE, 16000000, 57600,
                               (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                                UART_CONFIG_PAR_NONE));
    
       // Disable hardware flow control
       UARTFlowControlSet(DEBUG_UART_BASE, UART_FLOWCONTROL_NONE);
    }
    
    static void init_uart_interrupts(void)
    {
       // Generate UART receive / transmit interrupts when FIFO is more than 1/8 full
       ROM_UARTFIFOLevelSet(DEBUG_UART_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
    
       // Enable UART receive and receive timeout interrupts
       ROM_UARTIntEnable(DEBUG_UART_BASE, UART_INT_RX | UART_INT_RT);
    
       // Clear any pending interrupts
       ROM_UARTIntClear(DEBUG_UART_BASE, UART_INT_RX | UART_INT_RT);
    
       // Gate UART module interrupts to mcu core
       ROM_IntEnable(DEBUG_UART_INT);
    }
    
    void debug_uart_isr_handler(void)
    {
       uint8_t c;
       uint32_t status = ROM_UARTIntStatus(DEBUG_UART_BASE, true);
    
       if ((UART_INT_RX | UART_INT_RT) & status)
       {
          while (ROM_UARTCharsAvail(DEBUG_UART_BASE))
          {
    
             // NB! ~5 microseconds delay is needed to get correct RX FIFO data when
             // leaving deep sleep. Without this, ROM_UARTCharsAvail returns 0x00.
             // This should not be needed since UARTCharsAvail returns true.
             // Question to be answered by TI FAE.
    
             c = ROM_UARTCharGetNonBlocking(DEBUG_UART_BASE);
    
             // Send to debug channel parser
             ROM_UARTCharPutNonBlocking(DEBUG_UART_BASE, c);
          }
    
          ROM_UARTIntClear(DEBUG_UART_BASE, UART_INT_RX | UART_INT_RT);
       }
    }
    
    //*****************************************************************************
    //
    // This example demonstrates how to send a string of data to the UART.
    //
    //*****************************************************************************
    int
    main(void)
    {
        SysCtlPeripheralDisable(UART1_BASE);
    
        //
        // Set the clocking to run directly from the crystal.
        //
        SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_INT | SYSCTL_MAIN_OSC_DIS);
    
    
        init_uart_as_uart_master();
        init_uart_interrupts();
    
        ROM_SysCtlPeripheralClockGating(true);
        SysCtlDeepSleepClockSet(SYSCTL_DSLP_OSC_INT30);
        ROM_SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Set flash and SRAM into low power mode
        //
        HWREG(SYSCTL_LDODPCTL) 	 = 0x80000012;
        HWREG(SYSCTL_DSLPPWRCFG) = 0x00000023;
    
        while(1)
        {
        	ROM_SysCtlDeepSleep();
        }
    
    }
    

    Regards

    Amit