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.

ADC trigger always mode doesn't work on Tiva C TM4C1294

When configuring the ADC sequencer to trigger always the processor goes into the Fault ISR. 

Here's the code for configuration the ADC sequencer:

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    ADCHardwareOversampleConfigure(ADC0_BASE, 16);
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 6);

   GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);

    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_IE | ADC_CTL_END);

 ADCSequenceEnable(ADC0_BASE, 0);


Here's the code to get the ADC reading:

 while(!ADCIntStatus(ADC0_BASE, 0, false)) { }
    // Read the value from the ADC.
    ADCSequenceDataGet(ADC0_BASE, 0, adcValues);


Is there something I'm missing in the configuration?  Or any ideas why this isn't working?

Thanks,

  • Hello Lindsey,

    Couple of things about the code

    1. After enabling the ADC0 in System Control, please put a short delay of 10 clocks

    2. The GPIO Port E is being configured for ADC Pin but I do not see the clock enable function being called

    Regards

    Amit

  • I added a delay after the enable and that didn't seem to change anything.

    Here's how I'm configuration the system clock:

    g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);

    Is there some other clock I need to enable?


    The ADC works when I use the ADC_TRIGGER_PROCESSOR mode. 

  • Hello Lindsey,

        ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_IE | ADC_CTL_END);

    Should be

        ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_IE | ADC_CTL_END | ADC_CTL_CH1);

    when it does go to the FaultISR, you can read the Fault Registers at 0xE000ED28 and 0xE000ED38 that will give you the type of Fault and Faulting Address. Can you send across the same?

    Also

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 6);

    must be replaced by

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 30);

    as the ADC is rated for 16MHz clock and not 80MHz sampling clock.

    Regards

    Amit

  • Okay made those changes and still no change. 

    Here's the fault register values;

    0xE000ED28 => 0x00020000

    0xE000ED38 => 0xE000EDF8

    Also I changed the sampling rate but I'm curious how you came up with 30.  With a PLL clock of 120MHz should this be like 8 to sample at 15MHz.

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 8);

  • Hello Lindsey

    The ADC Sampling clock is derived from the PLL VCO Clock, which in this case is 480MHz. That is why a divide of 30 was suggested to get it to 16MHz.

    The Fault type is a INVSTAT fault, something that I have not seen for a long time. Can you step through the functions to see which function call results in the FaultISR. It would be rather easier to debug from that point onwards

    Regards

    Amit

  • Okay thanks for the explanation on the clock calculations.

    I did step through the functions in the debugger and what I found was I had my code to check the ADCInStatus and ADCSequenceDataGet in a function when I hit the return from that function I entered the fault ISR. 

    Next, I move that code out of the function and just call those functions from in my main and it doesn't have this issue. 

    The function was passing two variables by reference to store the ADC values, I changed that function to not pass any variable but just update a global with the ADC values.  This now works.

    Thanks for the help!

  • Just a quick update, you cannot have the following statements in a function call.  If so you enter the fault ISR.  Seems to be some type of bug with the processor.  As a work around put this code every place you need to read the ADC.

                while(!ADCIntStatus(ADC0_BASE, 0, false)) { }
                // Read the value from the ADC.
                ADCSequenceDataGet(ADC0_BASE, 0, adcValues);

  • Hello Lindsey,

    Do you mean that when you use a function wrapper for the following to pass the data, it gives a Fault?

    while(!ADCIntStatus(ADC0_BASE, 0, false)) { }
    // Read the value from the ADC.
    ADCSequenceDataGet(ADC0_BASE, 0, adcValues);

    Can you send the full function?

    Regards

    Amit

  • yes that is correct, if I put a function wrapper around the code I get the fault.  Actually, I have found that if I call those two functions in any other function other than my main() I get the fault. Also note that this function work fine when I use ADC_TRIGGER_PROCESSOR mode.

    Here's the function.

    uint32_t g_adcReading0;

    uint32_t g_adcReading1;

    void WaitAndReadADC()
    {
        uint32_t adcValues[2];
        // Wait until the sample sequence has completed.
        while(!ADCIntStatus(ADC0_BASE, 0, false)) { }
        // Read the value from the ADC.
        ADCSequenceDataGet(ADC0_BASE, 0, adcValues);
        g_adcReading0 = adcValues[0];
        g_adcReading1 = adcValues[1];
    }

  • Hello Lindsey,

    Please see the attached example code where the Read of the ADC is being done. It works fine and displays the two channels that I have configured and connected to different voltage supplies.

    //*****************************************************************************
    //
    // TM4C129_ADC0.c - ADC0 Example
    //
    // Copyright (c) 2013-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 DK-TM4C129X Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_adc.h"
    #include "driverlib/debug.h"
    #include "driverlib/adc.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/udma.h"
    #include "driverlib/gpio.h"
    #include "utils/uartstdio.h"
    
    uint32_t
    WaitAndReadADC(uint32_t *adcValues)
    {
    	ADCProcessorTrigger(ADC0_BASE,0);
        // Wait until the sample sequence has completed.
        while(!ADCIntStatus(ADC0_BASE, 0, false)) { }
        // Read the value from the ADC.
        return(ADCSequenceDataGet(ADC0_BASE, 0, adcValues));
    }
    
    void
    vInitADC(void)
    {
    	//	Initializing of the ADC Modules needed to poll the excitation frequency
    	//	And the data sincos data signals
    	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOE);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    	SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    	SysCtlDelay(10);
    
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2);
    
    	/*
    	// ******************************************************************************
    	// Initialization of ADC1 Module for Acquisition of the excitation Signal on PK3
    	// 		Settings:
    	//		1 Msps ^= 16MHz ADC clock
    	//
    	// Set up the Clock at | (VCO/15)/2 = (480/30) = 16MHz | which equals 1Msp/s
    	*/
    	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 30);
    
    	// Choose Sequencer 2 and set it at the highest Priority.
    	ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
    
    	// Choose Step 0 in Sequencer 2 as Data Buffer, set it as last Step and enable Interrupts
    	ADCSequenceStepConfigure(ADC0_BASE,0,0, ADC_CTL_CH0);
    	ADCSequenceStepConfigure(ADC0_BASE,0,1, ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END);
    
    	ADCSequenceEnable(ADC0_BASE, 0);
    
    }
    
    //*****************************************************************************
    //
    // Configure the UART and its pins.  This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
        //
        // Enable GPIOA
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Enable UART0
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Use the internal 16MHz oscillator as the UART clock source.
        //
        ROM_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000);
    }
    
    //*****************************************************************************
    //
    // Configure the ADC0 and ADC1
    //
    //*****************************************************************************
    int
    main(void)
    {
        uint32_t ui32SysClock;
        uint32_t ui32adcValues[2], ui32Count;
    
        //
        // Run from the PLL at 120 MHz.
        //
        ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480),
        		120000000);
    
        ConfigureUART();
    
        //
        // Configure the ADC Channels
        //
        vInitADC();
    
        UARTprintf("ADC System Clock %d\n",ui32SysClock);
    
        ui32Count = WaitAndReadADC(ui32adcValues);
        UARTprintf("NO %d\n",ui32Count);
        UARTprintf("S0 %x\n",ui32adcValues[0]);
        UARTprintf("S1 %x\n",ui32adcValues[1]);
    
        while(1);
    }
    

    Regards

    Amit