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.

Trigger ADC by using a PWM (MSP430FR5739)

Other Parts Discussed in Thread: MSP-EXP430FR5739

I would like to measure a value by using the ADC every 20 ms. Therefore I did a PWM with 10 % duty cycle (should be enougth time for sampling) and set the timer trigger ADC10SHSx to Timer trigger 0 (should be the correct one according to the data sheet).

Unfortunately the ADC never runs into the ISR but it produces ISR bits for conversation time overflow.

I don't find any mistake inside my code... is anybody out there who finds a wrong setting - I double checked everything.

I'm using the MSP-EXP430FR5739 Board.


void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;                // Stop WDT

    // Setup clock system
    CSCTL0_H = 0xA5;                        // Password
    CSCTL1 |= DCOFSEL0 + DCOFSEL1;          // DCO 8 MHz
    CSCTL2 = SELA_3 + SELS_3 + SELM_3;      // set ACLK = SMCLK = DCO/8

    // Port Setup
    P1DIR |= BIT0;                          // Set P1.0 to output direction
    P1SEL0 |= BIT0;                          // P1.0 is output for PWM
    P1SEL1 |= BIT1;                            // P1.1 is input for ADC
    P1SEL0 |= BIT1;                            // P1.1 is input for ADC

    // Setup Timer
    TA0CCR0 = 20000 - 1;                        // PWM Period
    TA0CCTL1 = OUTMOD_7;                        // CCR1 reset/set
    TA0CCR1 = 2000;                                // CCR1 PWM duty cycle
    TA0CTL = TASSEL_2 + MC_1 + TACLR;            // SMCLK, up mode, clear TAR

    // Setup ADC
    ADC10CTL0 &= ~ADC10ENC;
    ADC10CTL0 |= ADC10SHT_2 + ADC10ON;      // ADC10ON, S&H=16 ADC clks
    ADC10CTL1 |= ADC10CONSEQ_0;                // Single-channel
    ADC10CTL1 |= ADC10SHS_1;                // Set PWM as trigger source
    ADC10CTL1 &= ~ADC10SHP;                    // Bypass Sample timer
    ADC10CTL2 |= ADC10RES;                  // 10-bit conversion results
    ADC10MCTL0 |= ADC10INCH_1;              // A1 ADC input select; Vref=AVCC
    ADC10IE |= ADC10IE0;                    // Enable ADC conv complete interrupt
    ADC10CTL0 |= ADC10ENC;                    // Enable ADC conversation

    while(1)
    {
        __bic_SR_register(CPUOFF);
    }

}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
    __no_operation();
  switch(__even_in_range(ADC10IV,12))
  {
    case  0: break;                          // No interrupt
    case  2: break;                          // conversion result overflow
    case  4: break;                          // conversion time overflow
    case  6: break;                          // ADC10HI
    case  8: break;                          // ADC10LO
    case 10: break;                          // ADC10IN
    case 12:
        ADC_Result = ADC10MEM0;
        __no_operation();
        __bic_SR_register_on_exit(CPUOFF);
        break;

    default: break;
  }
}

  • Cornelius Poth90519 said:
    Unfortunately the ADC never runs into the ISR

    The code wasn't enabling interrupts (the GIE bit in the Status Register). Hence, the ISR was never entered.

     

    Cornelius Poth90519 said:
    but it produces ISR bits for conversation time overflow.

    With the GIE bit enabled a single ADC10_B memory interrupt occured. A single ADC10_B memory interrupt is expected, since the ADC10CONSEQx bits have selected "Single-channel, single-conversion".

    All further ADC10_B interrupts were then "Conversion time overflow". Since Single-channel, single-conversion" has been selected, and ADC10ENC remains high, based upon Figure 16-6. Single-Channel Single-Conversion Mode in the MSP430FR5xx Family User's Guide SLAU272 I wouldn't have expected any more conversions to be attempted. i.e. don't understand why "Conversion time overflow" is being indicated. Also noticed that the ADCBUSY bit was set.

    The code was changed to select "Repeat-single-channel" conversion mode instead:

    #include <msp430.h>

    volatile unsigned int ADC_Result = 0xffff;

    void main(void)
    {
        WDTCTL = WDTPW + WDTHOLD; // Stop WDT

        // Setup clock system
        CSCTL0_H = 0xA5; // Password
        CSCTL1 |= DCOFSEL0 + DCOFSEL1; // DCO 8 MHz
        CSCTL2 = SELA_3 + SELS_3 + SELM_3; // set ACLK = SMCLK = DCO/8

        // Port Setup
        P1DIR |= BIT0; // Set P1.0 to output direction
        P1SEL0 |= BIT0; // P1.0 is output for PWM
        P1SEL1 |= BIT1; // P1.1 is input for ADC
        P1SEL0 |= BIT1; // P1.1 is input for ADC

        // Setup Timer
        TA0CCR0 = 20000 - 1; // PWM Period
        TA0CCTL1 = OUTMOD_7; // CCR1 reset/set
        TA0CCR1 = 2000; // CCR1 PWM duty cycle
        TA0CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, up mode, clear TAR

        // Setup ADC
        ADC10CTL0 &= ~ADC10ENC;
        ADC10CTL0 |= ADC10SHT_2 + ADC10ON; // ADC10ON, S&H=16 ADC clks
        ADC10CTL1 |= ADC10CONSEQ_2; // Repeat Single-channel
        ADC10CTL1 |= ADC10SHS_1; // Set PWM as trigger source
        ADC10CTL1 &= ~ADC10SHP; // Bypass Sample timer
        ADC10CTL2 |= ADC10RES; // 10-bit conversion results
        ADC10MCTL0 |= ADC10INCH_1; // A1 ADC input select; Vref=AVCC
        ADC10IE |= ADC10TOVIE | ADC10IE0; // Enable ADC time overflow and conv complete interrupts
        ADC10CTL0 |= ADC10ENC; // Enable ADC conversation

        _bis_SR_register(GIE); // Enable interrupts
        while(1)
        {
          __bic_SR_register(CPUOFF);
        }

    }

    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
        __no_operation();
        switch(__even_in_range(ADC10IV,12))
        {
          case 0: break; // No interrupt
          case 2: // conversion result overflow
             __no_operation();
            break;
          case 4: // conversion time overflow
             __no_operation();
            break;
          case 6: break; // ADC10HI
          case 8: break; // ADC10LO
          case 10: break; // ADC10IN
          case 12:
            ADC_Result = ADC10MEM0;
           __no_operation();
           __bic_SR_register_on_exit(CPUOFF);
          break;

        default: break;
        }
    }

    Now multiple ADC10_B memory interrupts occur, and the "Conversion time overflow" interrupts no longer occur.

  • Oh man - thanks a lot. GIE - how could I forget it?!

    However - ADC10CONSEQ_2 was a good hint :)

    For ADC10CONSEQ_0 the manual says the following: "ADC10ENC must be toggled between each conversion". Then this mode works as well but it makes no sence since more CPU interaction is needed.

    Thanks a lot for your help - problem solved :)

  • Hi Chester,

    can you please tell me how to make port 1.2 as imput for the ADC ?
    I changed BIT1 in P1SEL0 and P1SEL1 into BIT2, but the ADC_Result is always in port 1.1 !

    Thanks,
    Fares

**Attention** This is a public forum