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.

MSP430FR6043: ADC12_B and REF_A configuration

Part Number: MSP430FR6043

Tool/software:

Hello,

I want to configure the ADC12_B and REF_A module based on the power state.

Power Source ADC Behavior
Internal Battery ADC12_B and REF_A is triggered once every 1 second, then turned off in the ISR to save power.
External Supply ADC12_B and REF_A is reconfigured to run in repeated sequence mode for continuous conversion.

Internal Battery Mode configuration:

void ADC_initInternalMode()
{
    ADC12_B_disableConversions(ADC12_B_BASE, ADC12_B_PREEMPTCONVERSION);
    ADC12_B_disable(ADC12_B_BASE);

    // Disable reference and wait for it to be free
    REFCTL0 &= ~REFON;
    while (REFCTL0 & REFGENBUSY);
    REFCTL0 |= REFVSEL_1 | REFON; // 2.0V internal ref
    while (!(REFCTL0 & REFGENRDY));
    __delay_cycles(75); // Allow settling time

    // ADC hardware setup
    adc_init.clockSourceSelect = ADC12_B_CLOCKSOURCE_ACLK;
    adc_init.clockSourceDivider = ADC12_B_CLOCKDIVIDER_1;
    adc_init.clockSourcePredivider = ADC12_B_CLOCKPREDIVIDER__1;
    adc_init.internalChannelMap = ADC12_B_NOINTCH;
    adc_init.sampleHoldSignalSourceSelect = ADC12_B_SAMPLEHOLDSOURCE_SC;

    // Configure channels: Battery (A8), Valve (A9), External (A14)
    // Memory buffer setup (0 to 2)
    // End-of-sequence marked on last channel

    memory_init1 = (ADC12_B_configureMemoryParam){
        .memoryBufferControlIndex = ADC12_B_MEMORY_0,
        .inputSourceSelect = ADC12_B_INPUT_A8,
        .refVoltageSourceSelect = ADC12_B_VREFPOS_INTBUF_VREFNEG_VSS,
        .endOfSequence = ADC12_B_NOTENDOFSEQUENCE
    };

    memory_init2 = (ADC12_B_configureMemoryParam){
        .memoryBufferControlIndex = ADC12_B_MEMORY_1,
        .inputSourceSelect = ADC12_B_INPUT_A9,
        .refVoltageSourceSelect = ADC12_B_VREFPOS_INTBUF_VREFNEG_VSS,
        .endOfSequence = ADC12_B_NOTENDOFSEQUENCE
    };

    memory_init3 = (ADC12_B_configureMemoryParam){
        .memoryBufferControlIndex = ADC12_B_MEMORY_2,
        .inputSourceSelect = ADC12_B_INPUT_A14,
        .refVoltageSourceSelect = ADC12_B_VREFPOS_INTBUF_VREFNEG_VSS,
        .endOfSequence = ADC12_B_ENDOFSEQUENCE
    };

    ADC12_B_init(ADC12_B_BASE, &adc_init);
    ADC12_B_setupSamplingTimer(ADC12_B_BASE, ADC12_B_CYCLEHOLD_32_CYCLES,
                               ADC12_B_CYCLEHOLD_4_CYCLES,
                               ADC12_B_MULTIPLESAMPLESENABLE);
    ADC12_B_configureMemory(ADC12_B_BASE, &memory_init1);
    ADC12_B_configureMemory(ADC12_B_BASE, &memory_init2);
    ADC12_B_configureMemory(ADC12_B_BASE, &memory_init3);

    ADC12_B_clearInterrupt(ADC12_B_BASE, 0, ADC12_B_IFG2);
    ADC12_B_enableInterrupt(ADC12_B_BASE, ADC12_B_IE2, 0, 0);
    ADC12_B_enable(ADC12_B_BASE);
    ADC12_B_startConversion(ADC12_B_BASE, ADC12_B_START_AT_ADC12MEM0, ADC12_B_SEQOFCHANNELS);
}

External power mode configuration:

void ADC_initExternalMode()
{
    ADC12_B_disableConversions(ADC12_B_BASE, ADC12_B_PREEMPTCONVERSION);
    ADC12_B_disable(ADC12_B_BASE);

    REFCTL0 &= ~REFON;
    while (REFCTL0 & REFGENBUSY);
    REFCTL0 |= REFVSEL_1 | REFON;
    while (!(REFCTL0 & REFGENRDY));
    __delay_cycles(75);

    adc_init.clockSourceSelect = ADC12_B_CLOCKSOURCE_ACLK;
    adc_init.clockSourceDivider = ADC12_B_CLOCKDIVIDER_1;
    adc_init.clockSourcePredivider = ADC12_B_CLOCKPREDIVIDER__1;
    adc_init.internalChannelMap = ADC12_B_NOINTCH;
    adc_init.sampleHoldSignalSourceSelect = ADC12_B_SAMPLEHOLDSOURCE_SC;

    // Same memory configuration as internal mode
    ADC12_B_init(ADC12_B_BASE, &adc_init);
    ADC12_B_setupSamplingTimer(ADC12_B_BASE, ADC12_B_CYCLEHOLD_32_CYCLES,
                               ADC12_B_CYCLEHOLD_4_CYCLES,
                               ADC12_B_MULTIPLESAMPLESENABLE);
    ADC12_B_configureMemory(ADC12_B_BASE, &memory_init1);
    ADC12_B_configureMemory(ADC12_B_BASE, &memory_init2);
    ADC12_B_configureMemory(ADC12_B_BASE, &memory_init3);

    ADC12_B_clearInterrupt(ADC12_B_BASE, 0, ADC12_B_IFG2);
    ADC12_B_disableInterrupt(ADC12_B_BASE, ADC12_B_IE2, 0, 0);
    ADC12_B_enable(ADC12_B_BASE);
    ADC12_B_startConversion(ADC12_B_BASE, ADC12_B_START_AT_ADC12MEM0, ADC12_B_REPEATED_SEQOFCHANNELS);
}

 

In internal battery mode, the ADC ISR is enabled. At each ISR trigger, I turn off both the ADC12_B and REF_A modules. They are re-enabled after a 1-second timeout.

void ADC_Handler()
{
// ADC handler running in 10ms timer loop
   if(PowerstateSwitch == "Internal")
   {
   //ADC_UPDATE_DURATION is 1000
       if (ADC_capture_enable_counter >= ADC_UPDATE_DURATION) {
           Ref_A_enableReferenceVoltage(REF_A_BASE);
           if(Ref_A_isRefGenActive(REF_A_BASE))
           {
               ADC12_B_enable(ADC12_B_BASE);
               ADC12_B_startConversion(ADC12_B_BASE, ADC12_B_START_AT_ADC12MEM0, ADC12_B_SEQOFCHANNELS);
               ADC_capture_enable_counter = 0;
           }
           ADC_DataRead();
       } else {
           ADC_capture_enable_counter += 10;
       }
   }
   else
   {
       ADC_DataRead();
   }
}

#pragma vector=ADC12_B_VECTOR
__interrupt void ADC12ISR(void)
{
    if (PowerstateSwitch == false) // internal supply
    {
        ADC12_B_disable(ADC12_B_BASE); // Save power
        Ref_A_disableReferenceVoltage(REF_A_BASE); // Save more power
    }

    ADC12_B_clearInterrupt(ADC12_B_BASE, 0, ADC12_B_IFG2);
    ADC_DataRead(); // Read the latest values
}

In external supply mode, both modules are reconfigured and run continuously without the ADC ISR. Could anyone confirm if my implementation is correct?

To reduce power consumption I made this setup.

Regards,

Sakhan

  • > Ref_A_enableReferenceVoltage(REF_A_BASE);
    > if(Ref_A_isRefGenActive(REF_A_BASE))

    This appears to expect the REF to be ready immediately, and I expect that won't be true. I think the function you want is "Ref_A_isVariableReferenceVoltageOutputReady(REF_A_BASE) // REFGENRDY?", and it should probably be in a loop similar to the ones in the "init" functions.

    Other than that, I don't see anything obviously wrong. 

    -----------

    Unsolicited: You may want to look at User Guide (SLAU367P) Sec 34.2.4 ("Auto Power Down"), since the ADC+REF can do much of this work for you.

    If the REF is used by one of the VRSEL-s, the reference is switched on automatically, then switched off after the conversion(s); for burst/continuous sampling (ADC12_B_MULTIPLESAMPLESENABLE) it stays on through the burst. The "cost" is that the first conversion has to wait for the REF to start up (40usec typical), but at 1sps I don't think you'll notice that.

    [Edit: Minor clarification]

  • Hi Sakan,

    Agree with Bruce suggestion.

    One thing from my side is that, how your ADC handler is triggered? if ADC module is not enabled, I think the ADC ISR will not enter.

    B.R.

    Sal

  • Hi Bruce,

    Thanks for your Response.

    As per your suggestion, I have made a changes in the adc handler.

    if (ADC_capture_enable_counter >= ADC_UPDATE_DURATION) {
    Ref_A_enableReferenceVoltage(REF_A_BASE);
    if(Ref_A_isVariableReferenceVoltageOutputReady(REF_A_BASE))
    {

    }
     else {
    }

    Regards,

    Sakhan

  • Hi Sal Ye,

    In 10ms Timer loop, the adc handler is running continuously. 

  • Hi Sakan,

    That looks good.

    As for the code, I suggest you can use a while loop to polling the VREF status and wait it ready.

    B.R.

    Sal

**Attention** This is a public forum