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.

how to write ADC12 result to Kentec LCD ?

Other Parts Discussed in Thread: TM4C123GH6PM

Hello:

I  am learning TM4C123XGL with CCS6.0.1.  I learned how to use grlib and ADC from the TM4C123G_LaunchPad_Workshop_Workbook.pdf.

The ADC12 and grlib work well in the practice Lab5 and Lab10 separately. However, when I put them together, It does not work.  I do not know the reason.

I use ADC0 S1 to get the temperature and want to display the temperature on Kentec  Lcd.

I use Timer5 A to trigger ADC0 and want to display the average temperature on LCD in Timer0 A's interrupt handler. I set Timer0 A timeout as 4seconds.

However, when I call the GrStringDraw in timer0A 's ISR, I got trapped in FaultISR. Somebody in this forum said it was because the stack size is too small,  I changed LINKer configuration for this project from 100 to 2048. However, after this change, all the data read from ADC12 keeps 0 and never change anymore.

After I comment out some code related to Kentec (include initailization and DrawString in timer0A's ISR) the ADC data comes back.

Does this because LCD and ADC fighting on same hardware resource so they can not work well simultaneously?  Can anyone give me any hints ?  Thanks a lot..

My code is below. I already commented out some code related to Kentec:

#include <stdint.h>
#include <stdio.h>                                  //for sprintf
#include <stdbool.h>
//#include "inc/tm4c123gh6pm.h"           // sames this one has already included by other .h file.
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/interrupt.h"                 //added for ADC interrupt mode
#include "driverlib/timer.h" // for timer interrupt
#include "inc/hw_adc.h"
#include "inc/hw_ints.h" // for  INT_ADC0SS1
#include "grlib/grlib.h"
#include "driverlib/gpio.h"
#include "Kentec320x240x16_ssd2119_8bit.h"
uint32_t ui32ADC0Value[4];
volatile int32_t oldTempf=0;
volatile uint32_t uiCount=0;
volatile uint32_t uiCountT0=0;
volatile uint32_t uiCountT5=0;
volatile int32_t   ui32TempAvg;
volatile int32_t i32TempValueC;
volatile int32_t i32TempValueF;
tContext sContext;
tRectangle sRect;
void ClrTempBar( uint32_t color) {
sRect.i16XMin = 160;
sRect.i16YMin = 132;
sRect.i16XMax = 312;
sRect.i16YMax = 232;
GrContextForegroundSet(&sContext, color);
GrRectDraw(&sContext, &sRect);
GrFlush(&sContext);
}
void ClrScreen()
{
sRect.i16XMin = 0;
sRect.i16YMin = 0;
sRect.i16XMax = 319;
sRect.i16YMax = 239;
GrContextForegroundSet(&sContext, ClrBlack);
GrRectFill(&sContext, &sRect);
GrFlush(&sContext);
}
//Timer 0 for display the ADC average per 4s
void Timer0Init() {
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE, TIMER_CFG_A_PERIODIC);
TimerLoadSet(TIMER0_BASE, TIMER_A, 4*SysCtlClockGet() -1 ); // 4s
TimerEnable(TIMER0_BASE, TIMER_A);
IntMasterEnable();
IntEnable(INT_TIMER0A);
}
//Timer 5 for trigger ADC
void Timer5Init() {
//  Timer (ADC Trigger)
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
TimerConfigure(TIMER5_BASE, TIMER_CFG_A_PERIODIC);
TimerLoadSet(TIMER5_BASE, TIMER_A, SysCtlClockGet() / 10 -1); // 10Hz
TimerControlTrigger(TIMER5_BASE, TIMER_A, true);
TimerEnable(TIMER5_BASE, TIMER_A);
IntMasterEnable();
IntEnable(INT_TIMER5A);
}
void ADCInit(void)
{
    // ADC
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
/* 28. Our selection means that each sample in the ADC FIFO will
be the result of 64 measurements being averaged together. */
ADCHardwareOversampleConfigure(ADC0_BASE, 64);
ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_TIMER, 0);
//Step 9. need to configure all four steps in the ADC sequencer.
ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_TS);
ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_TS);
ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_TS);
/*step 10. Sample the temperature
sensor (ADC_CTL_TS) and configure the interrupt flag (ADC_CTL_IE) to be set
when the sample is done. Tell the ADC logic that this is the last conversion on sequencer
1 (ADC_CTL_END). */
ADCSequenceStepConfigure(ADC0_BASE,1,3,ADC_CTL_TS|ADC_CTL_IE|ADC_CTL_END);
//Step 11. we enable ADC sequencer 1.
IntEnable(INT_ADC0SS1);
}
void ADC0SS1IntHandler(void)
{
    // Ack Interrupt
    ADCIntClear(ADC0_BASE, 0);
    uiCount++;
    // Read ADC Data
    ADCSequenceDataGet(ADC0_BASE, 1, ui32ADC0Value);
// 18. Calculate the average of the temperature sensor data, The addition of 2 is for rounding
ui32TempAvg = (ui32ADC0Value[0] + ui32ADC0Value[1] + ui32ADC0Value[2] + ui32ADC0Value[3] + 2)/4;
// 19. calculate the Celsius value of the temperature.
i32TempValueC = (1475 - ((2475 * ui32TempAvg)) / 4096)/10;
// 20. calculating the Fahrenheit temperature
i32TempValueF = ((i32TempValueC * 9) + 160) / 5;
}
void  Timer5IntHandler(void){
TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
uiCountT5++;
}
void outTemp(int32_t temp, int x, int y) {
char tempStr[10];
sprintf(tempStr,"%2d",temp);
GrContextFontSet(&sContext, &g_sFontCmss30b);
GrStringDraw(&sContext, tempStr, -1, x, y, 0);
GrFlush(&sContext);
}
enum COLORS {
BLUE = 2,
END
};
int color = BLUE;
void  Timer0IntHandler(void){
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3)) {
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);
} else {
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, (color<<1));
if(++color==8) {
color = 0;
}
}
/*if( uiCountT0 & 1 ) {
ClrTempBar(ClrYellow);
} else {
ClrTempBar(ClrBlue);
}*/
//if( oldTempf != i32TempValueF) {
//oldTempf = i32TempValueF;
//outTemp(oldTempf,200,10);
//}
uiCountT0++;
}
int main() {
SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
// enable GPIOF
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
// initialize perapherial
Timer0Init();
Timer5Init();
ADCInit();
//Kentec320x240x16_SSD2119Init();
//GrContextInit(&sContext, &g_sKentec320x240x16_SSD2119);
//ClrScreen(  );
//SysCtlDelay(SysCtlClockGet());
//ClrTempBar(ClrYellow);
//start timers and ADC
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
ADCSequenceEnable(ADC0_BASE, 1);
while(1) {
/*if( oldTempf != i32TempValueF) {
oldTempf = i32TempValueF;
outTemp(oldTempf,200,10);
}*/
}
}

  • Hello Bin,

    The first item is to use the Processor Trigger for ADC to be able to update the display panel. Always do the graphics update out of the interrupt routine and in the main application. In the main keep the code in a while loop to check for a flag that is set in the ADC conversion interrupt handler. When the flag is set then call the grlib to update the value on the panel. Only when the grlib draw call is over, clear the flag.

    Also implement a sw semaphore, such that values do not get updated by ADC interrupt handler. For this in the ISR, read the ADC value only when the flag is clear. If it is set then Flush the ADCFIFO by doing a dummy read.

    Regards
    Amit
  • Hi Amit:

    Thanks a lot for your prompt response. I really appreciate it.

    I will try processor_trigger ADC .  However, I am not sure how to implement the sw semaphore?

    does TM4C platform has already provided some API function to create semaphore.

    Could you please give  me more detail on it ?

    Thanks again.

    Bin

  • Hello Bin,

    There is no native SW semaphore in the driverlib, but one can be created easily in the application. It is just a SW interlock.

    Regards
    Amit
  • Hello,

    I am having a similar problem.

    I am using my TM4C123GXL Launchpad Board to measure external square frequencies with a timer.
    The timer is counting the edges of the signal.
    I am initializing the timer as follows.

    TimerConfigure(TIMER2_BASE, TIMER_CFG_A_CAP_COUNT);

    And I am using a second timer generating a periodic interrupt.

    The code works fine when I am using it without the Kentec QVGA Display.
    I have also read the Kentec QVGA datasheet and am not using any used GPIO ports by the display.
    I am using the port PB0 with TIMER2, TIMER_A, for measuring the frequency and TIMER0 for periodic interrupt.
    I am also not using the touchscreen interrupt and that timer.

    @Bin, can you post your solution in here?

    My code can be found here.

    github.com/.../LCDandTimer

    This is the main class initializing the display:
    github.com/.../main.c

    This is the measure class using interrupts and timers.
    github.com/.../measure.h

    Can anyone help me?
    What am I doing wrong?

    Greetings
    leabut
  • Ok, I have fixed the problem partially by myself.

    According to the Kentec QVGA Display library the Display is configuring all GPIO ports, whyever.
    Quote from the QVGA library:

    #define LCD_DATAH_PERIPH        SYSCTL_PERIPH_GPIOB
    #define LCD_DATAH_BASE          GPIO_PORTB_BASE
    #define LCD_DATAH_PINS          0xFF

    static void
    InitGPIOLCDInterface(uint32_t ulClockMS)
    {
        //
        // Configure the pins that connect to the LCD as GPIO outputs.
        //
        GPIOPinTypeGPIOOutput(LCD_DATAH_BASE, LCD_DATAH_PINS);

    [...]

    }

    Which means, they are using all pins.

    Therefore I am currently disabling the LCD for 200ms to measure my square frequency and then reenable/reconfigure
    the LCD pins using the init method of the LCD.

    So it kind of looks like this.

        while(1) {

        //configuring pins for measurement
       //overwriting the LCD pins
      //LCD will turn off during measurement
        GPIOPinConfigure (GPIO_PB0_T2CCP0);
        GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_0);

       //measure for 200ms with interrupts
       delayMS(200);

        calculate();

        initLCD();

        printToLCD();

        }

    Little problematic here, the LCD starts oscillating during a 200ms period and starts flashing.
    Does not look like it was meant to be used ^.^

    Anyway, I am now able to read my sensor data and be able to debug.

    Greetings

    leabut

  • I'm having similar problems.  I went through both of the labs just fine.  Now I've got a program that reads in 2 ADC values (PE2 and PE3) and then momentarily turns on the red led (PF1) whenever PE2>PE3 and I get a high signal on PE5.  That part works fine.

    The next thing I want to do is display those values on the Kentec screen.  I copied over the source and header files from lab 10 (the Kentec lab) and configured everything similarly.  Then my program got stuck at the SysCtlPeripheralEnable(LCD_DATAH_PERIPH);

    I found a work-around was to call the Kentec initialization routine before I called my initialization routine.  However, I still do not get images to pop up on the screen.  Using breakpoints I found that the program stops in main at:

        GrContextInit(&sContext, &g_sKentec320x240x16_SSD2119);

    I've searched the project and don't see GrContextInit defined anywhere.  I also tried looking at Lab 10 directly but it is not there either.  I'll post my initialization and main.c code below.  If there's any other part of my program that might be helpful please let me know and I'll post that as well.

    Thank you

    //******************************************************************************
    //                          Declare Header Files
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/tm4c123gh6pm.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/gpio.h"
    #include "driverlib/timer.h"
    #include "driverlib/debug.h"
    #include "driverlib/adc.h"
    #include "driverlib/fpu.h"
    #include "driverlib/rom.h"
    #include "grlib/grlib.h"
    #include "initialize.h"
    #include "Sample.h"
    #include "ZeroCrossing.h"
    #include "SCR_firing.h"
    #include "grlib/grlib.h"
    #include "Kentec320x240x16_ssd2119_8bit.h"
    #include "screen.h"
    
    
    
    
    //******************************************************************************
    
    //******************************************************************************
    //                          Declare Functions
    
    void Sample(void);
    int Control(void);
    int Manipulation(void);
    void ZeroCrossing(void);
    void Timer0(void);
    void ClrScreen(void);
    //******************************************************************************
    
    //******************************************************************************
    //                          Declare/Initialize Variables
    uint32_t Theta=0;
    
    
    
    
    
    //******************************************************************************
    
    
    int main(void)
    {
        //Initialize system clock to 40MHz
        //SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
    
    
        Kentec320x240x16_SSD2119Init();
        Initialize();   //Initialization routine
    
    
        GrContextInit(&sContext, &g_sKentec320x240x16_SSD2119);
        ClrScreen();
    
        //GrImageDraw(&sContext, g_pui8Image_DSI_logo, 0, 0);
        GrFlush(&sContext);
    
        SysCtlDelay(SysCtlClockGet());
        // Later lab steps go between here
    
        ClrScreen();
    
        GrImageDraw(&sContext, g_pui8Image_motor, 0, 0);
        GrFlush(&sContext);
    
        SysCtlDelay(SysCtlClockGet());
        // Later lab steps go between here
    
    
    
         ClrScreen();
    
        sRect.i16XMin = 1;
        sRect.i16YMin = 1;
        sRect.i16XMax = 318;
        sRect.i16YMax = 238;
        GrContextForegroundSet(&sContext, ClrRed);
        GrContextFontSet(&sContext, &g_sFontCmss30b);
        GrStringDraw(&sContext, "Texas", -1, 110, 2, 0);
        GrStringDraw(&sContext, "Instruments", -1, 80, 32, 0);
        GrStringDraw(&sContext, "Graphics", -1, 100, 62, 0);
        GrStringDraw(&sContext, "Lab", -1, 135, 92, 0);
        GrContextForegroundSet(&sContext, ClrWhite);
        GrRectDraw(&sContext, &sRect);
        GrFlush(&sContext);
    
        SysCtlDelay(SysCtlClockGet());
    
        GrContextForegroundSet(&sContext, ClrYellow);
        GrCircleFill(&sContext, 80, 182, 50);
    
        sRect.i16XMin = 160;
        sRect.i16YMin = 132;
        sRect.i16XMax = 312;
        sRect.i16YMax = 232;
        GrContextForegroundSet(&sContext, ClrGreen);
        GrRectDraw(&sContext, &sRect);
    
        SysCtlDelay(SysCtlClockGet());
    
    
        ClrScreen();
    
        //Run an infinite loop and let interrupts do the hard work
        while(1)
        {
        }
    }
    
    
    //*********************************************************************************
    //***************************   Function Declarations   ***************************
    //*********************************************************************************
    
    
    
    
    
    
    
    
    
    
    
    
    
    //**************************************************************************************
    //                                      Initialize() function
    
    
    extern void ZeroCrossing(void);
    uint32_t SampleFreq=0;
    
    int Initialize(void)
    {
    
    
    
        //enable Peripherals
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
        while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC1))   //Wait for last peripheral to be enabled
        {
        }
    
        //Configure Timer0A
        TimerConfigure(TIMER0_BASE,TIMER_CFG_A_ONE_SHOT);   //Configure Timer0 as one shot (for ZCD)
        TimerDisable(TIMER0_BASE, TIMER_B);                 //Disable Timer0B
        IntEnable(INT_TIMER0A);                             //Enable interrupt for Timer0A
        TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);    //Enable interrupt for Timer0A timeout
    
    
        //Timer1A set up
        TimerConfigure(TIMER1_BASE, TIMER_CFG_A_PERIODIC);      //Configure Timer 1A for periodic timing
        SampleFreq=(SysCtlClockGet()/5);                        //Calculate the sample freq based on system clock
        TimerLoadSet(TIMER1_BASE, TIMER_A, SampleFreq -1);      //Load Timer1A with sample freq
        TimerDisable(TIMER1_BASE, TIMER_B);                     //Disable Timer1B
        IntEnable(INT_TIMER1A);                                 //Enable interrupts for Timer1A
        TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);        //Enable interrupts for Timer1A on timeout
        TimerEnable(TIMER1_BASE, TIMER_A);                      //Enable Timer1A
    
        GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1); //Configure PF1 as output (red led)
    
        //Configure PC5
        GPIOPinTypeGPIOInput(GPIO_PORTC_BASE, GPIO_PIN_5);          //Configure PC5 as input
        IntEnable(INT_GPIOC);                                       //Enable interrupts on Port C
        GPIOIntRegister(INT_GPIOC,ZeroCrossing);                          //Register the interrupt for PortE
        GPIOIntEnable(GPIO_PORTC_BASE,GPIO_INT_PIN_5);                    //Enable interrupt for PC5
        GPIOIntTypeSet(GPIO_PORTC_BASE,GPIO_INT_PIN_5,GPIO_RISING_EDGE);  //Configure PC5 interrupt for rising level
    
        //Configure ADC's
        GPIOPinTypeADC(GPIO_PORTE_BASE,GPIO_PIN_2|GPIO_PIN_3);                      //initialize GPIO Port E Pin 2,3 as analog pins
        ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);               //Configure sequencer for ADC0
        ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);               //Configure sequencer for ADC1
        ADCSequenceStepConfigure(ADC0_BASE,0,0,ADC_CTL_CH0|ADC_CTL_IE|ADC_CTL_END); //Configure ADC0 step 0
        ADCSequenceStepConfigure(ADC1_BASE,0,0,ADC_CTL_CH1|ADC_CTL_IE|ADC_CTL_END); //Configure ADC1 step 1
        ADCSequenceEnable(ADC0_BASE,0);                                             //Enable sequencer for ADC0
        ADCSequenceEnable(ADC1_BASE,0);                                             //Enable sequencer for ADC1
    
        //Enable all interrupts
        IntMasterEnable();
    
        return(0);
    }
    //*********************************************************************************