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.

EK-TM4C123GXL: code does not enter the ADC ISR

Part Number: EK-TM4C123GXL
Other Parts Discussed in Thread: TM4C123GH6PM

Hello,

i am trying to make a simple program with the following funcionality:

Have periodic timer > It triggers and ADC sequence after sampling is done > after sampling is done ADC0 Sequence 0 ISR is called.

The idea is to use it later for control applications and entering the interrupt where the control law will be implemented periodically and with the sampling already done. I know that it will be simpler to just having a periodic interrupt and using the processor trigger for the ADC from there, but i think that it would be nicer entering the interruput with sampling already done.

From the debug screen i can see that the FIFO 0 from the ADC0 is being updated and also the register  ADC_RIS is set to 1. This indicates to me that sampling is being done and that the ISR flag is being set in the registers, however my code never enters the Interrupt handler.

Let me know if you detect something wrong or something is missing with my code that may cause this to happen. Also im a kind of new to C and embedded programming, only experience with arduinos, so any comments with my coding style will be also very much appriciated.

I wont put the startup.c code, to not make the post any longer, but the interrupt is declared as an extern function and also in the ADC sequence0 line.

#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c123gh6pm.h"
#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"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"

volatile    uint32_t ui32VoltageRead[8];
volatile float Voltage;

int main(void){

    uint32_t ui32TimerLoad;

    SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
    TimerControlTrigger(TIMER0_BASE,TIMER_A,true);

    ui32TimerLoad = (SysCtlClockGet() / 15000);
    TimerLoadSet(TIMER0_BASE, TIMER_A, ui32TimerLoad -1);

    GPIOPinTypeADC(GPIO_PORTE_BASE,GPIO_PIN_3);
    ADCHardwareOversampleConfigure(ADC0_BASE, 8);
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0|ADC_CTL_IE|ADC_CTL_END);
    ADCSequenceEnable(ADC0_BASE, 0);

    GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_1);

    ADCIntEnable(ADC0_BASE,0);
    IntMasterEnable();

    TimerEnable(TIMER0_BASE, TIMER_A);

    GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1, 0);
    while(1){
        SysCtlDelay(2000000);
        GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1, 2);
        SysCtlDelay(2000000);
        GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1, 0);
    }

}

void ADC0Sequence0IntHandler(void){
    ADCIntClear(ADC0_BASE, 0);
    ADCSequenceDataGet(ADC0_BASE, 1, ui32VoltageRead);
    Voltage = (ui32VoltageRead[1]/4095.0)*3.3;
}

the code i have added to tm4c123gh6pm_startup_ccs.c in bold:

extern void ADC0Sequence0IntHandler(void);

and

IntDefaultHandler,                      // Quadrature Encoder 0
ADC0Sequence0IntHandler,                      // ADC Sequence 0
IntDefaultHandler,                      // ADC Sequence 1

  • Hello Ariel,

    You should either place your ADC0Sequence0IntHandler above the main function, or add the line

    void ADC0Sequence0IntHandler(void); 

    Above the main function, I know for compilation functions that aren't declared above main() end up not being seen by main() and I never actually tested if the same was true for ISR's but I suspect it is, so perhaps that is the root cause.

    Also I don't see a call for ADCClockConfigSet in order to set the ADC peripherals clocking, please add that API call as well.

    If those steps don't work then to continue with debug please adjust the following and let me know if there are any changes.

    1) I don't think TimerADCEventSet is needed for this, I checked an example for an ADC triggered by timer and don't see it being used, so try and comment that out.

    2) I would also say for the moment comment out the Oversample unless you really need it to get the initial reading. Not sure if that's impacting anything (I haven't used Oversample much myself) so this is another variable we can remove.

    If none of these work, I may need to pick this up on Monday when in the office so I can run code and debug on my end.

  • Hi Ralph,

    After looking at the programming example of the peripheral dirverlib documentation and the example from the workbook i realized that the main problem was that i was missing the following line

        IntEnable(INT_ADC0SS0);
    

    Its crazy how many register need to be enable for using interrupts, but now i wont miss it again, its all part of the learning process.

    About your comments:

    indeed TimerADCEventSet isnt needed, it seems as TimerControlTrigger is enough, i then guess when it should be used TimerADCEventSet.

    i have moved the ISR on top of the main, as also its how it is implemented in the code examples. Thanks for the hint.

    I have not used ADCClockConfigSet since quoting from the worbook: For this lab, we’ll simply allow the ADC12 to run at its default rate of 1Msps. So it seems that if not modification is done it will be already be running at the maximum frequency? What could be the benefit of running at lower speeds?

    In case it may be of any use to anyone i will put here the full working code.

    Thanks very much for the help and the hints

    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/tm4c123gh6pm.h"
    #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"
    #include "driverlib/gpio.h"
    #include "driverlib/timer.h"
    
    volatile uint32_t ui32VoltageRead;
    volatile float Voltage;
    
    void ADC0Sequence0IntHandler(void){
        ADCIntClear(ADC0_BASE, 0);
        ADCSequenceDataGet(ADC0_BASE, 0, &ui32VoltageRead);
        Voltage = (ui32VoltageRead/4095.0)*3.3;
    }
    
    int main(void){
    
        uint32_t ui32TimerLoad;
    
        SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
        TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
        //TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
        TimerControlTrigger(TIMER0_BASE,TIMER_A,true);
    
        ui32TimerLoad = (SysCtlClockGet() / 15000);
        TimerLoadSet(TIMER0_BASE, TIMER_A, ui32TimerLoad -1);
    
        GPIOPinTypeADC(GPIO_PORTE_BASE,GPIO_PIN_3);
        ADCHardwareOversampleConfigure(ADC0_BASE, 8);
        ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0|ADC_CTL_IE|ADC_CTL_END);
        ADCSequenceEnable(ADC0_BASE, 0);
    
        GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_1);
    
        ADCIntEnable(ADC0_BASE,0);
        IntEnable(INT_ADC0SS0);
        IntMasterEnable();
    
        TimerEnable(TIMER0_BASE, TIMER_A);
    
        GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1, 0);
        while(1){
            if(Voltage>2.0){
               GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1, 2);
            }
            else{
            GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1, 0);
            }
        }
    }

  • Hello Ariel,

    Glad to hear you got it working. Sorry I missed that API call at first review, I saw the ADCIntEnable and forgot the IntEnable also was needed... like you said, a lot of registers to program.

    As far as the ADCClockConfigSet goes, I don't remember what the exact case was, but a customer had an issue a while back about getting different results with the ADC that ended up being due to not configuring the clock beforehand, so since then I've just kept in the back of my mind that as a best practice the ADCClockConfigSet API should be used too. Also I'd have to check what the default settings really are and if they are specific to the system clock configuration used by the lab.