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-TM4C1294XL: ADC - interrupts and program stuck

Part Number: EK-TM4C1294XL

Hi all,

I'm facing a strange issue regarding the ADC. I would like to convert X times the temperature sensor as fast as possible (in the future it will be an analog signal). So I enable the ADC, use the ADC handler and interrupt to put the result in a global variable and I want to wait for having my X samples. However even if the samples are done I m not able to use a loop for waiting for the end of the X samples. I don't understand why the code is stuck after the end of the sampling.

Actually if I put the line while(adc_seq < 1000{} in end of my main to wait for end of sampling then the code is stuck. If I don't use that line then it works. I must be sure that the X samples are done before starting the remaining code so I have to wait. Has someone an idea ?

thanks in advance

static int adc_seq = 0;					
static uint32_t adc_data[1000];					

void ADC0seq3_Handler(void){
    uint32_t ADC0Value[1];								
    ADCSequenceDataGet(ADC0_BASE, 3, ADC0Value);  		   // Retrieve value.
    adc_data[adc_seq] = (1475 - ((2475 * ADC0Value[0]))/4096)/10;  // Formula in data sheet VNREF 0 and VREFP 3.3 all *10 to avoid fraction.
    if(adc_seq < 1000){										// ADC must still work
	    adc_seq++;
	    ADCIntClear(ADC0_BASE, 3);							  
    }
    else{					//Disable ADC after 1000 samples
	    ADCSequenceDisable(ADC0_BASE, 3);
    }
}

void InitConvertADC(void){
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);			// Enable the ADC0.
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0)){}		// Wait till ADC0 is ready.
    ADCSequenceDisable(ADC0_BASE, 3); 				// Sequencer must be disabled before config : SS3 of ADC0
    ADCIntDisable(ADC0_BASE, 3);				// Disable interruption for ADC0
    IntDisable(INT_ADC0SS3_TM4C129);				// Disable interruption feature for the sequence 3 of ADC0
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1); 	
    ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_ALWAYS, 0);  // Use ADC0, sample sequencer 3 with always trigger
    ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_TS | ADC_CTL_IE | ADC_CTL_END);
    ADCIntClear(ADC0_BASE, 3);					// Clear interrupt flag.
    IntEnable(INT_ADC0SS3_TM4C129);				// Enable interrupt feature.
    ADCIntEnable(ADC0_BASE, 3);					// Enable sequencer interrupt.
    ADCSequenceEnable(ADC0_BASE, 3);			        // Enable sequencer ADC0 seq3.
}

int main(void)
{
    while(adc_seq < 1000){							
	    adc_data[adc_seq] = 0;
	    adc_seq++;
    }
    adc_seq = 0;								// Reset adc_seq

    BoardInit();								// Initialize the board.
    ConsComInit();								// Initialize the communication with the computer via UART0.

    UARTprintf("\033[2J\033[H");														
    UARTprintf("TEST\n\n");		// Print banner

    InitConvertADC();                   // Start convertion
    while(adc_seq < 1000{}              // If this line is used then the code is stuck and I never get farther. If not used then it works.
    UARTprintf("\nAnalog to digital conversion is now over\n");

}

  • Nicolas Demonty said:

    if(adc_seq < 1000){ // ADC must still work

    adc_seq++;

    ADCIntClear(ADC0_BASE, 3); }

    Does not this code eventually (advance) "adc_seq" to the value "1000?"    When adc_seq = 999 that value will be incremented.

    Then - when you employ:

    while(adc_seq < 1000{}

    with adc_seq equal to 1000 - that "while" loop is no longer true.    

    Shouldn't you "monitor" adc_seq - so that you know your program is properly handling that variable?    No such mention appears w/in your post.

  • Hi,

    I agree with cb1 about your code in interrupt routine. But I have also some other observations: you should clear ADC interrupt outside of if-else block - clearing only in if clause and not in else, when the code executes else clause, the interrupt is not cleared, and may cause to re-enter that, and spinning between in-out.

    Also, your program structure is not good:

    1. the initialization code for adc_data array can be written simpler as :static uint32_t adc_data[1000]=0;and the compiler will take care to have the array initialized as desired.
    2. you exit the program, after the last line, as in a PC program - this is not the case, you do not have an operating system, so you must have an expression as this: while(1){} at the end. Otherwise this will result in a fault.
    3. your conversion is not needed to be to the highest rate - start with a timer controlling the ADC conversion, use lower rates at the beginning, until your program "works", then you can increase the rate. In practice, an analog signal should be sampled with a little bit more than 2x the highest frequency component (say 4x...5x) and bandwidth limited. Depends also on what you do with that signal.

     

  • Hi cb1, Hi Petrei,

    thanks for having taken the time to answer. Here are more precisions about what I would like to do, to avoid and what I already tested.

    Actually with the full rate sampling all the 1000 interrupts occur faster than the execution of the code after but if I decrease the sampling rate I'm afraid to have the next code executed between two samplings. I really need to be 100% sure that 1000 samples are done before executing the next code. That is the reason why I need to wait for adc_seq to reach 1000.

    To answer the remark about adc_seq there are two scenarii :

    1. Sampling is fast enough and interrupts occur fast enough to never reach the while(adc_seq < 1000) line before the 1000 samples. It that case adc_seq equals 1000 and the "while" is not met and therefore it should skip it and do the last UARTPrint command. This scenario is what happen in my program. I mean that adc_seq reaches 1000 but the "while" seems to block the program and my last UARTPrint is never done.

    2. Sampling is too slow and we reach the while(adc_seq < 1000) between two interrupts. Then it should wait in a loop for all interrupts are done. This scenario is not met for now in my program.

    I would like the following points :

    - I tested by displaying all the adc_seq values in the adc handler "if" condition and it goes till 999

    - I also tested by displaying the adc_seq in the adc handler "else" condition and it is 1000 which is correct.

    - I have to confirm (because I don't really remember) but if I just add a UARTPrint in the "while(adc_seq <1000)" waiting loop then it works.

    So may be I'm wrong but I have the feeling that we enter the loop when adc_seq = 0 and before the loop checks the next time adc_seq it became 1000 because of all interrupts. I have difficulties to explain what I mean but I think there is an issue when having :

    1. adc_seq == 0 : enter while loop
    2. 1000 interrupts are done and sampling is disabled

    3. adc_seq == 1000 and the while is like in an incoherent state.

    What is sure it that the adc_seq is 1000 after the 1000 samlings. The "else" condition in the adc handler is done. But this "while" loop is like stuck.

    kr

    Nicolas

  • Thank you - response & detail appreciated.

    Now - I especially like friend Petrei's, "Guidance #3" which agrees much w/"KISS." He suggests that you, "Slow, Simplify and Test/Verify each element (section) of your program independently - before you "blend then all" together.

    Note too - that use of the UART always adds substantial time delay to your program - and may disrupt (any/all) routines which demand "reasonably fast & complete" execution.

    May I suggest that an Led blink replaces the UART usage - at least until your program performs as desired...
  • Nicolas Demonty said:
    static int adc_seq = 0;

    Given that the adc_seq is written to by an interrupt routine, and polled on a while loop in the main function, the variable should be declared as volatile. i.e. use:

    static volatile int adc_seq = 0;

    Otherwise, the compiler optimizer may turn the following into an infinite loop, since it may conclude that adc_seq won't be changed outside of the while loop:

        while(adc_seq < 1000{}              // If this line is used then the code is stuck and I never get farther. If not used then it works.

    [Also, the above while loop in the posted code looks invalid C, since it is missing the closing parenthesis]

  • Hi all,

    thanks for your tips and solutions. I ll try tomorrow and come back to you.

    for the missing parenthesis it is a typo when I copied the code in the forum post.

    thanks

    Nicolas