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.

CCS/TM4C1294NCPDT: Getting data from the ADC using interrupts

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: EK-TM4C1294XL,

Tool/software: Code Composer Studio

Hello, I'm trying to use the ADC0 module on the TM4C1294XL board with PE1 as the analog input. I'm trying to use interrupts for the sampling but the interrupts aren't triggering. Could you look at my code and see what's wrong? Thank you.

main:

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_adc.h"
#include "inc/hw_types.h"
#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "inc/tm4c1294ncpdt.h"

volatile static uint32_t adcResult = 0;

void ADC0SS3_Handler(void)  //interrupt function
{
  adcResult = ADC0_SSFIFO3_R;   //stores digital value in variable
  ADCIntClear(ADC0_BASE, 3);    //clears interrupt flag
}

int main()
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //enables clocks for ADC and GPIO
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);    //configures PE1 for analog ADC input

    IntDisable(INT_ADC0SS3);    //disables modules for configuration
    ADCIntDisable(ADC0_BASE, 3);
    ADCSequenceDisable(ADC0_BASE, 3);

    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);  //configures ADC0 to continuously trigger

    ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 | ADC_CTL_END |ADC_CTL_IE);   //ADC calls an interrupt when conversion step is complete

    ADCSequenceEnable(ADC0_BASE, 3);    //enables sample sequencer

    ADCIntClear(ADC0_BASE, 3);  //enables interrupts
    ADCIntEnable(ADC0_BASE, 3);
    IntEnable(INT_ADC0SS3);
    IntMasterEnable();

    while(1)    //dead loop
    {
        {}
    }
  return 0;
}

startup:
#include <stdint.h>
volatile static uint32_t adcResult = 0;

//*****************************************************************************
//
// Forward declaration of the default fault handlers.
//
//*****************************************************************************
void ResetISR(void);
static void NmiSR(void);
static void FaultISR(void);
static void IntDefaultHandler(void);
//*****************************************************************************
//
// External declaration for the reset handler that is to be called when the
// processor is started
//
//*****************************************************************************
extern void _c_int00(void);

//*****************************************************************************
//
// Linker variable that marks the top of the stack.
//
//*****************************************************************************
extern uint32_t __STACK_TOP;

//*****************************************************************************
//
// External declarations for the interrupt handlers used by the application.
//
//*****************************************************************************
extern void ADC0SS3_Handler(void);

//*****************************************************************************
//
// The vector table.  Note that the proper constructs must be placed on this to
// ensure that it ends up at physical address 0x0000.0000 or at the start of
// the program if located at a start address other than 0.
//
//*****************************************************************************
#pragma DATA_SECTION(g_pfnVectors, ".intvecs")
void (* const g_pfnVectors[])(void) =
{
    (void (*)(void))((uint32_t)&__STACK_TOP),
                                            // The initial stack pointer
    ResetISR,                               // The reset handler
    NmiSR,                                  // The NMI handler
    FaultISR,                               // The hard fault handler
    IntDefaultHandler,                      // The MPU fault handler
    IntDefaultHandler,                      // The bus fault handler
    IntDefaultHandler,                      // The usage fault handler
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // SVCall handler
    IntDefaultHandler,                      // Debug monitor handler
    0,                                      // Reserved
    IntDefaultHandler,                      // The PendSV handler
    IntDefaultHandler,                      // The SysTick handler
    IntDefaultHandler,                      // GPIO Port A
    IntDefaultHandler,                      // GPIO Port B
    IntDefaultHandler,                      // GPIO Port C
    IntDefaultHandler,                      // GPIO Port D
    IntDefaultHandler,                      // GPIO Port E
    IntDefaultHandler,                      // UART0 Rx and Tx
    IntDefaultHandler,                      // UART1 Rx and Tx
    IntDefaultHandler,                      // SSI0 Rx and Tx
    IntDefaultHandler,                      // I2C0 Master and Slave
    IntDefaultHandler,                      // PWM Fault
    IntDefaultHandler,                      // PWM Generator 0
    IntDefaultHandler,                      // PWM Generator 1
    IntDefaultHandler,                      // PWM Generator 2
    IntDefaultHandler,                      // Quadrature Encoder 0
    IntDefaultHandler,                      // ADC Sequence 0
    IntDefaultHandler,                      // ADC Sequence 1
    IntDefaultHandler,                      // ADC Sequence 2
    ADC0SS3_Handler,                      // ADC Sequence 3

...

  • In line 32 of main, you call ADCSequencyConfigure() configuring sequence 0, not 3. The second argument is the sequence number.

    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);  //configures ADC0 to continuously trigger

    should be

    ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_ALWAYS, 0);  //configures ADC0 to continuously trigger

  • Thank you for your response. I should've caught that myself, haha. I fixed the argument in the function, but the interrupts are still not being triggered. If someone could help me with that, I would be grateful. Thank you.

  • I took your code, changed line 32 as described above and ran it on an EK-TM4C1294XL Launchpad. I see the interrupt routine being executed. Put a breakpoint in your interrupt routine and let the code run. Breakpoints may be disabled if single stepping. I have attached the project I used. No need to unzip, just use CCS "File" "Import" function to copy this project into your workspace directly from the .zip file.

  • Thank you for responding again. I do not see your attached project. How can I download it? Thank you.

  • Thank you for the project file. It didn't compile for me. I think that might be because we have different Tivaware editions/folders. However, while I was looking through your project properties, I got the idea to import a "project0" project included in Tivaware and copy my program in there. What I did before was just create an empty project and link the library manually, but I might've done something wrong in the process.

    Sadly, that didn't work either. I'm not sure what to do at this point. If you have any ideas, I would be grateful (again).

  • Ok, here are some suggestions. Pick one.

    1) Let me know what version of TivaWare you have, and where it is installed. Also which version of Code Composer Studio you are using. I can make my project compatible.

    2) Install the latest version of TivaWare (v2.2.0.295) in the default directory (C:\ti\TivaWare_C_Series-2.2.0.295) and I will make a version of the project that matches. The one I sent earlier was using Code Composer Studio v8 and TivaWare library 2.1.4.178.

    3) Use the "File" -> "Export" feature to export your project into a .zip file and attach it to this thread. I can then look at it.

    4) Copy "project0" in your workspace and give it a new name. Now replace project0.c with main.c from the zip file, and replace startup_ccs.c with the file of the same name from the .zip file I provide.

  • Thank you for your response. I realized when I was going through option 4) that my "project0" was for an older version of TivaWare. I imported the newest project0, and the interrupt function started executing!

    I was wondering if I could still use this thread for another issue? Because I've connected both 3.3V and ground to my ADC pin, PE1, and adcResult always reads a digital value of around 390, which doesn't seem right. Is it something with my code? Does your project file also do this?

    Thank you for your help.

  • I just took your code and fixed the interrupt. Sorry, I did not check conversion values. Looking at the code again, I see you configured PE1 as an analog input, but you configured the conversion of ADC_CTL_CH0. PE1 is AIN2 (ADC_CTL_CH2). Change line 34 to:

        ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH2 | ADC_CTL_END |ADC_CTL_IE);   //ADC calls an interrupt when conversion step is complete
    

  • I'm not sure what happened, but my program has seemed to stop working overnight. The interrupt function stopped triggering. I did not change anything in the program. I'm not sure what to do. I have attached my project, if you could look at it, I would be grateful. Thank you.

    And thank you for the AIN code fix.test2.zip

  • I am not sure either, but it may have something to do with the 99+ warnings about incompatible redefinitions. To avoid those, I commented out your include of "tm4c1294ncpdt.h" and replaced your direct register read of the ADC sequence 3  FIFO with a all to ADCSequenceDataGet(). That seemed to resolve the issue for me.

    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "driverlib/adc.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    //#include "inc/tm4c1294ncpdt.h"
    
    uint32_t adcResult = 0;
    
    void ADC0SS3_Handler(void)  //interrupt function
    {
        //
        // Read ADC Value.
        //
        ADCSequenceDataGet(ADC0_BASE, 3, &adcResult);
        ADCIntClear(ADC0_BASE, 3);    //clears interrupt flag
    }
    
    int main()
    {
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //enables clocks for ADC and GPIO
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);    //configures PE1 for analog ADC input
    
        IntDisable(INT_ADC0SS3);    //disables modules for configuration
        ADCIntDisable(ADC0_BASE, 3);
        ADCSequenceDisable(ADC0_BASE, 3);
    
        ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_ALWAYS, 0);  //configures ADC0 to continuously trigger
    
        ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH2 | ADC_CTL_END |ADC_CTL_IE);   //ADC calls an interrupt when conversion step is complete
        ADCSequenceEnable(ADC0_BASE, 3);    //enables sample sequencer
    
        ADCIntClear(ADC0_BASE, 3);  //enables interrupts
        ADCIntEnable(ADC0_BASE, 3);
        IntEnable(INT_ADC0SS3);
        IntMasterEnable();
    
        while(1)    //dead loop
        {
            {}
        }
      return 0;
    }
    

  • The solution did get rid of the warnings, but, sadly, it still does not work for me. I tried reinstalling Code Composer Studio too, but that didn't help either.

  • I am using CCSv9.3 running on an EK-TM4C1294XL LaunchPad and it is working for me. How are you testing the code? I put a breakpoint on line 21 (ADCIntClear) and run the code. I see it stop at the breakpoint in the interrupt routine and I can see different values in "adcResult". Are you trying to C step or single step the code? Interrupts are disabled during single stepping.

  • Thanks for the response. I am indeed using breakpoints in the interrupt function. This is what I was doing when the program was working earlier to check the values of "adcResult".

  • Strange. It works for me. See if you can run this sample ADC program I have attached.

     /cfs-file/__key/communityserver-discussions-components-files/908/3482.ADC_5F00_single_5F00_ended.zip

  • Thank you for your response. The sample ADC program you attached did work for me. I wondered why it worked since it was so similar to the other program, so I went back to my program and it started working too. The interrupt function was triggering and the ADC conversion values were correct. I'm not sure what fixed it, but I am happy that it is fixed. This process leads me to believe that my board has some sort of bug, but since the project I'm using it for is pretty simple, I'm not worried about it.

    Thank you for all of your help. I appreciate it.

  • Note that occasionally my program's interrupt functions stops triggering, but switching from that program to the sample ADC program and then back again always fixes it.