Handling multiple analog inputs/polling rates using an Analog Mux/SAR ADC

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
KyTr_1955226
Level 6
Level 6
250 sign-ins 10 likes given 50 solutions authored

Hi all,

I'm working on a system that has multiple analog inputs that need to be handled at different rates, and I'd like a little feedback on what might be the best way to go about it.

I have 2 Analog inputs.  The first of which is a control voltage I need to average out and process quickly and constantly for an LED backlight.  The other is a thermal sensor which only needs to be updated every couple seconds.

The solution I came up with for this is an Analog Mux component with the 2 inputs going in and the output running to the input of the SAR ADC component.   I have the SAR ADC configured for 12 bits, free running, internal clock.  I have an ISR tied to EOC to process the incoming readings.  I am taking constant readings on input 0 of the mux, and every 2 seconds I switch to another input, take a single reading, then return to input 0.

The first (0) input of the mux is where it's spending the most time.  My concern is how to handle the switch to other inputs for a single read every 2 seconds or so.  Right now I am switching as shown:

void Svc_Ana_Mux(void){

/*Called repeatedly from main()*/

    if (Get_Temps){

        /*Every 2S*/

        ADC_EOC_Stop();

        ADC_SAR_StopConvert();

        while (!ADC_SAR_IsEndConversion(ADC_SAR_RETURN_STATUS));

        ADC_SAR_GetResult16();     //Clear last conversion

        ADMux_SelectedCh = 1;

        ANA_MUX_SET_TEMP;

        ADC_EOC_ClearPending();

        ADC_EOC_Start();

        ADC_SAR_StartConvert();

        Get_Temps = false;

    }

    if (Get_Brt){

        /*After 1 Read of Temperature Sensor*/

        ADC_EOC_Stop();

        ADC_SAR_StopConvert();

        while (!ADC_SAR_IsEndConversion(ADC_SAR_RETURN_STATUS));

        ADC_SAR_GetResult16();     //Clear last conversion

        ADMux_SelectedCh = 0;

        ANA_MUX_SET_BRT;

        ADC_EOC_ClearPending();

        ADC_EOC_Start();

        ADC_SAR_StartConvert();

        Get_Brt = false; 

    }

}

My interrupt code takes the most recent conversion and generates a moving average:

#define BRT_NUM_READS   32

#define TEMP_NUM_READS  8

volatile uint16_t BrtReadings[BRT_NUM_READS];

volatile uint16_t TempReadings[TEMP_NUM_READS];

volatile uint16_t ADC_Brt_Avg = 0;

volatile uint32_t ADC_Brt_Sum = 0;

volatile uint16_t ADC_Temp_Avg = 0;

volatile uint32_t ADC_Temp_Sum = 0;

uint8_t ADMux_SelectedCh = 0;

void ADC_EOC_Interrupt_InterruptCallback(void){

    /*We get here whenever a conversion is finished*/

    static uint8_t brt_index = 0, temp_index = 0;

    uint16_t adc_val = 0,prev_brt_val = 0,prev_temp_val = 0;

    ADC_EOC_GetState();

    adc_val = ADC_SAR_GetResult16();

    switch (ADMux_SelectedCh){

        case ANA_MUX_BRT_CH:

            prev_brt_val = BrtReadings[brt_index];

            BrtReadings[brt_index++] = adc_val;

            if (brt_index >= BRT_NUM_READS){

                brt_index = 0;  

            }

            ADC_Brt_Sum +=  adc_val;

            ADC_Brt_Sum -=  prev_brt_val;

            ADC_Brt_Avg = (ADC_Brt_Sum >> 5); //Bitshift divide by 32

        break;

       

        case ANA_MUX_FANTEMP_CH:

            prev_temp_val = TempReadings[temp_index];

            TempReadings[temp_index++] = adc_val;

            if (temp_index >= TEMP_NUM_READS){

                temp_index = 0;

            }

            ADC_Temp_Sum += adc_val;

            ADC_Temp_Sum -= prev_temp_val;

            ADC_Temp_Avg = ADC_Temp_Sum >> 3;   //Bitshift divide by 8

            Get_Brt = true;    //Flag to switch back to brightness input on mux back in main()

        break;

       

    }

    ADC_EOC_ClearPending();

}

Is this viable?  Are there considerations I'm not taking into account to accomplish something like this?  My main concern is the stopping/starting of the ADC Conversion process in Svc_Ana_Mux, and the effects that might have on readings once I start the ADC again (as I've noticed my thermal sensor readings seem to get some "rogue" points).  Possibly any way to make sure the SAR ADC is "Cleared" before switching to the other input?

Thanks in advance for any pointers!

0 Likes
2 Replies
EmHo_296241
Level 5
Level 5
10 solutions authored 50 replies posted 25 replies posted

Hi,

You can always use multiple channels to avoid one input affect affecting other. Is there any reason you went with AMUX?

0 Likes

Hi there,

Apologies for not getting back sooner.

When you say Multiple Channels, are you referring to using a Sequencing ADC?  The reason I'm avoiding a Sequencing SAR ADC is because I don't necessarily want to read all channels at all times.  One of the analog signals needs to be sampled and averaged frequently and the other only needs updating once every few seconds.  I figured "Why waste time reading all channels on every conversion of the ADC when I only need one of these channels relatively infrequently?".

I'm probably making too much of the impact that sampling multiple channels will have on individual channel response.  What I'm doing now with the mux could be less efficient, what with the starting and stopping of the ADC, than simply always keeping the ADC active and just pulling the values from each channel when needed.  Next chance I get I will see how it goes with a Sequencing SAR ADC component.

Another question regarding the Sequencing SAR ADC.

When a conversion is performed and ready to be read via GetResult16(), say I don't read the value immediately, but the ADC continues converting.  Do the values in the output buffer for each channel update after each conversion (clobbering the previous result)?  Or will the value remain in the output buffer until read out?

EDIT: Went to replace the SAR ADC with a Sequencing SAR ADC, and it looks like I'm running out of Macrocells (the design is pretty tight on resources).  So I may be forced to stick with my Analog Mux solution unfortunately.

0 Likes