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.

MSP430F2013: Code bug Help

Part Number: MSP430F2013


A professor is using the MSP430F2013 as ADU. He has  problems with the code below.

The sd16 is used to digitize two channels: The value at P1.1 and P1.2. From time to time the results will be taken via SPI. In principle it works. However: from time to time (estimated 10% of the samples) wrong values or 0 occurs. Is there something wrong with the code?

//using the MSP430F2013 as ADU
//data transfer works with blocks of 2 16-Bit-Words (INT16)
//new values are delivered from the ADU in the rhythm of 977Hz

#include "msp430x20x3.h"
unsigned int flag=4;  //4=INCH_4,P1.1; 1=INCH_1,P1.2
unsigned int values[4];
//values[0]=0;
//values[1]=0;               //value at P1.1, value to transfer
//values[2]=0;            //value at P1.2, value to transfer
//values[3]=0;

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_2;                 //divider through 4; 1MHz --> 250kHz both divider results for 250kHz for the ADU
 SD16INCTL0 = SD16INTDLY_0;                                    //Interrupt on 4th sample
 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;                                            //single 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 250kHz/256=977Hz Samplerate

 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 |= 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(GIE);                                                                   //enable all interrupts

 while(1)
 {
    USISR=values[1];          //write value at P1.1 into the SPI-Register; the second value (from P1.2) will loaded if the SPI-Request comes up
    P1IE = P1IE | BIT0;                                        //enable interrupt P1.0
    SD16CCTL0 |= SD16SC;                                //start conversion
 }
}

#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
 P1IE = P1IE & (~BIT0);                                     //disable interrupt
 SD16CCTL0 &= ~SD16SC;         //stop conversion ADU; to make sure, that no ADU-interrupt stops this current interrupt
 if (P1IFG & BIT0) //check if Bit 0 from P1 is relevant
 {
     SD16CCTL0 &= ~SD16SC;                           //stop ADU-conversion - to be on the save side
     //USISR=values[1];                     //write value at P1.1 into the SPI-Register; is already done in main()
     USICNT |= 16;                                                //load counter and start transmission with 16 Bit-Word
     while(!(USIIFG & USICTL1));                    //wait until data are tranfered

     USISR=values[2];                                          //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
//P1IE = P1IE | BIT0;                                           //enable interrupt; is made in main()
}

#pragma vector = SD16_VECTOR
 __interrupt void SD16ISR(void)
{
   //SD16CCTL0 &= ~SD16SC;         //stop conversion; because of single conversion mode: conversion stops automatically
   if (flag == 4)
   {
     values[1]=SD16MEM0;                                //save value to transfer value from P1.1 via SPI
     flag = 1;                                                             //switch for next value is from P1.2
     SD16INCTL0=SD16INCH_1;                         //switch for next value is from P1.2
   }
   else
   {
     values[2]=SD16MEM0;                               //save value to transfer value from P1.2 via SPI
     flag = 4;                                                            //switch for next value is from P1.1
     SD16INCTL0=SD16INCH_4;                         //switch for next value is from P1.1
   }
  // SD16CCTL0 &= ~SD16IFG;       //clear interrupt flag; automatically done by catching SD16MEM0-value
}

Could anyone help me this please?

Thank you in advance.

Kaustubh

  • There is a race condition between the main loop and the interrupt handlers; there is not guarantee that a new value is available when the port interrupt happens.

    You should write the first USISR value when it is available, i.e., in the ADC interrupt handler.

    And there is no error handling; it is possible to get a random value when you have aborted a conversion by clearing SD16SC and when the next conversion has not yet finished when the next port interrupt happens.
  • I agree with Clemens, the main loop is ineffective in that is does not make sure that a conversion has been completed before re-starting the sequence. This can be fixed by polling SD16IFG or using LPM0, the TI-provided code examples can be re-evaluated to understand this further.

    Regards,
    Ryan

**Attention** This is a public forum