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.

CCS/MSP430F2013: SD16 ADU from MSP430F2013

Part Number: MSP430F2013
Other Parts Discussed in Thread: TLC5951

Tool/software: Code Composer Studio

See my code below. I catch two analog values into two separate 16-Bit-Integer with the SD16 from the MSP430F2013. Now I do this only with the peripherals ADC and SPI in LMP0 (because of a hint of Mr. Kaustubh Kulkarni). However, the values still jumps. On P1.1 the value is constant 170 mV and on P1.2 the value is zero (GND).
For P1.1 I get values between 19561 and 18399.
For P1.2 the value jumps from 0 to 437.
Is this normal, or is still something not good in my code?

Best regards

Franz Peter Zantis

//using the MSP430F2013 as ADU
//23. Mai 2017, F.P.Zantis
//data transfer works with blocks of 2 16-Bit-Words (INT16)
//new values are delivered from the ADU in the rhythm of 1954Hz / 20
#include "msp430x20x3.h"
unsigned int flag=4;      //4=INCH_4,P1.1; 1=INCH_1,P1.2
unsigned int counter;
unsigned int valP11;    //value at P1.1, value to transfer
unsigned int valP12;    //value at P1.2, value to transfer
unsigned int val;        //current value from the ADC
unsigned int valP1x;    //result from 10 ADC-values
unsigned int trash;        //if wrong data appear

int main( void )
{
 WDTCTL = WDTPW + WDTHOLD;     //Stop watchdog timer to prevent time out reset
 BCSCTL1 = CALBC1_16MHZ;       //clock SMCLK=16MHz
 DCOCTL = CALDCO_16MHZ;        //use internal DCO as clock

 P1DIR &= ~BIT2;                       //P1.2 to input; voltage sample
 P1DIR &= ~BIT1;                       //P1.1 to input; current sample

 P1DIR |= BIT4;                        //P1.4 to output direction
 P1SEL |= BIT4;                        //SMCLK to P1.4

 P1DIR |= BIT3;                        //P1.3 to output direction
 P1SEL |= BIT3;                        //Uref to P1.3

 P1DIR |= BIT7;                            //P1.7 to output direction (LED)
 P1OUT &= ~BIT7;                        //LED off

 P2SEL &= ~BIT7;                       //select P2.7 for input/output - use
 P2DIR |=  BIT7;                       //P2.7 to output direction

  //init ADC SD16
  SD16CTL = SD16REFON;                  //activate reference 1,2V
  SD16CTL |= SD16SSEL_1;                //clock for ADU is SMCLK
  SD16CTL |= SD16XDIV_2;                //divider through 16   16MHz --> 1MHz
  SD16CTL |= SD16DIV_1;                 //divider through 2; 1MHz --> 500kHz both divider results for 500kHz for the ADU
  SD16INCTL0 = SD16INCH_4;              //default input via A4+, P1.1, Pin3
  SD16AE &= ~SD16AE1;                   //unipolar input via A4+, P1.1, Pin3, A4- to GND
  SD16AE &= ~SD16AE2;                   //unipolar input via A1+, P1.2, Pin4; A1- to GND
  SD16CCTL0 &= ~SD16SNGL;                //continous conversion
  SD16CCTL0 |= SD16UNI;                 //16-Bit unsigned
  SD16CCTL0 |= SD16IE;                  //interrupt enabled for ADU
  SD16CCTL0 &= ~SD16XOSR;               //set oversampling ratio selector
  SD16CCTL0 |= SD16OSR_256;             //oversampling ratio for the low-pass-filter 500kHz/256=1954Hz Samplerate
  SD16CCTL0 |= SD16SC;                     //start conversion

  USICTL0 &= ~USISWRST;                 //USI released for operation
  USICTL1 &= ~USII2C;                   //clear the I²C-Bit to switch USI to SPI-Mode
  USICTL0 &= ~USIMST;                   //reset Masterbit to be SPI-Slave
  USICTL0 |= USIPE5;                    //SPI-clock via Pin7 (from Warrior56)
  USICTL0 |= USIPE6;                    //SDO-Port enabled; Pin8
  USICTL0 &= ~USIPE7;                   //SDI-Port disabled; Pin9 can be used for normal in/out
  USICTL0 &= ~USILSB;                   //MSB first
  USICKCTL &= ~USICKPL;                 //clock is low when idle
  USICTL1 &= ~USICKPH;                  //get data on the first edge
  USICTL0 |= USIOE;                     //activate output (data goes from MSP to Warrior56
  USICNT |= USI16B;                     //init load counter for 16-bit-data

 //---------- init for data exchange -------------
 //init interrupt for P1.0 as CS
  P1DIR &= ~BIT0;       //P1.0 for input
  P1REN |= BIT0;        //P1.0 pullup
  P1IE = P1IE | BIT0;    //P1.0 enabled for interrupt via P1.0
  P1IES |= BIT0;        //select P1.0 for interrupt with falling edge --> in the ISR is that CS for SPI
  P1IFG = P1IFG & (~BIT0);  //clear Interrupt Flag

  _BIS_SR(LPM0_bits + GIE);   // Enter LPM0 with interrupt
}



#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
//ISR if the level at P1.0 jumps from high to low
// if ((P1IFG & BIT0) && !(P2IN & BIT7) ) check if Bit 0 from P1 is relevant and additional P2.7 is not high
  if (P1IFG & BIT0)             //check if Bit 0 from P1 is relevant
  {
      SD16CCTL0 &= ~SD16IE;         //interrupt disable for ADU; to make sure, that no ADU-interrupt stops this current interrupt
      //USISR=valP11;                  //write value at P1.1 into the SPI-Register; already done in SD16_ISR
      USICNT |= 16;                    //load counter and start transmission with 16 Bit-Word
      while(!(USIIFG & USICTL1));      //wait until data are tranfered

      USISR=valP12;                 //write value at P1.2 into the SPI-Register
      USICNT |= 16;                    //load counter and start transmission with 16 Bit-Word
      while(!(USIIFG & USICTL1));      //wait until data are tranfered

      P1OUT ^= BIT7;                  //toggle P1.7 if a new value has been transfered
  }
  P1IFG = P1IFG & (~BIT0);   //clear Interrupt Flag for P1
  SD16CCTL0 |= SD16IE;       //interrupt enabled for ADU
}



#pragma vector = SD16_VECTOR
  __interrupt void SD16ISR(void)
{
      switch (SD16IV)
      {
            case 2:            //SD16MEM Overflow
                trash = SD16MEM0;
                break;
            case 4:            //SD16MEM0 IFG
              val = SD16MEM0;
              if (val > valP1x)
              {
                    valP1x=val;
              }
              // SD16CCTL0 &= ~SD16IFG;     //clear interrupt flag; automatically done by catching SD16MEM0-value
              counter++;
              if (counter>9)            //the highest value of 9 is taken
              {
                   SD16CCTL0 &= ~SD16SC;      //stop conversion, because of switching the channels
                   if (flag == 4)                //value through A4+
                   {
                      valP11=valP1x;
                      USISR=valP1x;
                      flag = 1;                //switch for next value is from P1.2
                      SD16INCTL0 = SD16INCH_1;   //switch for next value is from P1.2
                   }
                   else                         //value through A1+
                   {
                       valP12=valP1x;
                       flag = 4;                //switch for next value is from P1.1
                       SD16INCTL0 = SD16INCH_4;   //switch for next value is from P1.1
                   }
                   counter=0;
                   valP1x=0;
                  SD16CCTL0 |= SD16SC;         //start conversion
               }
      }
}

  • Allow me some time to go through your code and I will get back to you.
  • I believe I have found an Issue. It is with the pin configuration.

    First issue I spotted is:

     SD16AE &= ~SD16AE1;                   //unipolar input via A4+, P1.1, Pin3, A4- to GND
     SD16AE &= ~SD16AE2;                   //unipolar input via A1+, P1.2, Pin4; A1- to GND

    That is not the unipolar bit. That is ANALOG ENABLE. You are disabling those pins as analog pins. You need to do the exact opposite.

    Second issue:

    SD16CCTL0 |= SD16UNI;                 //16-Bit unsigned

    That is not the 16 bit unsigned bit. That is Unipolar vs bipolar mode. The code is accidentally correct in this case but It was worth pointing out.

  • Dear Nima,

    many thanks! However: I have now changed the code in the SD16ISR. However there is no different - strange! The values from P1.1 jumps from 22000 to 22800 (round about). The voltage level at P1.1 is DC.

    #pragma vector = SD16_VECTOR
      __interrupt void SD16ISR(void)
    {
          switch (SD16IV)
          {
                case 2:            //SD16MEM Overflow
                    trash = SD16MEM0;
                    break;
                case 4:            //SD16MEM0 IFG
                  val = SD16MEM0;
                  if (val > valP1x)
                  {
                        valP1x=val;
                  }
                  // SD16CCTL0 &= ~SD16IFG;     //clear interrupt flag; automatically done by catching SD16MEM0-value
                  counter++;
                  if (counter>9)            //the highest value of 9 is taken
                  {
                       SD16CCTL0 &= ~SD16SC;      //stop conversion, because of switching the channels
                       if (flag == 4)                //value at P1.1 through A4+
                       {
                          valP11=valP1x;
                          flag = 1;                    //switch for next value is from P1.2
                          SD16INCTL0 = SD16INCH_1;       //switch for next value is from P1.2 (A1+)
                          SD16AE = SD16AE2;
                       }
                       else                             //value at P1.2 through A1+
                       {
                           valP12=valP1x;
                           flag = 4;                    //switch for next value is from P1.1
                           SD16INCTL0 = SD16INCH_4;   //switch for next value is from P1.1 (A4+)
                           SD16AE = SD16AE1;
                       }
                       counter=0;
                       valP1x=0;
                      SD16CCTL0 |= SD16SC;         //start conversion
                   }
          }
    }

  • I will test this code on my hardware to further debug it. I will get back to you.
  • #include <msp430.h>
    
    int main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
      P1DIR |= 0x01;                            // Set P1.0 to output direction
      SD16CTL = SD16REFON + SD16SSEL_1;         // 1.2V ref, SMCLK
      SD16INCTL0 = SD16INCH_1;                  // A1+/-
      SD16CCTL0 =  SD16UNI + SD16IE;            // 256OSR, unipolar, interrupt enable
      SD16AE = SD16AE2;                         // P1.1 A1+, A1- = VSS
      SD16CCTL0 |= SD16SC;                      // Set bit to start conversion
    
      __bis_SR_register(LPM0_bits + GIE);
    }
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = SD16_VECTOR
    __interrupt void SD16ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(SD16_VECTOR))) SD16ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      int result = SD16MEM0;
      //Place break point and read the data
    }
    

    Could you please run this simple example to test the ADC? place a break point on the int result = SD16MEM0 and see if the result is as expected. A1 channel is being used.

  • Did you solve this issue?
  • No, sorry. It is not solved. At the moment I am working on an urgent case with the TLC5951. I come back to the problem soon.

    Franz Peter

**Attention** This is a public forum