I am reading a serial stream of data at 1200 bits/second. The serial line goes high to acknowledge the request for data, then each byte starts with an low "Start" bit and starts with a high "End" bit. I am using Port2.4 for the serial data input, and polling the Port2.4 to see the Acknowledge, and then polling to detect the low "Start" bit. The MSP430F2272 always detects the Acknowledge, but sometimes (1 out of 6 times) delays detecting the start bit for 2.7ms to 30ms (by which time many bits of serial data have passed, as have many opportunities to detect the a low voltage level).
I am checking the signal (levels and quality) with a oscilloscope and a logic analyzer, and the serial data source is not presenting any problems. The logic analyzer _always_ reads the signal flawlessly.
The other problem I am having is that when I start timer A in the delay() function below, it often does not return. It gets assembled as follows, and it just doesn't make sense that it could fail (I originally tried checking the two interrupt flags individually, then resorted to checking them both when that didn't work). I put debug statements on either side of this statement and proved to myself that this is where the microprocessor is hanging.
//while(!(TACTL&BIT0 || TACCTL0&BIT0));
082de BIT.W #1, &0x0160
082e2 JNZ 0x082ea
082e4 BIT.W #1, &0x0162
082e8 JZ 0x082de
I am using the DCOCLK for MCLK, with the calibrated 8MHz clock. I am using Timer B (driven by VLO/ACLK) to count 10 seconds and send another request for data, and I am using Timer A (SMCLK = DCOCLK/8 = 1MHz) to count the microseconds between clocking in bits.
#define DEFAULT_CALBC1_8MHZ (XTS + RSEL3 + RSEL2) // RSEL12, XT2OFF, XTS, no divider (chooses a value of RSEL that guarantees that the oscillator is slower than 8Mhz to simplify look timing
#define DEFAULT_CALDCO_8MHZ (DCO1 + DCO0) // DCO3 + no modulation
BCSCTL1 = CALBC1_8MHZ; // Select preprogrammed BCSCTL1 8MHz calibration
DCOCTL = CALDCO_8MHZ; // Select preprogrammed DCOCTL 8MHz calibration
BCSCTL2 = DIVS_3; // MCLK = DCO, SMCLK = DCO/8
BCSCTL1 &= ~XTS; // Set Low-Freq mode (XTS should already be low)
BCSCTL3 |= LFXT1S_2; // VLO on (with XTS=0 already, sets ACLK = VLOclk)
// TimerB marks the time to read the sensor (accumulate 1 second at a time)
TBCTL = TBCLR; // clear TimerB counter
TBCCTL0 = CCIE; // Enable timer b Capture/compare interrupt
TBCCR0 = VLO_DIV8_1SEC; // ~20000 clock cycles = 20ms @ 1 MHz (SMCLK = 1MHz)
TBCTL = TBSSEL_1+ID_3+MC_1; // ACLK, divide by 8, start and count up to CCR0
P2SEL &= ~BIT4; // this should be the default
ADC10AE0 &= ~BIT4; // reinforcing the default
ADC10CTL0 = 0x00; // ADC off - reinforcing the default
P2IES &= ~BIT4; // Configure interrupt to trigger on low to high transition (doesn't matter because interrupt is not being used - this application just polls the bit)
P2IE &= ~BIT4; // Disable P2.4 interrupts
P2OUT &= ~BIT4; // Force low if we ever switch directions
P2DIR &= ~BIT4; // configure as input
/* power the sensor and request serial data, process the acknowledge and the start bit, then request one byte at a time*/
unsigned int TTLMeasure(char *buffer)
{
unsigned int i;
unsigned int retVal = 1;
char c;
P1OUT |= BIT2; // turn on sensor / request start of serial data
while(!(P2IN & BIT4)); // poll sensor (stop when signal is high) - ***always detects this ***
while((P2IN & BIT4)); // look for low signal - ***sometimes misses multiple periods of low voltage here***
i = 0;
do {
c = TTLRXChar(); // read in 1 character
buffer[i] = c;
i++;
}
while(c != 0 && c != '\n' && i < 60); // stop when c is null, \n, or buffer is full
buffer[i-1] = '\0'; // make sure the string is terminated
P1OUT &= ~BIT2; //turn off sensor
return(retVal);
}
//-----------------------------------------------------------------------------------------------
// TTLRXChar() bit-bangs in a 1200 bps, TTL level character from a digital sensor
//-----------------------------------------------------------------------------------------------
char TTLRXChar( void )
{
int i;
char c;
char p = 0; // Even parity bit
i = 0;
while((P2IN & BIT4)); // Wait for P2.4 to go low (start bit)
c = 0; // ensure initial value is 0
delay(HALF_BIT); // Delay to read at the middle of a bit
for (i=0;i<8;i++) {
delay(ONE_BIT); // already in the middle of a bit -> delay to middle of the next bit to be read
if(P2IN&BIT4)
c += 0x80; // Add bit to character buffer
if(i<7) {
c = c >> 1; // Prepare character buffer for next bit
}
}
delay(STOPBIT_DELAY); // delay to the stop bit
return(c);
}
void delay( unsigned int c ) { // delays 1 usec per c
unsigned int i = c;
if(12 <= i) { // protect against CCR0 = 0
i -= 6; // Subtract 48 clock cycles or 6uS for the computation
TACTL = TACLR; // clears TAR, Count Direction (MC), Clock Divider (ID), flags
TACTL = TASSEL_2 + MC_1; //SMCLK, Mode = up (MC0), ID=0 (clock divider = 0), clear TAIFG
TACCTL0 = 0;
TACCR0 = i;
while(!(TACTL&BIT0 || TACCTL0&BIT0)); // **** second frustration - sometimes processing this statement requires 40ms, 50ms, or even 58ms, even though 90% of the time it takes the expected amount of time ****
}
}