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.

AnalogRead() Faster

Other Parts Discussed in Thread: ENERGIA

I have an MSP430 & MSP432 and I am trying to figure out  how to sample a 5kHz wave. I have been using Energia and the problem I am running into is the analogread() function only samples once every 100us or 10,000 times per second. This would effectivley give me only 2 samples of this wave which is horrible! Is there a way to speed of this function or some work around I am not finding?

I have read some about modifying the analogRead() in 'hardware/msp430/cores/msp430/wiring_analog.c'. but I am unsure of what exactly I need to change. 

Thanks,

  • Will,

    is using Energia mandatory for you? Or would you use the "normal" programming in Code Composer / IAR as well?
  • I'd Prefer Energia. The learning curve is not as steep for a one off project. Would simply changing the clock divider and idle time be enough?

    I'm confused on what specific values need to be changed here. As you can see I have changed the divider from 4 > 1 and delay Cycles I cut in half.

    uint16_t analogRead(uint8_t pin)
    {
    // make sure we have an ADC
    uint8_t channel;

    // Check if pin is a special analog pin (A10 = temp sensor, A11 = Vcc/2, etc.)
    if (pin >=128)
    channel = pin - 128;
    else
    channel = digitalPinToADCIn(pin);

    // Check if pin is valid
    if (pin==NOT_ON_ADC)
    return 0;
    #if defined(__MSP430_HAS_ADC10__) || defined(__MSP430_HAS_ADC10_B__) || defined(__MSP430_HAS_ADC12_PLUS__) || defined(__MSP430_HAS_ADC12_B__) || defined(__MSP430_HAS_ADC__)
    // 0000 A0
    // 0001 A1
    // 0010 A2
    // 0011 A3
    // 0100 A4
    // 0101 A5
    // 0110 A6
    // 0111 A7
    // 1010 Internal temperature sensor

    //TODO: Only int. temp. sensor requires Tsample > 30us.
    // The below ADC configuration applies this rule to all channels right now.
    // ADC10CLK = 5MHz / 5 = 1Mhz
    // Tsample = S&H / ADC10CLK = 64 / 1 MHz = 64 us
    // Tconvert = 13 / ADC10CLK = 13 / 1 MHz = 13 us
    // Total time per sample = Tconvert + Tsample = 64 + 13 = 67 us = ~15k samples / sec

    #if defined(__MSP430_HAS_ADC10__)
    ADC10CTL0 &= ~ADC10ENC; // disable ADC
    ADC10CTL1 = ADC10SSEL_0 | ADC10DIV_1; // ADC10OSC as ADC10CLK (~5MHz) / 5
    ADC10CTL0 = analog_reference | // set analog reference
    ADC10ON | ADC10SHT_3 | ADC10IE; // turn ADC ON; sample + hold @ 64 × ADC10CLKs; Enable interrupts
    ADC10CTL1 |= (channel << 12); // select channel
    ADC10AE0 = (1 << channel); // Disable input/output buffer on pin
    __delay_cycles(64); // Delay to allow Ref to settle
    ADC10CTL0 |= ADC10ENC | ADC10SC; // enable ADC and start conversion
    while (ADC10CTL1 & ADC10BUSY) { // sleep and wait for completion
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
    }
    /* POWER: Turn ADC and reference voltage off to conserve power */
    ADC10CTL0 &= ~(ADC10ON | REFON);
    #endif
    #if defined(__MSP430_HAS_ADC10_B__)
    ADC10CTL0 &= ~ADC10ENC; // disable ADC
    ADC10CTL1 = ADC10SSEL_0 | ADC10DIV_1; // ADC10OSC as ADC10CLK (~5MHz) / 5
    while(REFCTL0 & REFGENBUSY); // If ref generator busy, WAIT
    REFCTL0 |= analog_reference & REF_MASK; // Set reference using masking off the SREF bits. See Energia.h.
    ADC10MCTL0 = channel | (analog_reference & REFV_MASK); // set channel and reference
    ADC10CTL0 = ADC10ON | ADC10SHT_4; // turn ADC ON; sample + hold @ 64 × ADC10CLKs
    ADC10CTL1 |= ADC10SHP; // ADCCLK = MODOSC; sampling timer
    ADC10CTL2 |= ADC10RES; // 10-bit resolution
    ADC10IFG = 0; // Clear Flags
    ADC10IE |= ADC10IE0; // Enable interrupts
    __delay_cycles(64); // Delay to allow Ref to settle
    ADC10CTL0 |= ADC10ENC | ADC10SC; // enable ADC and start conversion
    while (ADC10CTL1 & ADC10BUSY) { // sleep and wait for completion
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
    }
    /* POWER: Turn ADC and reference voltage off to conserve power */
    ADC10CTL0 &= ~(ADC10ON);
    REFCTL0 &= ~REFON;
    #endif
    #if defined(__MSP430_HAS_ADC__)
    ADCCTL0 &= ~ADCENC; // disable ADC
    ADCCTL1 = ADCSSEL_0 | ADCDIV_1; // ADC10OSC as ADC10CLK (~5MHz) / 5
    //REFCTL0 |= analog_reference & REF_MASK; // Set reference using masking off the SREF bits. See Energia.h.
    PMMCTL0_H = PMMPW_H; // open PMM
    PMMCTL2 |= INTREFEN; // enable Ref
    if (pin == TEMPSENSOR) PMMCTL2 |= TSENSOREN; // enable TC
    ADCMCTL0 = channel | (analog_reference & REFV_MASK); // set channel and reference
    ADCCTL0 = ADCON | ADCSHT_4; // turn ADC ON; sample + hold @ 64 × ADC10CLKs
    ADCCTL1 |= ADCSHP; // ADCCLK = MODOSC; sampling timer
    ADCCTL2 |= ADCRES; // 10-bit resolution
    ADCIFG = 0; // Clear Flags
    ADCIE |= ADCIE0; // Enable interrupts
    __delay_cycles(64); // Delay to allow Ref to settle
    ADCCTL0 |= ADCENC | ADCSC; // enable ADC and start conversion
    while (ADCCTL1 & ADCBUSY) { // sleep and wait for completion
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
    }
    /* POWER: Turn ADC and reference voltage off to conserve power */
    ADCCTL0 &= ~(ADCON);
    //REFCTL0 &= ~REFON;
    PMMCTL2 &= ~(INTREFEN | TSENSOREN);
    PMMCTL0_H = 0; // close PMM
    #endif
    #if defined(__MSP430_HAS_ADC12_PLUS__)
    ADC12CTL0 &= ~ADC12ENC; // disable ADC
    ADC12CTL1 = ADC12SSEL_0 | ADC12DIV_1; // ADC12OSC as ADC12CLK (~5MHz) / 5
    while(REFCTL0 & REFGENBUSY); // If ref generator busy, WAIT
    if (pin == TEMPSENSOR) {// if Temp Sensor
    REFCTL0 = (INTERNAL1V5 & REF_MASK); // Set reference to internal 1.5V
    ADC12MCTL0 = channel | ((INTERNAL1V5 >> 4) & REFV_MASK); // set channel and reference
    } else {
    REFCTL0 = (analog_reference & REF_MASK); // Set reference using masking off the SREF bits. See Energia.h.
    ADC12MCTL0 = channel | ((analog_reference >> 4) & REFV_MASK); // set channel and reference
    }
    ADC12CTL0 = ADC12ON | ADC12SHT0_4; // turn ADC ON; sample + hold @ 64 × ADC10CLKs
    ADC12CTL1 |= ADC12SHP; // ADCCLK = MODOSC; sampling timer
    ADC12CTL2 |= ADC12RES1; // 12-bit resolution
    ADC12IFG = 0; // Clear Flags
    ADC12IE |= ADC12IE0; // Enable interrupts
    __delay_cycles(128); // Delay to allow Ref to settle
    ADC12CTL0 |= ADC12ENC | ADC12SC; // enable ADC and start conversion
    while (ADC12CTL1 & ADC12BUSY) { // sleep and wait for completion
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
    }
    /* POWER: Turn ADC and reference voltage off to conserve power */
    ADC12CTL0 &= ~(ADC12ON);
    REFCTL0 &= ~REFON;
    #endif
    #if defined(__MSP430_HAS_ADC12_B__)
    ADC12CTL0 &= ~ADC12ENC; // disable ADC
    ADC12CTL0 = ADC12ON | ADC12SHT0_4; // turn ADC ON; sample + hold @ 64 × ADC12CLKs
    ADC12CTL1 = ADC12SSEL_0 | ADC12DIV_1; // ADC12OSC as ADC12CLK (~5MHz) / 5
    ADC12CTL3 = ADC12TCMAP | ADC12BATMAP; // Map Temp and BAT
    ADC12CTL1 |= ADC12SHP; // ADCCLK = MODOSC; sampling timer
    ADC12CTL2 |= ADC12RES_2; // 12-bit resolution
    ADC12IFGR0 = 0; // Clear Flags
    ADC12IER0 |= ADC12IE0; // Enable interrupts
    while(REFCTL0 & REFGENBUSY); // If ref generator busy, WAIT
    if (pin == TEMPSENSOR) {// if Temp Sensor
    REFCTL0 = (INTERNAL1V2 & REF_MASK); // Set reference to internal 1.2V
    ADC12MCTL0 = channel | (INTERNAL1V2 & REFV_MASK); // set channel and reference
    } else {
    REFCTL0 = (analog_reference & REF_MASK); // Set reference using masking off the SREF bits. See Energia.h.
    ADC12MCTL0 = channel | (analog_reference & REFV_MASK); // set channel and reference
    }
    if (REFCTL0 & REFON)
    while(!(REFCTL0 & REFGENRDY)); // wait till ref generator ready
    ADC12CTL0 |= ADC12ENC | ADC12SC; // enable ADC and start conversion
    while (ADC12CTL1 & ADC12BUSY) { // sleep and wait for completion
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
    }
    /* POWER: Turn ADC and reference voltage off to conserve power */
    ADC12CTL0 &= ~(ADC12ON);
    REFCTL0 &= ~(REFON);
    #endif
    return ADCxMEM0; // return sampled value after returning to active mode in ADC10_ISR
  • You could try to increase the ADC clock, or reduce its accuracy (number of cycles).

    But the main problem with Energia is that the analogRead() function must work independently, i.e., it configures the ADC and REF, starts the ADC conversion, and then waits for it to finish.

    To get maximum speed out of the ADC, you should configure it once (when the program starts) to run continuously, and let the conversion happen concurrently with your code (i.e., the ADC captures the next value while your code is handling the previous value).

**Attention** This is a public forum