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.

MSP430FR2533: MSP430FR2X/4X ADC sequence of channel issue

Part Number: MSP430FR2533


hello,TI employee 

i am using FR2533‘s  ADC,and i want to  use  single sequence of channel modes with Timer B trigger,

but  the quesiton is:

1) FR2X/4X series MCU only have one ADC conversion result memory,and  DMA do not supported,

     this means,in sequence  of  channel mode ,ADC ISR will be entered each time ADCIFG set when ADC convert complete

2)when using Timer B trigger ADC,according to the UG,ADCENC must be toggled bettween sequence,so when should i toggle the ADCENC.

   and my code just the follow:

after the routine executed,the result seems to be wrong that the order of the ADC result in the array is not correct,how should i do ?

/*
@ powered by SS
@Author kissn liu
@date 2017-12-8
@fution:ADC multi channel sample using TA1 trigger;
*/
#include "msp430fr2533.h"
/*
   A7-ADC_Result[7]
         .
         .
         .
   A0-ADC_Result[0]

*/
unsigned char ADC_Result[8]={0};
void init_ADC_using_TA1_trigger()
{
  // Configure ADC A0~7 pins
  SYSCFG2  = ADCPCTL0 | ADCPCTL1 | ADCPCTL2 | ADCPCTL3 | ADCPCTL4 | ADCPCTL5 | ADCPCTL6 | ADCPCTL7;
  
  
  // Configure ADC 
  //change ADCSHTx bits to change the sample time
  ADCCTL0 |= ADCSHT_2 | ADCMSC | ADCON;                       // 16ADCclks, MSC, ADC ON
  ADCCTL1 |= ADCSHS_2 | ADCSHP | ADCCONSEQ_1 | ADCSSEL_0;     // ADC clock MODCLK, sampling timer, TA1 trig.,single sequence
  ADCCTL2 &= ~ADCRES;                                         // 8-bit conversion results
  ADCMCTL0 |= ADCINCH_7 | ADCSREF_0;                          // A0~7(EoS); Vref=Vcc
  ADCIE |= ADCIE0;                                            // Enable ADC conv complete interrupt
  ADCCTL0 |= ADCENC;                                           // ADC Enable
  
  TA1CCR0 = 33;
  TA1CCR1 = 16;
  //TA1CCTL0 = (CCIE);//Enable CCIFG
  TA1CCTL1 = OUTMOD_7;//PWM output mode: 7 - reset/set
  TA1CTL = (TASSEL__ACLK | MC__UP);
  
  __bis_SR_register(GIE);                       // Enter LPM3 w/ interrupts
  
}
void main()
{
  WDTCTL = WDTPW | WDTHOLD;                                   // Stop WDT
  // Disable the GPIO power-on default high-impedance mode to activate
  // previously configured port settings
  PM5CTL0 &= ~LOCKLPM5;
  init_ADC_using_TA1_trigger();
  
  while(1)
  {
    
  }
  
}
// ADC interrupt service routine

#pragma vector=ADC_VECTOR
__interrupt void ADC_ISR(void)
{
  static  char i = 7;
  switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
  {
  case ADCIV_NONE: 
    break;                              
  case ADCIV_ADCOVIFG: 
    break;             
  case ADCIV_ADCTOVIFG: 
    break;            
  case ADCIV_ADCHIIFG: 
    break;             
  case ADCIV_ADCLOIFG: 
    break;             
  case ADCIV_ADCINIFG: 
    break;             
  case ADCIV_ADCIFG:
    /*
      When ADCSC triggers a sequence, successive sequences can be triggered by the ADCSC bit. 
      When any  other trigger source is used, ADCENC must be toggled between each sequence.
      !!!ADC12ENC must be toggled between sequences  
    */
    ADCCTL0 &= ~ADCENC; 
    ADC_Result[i] = ADCMEM0;
    if(i == 0)
    {   
      i = 7;
      __no_operation();
    }
    else
    {
      i--;
    }
    ADCCTL0 |= ADCENC; 
    break;                                             
  default: 
    break; 
  }  
}

#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0(void)
{
  __no_operation();
  
}

  • With MSC=1, you need to toggle ENC between bursts, i.e. when you (re)set i=7. [See also SLAU445G Fig 20-10]

    What you're almost certainly encountering here is a race. The burst itself is (effectively) driven by the ADC clock, since it starts the next sample/convert immediately after the previous one completes. MODCLK is quite fast; the (16+11) MODCLKs in the conversion sequence is only about 27/5=6 MCLKs -- barely enough time to get to the ISR; the entire burst will probably be done by the time you get out of the ISR. You won't have time to capture MEM0 before it gets re-filled, and your array counter [i] (not to mention your data) will be off. Options I see:

    1) Use ACLK rather than MODCLK. This will slow down the conversion (by about 30.5*5=~150x) giving you more time to get into/out of the ISR. This will also extend your sample/hold time so you'll probably want to set SHT really low.
    2) Set MSC=0 and run your timer at 8x the speed. This will mean your burst isn't really "simultaneous", but rather spaced evenly over the nominal sample period, but you will have a known/settable number of CPU clocks to grab MEM0 before it is overwritten. I'll just add: once you've done all this you might as well set CONSEQ=3 and then you won't have to toggle ENC. (That's what I ended up doing.)
  • this suggestion sounds good !
  • Great reply, Bruce. Thanks for the support.

    Regards,
    Ryan
  • thanks,you suggestion  solved my issue

    /* @ powered by SS @Author kissn liu @date 2017-12-8 @fution:ADC multi channel sample using TA1 trigger; @ ADC work in repeat sequence of channel mode */ #include "msp430fr2533.h" /* A7-ADC_Result[7] . . . A0-ADC_Result[0] */ unsigned char ADC_Result[8]={0}; void init_ADC_using_TA1_trigger() { // Configure ADC A0~7 pins SYSCFG2 = ADCPCTL0 | ADCPCTL1 | ADCPCTL2 | ADCPCTL3 | ADCPCTL4 | ADCPCTL5 | ADCPCTL6 | ADCPCTL7; // Configure ADC //@\! change ADCSHTx bits to change the sample time to get presicion ADC result ADCCTL0 |= ADCSHT_2 | ADCON; // 16ADCclks, , ADC ON ADCCTL1 |= ADCSHS_2 | ADCSHP | ADCCONSEQ_3 | ADCSSEL_0; // ADC clock MODCLK, sampling timer, TA1 trig.,repeat sequence channel ADCCTL2 &= ~ADCRES; // 8-bit conversion results ADCMCTL0 |= ADCINCH_7 | ADCSREF_0; // A7~0(EoS); Vref=Vcc ADCIE |= ADCIE0; // Enable ADC conv complete interrupt ADCCTL0 |= ADCENC; // ADC Enable TA1CCR0 =250 ;//2000/8 trigger ADC per 125us , the seqence period is 125us * 8 = 1000us TA1CCR1 = 125; //TA1CCTL0 = (CCIE);//Enable CCIFG TA1CCTL1 = OUTMOD_7;//PWM output mode: 7 - reset/set TA1CTL = (TASSEL__SMCLK | MC__UP); //select SMCLK 2MHz __bis_SR_register(GIE); // Enter LPM3 w/ interrupts } void main() { WDTCTL = WDTPW | WDTHOLD; // Stop WDT // Disable the GPIO power-on default high-impedance mode to activate // previously configured port settings PM5CTL0 &= ~LOCKLPM5; init_ADC_using_TA1_trigger(); //P2DIR |= BIT0; for debug. while(1) { } } // ADC interrupt service routine #pragma vector=ADC_VECTOR __interrupt void ADC_ISR(void) { static char i = 7; switch(__even_in_range(ADCIV,ADCIV_ADCIFG)) { case ADCIV_NONE: break; case ADCIV_ADCOVIFG: break; case ADCIV_ADCTOVIFG: break; case ADCIV_ADCHIIFG: break; case ADCIV_ADCLOIFG: break; case ADCIV_ADCINIFG: break; case ADCIV_ADCIFG: ADC_Result[i] = ADCMEM0; /* if i = 0,means: (1)sequence ADC channels sample has been completed, (2)you can stop ADC conversion here to ignore data overiwrite to the ADC result array */ if(i == 0) { i = 7; //P2OUT ^= BIT0;//toggle P2.0 to see whether the period of the ADC sample is correct __no_operation(); } else { i--; } break; default: break; } } #pragma vector=TIMER1_A0_VECTOR __interrupt void TIMER1_A0(void) { __no_operation(); }
  • Unsolicited: Reading the ADCINCH field reflects the next channel in the sequence, so you could derive "i" from it. (It's the "x" in SLAU445G Fig 20-14, so for your purposes it's always off by 1.) It's slightly more work to compute, but it can't get out of synch.

**Attention** This is a public forum