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.

ADCSequenceDataGet, XM4C129XNCZADI rev.G1

Hi.

I try use function ADCSequenceDataGet in interrupt ADC Sequence 0. 

void ADCIntHandler(void)
{int I;
	uint32_t pui32ADC0Value[6];
	ADCIntClear(ADC0_BASE, 0);

	while(!ADCIntStatus(ADC0_BASE, 0, false)) { }
	ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);
}

Inteerupt properly executed, but then there is an interrupt FaultISR (Hard Fault 0x3). 

If I don't use ADCSequenceDataGet everything is working properly:

void ADCIntHandler(void)
{int I;
	uint32_t pui32ADC0Value[6];
	ADCIntClear(ADC0_BASE, 0);

	while(!ADCIntStatus(ADC0_BASE, 0, false)) { }
	//ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);
}

SysCtrl init:

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

ADC Init:

     SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
     //
     // For this example ADC0 is used with AIN0/1 on port E7/E6.
     // 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);
	 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
     //
	 // 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_1 | GPIO_PIN_3 );
	 GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | 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.
	    //
	 	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 30);
	    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);

	    //
	    // Configure step 0 on sequence 3.  Sample channel 0 (ADC_CTL_CH0) in
	    // differential mode (ADC_CTL_D) 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, refer to the datasheet.
	    //
	    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 );
	    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH2 );
	    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH16);
	    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH17);
	    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH18);
	    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH19 | ADC_CTL_IE | ADC_CTL_END);

	    //
	    // Since sample sequence 3 is now configured, it must be enabled.
	    //
	    ADCSequenceEnable(ADC0_BASE, 0);

	    //
	    // Clear the interrupt status flag.  This is done to make sure the
	    // interrupt flag is cleared before we sample.
	    //
	    ADCIntEnable(ADC0_BASE, 0);
	    IntEnable(INT_ADC0SS0);
	    ADCIntClear(ADC0_BASE, 0);

Timer init

	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
	TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
	ui32Period1 = (ui32SysClk / 100) / 2;
	TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period1 -1);
	//TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
	TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
	TimerEnable(TIMER0_BASE, TIMER_A);

Please help, I do not know what to do

  • Hello Ivan,

    1. Where is pui32ADC0Value[0] declared?
    2. Why are you clearing the interrupt status using ADCIntClear before getting the interrupt status in the while loop of the interrupt handler? If the Interrupt has been asserted then the clear operation is sufficient and you do not need to wait for the status

    Regards
    Amit
  • 1. Where is pui32ADC0Value[0] declared?

    3th string.

    void ADCIntHandler(void)
    {int I;
        uint32_t pui32ADC0Value[6];
        ADCIntClear(ADC0_BASE, 0);
    
        while(!ADCIntStatus(ADC0_BASE, 0, false)) { }
        ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);
    }

    2. Why are you clearing the interrupt status using ADCIntClear before getting the interrupt status in the while loop of the interrupt handler? If the Interrupt has been asserted then the clear operation is sufficient and you do not need to wait for the status

    while(!ADCIntStatus(ADC0_BASE, 0, false)) { }

    I added this line after reading this post  .I know that it is not necessary to do so. I just tried different options. However, the presence or absence of this line does not affect the work of the code - there is still a mistake. 

    Maybe I set the wrong settings somewhere.

  • Hello Ivan,

    The code looks fine to me. Can you check the NVIC_FAULTSTAT register and NVIC_FAULTADDR register and let me know what the Fault Value and Address are?

    Regards
    Amit
  • Hi,

    Your code to get the samples should be written as this:

    ADCSequenceDataGet(ADC0_BASE, 0, pui32ADC0Value);

    and your pui32ADC0Value should be declared outside the interrupt routine - if inside, the array is created on stack and is lost when leaving the interrupt routine - depends on how you write further your code.

    Hungarian notations is confusing here...

    Petrei 

  •  Can you check the NVIC_FAULTSTAT register and NVIC_FAULTADDR register and let me know what the Fault Value and Address are?

    NVIC_FAULTSTAT  0x00000400 / 0x00000001 (there are different values)

    NVIC_FAULTADDR  0xE000EDF8

    xPRS 0x01000003

  • Hello Ivan

    Petrei is right (and I may be wrong). The Fault Status is indicating an IMPRECISE bus fault which is caused by a LDR or STR to an incorrect address in the memory map.

    Regards
    Amit
  • Hi.

    I take into account your comments. The effect is, but the problem remained. Interrupting happens several times, but later reappears faulrSR.

    I tried to call the ADCSequenceDataGet not interrupted.

    uint32_t pui32ADC0Value[6];
    void ADCIntHandler(void)
    {
    TEST_PIN(1)
    	ADCIntClear(ADC0_BASE, 0);
    	adc_flag=1;
    	//ADCSequenceDataGet(ADC0_BASE, 0, pui32ADC0Value);
    TEST_PIN(0)
    }
    int main(void)
    {
    ...
        while(1)
        {
    
        	if(adc_flag)
        	{
        		ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);
        		adc_flag=0;
        	}
        }
    }

    And it works. It turns out that this function can not be called from interrupt?

  • Hi,

    Ivan Kapustin said:
    if(adc_flag) { // NOT here gain! ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]); adc_flag=0; }

    Do not duplicate the call there. Just process pui32ADC0Value[x] since the data is already there if you uncomment the line in interrupt routine. BTW, is written wrong, not even copy/paste? 

    Maybe it will be useful to run another simpler ADC project and see/understand how it works - see the file Tiva/examples/peripherals/adc/single_ended.c file.

    Also, keep in mind that faultISR can be generated if another problem, giving you the impression the bug is there. If fault, go to Debug window in debugger and you will see the stack frames - below the faultISR line is another one - just click on that to see which line/function generated that fault - and tell us...

    Petrei

  • Maybe it will be useful to run another simpler ADC project and see/understand how it works - see the file Tiva/examples/peripherals/adc/single_ended.c file.

            I watched this project and it totally works for me.

    Also, keep in mind that faultISR can be generated if another problem, giving you the impression the bug is there. If fault, go to Debug window in debugger and you will see the stack frames - below the faultISR line is another one - just click on that to see which line/function generated that fault - and tell us...

    Do not duplicate the call there. Just process pui32ADC0Value[x] since the data is already there if you uncomment the line in interrupt routine. BTW, is written wrong, not even copy/paste? 

    I will try to describe all the details, because I think that I do not understand.

    I want to set the measurement of the ADC. Trigger - ADC_TRIGGER_TIMER. Processing of the results - to interrupt the ADC.

    If I call the function ADCSequenceDataGet to interrupt, then there FaultISR (see image above). The code (I removed all the comments, which can not be properly interpreted):

    uint32_t pui32ADC0Value[6];
    void ADCIntHandler(void)
    {
    TEST_PIN(1)
    	ADCIntClear(ADC0_BASE, 0);
    	adc_flag=1;
    	ADCSequenceDataGet(ADC0_BASE, 0, pui32ADC0Value);
    TEST_PIN(0)
    }
    
    int main(void)
    {
        ui32SysClk =SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                SYSCTL_CFG_VCO_480), 120000000);
    ...
            
            unsigned long ui32Period1;
    	//таймер для ADC 100Гц
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    	TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    	ui32Period1 = (ui32SysClk / 100) / 2;
    	TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period1 -1);
    	//TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
    	TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    	TimerEnable(TIMER0_BASE, TIMER_A);
    
             GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1 | GPIO_PIN_3 );
    	 GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 );
    	
    	 ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 30);
    	 ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
    
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 );
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH2 );
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH16);
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH17);
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH18);
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH19 | ADC_CTL_IE | ADC_CTL_END)
    	 
             ADCSequenceEnable(ADC0_BASE, 0);
    
    	 ADCIntEnable(ADC0_BASE, 0);
    	 IntEnable(INT_ADC0SS0);
    	 ADCIntClear(ADC0_BASE, 0);
    ...
             while(1) {  }
    }

    If I call the function ADCSequenceDataGet not interrupt, then everything works fine. The сode:

    uint32_t pui32ADC0Value[6];
    void ADCIntHandler(void)
    {
    TEST_PIN(1)
    	ADCIntClear(ADC0_BASE, 0);
    	adc_flag=1;
    TEST_PIN(0)
    }
    
    int main(void)
    {
        ui32SysClk =SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                SYSCTL_CFG_VCO_480), 120000000);
    ...
            
            unsigned long ui32Period1;
    	//таймер для ADC 100Гц
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    	TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    	ui32Period1 = (ui32SysClk / 100) / 2;
    	TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period1 -1);
    	//TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
    	TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    	TimerEnable(TIMER0_BASE, TIMER_A);
    
             GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1 | GPIO_PIN_3 );
    	 GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 );
    	
    	 ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 30);
    	 ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
    
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 );
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH2 );
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH16);
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH17);
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH18);
    	 ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH19 | ADC_CTL_IE | ADC_CTL_END)
    	 
             ADCSequenceEnable(ADC0_BASE, 0);
    
    	 ADCIntEnable(ADC0_BASE, 0);
    	 IntEnable(INT_ADC0SS0);
    	 ADCIntClear(ADC0_BASE, 0);
    ...
             while(1)
             { 
        	       if(adc_flag)
        	       {
        		   ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);
        		   adc_flag=0;
        	       }        
             }
    }

    If anyone can check my code into your CPU or bring your exact working code, please help.

  • Hello Ivan,

    I ran the first scenario (interrupt based) and it is working on my connected launchpad

    Of course the code was not compiling...

    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH19 | ADC_CTL_IE | ADC_CTL_END) does not end with ";"

    Also what was interesting to me was the fact that the timer is supposed to generate trigger at 600KHz but the ADC is configured to sample at 125KHz. That is not correct behavior. The timer trigger has to be less than or equal to ADC Sample Rate

    Regards
    Amit
  • Hi.

                     Of course the code was not compiling...

                    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH19 | ADC_CTL_IE | ADC_CTL_END) does not end with ";"

    Yes, I accidentally deleted it along with comments.

                      Also what was interesting to me was the fact that the timer is supposed to generate trigger at 600KHz but the ADC is configured to sample at 125KHz.                         That is not correct behavior. The timer trigger has to be less than or equal to ADC Sample Rate

            TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    	ui32Period1 = (ui32SysClk / 100) / 2;
    	TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period1 -1);
    	//TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
    	TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    	TimerEnable(TIMER0_BASE, TIMER_A);

    I think you're wrong. The trigger outputs frequency measurement 200 Hz, I checked with an oscilloscope.

  • Hi,

    Looking to your debug window - seems strange and weird - you should have, starting from the bottom: "C_init_00" which is TI's C initialization module, then "main" , (maybe some other function), and the last FaultISR. This suggest you have some problems with building the application and the fault is generated before entering main function.

    To verify, just import one TI made application, set a breakpoint somewhere into a function and then look at the debug window.  Play with clicking on each frame - of coarse the bottom one will report missing code (that is normal).

    Petrei

     

  • Hi.

    Looking to your debug window - seems strange and weird - you should have, starting from the bottom: "C_init_00" which is TI's C initialization module, then "main" , (maybe some other function), and the last FaultISR. This suggest you have some problems with building the application and the fault is generated before entering main function.

    All right. If there FaultISR I always displayed (without the stack of function calls). If everything works correctly, as in this picture:

  • I have found the right solution. First, you need to initialize the ADC, later timer. And to add waiting readiness FIFO ADC. Safety code:

    uint32_t pui32ADC0Value[6];
    uint32_t asdf =0;
    void ADCIntHandler(void)
    {
    asdf=~asdf;
    TEST_PIN(asdf)
    	//
    	ADCIntClear(ADC0_BASE, 0);
    	ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);
    }
    
    int main(void)
    {
        uint32_t ui32Val,tmp=0xFF;
    
        uint32_t ui32X, ui32Y;
    
    
        //
        // Set the PLL and system clock to the frequencies needed to allow
        // generation of the required pixel clock.
        //
        ui32SysClk =SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                SYSCTL_CFG_VCO_480), 120000000);
    
         InitConsole();
    
    
         IntMasterDisable();
    
         Hard_Init();
    
         Init_All_Coeff();
        //
        // Enable interrupts.
        //
        IntMasterEnable();
    ...
    }
    
    
    
    void Init_ADC(void)
    {unsigned long tmpul_0=0;
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
    
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1 | GPIO_PIN_3 );
    	GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 );
    
    	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 60);
    	ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
    
    	ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 );
    	ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH2 );
    	ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH16);
    	ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH17);
    	ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH18);
    	ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH19 | ADC_CTL_IE | ADC_CTL_END);
    
    	while(!(HWREG(ADC0_BASE + ADC_O_SSFSTAT0) & ADC_SSFSTAT0_EMPTY))
    	{
    		tmpul_0 = HWREG(ADC0_BASE + ADC_O_SSFIFO0);
    	}
    
    	ADCSequenceEnable(ADC0_BASE, 0);
    	ADCIntEnable(ADC0_BASE, 0);
    	IntEnable(INT_ADC0SS0);
    	ADCIntClear(ADC0_BASE, 0);
    }
    
    void Init_Timers(void)
    {
    	unsigned long ui32Period1;
    	//таймер для ADC 200Гц
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    	TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    	ui32Period1 = (ui32SysClk / 100) / 2;
    	TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period1 -1);
    	//TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
    	TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    	TimerEnable(TIMER0_BASE, TIMER_A);
    	//таймер для мс 1кГц
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    	TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
    	ui32Period1 = (ui32SysClk / 1000) / 2;
    	TimerLoadSet(TIMER1_BASE, TIMER_A, ui32Period1 -1);
    	IntEnable(INT_TIMER1A);
    	TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    	TimerEnable(TIMER1_BASE, TIMER_A);
    }
    
    void Hard_Init(void)
    {
    	Init_ADC();
    	Init_Timers();
    	//Init_LDC1000_Interface();
    	Init_SW01_Interface();
    	Init_keys_8();
    	Init_solenoids();
    	Init_EEPROM();
    	//тестовые выходы
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    	GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_1);
    }

    Thank you all.

  • Hello Ivan

    Looks like you have corrected the sample rate as well!!!

    Regards
    Amit