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.

how to use a timer to trigger adc sampling on MSP430FR5969?

Other Parts Discussed in Thread: MSP430F2618, MSP430FR5969

I want to use a timer to trigger the adc sampling. I can see the TB0 CCR1 output signal on P1.4. However, the adc never gets triggered. I did not have a chance to enter the adc ISR. Can you help check the code? Thanks.

#include <msp430.h>

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

// Timer output config
P1DIR |= BIT4;
P1SEL0 |= BIT4;

// ADC config
P1SEL1 |= BIT1; // Configure P1.1 for ADC
P1SEL0 |= BIT1;

PM5CTL0 &= ~LOCKLPM5;

// Startup clock system with max DCO setting ~8MHz
CSCTL0_H = CSKEY >> 8; // Unlock clock registers
CSCTL1 = DCOFSEL_1 | DCORSEL; // Set DCO to 8MHz
CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // set all dividers
CSCTL0_H = 0; // Lock CS registers

// Configure ADC12
ADC12CTL0 = ADC12SHT0_2 | ADC12ON; // Sampling time, S&H=16, ADC12 on
ADC12CTL1 = ADC12SHP; // Use sampling timer
ADC12CTL2 |= ADC12RES_0; // 12-bit conversion results
ADC12MCTL0 |= ADC12INCH_1; // A1 ADC input select; Vref=AVCC
ADC12IER0 |= ADC12IE0; // Enable ADC conv complete interrupt

ADC12CTL0 |= ADC12ENC;

ADC12CTL1 |= ADC12SHS_3;

TB0CCR0 = 30000;
TB0CCR1 = 750;
TB0CCTL1 = OUTMOD_7;

TB0CTL = TBSSEL__SMCLK | MC__UP | TBCLR;

while(1);

}

#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
switch(__even_in_range(ADC12IV, ADC12IV_ADC12RDYIFG))
{
case 0: break; // Vector 0: No interrupt
case 2: break; // Vector 2: ADC12MEMx Overflow
case 4: break; // Vector 4: Conversion time overflow
case 6: break; // Vector 6: ADC12HI
case 8: break; // Vector 8: ADC12LO
case 10: break; // Vector 10: ADC12IN
case 12: // Vector 12: ADC12MEM0 Interrupt
if (ADC12MEM0 >= 0x7ff) // ADC12MEM0 = A1 > 0.5AVcc?
P1OUT |= BIT0; // P1.0 = 1
else
P1OUT &= ~BIT0; // P1.0 = 0
__bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
break; // Clear CPUOFF bit from 0(SR)
case 14: break; // Vector 14: ADC12MEM1
case 16: break; // Vector 16: ADC12MEM2
case 18: break; // Vector 18: ADC12MEM3
case 20: break; // Vector 20: ADC12MEM4
case 22: break; // Vector 22: ADC12MEM5
case 24: break; // Vector 24: ADC12MEM6
case 26: break; // Vector 26: ADC12MEM7
case 28: break; // Vector 28: ADC12MEM8
case 30: break; // Vector 30: ADC12MEM9
case 32: break; // Vector 32: ADC12MEM10
case 34: break; // Vector 34: ADC12MEM11
case 36: break; // Vector 36: ADC12MEM12
case 38: break; // Vector 38: ADC12MEM13
case 40: break; // Vector 40: ADC12MEM14
case 42: break; // Vector 42: ADC12MEM15
case 44: break; // Vector 44: ADC12MEM16
case 46: break; // Vector 46: ADC12MEM17
case 48: break; // Vector 48: ADC12MEM18
case 50: break; // Vector 50: ADC12MEM19
case 52: break; // Vector 52: ADC12MEM20
case 54: break; // Vector 54: ADC12MEM21
case 56: break; // Vector 56: ADC12MEM22
case 58: break; // Vector 58: ADC12MEM23
case 60: break; // Vector 60: ADC12MEM24
case 62: break; // Vector 62: ADC12MEM25
case 64: break; // Vector 64: ADC12MEM26
case 66: break; // Vector 66: ADC12MEM27
case 68: break; // Vector 68: ADC12MEM28
case 70: break; // Vector 70: ADC12MEM29
case 72: break; // Vector 72: ADC12MEM30
case 74: break; // Vector 74: ADC12MEM31
case 76: break; // Vector 76: ADC12RDY
default: break;
}
}

  • Hello Pengyu,

    There are a couple of things that I see that are incorrect, one in your code and one in the general way in which you approached the solution.

    Firstly, you will never get an interrupt from the MSP430 without setting the general interrupt bit in the status register. You can accomplish this using the command __bis_SR_register(GIE).

    Also, as far as the basic setup of getting a timer to trigger an ADC conversion, I would suggest that you set up the timer for a proper interval (as is shown in msp430fr59xx_tb0_02.c) and have the timer module create an interrupt based on this interval. Then, when you receive the timer interrupt you can start the ADC conversion by setting the ADC12SC bit in ADC12CTL0. You can also have interrupts enabled on the ADC12 similar to in msp430fr59xx_adc12_01.c to then retrieve the conversion results.

    Hopefully by heeding the directions I have given and those shown in the examples, you will be able to fix your problems.

  • Hi Tyler,

    Thanks for pointing out the miss of __bis_SR_register(GIE). I have corrected it.

    I do not want to use the ADC12SC bit to start the ADC conversion in the Timer ISR. I want to use the TB0 CCR1 output to trigger the ADC sampling. For example, setting ADC12SHS_3 in the ADC12CTL1 register. However, it does not work for some reasons... Similar approach works when I use the MSP430F2618, but does not work on the MSP430FR5969.

    Pengyu

  • Pengyu,

    I see what you want to do, and that  is definitely manageable with the FR5969.

    I also think I see what may be causing the problem now. The ADC12SHSx bits can only be modified when ADC12ENC = 0 as is stated in 18.3.2 of the FR59xx UG. You will want to move that line above where you enable conversions.

    Upon further examination of the code, everything else looks to be fine.

    Let me know if this fixes your problem.

  • Hi Tyler,

    Oh. Yes. I should enabling the ADC after finishing all the configurations. Thanks for correcting this. 

    I find another bug of the ADC configuration. You need to configure the ADC to support repeated triggers. After fixing this, I can go into the ADC ISR multiple times. The correct code is attached. Thanks for your help.

    Pengyu

    #include <msp430.h>

    char buf = 0x00;

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

    // Timer output config
    P1DIR |= BIT4;
    P1SEL0 |= BIT4;

    // ADC config
    P1SEL1 |= BIT1; // Configure P1.1 for ADC
    P1SEL0 |= BIT1;

    PJSEL0 |= BIT4 | BIT5; // For XT1

    PM5CTL0 &= ~LOCKLPM5;

    // Startup clock system with max DCO setting ~8MHz
    CSCTL0_H = CSKEY >> 8; // Unlock clock registers
    CSCTL1 = DCOFSEL_3 | DCORSEL; // Set DCO to 8MHz
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // set all dividers
    CSCTL0_H = 0; // Lock CS registers

    // Configure ADC12
    ADC12CTL0 = ADC12SHT0_2 | ADC12ON; // Sampling time, S&H=16, ADC12 on
    ADC12CTL1 = ADC12SHP | ADC12CONSEQ_2; // Use sampling timer
    ADC12CTL2 |= ADC12RES_0; // 12-bit conversion results
    ADC12MCTL0 |= ADC12INCH_1; // A1 ADC input select; Vref=AVCC
    ADC12IER0 |= ADC12IE0; // Enable ADC conv complete interrupt
    ADC12CTL1 |= ADC12SHS_3;

    ADC12CTL0 |= ADC12ENC;

    TB0CCR0 = 30000;
    TB0CCR1 = 750;
    TB0CCTL1 = OUTMOD_7;

    TB0CTL = TBSSEL__SMCLK | MC__UP | TBCLR;

    __bis_SR_register(LPM0_bits | GIE);
    }

    #pragma vector = ADC12_VECTOR
    __interrupt void ADC12_ISR(void)
    {
    switch(__even_in_range(ADC12IV, ADC12IV_ADC12RDYIFG))
    {
    case 0: break; // Vector 0: No interrupt
    case 2: break; // Vector 2: ADC12MEMx Overflow
    case 4: break; // Vector 4: Conversion time overflow
    case 6: break; // Vector 6: ADC12HI
    case 8: break; // Vector 8: ADC12LO
    case 10: break; // Vector 10: ADC12IN
    case 12: // Vector 12: ADC12MEM0 Interrupt
    buf = ADC12MEM0 & 0xFF;
    break; // Clear CPUOFF bit from 0(SR)
    case 14: break; // Vector 14: ADC12MEM1
    case 16: break; // Vector 16: ADC12MEM2
    case 18: break; // Vector 18: ADC12MEM3
    case 20: break; // Vector 20: ADC12MEM4
    case 22: break; // Vector 22: ADC12MEM5
    case 24: break; // Vector 24: ADC12MEM6
    case 26: break; // Vector 26: ADC12MEM7
    case 28: break; // Vector 28: ADC12MEM8
    case 30: break; // Vector 30: ADC12MEM9
    case 32: break; // Vector 32: ADC12MEM10
    case 34: break; // Vector 34: ADC12MEM11
    case 36: break; // Vector 36: ADC12MEM12
    case 38: break; // Vector 38: ADC12MEM13
    case 40: break; // Vector 40: ADC12MEM14
    case 42: break; // Vector 42: ADC12MEM15
    case 44: break; // Vector 44: ADC12MEM16
    case 46: break; // Vector 46: ADC12MEM17
    case 48: break; // Vector 48: ADC12MEM18
    case 50: break; // Vector 50: ADC12MEM19
    case 52: break; // Vector 52: ADC12MEM20
    case 54: break; // Vector 54: ADC12MEM21
    case 56: break; // Vector 56: ADC12MEM22
    case 58: break; // Vector 58: ADC12MEM23
    case 60: break; // Vector 60: ADC12MEM24
    case 62: break; // Vector 62: ADC12MEM25
    case 64: break; // Vector 64: ADC12MEM26
    case 66: break; // Vector 66: ADC12MEM27
    case 68: break; // Vector 68: ADC12MEM28
    case 70: break; // Vector 70: ADC12MEM29
    case 72: break; // Vector 72: ADC12MEM30
    case 74: break; // Vector 74: ADC12MEM31
    case 76: break; // Vector 76: ADC12RDY
    default: break;
    }
    }

**Attention** This is a public forum