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