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 problem with Tiva



Hi, i'm trying to read an analog value from AIN0 = PE3, but the adc module after start the trigger is stuck with busy pin active. I followed the instructions on the microprocessor datasheet, without using the driverlib.

#include <stdint.h>
#include <stdio.h>
#include "tm4c1294ncpdt.h"
#include <TM4C1294NCPDT.H>
#include "delay.h"

void UART0_puts(char* s);
void UART0Tx(char c);

int main(){
   	SYSCTL_RCGCGPIO_R           |= (1U << 8);           /*enable cock for GPIOJ*/
   	SYSCTL_RCGCGPIO_R           |= (1U << 12);          /*enable clock for GPION*/
   	SYSCTL_RCGCGPIO_R           |= (1U << 0);           /*enable clock for GPIOA*/
	SYSCTL_RCGCADC_R	    |= (1U << 0);	/*enable clock for ADC0*/
	SYSCTL_RCGCGPIO_R           |= (1U << 4);           /*enable clock for GPIOE*/
    SYSCTL_RCGCUART_R           |= (1U << 0);           /*enable clock for UART_0*/
    delay(100);	
	

   /*UART_0 initialization*/
    UART0_CTL_R                 |= 0x00;				/*disable UART_0*/
    UART0_IBRD_R                 = 104;					/*16MHz/16=1MHz, 1MHz/104=9600 baudrate*/
    UART0_FBRD_R                 = 11;					/*fraction part*/
    UART0_CC_R                  |= 0x0;					/*use system clock*/
    UART0_LCRH_R                |= 0x60;				/*8-bit, no parity, 1-stop bit, no FIFO*/
    UART0_CTL_R                 |= 0x301;				/*enable UART_0, TXE, RXE */

	
/*enable PA0, PA1 for UART use*/
    GPIO_PORTA_AHB_DEN_R        |= 0x03;				/*make PA1 and PA0 as digital*/
    GPIO_PORTA_AHB_AFSEL_R      |= 0x03;   				/*use PA0 PA1 alternate function*/
    GPIO_PORTA_AHB_PCTL_R       |= 0x11;				/*configure PA0 and PA1 for UART*/

	
/*initialize PE3 for AIN0 input*/
   GPIO_PORTE_AHB_AFSEL_R	|= 0x08U;		/*enable alternate function*/
   GPIO_PORTE_AHB_DEN_R		&= ~0x08U;		/*disable digital function*/
   GPIO_PORTE_AHB_AMSEL_R	|= 0x08U;		/*enable analog function*/

   /*initialize ADC0*/
   ADC0_ACTSS_R		&= ~0x08U;				/*disable SS3 during configuration*/
   ADC0_EMUX_R		&= ~0xF000U;			/*software trigger conversion*/
   
   ADC0_SSMUX3_R	 = 0;					/*get input from channel 0*/
   ADC0_SSEMUX3_R	&= ~0x01U;
   ADC0_SSCTL0_R	|= 0x02;
   ADC0_SSCTL3_R	|= 0x06U;				/*take 1 saple at the time set flag 1st sample*/
   ADC0_ACTSS_R		 = 0x08U;				/*enable ADC0 sequencer*/	


   
volatile int result;

int temperature;
char buffer[16];
   
      while(1){
		ADC0_PSSI_R |= 0X08U;
		while((ADC0_RIS_R & 0x08U)==0);               // -> ALWAYS STUCK HERE
		temperature = (ADC0_SSFIFO3_R - 500)/10;
		ADC0_ISC_R = 0x08U;
		sprintf(buffer, "\r\nTemp = %dC" , temperature);
		UART0_puts(buffer);
		delay(100000);
	 }
       
    return 0;
  
    }	

void UART0Tx(char c){
   while((UART0_FR_R & (1 << 5)) != 0);
   UART0_DR_R = c;
}

void UART0_puts(char* s){
   while(*s != 0)
	  UART0Tx(*s++);
}	

the program remains locked in while loop and the register ADC0ACTSS remains with the Busy bit high.
I'm working on it for two days, but i can't find a solution, thanks in advance for your support.
  • Hello Georg,

    If the while loop is continuously running, then you may always see the ADC0ACTSS set. If you halt the code does it clear or not?

    Secondly, the use of DRM's style of coding reduces the readability and increases the chances of error. May I suggest moving to TivaWare to help us help you?

    Having said that the is the END bit set in the SS3? Also what is the System Clock Frequency?

    Regards
    Amit
  • Georg,

    I strongly suggest you use the driverlib. Most, if not all, of TI's examples are based on the driverlib, so you will have a lot of reference material. The direct register access mode, especially when programmed with hard-coded values (instead of the macros defined in the driverlib), is unreadable to anyone but yourself.

    I have made a decision to not even look at direct register code unless a very compelling reason (such as performance limits) that discourages the use of the driverlib is presented. Here I can't see any such reason.

    I'm not sure what is TI's (ie. Amit's) official stance to the matter, but here's how I see it: Every time someone needs help with direct register access mode and their reason for using it is "just because", it reduces the time Amit can focus on more important issues, which there are enough of. So please, use the driverlib.

    -Veikko

  • Thankyou for your answer, i have not set the clock speed so i think is in the default mode, but according to Veikko, i'm trying to rewrite this project by using tivaware, to make more easy for you to help me. Best regards and have a nice day
  • ok, i try to upload the adc example from tivaware, i'm using the tm4c1294xl board, iar compile without problems, but the result is the same, the program is stuck in the while loop, and if i look to the adc0 register in debug i see the same busy bit high in ADC0ACTSS, have you got any suggestions?

    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "driverlib/adc.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    //! \addtogroup adc_examples_list
    //! <h1>Single Ended ADC (single_ended)</h1>
    //!
    //! This example shows how to setup ADC0 as a single ended input and take a
    //! single sample on AIN0/PE7.
    //!
    //! This example uses the following peripherals and I/O signals.  You must
    //! review these and change as needed for your own board:
    //! - ADC0 peripheral
    //! - GPIO Port E peripheral (for AIN0 pin)
    //! - AIN0 - PE7
    //!
    //! The following UART signals are configured only for displaying console
    //! messages for this example.  These are not required for operation of the
    //! ADC.
    //! - UART0 peripheral
    //! - GPIO Port A peripheral (for UART0 pins)
    //! - UART0RX - PA0
    //! - UART0TX - PA1
    //!
    //! This example uses the following interrupt handlers.  To use this example
    //! in your own application you must add these interrupt handlers to your
    //! vector table.
    //! - None.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // This function sets up UART0 to be used for a console to display information
    // as the example is running.
    //
    //*****************************************************************************
    void
    InitConsole(void)
    {
        //
        // Enable GPIO port A which is used for UART0 pins.
        // TODO: change this to whichever GPIO port you are using.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Configure the pin muxing for UART0 functions on port A0 and A1.
        // This step is not necessary if your part does not support pin muxing.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
    
        //
        // Enable UART0 so that we can configure the clock.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Use the internal 16MHz oscillator as the UART clock source.
        //
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
        //
        // Select the alternate (UART) function for these pins.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000);
    }
    
    //*****************************************************************************
    //
    // Configure ADC0 for a single-ended input and a single sample.  Once the
    // sample is ready, an interrupt flag will be set.  Using a polling method,
    // the data will be read then displayed on the console via UART0.
    //
    //*****************************************************************************
    int
    main(void)
    {
        //
        // This array is used for storing the data read from the ADC FIFO. It
        // must be as large as the FIFO for the sequencer in use.  This example
        // uses sequence 3 which has a FIFO depth of 1.  If another sequence
        // was used with a deeper FIFO, then the array size must be changed.
        //
        uint32_t pui32ADC0Value[1];
    
        //
        // Set the clocking to run at 20 MHz (200 MHz / 10) using the PLL.  When
        // using the ADC, you must either use the PLL or supply a 16 MHz clock
        // source.
        // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
        // crystal on your board.
        //
        SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
        //
        // Set up the serial console to use for displaying messages.  This is
        // just for this example program and is not needed for ADC operation.
        //
        InitConsole();
    
        //
        // Display the setup on the console.
        //
        UARTprintf("ADC ->\n");
        UARTprintf("  Type: Single Ended\n");
        UARTprintf("  Samples: One\n");
        UARTprintf("  Update Rate: 250ms\n");
        UARTprintf("  Input Pin: AIN0/PE3\n\n");
    
        //
        // The ADC0 peripheral must be enabled for use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    
        //
        // For this example ADC0 is used with AIN0 on port E7.
        // The actual port and pins used may be different on your part, consult
        // the data sheet for more information.  GPIO port E needs to be enabled
        // so these pins can be used.
        // TODO: change this to whichever GPIO port you are using.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
        //
        // Select the analog ADC function for these pins.
        // Consult the data sheet to see which functions are allocated per pin.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    
        //
        // Enable sample sequence 3 with a processor signal trigger.  Sequence 3
        // will do a single sample when the processor sends a signal to start the
        // conversion.  Each ADC module has 4 programmable sequences, sequence 0
        // to sequence 3.  This example is arbitrarily using sequence 3.
        //
        ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
    
        //
        // Configure step 0 on sequence 3.  Sample channel 0 (ADC_CTL_CH0) in
        // single-ended mode (default) 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 sequence 3 (ADC_CTL_END).  Sequence
        // 3 has only one programmable step.  Sequence 1 and 2 have 4 steps, and
        // sequence 0 has 8 programmable steps.  Since we are only doing a single
        // conversion using sequence 3 we will only configure step 0.  For more
        // information on the ADC sequences and steps, reference the datasheet.
        //
        ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);
    
        //
        // Since sample sequence 3 is now configured, it must be enabled.
        //
        ADCSequenceEnable(ADC0_BASE, 3);
    
        //
        // Clear the interrupt status flag.  This is done to make sure the
        // interrupt flag is cleared before we sample.
        //
        ADCIntClear(ADC0_BASE, 3);
    
        //
        // Sample AIN0 forever.  Display the value on the console.
        //
        while(1)
        {
            //
            // Trigger the ADC conversion.
            //
            ADCProcessorTrigger(ADC0_BASE, 3);
    
            //
            // Wait for conversion to be completed.
            //
            while(!ADCIntStatus(ADC0_BASE, 3, false))       // ---> program stuck HERE
            {
            }
    
            //
            // Clear the ADC interrupt flag.
            //
            ADCIntClear(ADC0_BASE, 3);
    
            //
            // Read ADC Value.
            //
            ADCSequenceDataGet(ADC0_BASE, 3, pui32ADC0Value);
    
            //
            // Display the AIN0 (PE7) digital value on the console.
            //
            UARTprintf("AIN0 = %4d\r", pui32ADC0Value[0]);
    
            //
            // This function provides a means of generating a constant length
            // delay.  The function delay (in cycles) = 3 * parameter.  Delay
            // 250ms arbitrarily.
            //
            SysCtlDelay(SysCtlClockGet() / 12);
        }
    }

  • Hello Georg,

    Thanks for taking the advice from Veikko and myself. OK so in the code mentioned above there is an important information. The code is for ADC is for TM4C123 and as you mentioned since you are running it on TM4C129. The following change needs to be made

    1. SysCtlClockSet to be replaced by SysCtlClockFreqSet
    2. SysCtlClockGet to be replaced by the return value SysCtlClockFreqSet

    For the same you can check one of the TM4C129 example like udma_demo

    Regards
    Amit
  • I removed all of the UART stuff + commented out the SysCtlDelay. Worked for me, even with the wrong clock configuration commands (the SysCtlClockSet & Get are for the TM4C123 only, you have TM4C129, so did I for this run)

    I set a breakpoint after ADCSequenceDataGet and could see slightly fluctuating values, as expected. Then again, I'm on CCS, so it just might be a compiler issue? Anyway, I'm not equipped to help you further - no IAR licenses here...
  • Hello Amit,

    It Works! Thanks a lot for the solution, I had not noticed the different name of the function , I made ​​a silly mistake , but thanks to you I have now solved!

    Best Regards
    Georg
  • Hello Georg,

    That and the fact that the define for TM4C129 are different in compilation flow.

    Regards
    Amit