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.

MSP430F5529: ADC12 repeat sequence problem

Part Number: MSP430F5529


I am trying to do the following:

On each trigger from timer B CCR1, sample 9 channels and stop, with a single interrupt on the last conversion, to collect the data.

I would like this to run automatically, without having to manually toggle any bits. Is this possible?

I initialize stuff like this:


//timer B: 400Hz & A/D trigger
P3DIR |= BIT6;                        // P3.6 output PIN 43 400Hz
P3SEL |= BIT6;                        // P3.6 option select (TB0.6)
//ccr0 sets period
TBCCR0 = 29999;                       // 400Hz @24MHz (half period, toggle)
//ccr1 triggers A/D
TBCCR1 = 5;                           // just a narrow pulse for trigger
TBCCTL1 = OUTMOD_7;                   // CCR1 reset/set mode A/D trig
P5DIR |= BIT7; P5SEL |= BIT7;         // (DEBUG) output pin 56 (disp pin 6)
//ccr6 generates 400Hz output
TBCCTL6 = OUTMOD_4;                   // toggle, pin 43 for 400Hz output
TBCCR6 = 3000;                        // phase offset (to sample at sinewave peaks)
TBCTL = TBSSEL_2 + MC_1;              // SMCLK, upmode

//ADC12 (tudi za potenciometre)
ADC12CTL0 = ADC12ON;                  // ADC12 on
ADC12CTL0 &= ~ADC12ENC;
while (ADC12CTL1 & ADC12BUSY);
P6SEL |= BIT4+BIT5+BIT6+BIT7;         // P6 ADC option select
P7SEL |= BIT0+BIT1+BIT2+BIT3;         // P7 ADC option select
P5SEL |= BIT0+BIT1;                   // P7 ADC option select (potenc)
ADC12CTL0 |= ADC12SHT00 + ADC12SHT10; // Sampling time, chans 0...7 & 8...15
ADC12CTL0 |= ADC12MSC;
ADC12MCTL0 = ADC12INCH_4;             // ref=Vcc,Vss, chan 4
ADC12MCTL1 = ADC12INCH_5;             // ref=Vcc,Vss, chan 5
ADC12MCTL2 = ADC12INCH_6;             // ref=Vcc,Vss, chan 6
ADC12MCTL3 = ADC12INCH_7;             // ref=Vcc,Vss, chan 7
ADC12MCTL4 = ADC12INCH_12;            // ref=Vcc,Vss, chan 12
ADC12MCTL5 = ADC12INCH_13;            // ref=Vcc,Vss, chan 13
ADC12MCTL6 = ADC12INCH_14;            // ref=Vcc,Vss, chan 14
ADC12MCTL7 = ADC12INCH_15;            // ref=Vcc,Vss, chan 15
ADC12MCTL8 = ADC12INCH_8;             // ref=Vcc,Vss, chan 8 (potenc)
ADC12MCTL9 = ADC12INCH_9 + ADC12EOS;  // ref=Vcc,Vss, chan 9 (potenc), end of seq
ADC12CTL1 = ADC12SHS_3;               // trig = timer B CCR1
ADC12CTL1 |= ADC12SHP;                // pulse mode sampling
ADC12CTL1 |= ADC12CSTARTADD_0;        // start address
ADC12CTL1 |= ADC12CONSEQ_3;           // repeat sequence of chans
//ADC12CTL1 |= ADC12CONSEQ_1;         // sequence of chans (toggle ADC12ENC!)
ADC12CTL2 |= ADC12RES_2;              // 12 bit resolution
ADC12IE = ADC12IE9;                   // enable interrupt on last conversion
ADC12CTL0 |= ADC12ENC;                // enable conversion (must be last)

for now, the interrupt just toggles a pin, so I can see it happen:

 

#pragma vector = ADC12_VECTOR

__interrupt void ADC12_ISR(void)
{
switch (ADC12IV)
  {
  case 0: break;      // Vector 0: No interrupt
  case 2: break;      // Vector 2: ADC overflow
  case 4: break;      // Vector 4: ADC timing overflow
  case 6: break;      // Vector 6: ADC12IFG0
  case 8: break;      // Vector 8: ADC12IFG1
  case 10: break;     // Vector 10: ADC12IFG2
  case 12: break;     // Vector 12: ADC12IFG3
  case 14: break;     // Vector 14: ADC12IFG4
  case 16: break;     // Vector 16: ADC12IFG5
  case 18: break;     // Vector 18: ADC12IFG6
  case 20: break;     // Vector 20: ADC12IFG7
  case 22: break;     // Vector 22: ADC12IFG8
  case 24: break;     // Vector 24: ADC12IFG9
  case 26: break;     // Vector 26: ADC12IFG10
  case 28: break;     // Vector 28: ADC12IFG11
  case 30: break;     // Vector 30: ADC12IFG12
  case 32: break;     // Vector 32: ADC12IFG13
  case 34: break;     // Vector 34: ADC12IFG14
  case 36: break;     // Vector 36: ADC12IFG15
  default: break;
  }
int a=ADC12MEM9;
P1OUT ^= 0x01;      // Toggle P1.0 (DEBUG)
}

The problem is, that if I set the MSC bit, the ADC keeps sampling continuously, ignoring the EOS bit, not waiting for a trigger.

If I don't set the MSC bit, ADC converts only one input for each trigger from the timer, so that the ADC interrupt hapens only after nine triggers.

  • Hi Marko,

    You could implement this by Sequence-of-Channels Mode (Autoscan Mode) with Multiple Sample and Convert Mode(ADC12MSC = 1). Each trigger will let all the 9 channels be sampled-and-converted. After each sequence, you could use DMA to toggle the ADCENC bit automatically and then wait for next trigger event.

    A flow chart for 2 channels is shown below for your reference.

  • Thanks Wei, Í will try this.
    I whaven't yet used DMA, so I'll have to study a bit first.
  • You wrote
    "you could use DMA to toggle the ADCENC bit automatically"
    I have studied the datasheets and found no way to do that? (DMA hardware toggling the ENC bit)
    Now I "manually" toggle the ADC12ENC bit in the DMA ( or ADC) interrupt routine.
    I'ts not really a big problem, I have enough time, and the sample timing should be OK - I just wanted to know if there is a "fully automatic" way of running the ADC.

  • I think the short answer is No. (There are DMA tricks used to set control registers, but I'm not quite sure how Wei's works.)

    With CONSEQ=0 or 1 and SHS != 0, you have to toggle ENC between triggers. With CONSEQ=2 or 3, you don't have to toggle ENC but if you use MSC=1 they run non-stop. [Ref User Guide (SLAU208Q) Figs 28-7,8,9,10]

    The combination of CONSEQ=3 and MSC=0 isn't necessarily strange, if you don't need (quasi-)simultaneous sampling between the channels. I have applications where this doesn't matter. Just multiply your timer trigger rate by 9.
  • OK thanks. So I'll just toggle ENC on the interrupt, it's not really that much of an overhead.

    I am sampling a 400Hz sinewave and comparing the channels, so I want the samples to be as close as possible.

  • Hi Marko,

    What I means for "toggle the ADCENC bit automatically" is that the CPU doesn't need to wake to run code for toggling.
    1. DMA0 to be triggered by ADC12IFGx when ADC completes the sequence conversion. Then DMA0 copies a constant value to ADC12CTL0 with ADCENC disabled.
    2. DAM1 to be triggered by DMA0. Then DMA1 copies a constant value to ADC12CTL0 with ADCENC enabled.

    You could configure the DMA0&1 when initial the MCU and then let it run. Every ADC12IFGx could trigger the steps above to toggle the ADCENC after every sequence of conversion without any code running.

**Attention** This is a public forum