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.

DTC and ADC10

Other Parts Discussed in Thread: MSP430F2272

Greetings,

What is allowed to interrupt an automatic block data conversion and transfer?

I occasionally bomb out of a 33 conversion single channel for no apparent reason. The ADC10B1 indicates the block is not filled, which I knew.

If an automatic data transfer can be interrupted, is the proper thing to do is watch the ADC10B1 bit and redo the sequence if it's not set?

Maybe it's just me, but after reading the ADC10 section it isn't clear if a DTC sequence will always do all of the conversions before relinquishing control.

Thanks for any insight and knowledge you can give.

Edd

  • I am not sure as to which MSP430 device you are using, but I can suggest the following:

    1. Please run the code example (msp430x22x4_adc10_08.c) "as-is" from the following zip file and see if the issue occurs at any time.
    http://www.ti.com/lit/zip/slac123

    2. I am not sure about what other processes are running in your code, but the CPU is halted for the one cycle that it takes for each ADC10MEM transfer. Please see section 20.2.7 and pg 20-20 of the 2xx user's guide:
    http://www.ti.com/litv/pdf/slau144e

    3. Then you can slowly (one at a time) add the processes/interrupts from your code in the code example to see when it is that the issue occurs and the timings that cause that.

  • Thanks. I'll give it a try.

    Using  a 2272.

  • It seems I had a Timer A interrupt enabled. Thought I had 'em all off. Which answers my own question:

    Yes, the sequence is interruptible and, once interrupted, doesn't finish.

  • Hi,

    I am working with MSP430F2272. Does every interrupt stop a conversation sequence? So I have to disable all interrupt except ADC10 interrupt, before starting a conversation sequence? If a sequence was once interrupted will the next sequence be converted and transfered correct?

    Thanks

    Anita

  • Anita said:

    Hi,

    I am working with MSP430F2272. Does every interrupt stop a conversation sequence? So I have to disable all interrupt except ADC10 interrupt, before starting a conversation sequence? If a sequence was once interrupted will the next sequence be converted and transfered correct?

    Thanks

    Anita

     

    No, every interrupt should not stop a conversion sequence. I believe with the above scenario (I may be wrong) that Timer_A was being used to trigger ADC10 and perhaps the Timer was triggering a new conversion sequence before the previous had finished, thus interrupting it.

  • Greetings,

    I'm the original poster. I was  triggering the ADC10 with a pushbutton or a command coming in from the UART, not timer A, but I found that if an interrupt hit during the sequence, it was serviced and the conversions never finished.

    I doubt that this is peculiar to timer A.

    What I do is turn all interrupts off during the conversion sequence, then back on. Further sequences are just fine.

     

    Edd

  • eltury said:

    I was  triggering the ADC10 with a pushbutton or a command coming in from the UART, not timer A, but I found that if an interrupt hit during the sequence, it was serviced and the conversions never finished.

    You saw this with any interrupt? I have not personally experienced this but I suppose it is possible.

  • I didn't do any experimenting, so I can't say for sure, but I'd hazard a guess that there's a good possibility that any interrupt, if occuring at just the right (wrong?) time would halt the sequence.

  • Hi, I'm using ADC10 and DTC too; a have TimerA compare interrupt every 0.7ms (worst case) and didn't recognized any problems so far.

    My setup code lis below

    // P2.0 and P2.1 are used as analog inputs
    // P2.0 --> A0 --> samples R16
    // P2.1 --> A1 --> samples R15
    ADC10CTL1 = INCH_1 + CONSEQ_3;          // A1/A0, repeat multi channel
    ADC10CTL0 = ADC10SHT_1 + MSC + ADC10ON + ADC10IE;
    ADC10AE0 = 0x03;                        // P2.0, P2.1 ADC option selected
    ADC10DTC1 = 8;                          // 8 conversions

    Starting the conversion is done like:

    ADC10CTL0 &= ~ENC;
    while (ADC10CTL0 & BUSY);
    ADC10SA = 0x0200; // define data buffer start
    // start ADC10 conversion
    ADC10CTL0 |= ENC + ADC10SC;             // sampling and conversion start

    To prevent from data corruption I'm storing the ADC results in a seperate RAM segment only (write) accessed by the DTC. I made this because I have had bad results when I had high interrupt loads. After introducing the new RAM segment everything works without problems.

    Rgds
    G**buster 

  • My problem is that DTC does not work. I can see that the channels are sampled (peak on signal). Single-channel-coversation is also working.

    If I change order in setup code DTC works always.

    I have TimerA CCR0 interrupt every 20 ms and TimerA CCR2 interrupt ervery 1ms.

    In TimerA CCR2 interrupt I start conversation.

    Setup code not working DTC:

    // Watchdog off and MCLK 12 MHz

    ADC_Init()

    TimerA_Init()

    //Init some global variables

    __enable_interrupt();   //enable global interrupt

    Setup code working DTC:

    swap __enable_interrupt()    and initialisiation of global variables

    ADC_Init:

      ADC10CTL0 &= ~ENC;
        while (ADC10CTL1 & BUSY); 
        ADC10CTL0  = SREF_2  |                       
          ADC10SHT_3 |  MSC  |                             
            ADC10ON    | ADC10IE;                           
        
        ADC10CTL1  = dAD_Channel_Start | SHS_0       | 
          ADC10DIV_2        | ADC10SSEL_3 |            
            CONSEQ_1;                                     
        
        ADC10DTC0  = ADC10CT;                          
        ADC10DTC1  = 16;                
        ADC10SA    = (WORD) mwADC_Values;         //mwADC_Values is an array length 16

          ADC10AE0   = dAD_PortEnable0;                   
         ADC10AE1   = dAD_PortEnable1;

    init Timer A:
      TACTL = TASSEL_2 + ID_2 +  MC_0;           // SMCLK, /4, stop
     
       TACCR0 = 65535;
      TACCR1 = 1080;
      TACCTL1  = OUTMOD_0;  
      
      TAR = 0;
     
      TACCR2 = 60;   
      TACCTL2 = CCIE;
     
      TACCTL0 |=CCIE;                     //Interrupt enablen
      TACTL |= MC_1 ;                     //upmode

     TimerA CCR0 Interrupt:

    does nothing

     TimerA CCR2 Interrupt:

     // next Interrupt 1ms or 60 counts after CCR0 
      long lTACCR2_next = (long)TACCR2 + TimerATACCR2Steps;    
      if(lTACCR2_next > TACCR0 ){
       lTACCR2_next =  60;
      }
      TACCR2 = (WORD)lTACCR2_next;
    }

     ADC10CTL0 |= ENC + ADC10SC;  //start ADC

    ADC Interrupt:

    A not used port pin ist toggle to see on oscilloscope if DTC is working.
           

  • Hi,

    from my point of view the DTC is a little bit complicated in case of it's initialization sequence. Because of that I used to re-write ADC10SA before I start a new conversion.

    Im' not quite shure what you expect from this c-line: ADC10SA    = (WORD) mwADC_Values;         //mwADC_Values is an array length 16

    ADC10SA must be written with an adress (in RAM; i.e. ADC10SA = 0x0200;). One trap door when doing this is that you possibly do not know where you array (mwADC_Values in your example) is located. O.K., you can initialise a pointer, assign it to the variable and then write the address this pointer is pointing to to ADC10SA.

    My approach (reserving a segment in RAM for the results --> start address is KNOWN by default and is UNCHANGED regardless what my app does in RAM) seems a little bit simpler to me (although I need to reserve xbytes in RAM; x= no of conversions * no of channels). How many channels do you want to sample? since I do not know what 'dAD_Channel_Start' is (default defines in header files are like INCH_x).

    Furthermore, you need to check if there's an AD conversion ongoing before you attempt to start a new one. Because of that, I start all ad conversions like this:

    Starting the conversion is done like:

     

    ADC10CTL0 &= ~ENC;
    while (ADC10CTL0 & BUSY);  // ongoing ad conversion
    ADC10SA = 0x0200; // define data buffer start
    // start ADC10 conversion
    ADC10CTL0 |= ENC + ADC10SC;             // sampling and conversion start

    So, pls provide some mor details on the two variables to help me in understanding your C-Source.

    Rgds
    G**buster

  • This code works fine. I throw away the first conversion and average the remaining 32. Add 'em up and right shift 3 for 12 bit resolution.

    I also do a check to see if there are any "flyers" in the 32 results, since my input should be a steady DC voltage. That's how I discovered the occasional interrupt problem.

     

     //           ADC on    Int Vr    Vr on   Vr out   burst     64 clocks   multi  isr en.   50khz
      ADC10CTL0 = ADC10ON + SREF_1 + REFON +  REFOUT + REFBURST + ADC10SHT_3 + MSC + ADC10IE + ADC10SR + REF2_5V;
      //           channel                                       rpt. 1     adc_osc     
      ADC10CTL1 = ((unsigned int)channel*(unsigned int)0x1000) + CONSEQ_2 + ADC10SSEL_0;
     
      ADC10DTC1 = 33;                          // 33 conversions and transfers
     
      ADC10SA = (unsigned int)fg_buff;         // Starts at fg_buff[0]
       
      ADC10CTL0 |= ENC + ADC10SC;              // Enable and start
     
      _BIS_SR(LPM3_bits + GIE);                // Go to sleep until conversions are finished
     
      ADC10CTL0 &= ~ENC;                      

      ADC10CTL0 = 0x0000;                      // Everything off

     

    eltury

  • Hi G**buster,

    #define dAD_Channel_Start INCH_15

    WORD mwADC_Values [16];

    thanks for your help I will try your approach.

     

  • It seems that I had watchdog enabled.

    In TimerA CCR2 was:

      WDTCTL = WDT_MRST_32;  // 32768/12 MHz = 2,7 ms

    This should reset watchdog every 1 ms.

    In combination with a long time between TimerA setup and global interrupt enable CCR2 interrupt flag is set before GIE und executed when GIE is set.

    There  the watchdog is enable. Next TACCR2 is programmed to (old_TACCR2 + TimerATACCR2Steps) = 3060. But TAR is at this time already higher. So the next CCR2 interrupt is after one period with 20 ms. watchdog elapses before.

    In a small test software I could observe this behavoir. Everything was removed except TimerA and ADC10. I had removed all calculations.

    Weird is that with the original software the system does not reset. I proved TimerA, UART and also the external DAC work fine. Only ADC does not work.

    By removing the watchdog the problem is removed.

    Now I am searching for the difference between test and original software.

  • I found the difference.

    In  timerA setup in test software (the one with the watchdog resets) TAR set to 0. In original software not.

    There the PUC triggered by watchdog does not reset TAR. So after PUC TAR continued counting. After some PUC TAR reached a value which fits the timing of TACCR2 interrupts and watchdog. Then the controller works normal. ADC10 and DTC seem not to like this sequence of resets and new intitalisations and so  do not work properly.

    Actually the problem was not cause by ADC10 and DTC. It was a timing problem between TimerA and watchdog. 

**Attention** This is a public forum