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.

RTOS: EK-TM4C1294XL, UART Thread not working

Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

Hello,


I have an RTOS Project on TM4C1294XL which is currently being used to receive and transmit data to a UART on an external sensor.  There is only one thread running on this project: a Timer Module whose ISR is the UART receive/transmit function.  There is nothing else going on.  The CPU is set to 40 Mhz, and the timer module is called every 500,000 microseconds, or every 0.5 seconds.  It seems I get a different error every time, but most recently it is: ti.sysbios.gates.GateMutex: line 99: assertion failure: A_badContext: bad calling context. See GateMutex API doc for details.
xdc.runtime.Error.raise: terminating execution


I have seen other threads which ask about this error and the solution is to change the thread to a task with a semaphore pend.  But I really do not want to do this.  I simply want the Timer module to do its job.  I do not know why I would need to block anything with a semaphore when this is the ONLY thread in the system.  Code is below.

//----------------------------------------
// BIOS header files
//----------------------------------------
#include <xdc/std.h>                        //mandatory - have to include first, for BIOS types
#include <ti/sysbios/BIOS.h>                //mandatory - if you call APIs like BIOS_start()
#include <xdc/runtime/Log.h>                //needed for any Log_info() call
#include <xdc/cfg/global.h>                 //header file for statically defined objects/handles
#include <xdc/runtime/System.h>


//------------------------------------------
// TivaWare Header Files
//------------------------------------------
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "inc/hw_ints.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"
#include "driverlib/uart.h"
#include "Board.h"
#include "driverlib/pin_map.h"

//----------------------------------------
// Definitions
//----------------------------------------

#define UART2_BAUDRATE      9600

//----------------------------------------
// Prototypes
//----------------------------------------
void hardware_init(void);
void UART_exchange(void);


//---------------------------------------
// Globals
//---------------------------------------

//Array which contains the "Read CO2 concentration" command.  This is sent from
//the target UART to the CO2 Sensor UART, to signal we want the sensor to send us
//its current CO2 reading.
uint8_t read_bytes[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};

//Array which contains the Sensor Tx response.
uint8_t response_bytes[9] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

//Holds calculated value of CO2 Concetration
uint32_t CO2_Value = 0;

//Current clock Rate
uint32_t sys_clock = 40000000;

//---------------------------------------------------------------------------
// main()
//---------------------------------------------------------------------------
void main(void)

{
   hardware_init();                         // init hardware via TIVAware
   BIOS_start();

}


void hardware_init(void)
{

    //Set CPU Clock to 40MHz. 400MHz PLL/2 = 200 DIV 5 = 40MHz
    //SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART2);
    GPIOPinConfigure(GPIO_PA6_U2RX);
    GPIOPinConfigure(GPIO_PA7_U2TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_6 | GPIO_PIN_7);

    UARTEnable(UART2_BASE);
    UARTConfigSetExpClk(UART2_BASE, sys_clock, UART2_BAUDRATE,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

}


//---------------------------------------------------------------------------
// UART_exchange()
//
// Sends command to Sensor Rx, waits for response, stores response
// in response_bytes[9] array.
//---------------------------------------------------------------------------
void UART_exchange(void)
{
    TimerIntClear(TIMER2_BASE, TIMER_TIMA_TIMEOUT);         // must clear timer flag FROM timer

    uint32_t w,x = 0;

    for(w = 0; w < 9; w++)
    {
        UARTCharPut(UART2_BASE, read_bytes[w]);
    }

    while(UARTBusy(UART2_BASE))
    {
        //spin here until UART is done transmitting
    }

    System_printf("UART is done transmitting.\n");

    //Get the bytes in the receive FIFO

    while(UARTCharsAvail(UART2_BASE))
    {
        response_bytes[x] = UARTCharGet(UART2_BASE);
        x++;
    }

    System_printf("UART is done receiving. \n");


    CO2_Value = response_bytes[2]*256 + response_bytes[3];

    System_printf("CO2 Value in ppm is: ");
    System_printf("%d \n", CO2_Value);

}



  • Hi Rodney,

    How are you setting up the UART interrupt and what is the interrupt's function? Is there a reason you don't want to use the UART driver in TI-RTOS (e.g. look at the UART Echo example).

    Todd

  • Sorry for delayed response.

    My reason for doing it this way is because while the UART Echo example seems to be plug and play for communicating with PuTTY (with UART0), using UART1 or any other UART to communicate with an external device requires the editing of a seemingly limitless number of header files and libraries. Within which it is not very clear to me what changes to make. This makes the process much more difficult and time consuming.
  • Hi Rodney,

    Fair feedback. How are you setting up the interrupt in your application?

    If you are not using UART0, you could just just the EK_TM4C1294XL.c file to pinmux UART1 instead of UART0 in uartTivaHWAttrs and in EK_TM4C1294XL_initUART. Then still use Board_UART0. Or change Board_UART0 to Board_UART1 (in Board.h) and EK_TM4C1294XL_UART0 to EK_TM4C1294XL_UART1 (in EK_TM4C1294XL.h) for completeness.

    Todd
  • Todd,

    The interrupt is triggered by an RTOS Timer module. Once this timer counts down (every 0.5 seconds) "UART_exchange" is the ISR which is called.
  • Hi Rodney,

    That assert is called when you try to enter a GateMutex (which is basically a semaphore). You cannot do this in the context of a Hwi or Swi. If you are calling your function in a SYS/BIOS managed Timer, it is executing in Hwi context. Depending on how you setup your System provider in the .cfg, System_printf might be calling GateMutx_enter (since a GateMutex is plugged into the RTS library ...assuming you are using a TI compiler). There are a couple ways to figure this out, but the easiest is probably to either comment out the System_printf functions in the UART_exchange or change to
    var SysCallback = xdc.useModule('xdc.runtime.SysCallback');
    System.SupportProxy = SysCallback;
    in the .cfg file. This plugs in a essentially empty system provider.

    Note: you might be getting this also if you are not using a kernel managed timer interrupt. You're fine if you are using the Clock module or you used Timer_create (or Timer_construct). Non-managed interrupts cannot call into kernel APIs.

    Todd
  • Todd,

    This did resolve my error, so thank you very much. However, I wish my debugging tools did not have to be so limited.