I am having trouble initializing and reading from an ADC that uses I2C to talk to my MSP430G2553. I have set breakpoints while debugging and have found that the problem occurs right after I send a start sequence. It seems that the start bit is not cleared after I send the start sequence even though that is what the data sheet told me would happen. The two functions that should be of interest are:
void initI2C_USCIB(void)
and
void sendASIADC(unsigned char location, unsigned char data);
//*************************************************************************************** // MSP430 Blink the LED Demo - Software Toggle P1.0 // // Description; Toggle P1.0 by xor'ing P1.0 inside of a software loop. // ACLK = n/a, MCLK = SMCLK = default DCO // // MSP430x5xx // ----------------- // /|\| XIN|- // | | | // --|RST XOUT|- // | | // | P1.0|-->LED // // J. Stevenson // Texas Instruments, Inc // July 2011 // Built with Code Composer Studio v5 //*************************************************************************************** #include <msp430.h> void transmitByteUART(unsigned char data); void initSPI_USCIA(void); //initializes SPI on USCIA0 for the sd card reader/writer void initI2C_USCIB(void); //initializes I2C on USCIB0 for the ADC from ASI void initLED(void); //initializes led so we can toggle it __interrupt void USCIAB0RX_ISR(void); //interrupt for usci void initASIadc(void); //inits our external adc using i2c void initUART_USCIA(void); //use this for checking the adc void delay(unsigned long time); //simple delay function void transmitDecimal(unsigned char data); //this sends the decimal representaton of an 8 bit number to terminal void sendASIADC(unsigned char location, unsigned char data); //sends data to specified register to ASI ADC void askForASIData(unsigned char channel); //input channel and should receive rx interrupt on uscib0 void readASIData(unsigned char channel); //read only used w/in askfordata void main(void) { WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer //initSPI_USCIA(); //while (!(IFG2 & UCA0TXIFG)){ //IFG2 =0x00; //clear flags after waiting for tx flag //} //UCA0TXBUF = 0x11; //writes to spi data register __bis_SR_register(GIE); //interrupts enabled initLED(); initI2C_USCIB(); //inits with rx interrupt initUART_USCIA(); //use this to check the adc with tera term initASIadc(); while(1){ delay(1000); askForASIData(0x00); //should cause an interrupt that sends adc stuff to teraterm //wait for interrupt } } void delay(unsigned long time){ unsigned char i = 0; while(i<time){ //pretty simple delay function i++; } } void initSPI_USCIA(void){ P1SEL = (BIT1 | BIT2 | BIT4); //configures pins for three pin SPI. MISO P1.1, MOSI P1.2, CLK P1.4 P1SEL2 = (BIT1 | BIT2 | BIT4); //configures pins for their peripheral setting UCA0CTL1 |= UCSWRST; //set software reset to 1 so we can configure SPI //UCA0STAT |= UCLISTEN; //the launchpad listens to itself (use for testing) UCA0CTL0 |= UCCKPH + UCMSB + UCMST + UCSYNC; //clkphase,clkpolarity,MSBfirst,8-bit,master mode, 3-pin, synchronous SPI UCA0CTL1 |= UCSSEL_2; //choose SMCLK as our clock. SMCLK is 1.1 MHz. We divise it with the baud register UCA0BR0 |= 0x02; //Baud rate is 1.1MHZ/(2+1) = 366 KHz UCA0BR1 = 0x00; //upper byte of br register. set to zero UCA0MCTL = 0; //No modulation UCA0CTL1 &= ~UCSWRST; //enables the SPI to work IE2 |= UCA0RXIE; // Enable USCI0 RX interrupt } void initLED(void){ P1DIR |= BIT0; //sets red led to output and turns it on P1OUT &= ~BIT0; //turn red led off } void initI2C_USCIB(void){ //initializes I2C on USCIB0 for the ADC from ASI P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0 P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 |= UCSSEL_2 + UCTR + UCSWRST; // Use SMCLK which is 1.1 MHZ, keep SW reset, receiver mode UCB0BR0 = 60; // fSCL = SMCLK/60 = ~18.3kHz UCB0BR1 = 0; //leave upper bits 0 UCB0I2CSA = 0x12; // Slave Address is 0x12 UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation IE2 |= UCB0RXIE; //Enable USCI0 RX interrupt } void initASIadc(void){ P2DIR |= BIT0; //sets p2.0 output P2OUT |= BIT0; //sets p2.0 HIGH. This resets the ADC delay(100); //waits for a few clock cycles P2OUT &= ~BIT0; //sets p2.0 LOW sendASIADC(0x04, 0x00); //clear the ADC_CHENAB register sendASIADC(0x00, 0x00); //sends 0x04 to the control register of Asi's ADC sendASIADC(0x01, 0x00); //ensures that CSEND is low by clearing sendASIADC(0x02, 0x06); //divides the 1 MHZ internal oscillator by 64 by setting ADC_CLKPRE sendASIADC(0x03, 0x02); // ADC_CLKDV register divides the internal oscillator by 2 } void initUART_USCIA(void){ //set clock to 1 MHZ BCSCTL1 = CALBC1_1MHZ; // Set Digitally Controlled Oscilaltor to 1MHz DCOCTL = CALDCO_1MHZ; // Set DCO to 1MHz //configure hardware UART P1SEL = (BIT1 | BIT2); //configures pins for Uart. MISO P1.1, MOSI P1.2, CLK P1.4 P1SEL2 = (BIT1 | BIT2); //configures pins for their peripheral setting UCA0CTL1 |= UCSWRST; //set software reset to 1 so we can configure SPI UCA0CTL0 = 0x00; //Basic 8-bit UART mode UCA0CTL1 |= UCSSEL_2; //choose SMCLK as our clock. SMCLK is 1.1 MHz. We divise it with the baud register UCA0BR0 |= 104; //lower baud rate register UCA0BR1 = 0; //Baud rate is 1.1MHZ/(108+1) = 9600 (approximately) UCA0MCTL = 0; //No modulation UCA0CTL1 &= ~UCSWRST; //enables the UART to work //enable RX interrupt IE2 |= UCA0RXIE; // Enable USCI0 RX interrupt } void transmitByteUART(unsigned char data){ while (!(IFG2 & UCA0TXIFG)){} //waits until ready to transmit IFG2 =0x00; //clear flags after waiting for tx flag UCA0TXBUF = data; //send 7 to terminal } void transmitDecimal(unsigned char data){ unsigned char first; unsigned char second; unsigned char third; first = data % 10; //this gives us the first digit /lsb of decimal second = data/10; second = second %10; //gives us middle digit third = data / 100; //gives last digit first |= 0x30; //turns it into ascii character second |= 0x30; //turns it into ascii character third |= 0x30; //turns it into ascii character transmitByteUART(third); transmitByteUART(second); transmitByteUART(first); transmitByteUART(0x0A); //new line transmitByteUART(0x08); //carriage return transmitByteUART(0x08); //carriage return transmitByteUART(0x08); //carriage return } void sendASIADC(unsigned char location, unsigned char data){ //sends data via spi to asi's adc //UCB0CTL1 |= UCTXNACK; //precede start condition with NACK UCB0CTL1 |= UCTXSTT; //send start sequence while(UCB0CTL1 & UCTXSTT){ //wait for start sequence to be sent } UCB0TXBUF = 0x24; //send i2c address of slave w/ lsb as 0 for write and 1 for read UCB0TXBUF = location; //send internal register number UCB0TXBUF = data; //send data byte to selected register in adc UCB0CTL1 |= UCTXSTP; //send stop sequence while(UCB0CTL1 & UCTXSTP){ //wait for stop sequence to be sent } } void askForASIData(unsigned char channel){ unsigned char bitNum; unsigned char controlSettings; bitNum = 0x01 << channel; //sets the bit to 1 that is the channel number sendASIADC(0x04, bitNum); //puts the selected bit high in the ADC_CHENAB register controlSettings = channel << 2; //shifts channel by two so it's in the correct position for CTRL register controlSettings |= 0x01; //or it with 1 to start the conversion sendASIADC(0x00, controlSettings); //selects the desired channel and starts the conversion delay(10000); //just wait for the conversion to complete readASIData(channel); //should try to read from the selected channel sendASIADC(0x04, 0x00); //clear the ADC_CHENAB register in preparation for the next read } void readASIData(unsigned char channel){ UCB0CTL1 |= UCTXSTT; //send start sequence while(UCB0CTL1 & UCTXSTT){ //wait for start sequence to be sent } UCB0TXBUF = 0x24; //send i2c address of slave w/ lsb as 0 for write channel += 0x08; //dac register UCB0TXBUF = channel; //send internal register number(for DAC reg) UCB0CTL1 |= UCTXSTT; //Send a start sequence again (repeated start) while(UCB0CTL1 & UCTXSTT){ //wait for start sequence to be sent } UCB0TXBUF = 0x25; //send i2c address of slave w/ lsb as 1 for read UCB0CTL1 |= UCTXSTP; //send stop sequence while(UCB0CTL1 & UCTXSTP){ //wait for stop sequence to be sent } } #pragma vector = USCIAB0RX_VECTOR __interrupt void USCIAB0RX_ISR(void){ unsigned char data; if(IFG2 & UCA0RXIFG){ data = UCA0RXBUF; //reading should clear the RX int flag } else if(IFG2 & UCB0RXIFG){ data = UCB0RXBUF; } transmitDecimal(data); //sends data to terminal P1OUT |= BIT0; //turns led on //UCA0TXBUF = UCB0RXBUF; //sends adc data to terminal //IFG2 = 0x00; //clears flags }