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 Sample Sequencers



I am using TIVA Series TM4C129 chip in my application.  Currently I am working on ADC module and I have come across Sample Sequencer which is not common as traditional single or double sampling approaches.  I have few questions on this:

Why this sample sequencer?  What are the advantages of this?

There is a term used “step” in this regard? What is the relation between step and sample sequencer?

Datasheet uses the term samples which is matching with “steps” (step is used in other documents like ROM user’s guide) in terms of numbers, are both the same?

To understand this I have conducted an experiment as below:

My hardware has only one analog channel connected to AIN0 (with potentiometer connected to it) and my code is as below:

static void init_adc(void) {

MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);

MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);

MAP_ADCSequenceDisable(ADC0_BASE, SAMPLE_SEQUENCER_2);

MAP_ADCSequenceConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, ADC_TRIGGER_ALWAYS, SS_priority_3);

MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, 0, ADC_CTL_CH1 | ADC_CTL_END);

MAP_ADCHardwareOversampleConfigure(ADC0_BASE, _NO_HARDWARE_OVERSAMPLING);

MAP_ADCSequenceEnable(ADC0_BASE, SAMPLE_SEQUENCER_2);

}

void adc_testing_task(UArg arg0, UArg arg1) {

                while(1)

                {

Task_sleep(10000);

                                test_read_adc_polling();

                }

}

 

static void test_read_adc_polling()

{

                uint32_t tempBuf[SS2_FIFO_depth];

                MAP_ADCSequenceDataGet(ADC0_BASE, 2, tempBuf);

}

 

After running the program my tempBuf values are as below:

Potentiometer position minimum: tempBuf values : 170, 171, 171, 173

Potentiometer position middile: tempBuf values : 455, 462, 459, 458

Potentiometer position maximum: tempBuf values : 4095, 4095, 4081, 4070

My understanding:  Values which is read to tempBuf corresponds to a single analog channel (AIN0) retrieved from a FIFO.

Note: Sometimes samplesRead is 5 but my tempBuf size is of 4 (still the program runs without crashing)

If I configure the 4 analog channels at once as below:

MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, SS_2_step_0, ADC_CTL_CH0);
MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, SS_2_step_1, ADC_CTL_CH1);
MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, SS_2_step_2, ADC_CTL_CH2);
MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, SS_2_step_3, ADC_CTL_CH3 | ADC_CTL_END);

How do I read the analog values of all 4 channels at once?

Do I need to have temBuf[16] (4 *4) to read four channels?

Regards

Srinivasa

  • Hi Srinivasa,

    Since your inquiry is focused on ADC hw rather than TI-RTOS, I am moving your post to the TM4C forum in hopes of a quicker response.

    Regards,
    -- Emmanuel
  • As I mentioned earlier, my hardware has only one analog channel connected to AIN0 (with potentiometer connected to it).

    I have complete ADC code attached.

    Case 1 (Polling mode):

    ADC_MODE_POLLING_TESTING and SAMPLE_SEQUENCER_2_TESTING enabled:

    Breakpoint in function test_read_adc_polling shows that all four values of tempBuf is updated and are almost same as below:

    Potentiometer position minimum: tempBuf values : 170, 171, 171, 173

    Potentiometer position middile: tempBuf values : 455, 462, 459, 458

    Potentiometer position maximum: tempBuf values : 4095, 4095, 4081, 4070

    Since only 1 ADC channel (AIN0) is connected, I was expecting only tempBuf[0] to be updated, why tempBuf[1], tempBuf[2], and tempBuf[3] are updated with same values.

    Case 2 (Interrupt mode):

    ADC_MODE_INTERRUPT_TESTING and SAMPLE_SEQUENCER_2_TESTING) enabled:

    Breakpoint in function ADC0_Sequence3_Interrupt shows that only tempBuf[0] is updated as below:

    Potentiometer position minimum: tempBuf values : 173, 0, 53691552, 448193

    Potentiometer position middile: tempBuf values : 402, 0, 53691552, 448193

    Potentiometer position maximum: tempBuf values : 4081, 0, 53691552, 448193

    Since only 1 ADC channel (AIN0) is connected, only tempBuf[0] is updated, tempBuf[1], tempBuf[2], and tempBuf[3] are filled with garbage values. 

    My understanding says polling mode has improper behavior and interrupt has correct behavior.

    Any justification towards this is appreciated.

    Regards

    Srinivasa

    #if(0)
      #define  ADC_MODE_POLLING_TESTING
    #else
      #define  ADC_MODE_INTERRUPT_TESTING
    #endif
    
    
    //#define  SAMPLE_SEQUENCER_3_TESTING
    #define  SAMPLE_SEQUENCER_2_TESTING
    //#define  SAMPLE_SEQUENCER_1_TESTING
    //#define  SAMPLE_SEQUENCER_0_TESTING
    
    
    /*
     *
     * SAMPLE SEQUENCERS
     *
     * */
    
    enum sample_sequencer {
      SAMPLE_SEQUENCER_0,
      SAMPLE_SEQUENCER_1,
      SAMPLE_SEQUENCER_2,
      SAMPLE_SEQUENCER_3,
      MAX_SAMPLE_SEQUENCER
    };
    
    
    /*
     *
     * SAMPLE SEQUENCERS STEPS
     *
     * */
    
    enum SS_3_step_number {
        SS_3_step_0,
        SS_3_MAX_STEPS
    };
    
    
    enum SS_2_step_number {
        SS_2_step_0,
        SS_2_step_1,
        SS_2_step_2,
        SS_2_step_3,
        SS_2_MAX_STEPS
    };
    
    
    enum SS_1_step_number {
        SS_1_step_0,
        SS_1_step_1,
        SS_1_step_2,
        SS_1_step_3,
        SS_1_MAX_STEPS
    };
    
    
    enum SS_0_step_number {
        SS_0_step_0,
        SS_0_step_1,
        SS_0_step_2,
        SS_0_step_3,
        SS_0_step_4,
        SS_0_step_5,
        SS_0_step_6,
        SS_0_step_7,
        SS_0_MAX_STEPS
    };
    
    enum SS_FIFO_depth {
      SS0_FIFO_depth = 8,
      SS1_FIFO_depth = 4,
      SS2_FIFO_depth = 4,
      SS3_FIFO_depth = 1
    };
    
    /*
     * SAMPLE SEQUENCERS PRIORITY
     *
     * Relative priority of the sample sequence with respect to
     * the other sample sequences.
     *
     * */
    enum SS_priority {
      SS_priority_0,  // Highest Priority
      SS_priority_1,
      SS_priority_2,
      SS_priority_3,  // Lowest Priority
      SS_MAX_PRIORITY
    };
    
    
    enum HW_AVG_CONTROL {
        _NO_HARDWARE_OVERSAMPLING,
        _2X_HARDWARE_OVERSAMPLING,
        _4X_HARDWARE_OVERSAMPLING,
        _8X_HARDWARE_OVERSAMPLING,
        _16X_HARDWARE_OVERSAMPLING,
        _32X_HARDWARE_OVERSAMPLING,
        _64X_HARDWARE_OVERSAMPLING,
        MAX_AVERAGING_LEVELS
    };
    
    
    static void init_adc(void)
    {
    
    
      /*
       *
       *   A D C   I N I T  (P O L L I N G).
       *
       * */
    
    
    #ifdef ADC_MODE_POLLING_TESTING
    
        #ifdef SAMPLE_SEQUENCER_3_TESTING
          MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    
          MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    
          MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);
    
          MAP_ADCSequenceDisable(ADC0_BASE, SAMPLE_SEQUENCER_3);
    
          MAP_ADCSequenceConfigure(ADC0_BASE, SAMPLE_SEQUENCER_3, ADC_TRIGGER_ALWAYS, SS_priority_3);
    
          MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_3, SS_3_step_0, ADC_CTL_CH0 | ADC_CTL_END);
    
          MAP_ADCHardwareOversampleConfigure(ADC0_BASE, _NO_HARDWARE_OVERSAMPLING);
    
          MAP_ADCSequenceEnable(ADC0_BASE, SAMPLE_SEQUENCER_3);
        #endif
    
        #ifdef SAMPLE_SEQUENCER_2_TESTING
          MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    
          MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    
          MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);
    
          MAP_ADCSequenceDisable(ADC0_BASE, SAMPLE_SEQUENCER_2);
    
          MAP_ADCSequenceConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, ADC_TRIGGER_ALWAYS, SS_priority_3);
    
          MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, SS_2_step_0, ADC_CTL_CH0 | ADC_CTL_END);
    
          MAP_ADCHardwareOversampleConfigure(ADC0_BASE, _NO_HARDWARE_OVERSAMPLING);
    
          MAP_ADCSequenceEnable(ADC0_BASE, SAMPLE_SEQUENCER_2);
        #endif
    
    #endif
    
    
    
    /*
     *
     *   E N D   O F  A D C  I N I T   (P O L L I N G).
     *
     * */
    
    
    
    /*
     *
     *   A D C   I N I T  ( I N T E R R U P T).
     *
     * */
    
    #ifdef ADC_MODE_INTERRUPT_TESTING
    
        #ifdef SAMPLE_SEQUENCER_3_TESTING
          MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    
          MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    
          MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);
    
          MAP_ADCSequenceDisable(ADC0_BASE, SAMPLE_SEQUENCER_3);
    
          MAP_ADCSequenceConfigure(ADC0_BASE, SAMPLE_SEQUENCER_3, ADC_TRIGGER_PROCESSOR, SS_priority_3);
    
          MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_3, SS_3_step_0, ADC_CTL_CH0 | ADC_CTL_END | ADC_CTL_IE);
    
          MAP_ADCHardwareOversampleConfigure(ADC0_BASE, _NO_HARDWARE_OVERSAMPLING);
    
          MAP_ADCIntEnable(ADC0_BASE, SAMPLE_SEQUENCER_3);
    
          MAP_ADCSequenceEnable(ADC0_BASE, SAMPLE_SEQUENCER_3);
        #endif
    
        #ifdef SAMPLE_SEQUENCER_2_TESTING
          MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    
          MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    
          MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);
    
          MAP_ADCSequenceDisable(ADC0_BASE, SAMPLE_SEQUENCER_2);
    
          MAP_ADCSequenceConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, ADC_TRIGGER_PROCESSOR, SS_priority_3);
    
          MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_2, SS_2_step_0, ADC_CTL_CH0 | ADC_CTL_END | ADC_CTL_IE);
    
          MAP_ADCHardwareOversampleConfigure(ADC0_BASE, _NO_HARDWARE_OVERSAMPLING);
    
          MAP_ADCIntEnable(ADC0_BASE, SAMPLE_SEQUENCER_2);
    
          MAP_ADCSequenceEnable(ADC0_BASE, SAMPLE_SEQUENCER_2);
        #endif
    
    #endif
    
    /*
    *
    *   E N D   O F  A D C  I N I T  ( I N T E R R U P T).
    *
    * */
    
    }
    
    
    
    unsigned int value;
    unsigned int value1;
    
    int32_t samplesRead;
    
    static void test_read_adc_polling()
    {
      int32_t samplesCopied;
    
        #ifdef SAMPLE_SEQUENCER_3_TESTING
            uint32_t tempBuf[SS3_FIFO_depth];
    
            MAP_ADCSequenceDataGet(ADC0_BASE, SAMPLE_SEQUENCER_3, tempBuf);
    
            value = tempBuf[0];
            value =   value1 + value;
        #endif
    
    
        #ifdef SAMPLE_SEQUENCER_2_TESTING
            uint32_t tempBuf[SS2_FIFO_depth];
    
            samplesCopied = MAP_ADCSequenceDataGet(ADC0_BASE, SAMPLE_SEQUENCER_2, tempBuf);
    
            samplesRead = samplesCopied;
    
            value = tempBuf[0];
            value =   value1 + value;
        #endif
    
    }
    
    /*
     *
     * A D C   T A S K
     *
     * */
    
    void adc_testing_task(UArg arg0, UArg arg1)
    {
      Task_sleep(10000);
    
        #ifdef ADC_MODE_INTERRUPT_TESTING
    
        #ifdef SAMPLE_SEQUENCER_3_TESTING
            Hwi_Params ADC0_SS3_Params;
            Hwi_Handle ADC0_SS3_interrupt;
    
    
            /*
             * Register ADC SS2 interrupt handler.
             * */
            Hwi_Params_init(&ADC0_SS3_Params);
    
            ADC0_SS3_Params.enableInt = true;
            ADC0_SS3_Params.instance->name = "ADC_SS3_interrupt";
    
            ADC0_SS3_interrupt = Hwi_create(33, ADC0_Sequence3_Interrupt, &ADC0_SS3_Params, NULL);
        #endif
    
    
        #ifdef SAMPLE_SEQUENCER_2_TESTING
            Hwi_Params ADC0_SS2_Params;
            Hwi_Handle ADC0_SS2_interrupt;
    
    
            /*
            * Register ADC SS2 interrupt handler.
            * */
            Hwi_Params_init(&ADC0_SS2_Params);
    
            ADC0_SS2_Params.enableInt = true;
            ADC0_SS2_Params.instance->name = "ADC_SS2_interrupt";
    
    
            ADC0_SS2_interrupt = Hwi_create(32, ADC0_Sequence2_Interrupt, &ADC0_SS2_Params, NULL);
    
        #endif
    
        #endif
    
        Task_sleep(10000);
    
        while(1)
        {
            Task_sleep(1000);
    
            #ifdef ADC_MODE_POLLING_TESTING
                test_read_adc_polling();
            #endif
    
    
            #ifdef ADC_MODE_INTERRUPT_TESTING
    
                #ifdef SAMPLE_SEQUENCER_3_TESTING
                    MAP_ADCProcessorTrigger(ADC0_BASE, SAMPLE_SEQUENCER_3);
                #endif
    
                #ifdef SAMPLE_SEQUENCER_2_TESTING
                    MAP_ADCProcessorTrigger(ADC0_BASE, SAMPLE_SEQUENCER_2);
                #endif
    
            #endif
      }
    
    }
    
    /*
     *
     * A D C  I N T E R R R U P T   H A N D L E R S
     *
     * */
    
    #ifdef ADC_MODE_INTERRUPT_TESTING
    
        #ifdef SAMPLE_SEQUENCER_3_TESTING
    
            void ADC0_Sequence3_Interrupt(UArg arg)
            {
                uint32_t tempBuf[SS3_FIFO_depth];
                MAP_ADCIntClear(ADC0_BASE, SAMPLE_SEQUENCER_3);
                MAP_ADCSequenceDataGet(ADC0_BASE, SAMPLE_SEQUENCER_3, tempBuf);
                value = tempBuf[0];
                value =   value1 + value;
            }
    
        #endif
    
    
        #ifdef SAMPLE_SEQUENCER_2_TESTING
    
            void ADC0_Sequence2_Interrupt(UArg arg)
            {
                uint32_t tempBuf[SS2_FIFO_depth];
                MAP_ADCIntClear(ADC0_BASE, SAMPLE_SEQUENCER_2);
                MAP_ADCSequenceDataGet(ADC0_BASE, SAMPLE_SEQUENCER_2, tempBuf);
                value = tempBuf[0];
                value =   value1 + value;
            }
    
        #endif
    
    #endif
    
    
    
    

  • Continuation of debugging for polling mode:

    Tried to read  the data from FIFO with sample sequence disabled and checking for ADC_busy flag but still results are not good.

    MAP_ADCSequenceDisable(ADC0_BASE, SAMPLE_SEQUENCER_0);

    MAP_ADCSequenceConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, ADC_TRIGGER_NEVER, SS_priority_3);

    /*

    Wait for ADC to be free.

    */

    while(ADCBusy(ADC0_BASE) );

    samplesCopied = MAP_ADCSequenceDataGet(ADC0_BASE, SAMPLE_SEQUENCER_0, tempBuf);

    samplesRead = samplesCopied;

    value = tempBuf[0];
    value = value1 + value;

    MAP_ADCSequenceConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, ADC_TRIGGER_ALWAYS, SS_priority_3);

    MAP_ADCSequenceEnable(ADC0_BASE, SAMPLE_SEQUENCER_0);

    Regards

    Srinivasa

  • Tried with SS0 by assigning different channels as below:

    MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);

    MAP_ADCSequenceDisable(ADC0_BASE, SAMPLE_SEQUENCER_0);

    MAP_ADCSequenceConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, ADC_TRIGGER_ALWAYS, SS_priority_3);

    MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, SS_0_step_0, ADC_CTL_CH7);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, SS_0_step_1, ADC_CTL_CH6);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, SS_0_step_2, ADC_CTL_CH5);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, SS_0_step_3, ADC_CTL_CH4);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, SS_0_step_4, ADC_CTL_CH3);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, SS_0_step_5, ADC_CTL_CH2);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, SS_0_step_6, ADC_CTL_CH1);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, SAMPLE_SEQUENCER_0, SS_0_step_7, ADC_CTL_CH0 | ADC_CTL_END);

    MAP_ADCHardwareOversampleConfigure(ADC0_BASE, _NO_HARDWARE_OVERSAMPLING);

    MAP_ADCSequenceEnable(ADC0_BASE, SAMPLE_SEQUENCER_0);

    Still the results are not good.

    Srinivasa

  • Hello Srinivasa

    You are requesting for 8 channels but configuring only 1 as a analog pin. Secondly set the IE bit for the last sample and then use the Interrupt Status API to check when conversion is complete before reading the data.

    Regards
    Amit
  • Tried with one channel but it was not working for polling mode. The behavior is different in Interrupt mode and polling mode.

    Setting the IE bit is done in interrupt mode and it is working fine. What about polling mode?

    I have explained this in detail in my previous blog dated "Jun 29, 2015 7:11 PM" and have attached "adc_polling_interrupt.c" code also.

    Srinivasa
  • Hello Srinivasa,

    The interrupt mask must be set for the interrupt to reach the CPU. when the Interrupt mask bit is not set or the interrupt not enabled then the status can be polled.

    Regards
    Amit
  • Yes, I understand that. In polling mode,
    But when I have configured for only one channel in SS2 why all the buffers are filled with channel 0 data.
    Why the output is not same as interrupt mode?

    Regards
    Srinivasa
  • Hello Srinivasa,

    What I believe is happening is that the FIFO is filled up with Channel 0 data and hence it is returning the same on all 4 locations. Check the return value of the API ADCSequenceDataGet which will tell how many locations were read.

    Regards
    Amit
  • Return value of ADCSequenceDataGet is 4.
    Interrupt mode:
    Return value of ADCSequenceDataGet is 1.

    As you rightly pointed, FIFO is filled with Channel 0 data.

    Need clarity of below points:

    If I have a sample sequencer (say SS2) associated with four input channels say (AIN0 to AIN3) and I have below code to read data:

    int32_t samplesRead;
    uint32_t tempBuf[4];
    samplesRead = MAP_ADCSequenceDataGet(ADC0_BASE, SAMPLE_SEQUENCER_2, tempBuf);

    I was under the understanding that
    tempBuf[0] contains data pertaining to AIN0
    tempBuf[1] contains data pertaining to AIN1
    tempBuf[2] contains data pertaining to AIN2
    tempBuf[3] contains data pertaining to AIN3

    But what is happening here is different. tempBuf[0] to tempBuf[3] is filled with AIN0 data.

    In case of 4 channels configured simultaneously and read, where do I get other channel data?
    Or do I need to have a tempBuf of size 16?

    Regards
    Srinivasa
  • Hello Srinivasa,

    Your understanding is correct. but you should note that the data read must be done only when the Interrupt Status indicates that the buffer is ready.

    Regards
    Amit
  • Hi Amit,

    What you are telling is when ADC is configured in interrupt mode.
    I have two versions of code (Please see “adc_polling_interrupt.c”). In interrupt mode, AIN0 data is available only in tempBuf[0] and tempBuf[1] to tempBuf[3] are filled with garbage values (because I have not connected AIN1 TO AIN3). I am convinced with interrupt mode but not polling mode.

    How about in polling mode? I have not enabled the interrupt (I presume interrupt status will not play a role here)
    Data is available in read buffer (tempBuf), but the sequence of data available in read buffer I am not getting clarity.

    Regards
    Srinivasa
  • Hello Srinivasa,

    The END bit tells the sequencer when to STOP. It does not tell the CPU when the conversion is completed. That is why the IE bit is required so that CPU when polling the status know when the conversion is completed.

    Regards
    Amit
  • Hi Amit,

    In polling mode, do you mean to say, I need to check for IE bit to know whether conversion is complete or not?

    Regards

    Srinivasa

  • Hello Srinivasa,

    You would need to poll the interrupt status bit and not the IE bit.

    Regards
    Amit
  • Hi Amit,

    I hope you are referring to SSx Raw Interrupt Status bit (INRx) in Register ADCRIS.

    Is this correct register and bit.

    Regards
    Srinivasa
  • Hello Srinivasa,

    Yes, that is correct.

    Regards
    Amit
  • Hi Amit,

    This bit is always 0, it is never being set. Control gets stop over there forever if I wait for this bit to become 1.

    If I won't check for this bit, ADC data is available but same data in all buffers.

    Since I am operating ADC in polling mode, MASKx bit in ADCIM register is 0.

    Is this bit valid even if interrupt bit mask is disabled.

    Regards
    Srinivasa
  • Hello Srinivasa,

    Yes. The ADCRIS is valid even when MASK is 0. The MASK when set is AND-ed with ADCRIS and put in ADCISC register.

    Let us also rewind here, can you refer to the ADC example in TivaWare? Also please do share the code that you have (full project zipped and attached)

    Regards,
    Amit
  • Hi Amit,


    TivaWare does not have any ADC examples or TI-RTOS provide any drivers for ADC. Below is the link where I have raised it earlier.

    e2e.ti.com/.../433201

    I have built an example project for this and working on the same. I have posted the same on "Jun 29, 2015 7:11 PM".
    It contains code for polling and interrupt mode. I have compared the behavior of polling mode and interrupt mode.

    Code is available in file adc_polling_interrupt.c dated "Jun 29, 2015 7:11 PM".

    Regards
    Srinivasa
  • Hello Srinivasa,

    Might I suggest the following path in TivaWare D:\ti\TivaWare_C_Series-2.1.1.71\examples\peripherals\adc\single_ended.c

    Regards
    Amit
  • Hi Amit,

    Its an example for single ended interrupt mode (I am clear with interrupt mode and its working fine).

    Do you have any example for single ended polling mode.

    Regards
    Srinivasa
  • Hello Srinivasa,

    Please note it is not triggering a CPU interrupt, but using the ADCRIS polling to make sure conversion is complete.

    Regards
    Amit
  • Hi Amit,

    The code works now as per this example, now only tempBuf[0] is updated.

    The terms used in configuring ADC were confusing. Below statement

    // single-ended mode (default) and configure the interrupt flag
    // (ADC_CTL_IE) to be set when the sample is done. Tell the ADC logic

    ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);

    ADCIntClear(ADC0_BASE, 3);

    1. Configure the interrupt flag
    2. Clear the ADC interrupt flag

    Above statements misleads us that ADC is configured in interrupt mode. (usually busy bit will be used)

    But we don’t have interrupt handler and interrupt is not registered which convinces that this is working in polling mode.

    There were some differences between my code and this example. My code had below statement

    MAP_ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);

    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 | ADC_CTL_END);

    ADC_TRIGGER_ALWAYS and Interrupt flag (ADC_CTL_IE) was not used.

    Will update my code as per above example.

    Regards
    Srinivasa
  • Hello Srinivasa

    And we will try to clarify what polling and interrupt mechanism means in the context of this example

    Regards
    Amit
  • ADC in interrupt mode:

    I have four ADC channels (Ain0, Ain1, Ain2 and Ain3) associated with Sample sequencer SS2.

    Upon MAP_ADCProcessorTrigger(ADC0_BASE, 2);

    I will get all four channels in the array as shown below:

    void ADC0_Seq2_Int_Handler(UArg arg) {
    uint32_t tempBuf[4];
    MAP_ADCIntClear(ADC0_BASE, 2);
    MAP_ADCSequenceDataGet(ADC0_BASE, 2, tempBuf);
    }

    Now the tempBuf contains the ADC data of all four channels as below:

    tempBuf[0] contains adc data for channel 0;
    tempBuf[1] contains adc data for channel 1;
    tempBuf[2] contains adc data for channel 2;
    tempBuf[3] contains adc data for channel 3;

    Sometimes, I may not be interested in all four channels data at once but I would like to pass only one channel data to application layer. Because application layer asks driver a particular channel data, so I want to pass only one channel data (i.e 2 bytes maximum) to application using mail box.

    But in interrupt I have data for four channel and we cannot do a trigger on a particular channel.

    Somehow I feel that associating multiple analog channels to a common sample sequencer makes design of ADC driver problematic to get individual channel data.

    Looking for your thoughts on this.
  • Hello Srinivasa,

    So what is the issue in passing the data as requested by the application layer. You need to architect the middleware correctly to handle such requests.
    Having multiple channels in a Sample Sequencer allows others to get data for a set of channels without having to reconfigure every time.

    Regards
    Amit
  • Hi Amit,

    Since application layer cannot trigger on individual channel, ADCProcessorTrigger is done for all channels in the selected Sample sequencer.

    Once we are in ISR, we don’t have a track of which channel user was interested in?

    Though user is interested in one channel data he is forced to trigger for a Sample sequence and will get all channel data.

    Until we have underlying hardware registers to get individual ADC channel data, I am not quite sure how middleware will be able to resolve this.

    Regards
    Srinivasa
  • It would be a poor system that lost track of which channel you were converting. You know which channel since you know how the sequence was set up.

    Note: it is possible to set up a sequence to convert a single channel. Maybe not efficient but certainly possible. I do that myself during initialization to preload my filters.

    Robert
  • Hello Srinivasa

    I agree with Robert. It would indeed be a poor system if it cannot track the channel request. Also as Robert mentioned, it would be wiser to put one sample sequencer per channel. The last option if you have more than 8 channels and you have run out of Sample Sequencer on the two ADCs would be to reconfigure the Sample Sequencer as instructed by the application/

    Regards
    Amit
  • Hi Amit,

    As Robert mentioned it is possible to setup a sample sequencer to a single channel and currently my code is doing the same (it is as below)

    SS0 is associated with AIN0
    SS1 is associated with AIN1
    SS2 is associated with AIN2
    SS3 is associated with AIN3

    By doing so I have a track of channel request and everything works fine and as Robert mentioned it is not efficient method.

    If a Sample sequencer is capable of handling 8 channels at a time why should I use it for only 1 channel?

    If I want to use more than 4 analog channels, I cannot follow this approach because I have max of 4 sample sequencer. As you mentioned application has to reconfigure the Sample sequencer and which is again overhead on application.

    Having four Interrupt handlers for four channels is not efficient method, so thought of grouping all four channels to a single sample sequencer and keeping track of channels numbers. Is this possible?

    Regards
    Srinivasa
  • That's the normal technique Srinivasa.

    Robert
  • Hello Srinivasa,

    I can suggest the TMS470M device which has ADC channels as bit masked in a register. So by setting the appropriate bit the channels that are set will be converted. However if there is an order of channel conversion that can't be done. That is an alternative

    Coming back to the topic of TM4C129x devices, the demand from your application is such that the HW has to be told which channels to convert. Since the application layer is not predictable, the overhead in the middleware shall be there.

    Eventually you have to pick the most optimum solution for your end product.

    Regards
    Amit