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.
Tool/software: Code Composer Studio
Team,
I am a filed appications rotator working on getting a new sensor demo up and running for a customer. The sensor requires i2c and we are demoing on the MSP430F5529. Currently I am struggling just to get the i2c working so that I can write to and read from registers. I am not sure the sensor I am supposed to be demoing works correctly so currently I am just trying to read and write to/from a INA260 EVM over i2c. I have tried multiple approaches so far. I tried basing code off the USCIB0 read and write multiple bytes "examples". I also tried porting other peoples I2c code from other microcontrollers to the 5529 but have had little success. I believe my main issue is writing the ISR, I have found no good examples for this.
Question #1:
Does TI have any good I2C examples for reading/writing to a device?
Question#2:
I included my 3 approaches below. If any of them seem close I would greatly appreciate your input on how I can get up and running with I2C. I have used I2C before on microchip controllers and have read all the TI literature I can find (User guide, datasheet, how to use I2C, basics of I2C, and mspware). I am also now familiar with the USCI library.
Approach 1: wrote i2c based on the example code for the MSP430F2619.
main.c
#include <stdio.h> #include <msp430f5529.h> #include <lib5529i2c.h> unsigned char array[5] = { 0x00, 0x07, 0x27}; unsigned char array2[5]; signed char byteCtr; unsigned char *TI_receive_field; unsigned char *TI_transmit_field; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Disable Watchdog P1DIR |= 0x01; P1OUT= 0x00;// configure P1.0 as output _EINT(); // enable interrupts __enable_interrupt(); TI_USCI_I2C_transmitinit(0x40, 0x12); // initialize USCI while ( TI_USCI_I2C_notready() ); TI_USCI_I2C_transmit(3,array); // transmit the first 3 bytes of array //LPM0; // put CPU to sleep during communication TI_USCI_I2C_receiveinit(0x40,0x12); while ( TI_USCI_I2C_notready() ); TI_USCI_I2C_receive(3,array2); }
lib5529i2c.h
/* * lib5529i2c.h * * Created on: Feb 9, 2018 * Author: a0226654 */ #ifndef LIB5529I2C_H_ #define LIB5529I2C_H_ #define SDA_PIN BIT0 // msp430x261x UCB0SDA pin #define SCL_PIN BIT1 // msp430x261x UCB0SCL pin void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale); void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale); void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field); void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field); unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address); unsigned char TI_USCI_I2C_notready(); #endif /* LIB5529I2C_H_ */
lib5529i2c.c
//****************************************************************************** // MSP430 USCI I2C Transmitter and Receiver // // Description: This code configures the MSP430's USCI module as // I2C master capable of transmitting and receiving bytes. // // ***THIS IS THE MASTER CODE*** // // Master // MSP430F2619 // ----------------- // /|\| XIN|- // | | | // --|RST XOUT|- // | | // | | // | | // | SDA/P3.1|-------> // | SCL/P3.2|-------> // // Note: External pull-ups are needed for SDA & SCL // // Uli Kretzschmar // Texas Instruments Deutschland GmbH // November 2007 // Built with IAR Embedded Workbench Version: 3.42A //****************************************************************************** #include "msp430f5529.h" // device specific header //#include "msp430x22x4.h" //#include "msp430x23x0.h" //#include "msp430xG46x.h" // ... // more devices are possible #include "lib5529i2c.h" signed char byteCtr; unsigned char *TI_receive_field; unsigned char *TI_transmit_field; int q=0; //------------------------------------------------------------------------------ // void TI_USCI_I2C_receiveinit(unsigned char slave_address, // unsigned char prescale) // // This function initializes the USCI module for master-receive operation. // // IN: unsigned char slave_address => Slave Address // unsigned char prescale => SCL clock adjustment //----------------------------------------------------------------------------- void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale){ P3SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0 UCB0CTL1 = UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = prescale; // set prescaler UCB0BR1 = 0; UCB0I2CSA = slave_address; // set slave address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE = UCNACKIE; UCB0IE = UCRXIE; // Enable RX interrupt } //------------------------------------------------------------------------------ // void TI_USCI_I2C_transmitinit(unsigned char slave_address, // unsigned char prescale) // // This function initializes the USCI module for master-transmit operation. // // IN: unsigned char slave_address => Slave Address // unsigned char prescale => SCL clock adjustment //------------------------------------------------------------------------------ void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale){ P3SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = prescale; // set prescaler UCB0BR1 = 0; UCB0I2CSA = slave_address; // Set slave address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE = UCNACKIE; UCB0IE |= UCTXIE; // Enable TX ready interrupt } //------------------------------------------------------------------------------ // void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field) // // This function is used to start an I2C commuincation in master-receiver mode. // // IN: unsigned char byteCount => number of bytes that should be read // unsigned char *field => array variable used to store received data //------------------------------------------------------------------------------ void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){ TI_receive_field = field; if ( byteCount == 1 ){ byteCtr = 0 ; __disable_interrupt(); UCB0CTL1 |= UCTXSTT; // I2C start condition while (UCB0CTL1 & UCTXSTT); // Start condition sent? UCB0CTL1 |= UCTXSTP; // I2C stop condition __enable_interrupt(); } else if ( byteCount > 1 ) { byteCtr = byteCount - 2 ; UCB0CTL1 |= UCTXSTT; // I2C start condition } else while (1); // illegal parameter } //------------------------------------------------------------------------------ // void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field) // // This function is used to start an I2C commuincation in master-transmit mode. // // IN: unsigned char byteCount => number of bytes that should be transmitted // unsigned char *field => array variable. Its content will be sent. //------------------------------------------------------------------------------ void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){ TI_transmit_field = field; byteCtr = byteCount; UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition } //------------------------------------------------------------------------------ // unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address) // // This function is used to look for a slave address on the I2C bus. // // IN: unsigned char slave_address => Slave Address // OUT: unsigned char => 0: address was not found, // 1: address found //------------------------------------------------------------------------------ unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){ unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue; ucb0i2cie = UCB0IE; // restore old UCB0I2CIE ie2_bak = UCB0IE; // store IE2 register slaveadr_bak = UCB0I2CSA; // store old slave address UCB0IE &= ~ UCNACKIE; // no NACK interrupt UCB0I2CSA = slave_address; // set slave address UCB0IE &= ~(UCTXIE + UCRXIE); // no RX or TX interrupts __disable_interrupt(); UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP; // I2C TX, start condition while (UCB0CTL1 & UCTXSTP); // wait for STOP condition returnValue = !(UCB0STAT & UCNACKIFG); __enable_interrupt(); UCB0IE = ie2_bak; // restore IE2 UCB0I2CSA = slaveadr_bak; // restore old slave address UCB0IE = ucb0i2cie; // restore old UCB0CTL1 return returnValue; // return whether or not // a NACK occured } //------------------------------------------------------------------------------ // unsigned char TI_USCI_I2C_notready() // // This function is used to check if there is commuincation in progress. // // OUT: unsigned char => 0: I2C bus is idle, // 1: communication is in progress //------------------------------------------------------------------------------ unsigned char TI_USCI_I2C_notready(){ return (UCB0STAT & UCBBUSY); } #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) { switch (__even_in_range(UCB0IV, 12)) { case 10: q=10;// Vector 10: RXIFG -- I am not using it yet (but I'll need it) if (UCB0STAT & UCNACKIFG){ // send STOP if slave sends NACK UCB0CTL1 |= UCTXSTP; UCB0STAT &= ~UCNACKIFG; } break; case 12: q=12;// Vector 12: TXIFG if (P2IFG & UCRXIFG){ if ( byteCtr == 0 ){ UCB0CTL1 |= UCTXSTP; // I2C stop condition *TI_receive_field = UCB0RXBUF; TI_receive_field++; } else { *TI_receive_field = UCB0RXBUF; TI_receive_field++; byteCtr--; } } else { if (byteCtr == 0){ UCB0CTL1 |= UCTXSTP; // I2C stop condition P2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag } else { UCB0TXBUF = *TI_transmit_field; TI_transmit_field++; byteCtr--; } } break; default: break; } }
Approach 2: Wrote library based off 5529 read/write example code
#include "msp430f5529.h" // device specific header //#include "msp430x22x4.h" //#include "msp430x23x0.h" //#include "msp430xG46x.h" // ... // more devices are possible #include "lib5529i2c.h" signed char byteCtr; unsigned char *TI_receive_field; unsigned char *TI_transmit_field; unsigned char TXByteCtr=0; unsigned char RXByteCtr=0; void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale){ P3SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0 UCB0CTL1 = UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = prescale; // set prescaler UCB0BR1 = 0; UCB0I2CSA = slave_address; // set slave address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE = UCNACKIE; UCB0IE = UCRXIE; // Enable RX interrupt } void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale){ P3SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = prescale; // set prescaler UCB0BR1 = 0; UCB0I2CSA = slave_address; // Set slave address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE = UCNACKIE; UCB0IE |= UCTXIE; // Enable TX ready interrupt } void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){ TI_receive_field = field; if ( byteCount == 1 ){ RXByteCtr = 0 ; __disable_interrupt(); UCB0CTL1 |= UCTXSTT; // I2C start condition while (UCB0CTL1 & UCTXSTT); // Start condition sent? UCB0CTL1 |= UCTXSTP; // I2C stop condition __enable_interrupt(); } else if ( byteCount > 1 ) { RXByteCtr = byteCount - 2 ; UCB0CTL1 |= UCTXSTT; // I2C start condition } else while (1); // illegal parameter } void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){ TI_transmit_field = field; TXByteCtr = byteCount; UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition } unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){ unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue; ucb0i2cie = UCB0IE; // restore old UCB0I2CIE ie2_bak = UCB0IE; // store IE2 register slaveadr_bak = UCB0I2CSA; // store old slave address UCB0IE &= ~ UCNACKIE; // no NACK interrupt UCB0I2CSA = slave_address; // set slave address UCB0IE &= ~(UCTXIE + UCRXIE); // no RX or TX interrupts __disable_interrupt(); UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP; // I2C TX, start condition while (UCB0CTL1 & UCTXSTP); // wait for STOP condition returnValue = !(UCB0STAT & UCNACKIFG); __enable_interrupt(); UCB0IE = ie2_bak; // restore IE2 UCB0I2CSA = slaveadr_bak; // restore old slave address UCB0IE = ucb0i2cie; // restore old UCB0CTL1 return returnValue; // return whether or not // a NACK occured } unsigned char TI_USCI_I2C_notready(){ return (UCB0STAT & UCBBUSY); } #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) { switch (__even_in_range(UCB0IV, 12)) { case 10: RXByteCtr--; // Decrement RX byte counter if (RXByteCtr) { *TI_receive_field = UCB0RXBUF; // Move RX data to address PRxData if (RXByteCtr == 1) // Only one byte left? UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition } else { *TI_receive_field = UCB0RXBUF; // Move final RX data to PRxData __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU } case 12: if (TXByteCtr) // Check TX byte counter { UCB0TXBUF = *TI_transmit_field; // Load TX buffer TXByteCtr--; // Decrement TX byte counter } else { UCB0CTL1 |= UCTXSTP; // I2C stop condition UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } default: break; } }
/* * Here's an example using an MSP430G2553 to read/write using I2C to an 24LC512 and DS3231 RTC. * Two functions are provided for read and write. * * The code avoids any while loops, and relies completely on interrupts and low power modes of the MSP430 to reduce the power consumption to the * minimum. * * Author: Ahmed Talaat (aa_talaat@yahoo.com) * Date: 19 October 2012 */ #include "msp430f5529.h" #define ONEBYTEADDR 1 #define TWOBYTEADDR 2 #define WRITE 0 // ISR mode WRITE or READ #define READ 1 #define NOACK 2 #define EEPROM_ADDR 0x40 #define DS3231_ADDR 0x00 unsigned char txdataEEPROM[2]; unsigned char txdataDS3231[7] = {0x20, 0x30, 0x20, 0x04, 0x17, 0x10, 0x12}; unsigned char rxdata[150]; typedef struct { volatile unsigned char *data_buf; // address of tx or rx data buffer volatile unsigned char buf_size; // size of the buffer volatile unsigned char buf_index; // index in the buffer volatile unsigned char addr_index; // index of the byte address (0,1) volatile unsigned char isr_mode; // Tx or Rx affects the interrupt logic volatile unsigned char addr_high_byte; // High byte of the address to read/write to volatile unsigned char addr_low_byte; // Low byte of the address to read/write to volatile unsigned char addr_type; // two bytes like eeprom or 1 byte like RTC for example } i2c_t; i2c_t i2c_packet; void i2c_init(void); void i2c_tx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char); void i2c_rx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char); void usdelay(int); void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT i2c_init(); // Initialize I2C txdataEEPROM[0]=0x61; txdataEEPROM[1]=0x3F; i2c_tx(EEPROM_ADDR, txdataEEPROM, sizeof(txdataEEPROM)-1,ONEBYTEADDR,0x00,0x00);//i2c TX 115 bytes starting @ address 01:00 i2c_rx(EEPROM_ADDR, rxdata, 2,ONEBYTEADDR,0x00,0x00);//i2c RX 115 bytes from EEPROM starting @ address 01:00 LPM0; // Enter LPM0 w/ interrupts } void i2c_init(void){ P3SEL |= BIT0 + BIT1; //Set I2C pins //P1SEL2|= BIT6 + BIT7; UCB0CTL1 |= UCSWRST; //Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; //I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; //Use SMCLK, keep SW reset UCB0BR0 = 10; //fSCL = SMCLK/11 = ~100kHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; //Clear SW reset, resume operation UCB0IE |= UCTXIE; //Enable TX interrupt UCB0IE |= UCRXIE; //Enable RX interrupt UCB0IE |= UCNACKIE; //Need to enable the status change interrupt __enable_interrupt(); //Enable global interrupt } void i2c_tx(unsigned char slave_addr, unsigned char *txdata, unsigned char bufSize, unsigned char addr_size, unsigned char high_byte_addr, unsigned char low_byte_addr) { i2c_packet.isr_mode=WRITE; i2c_packet.data_buf=txdata; i2c_packet.buf_size=bufSize; i2c_packet.buf_index=0; i2c_packet.addr_type=addr_size; i2c_packet.addr_high_byte=high_byte_addr; i2c_packet.addr_low_byte=low_byte_addr; i2c_packet.addr_index=0; UCB0I2CSA = slave_addr; //Slave Address while (1) { UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition LPM0; // Enter LPM0 // and remain until all data is TX'd if (i2c_packet.isr_mode == NOACK){ // If no ack received, then sleep for 0.5ms and try again i2c_packet.isr_mode = WRITE; i2c_packet.addr_index=0; // Reset the address index for the next write operation usdelay(500); } else { break; // Successful write, then quit } } } /* * This functions reads from any I2C device. It takes as parameters: * - The slave address (7 bits) * - Pointer to the data buffer to fill with data read. * - Size of the buffer * - Size of the address location to start writing at. Being 2 bytes for some of the EEPROMs and single byte * for other devices. Please note that the ISR of this function assumes that the address bytes are written high * byte first, then low byte second. * In case of single byte address device, only the high byte will be used to set the address. * - The high byte and low byte address for the location to start reading at. * * The function starts with a write operation to specify the address at which the read operation with start * In case the start condition of the write operation is not ack (for example EEPROM busy with a a previous write cycle), * the corresponding interrupts detects this condition, generates a stop signal, and a Timer A1 (not Timer A0) * is activated for 0.5 ms, then the trial for writing is repeated. * * Once the write address is successful, the functions switch to read mode, and fills the buffer provided * */ void i2c_rx(unsigned char slave_addr, unsigned char *rxdata, unsigned char bufSize, unsigned char addr_size, unsigned char high_byte_addr, unsigned char low_byte_addr) { i2c_packet.isr_mode=READ; // The ISR will send the address bytes, then wake CPU. i2c_packet.addr_type=addr_size; i2c_packet.addr_high_byte=high_byte_addr; i2c_packet.addr_low_byte=low_byte_addr; i2c_packet.addr_index=0; UCB0I2CSA = slave_addr; // Slave Address while (1) { UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition LPM0; // Enter LPM0 // and remain until all data is TX'd if (i2c_packet.isr_mode == NOACK){ // If no ack received, then sleep for 0.5ms and try again i2c_packet.isr_mode = READ; i2c_packet.addr_index=0; // Reset the address index for the next write operation usdelay(500); } else { break; // Successful write, then quit } } // We wrote already the address, so now read only data. i2c_packet.addr_index=i2c_packet.addr_type; i2c_packet.data_buf=rxdata; i2c_packet.buf_size=bufSize; i2c_packet.buf_index=0; UCB0CTL1 &= ~UCTR; // I2C RX UCB0CTL1 |= UCTXSTT; // I2C re-start condition LPM0; // Enter LPM0 // and remain until all data is received } //interrupt(USCIAB0RX_VECTOR) state change to trap the no_Ack from slave case /* * This interrupt is called each time the UCSI_B module is either ready to get a new byte in UCB0TXBUF to send to the I2C device, or * a new byte is read into UCB0RXBUF and we should pick it up. * The interrupt is called as both UCB0TXIE and UCB0RXIE are enabled. To stop this interrupt being called indefinitely, the corresponding * interrupt flag should be cleared. * These flags are automatically clearly by the USCI_B module if the UCB0XXBUF is access. However, if we are to do something different than reading * or writing a byte to/from the UCB0XXBUF, we need to clear the corresponding flag by ourselves or the ISR will be called for ever, * and the whole program will hang. */ #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) { switch (__even_in_range(UCB0IV, 12)) { case 10: RXByteCtr--; // Decrement RX byte counter if (RXByteCtr) { *PRxData++ = UCB0RXBUF; // Move RX data to address PRxData if (RXByteCtr == 1) // Only one byte left? UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition } else { *PRxData = UCB0RXBUF; // Move final RX data to PRxData __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU } case 12: // Transmit address bytes irrespective of send or receive mode.*/ if (i2c_packet.addr_index==0){ UCB0TXBUF = i2c_packet.addr_high_byte; i2c_packet.addr_index++; } else if (i2c_packet.addr_index==1 && i2c_packet.addr_type==TWOBYTEADDR){ UCB0TXBUF = i2c_packet.addr_low_byte; i2c_packet.addr_index++; } else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==READ) { // USCI_B is ready to get a new data byte to transmit it, and we are in READ mode. // So, we should not continue writing, but should exit to the calling function to // switch the USCI_B into read mode P2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF LPM0_EXIT; // Exit LPM0 } else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==WRITE){// USCI_B is ready to get a new data byte to transmit it, and we are in write mode. if(i2c_packet.buf_index == i2c_packet.buf_size){ // If no more data to transmit, then issue stop condition and wake CPU. P2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF UCB0CTL1 |= UCTXSTP; // I2C stop condition LPM0_EXIT; // Exit LPM0 } else { UCB0TXBUF = i2c_packet.data_buf[i2c_packet.buf_index]; i2c_packet.buf_index++; // Increment TX byte counter } } else if (UCRXIFG & P2IFG && i2c_packet.addr_index==i2c_packet.addr_type) { // Read mode, and we already completed writing the address i2c_packet.data_buf[i2c_packet.buf_index]= UCB0RXBUF; i2c_packet.buf_index++; // Increment RX byte counter if(i2c_packet.buf_index == i2c_packet.buf_size){ // If last byte to receive, then issue stop condition and wake CPU. P2IFG &= ~UCRXIFG; // Clear USCI_B0 RX int flag UCB0CTL1 |= UCTXSTP; // I2C stop condition here to avoid reading any extra bytes LPM0_EXIT; // Exit LPM0 } } /* break; default: break; */ } } //------------------------------------------------------------------------------ // micro seconds delays // void usdelay(int interval){ // Setup TimerA TA1CCTL0 = CCIE; // interrupt enabled TA1CCR0 = TA1R + interval; // micro secs @ 1Mhz Clock TA1CTL = TASSEL_2 + MC_2; // SMCLK, continuous mode. LPM0; // suspend CPU } // Timer A1 interrupt service routine. TIMERx_Ay_VECTOR.(x being the index of the timer, y of the vector for this timer) #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer1_A0 (void) { TA1CTL = 0; // Stop Timer_A1 LPM0_EXIT; // Return active }
//******************************************************************************// MSP430 USCI I2C Transmitter and Receiver//// Description: This code configures the MSP430's USCI module as// I2C master capable of transmitting and receiving bytes.//// ***THIS IS THE MASTER CODE***//// Master// MSP430F2619// -----------------// /|\| XIN|-// | | |// --|RST XOUT|-// | |// | |// | |// | SDA/P3.1|------->// | SCL/P3.2|------->//// Note: External pull-ups are needed for SDA & SCL//// Uli Kretzschmar// Texas Instruments Deutschland GmbH// November 2007// Built with IAR Embedded Workbench Version: 3.42A//******************************************************************************/*#include "msp430f5529.h" // device specific header//#include "msp430x22x4.h"//#include "msp430x23x0.h"//#include "msp430xG46x.h"// ... // more devices are possible
#include "lib5529i2c.h"
signed char byteCtr;unsigned char *TI_receive_field;unsigned char *TI_transmit_field;int q=0;//------------------------------------------------------------------------------// void TI_USCI_I2C_receiveinit(unsigned char slave_address,// unsigned char prescale)//// This function initializes the USCI module for master-receive operation.//// IN: unsigned char slave_address => Slave Address// unsigned char prescale => SCL clock adjustment//-----------------------------------------------------------------------------void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale){ P3SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0 UCB0CTL1 = UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = prescale; // set prescaler UCB0BR1 = 0; UCB0I2CSA = slave_address; // set slave address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE = UCNACKIE; UCB0IE = UCRXIE; // Enable RX interrupt}
//------------------------------------------------------------------------------// void TI_USCI_I2C_transmitinit(unsigned char slave_address,// unsigned char prescale)//// This function initializes the USCI module for master-transmit operation.//// IN: unsigned char slave_address => Slave Address// unsigned char prescale => SCL clock adjustment//------------------------------------------------------------------------------void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale){ P3SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = prescale; // set prescaler UCB0BR1 = 0; UCB0I2CSA = slave_address; // Set slave address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE = UCNACKIE; UCB0IE |= UCTXIE; // Enable TX ready interrupt}
//------------------------------------------------------------------------------// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)//// This function is used to start an I2C commuincation in master-receiver mode.//// IN: unsigned char byteCount => number of bytes that should be read// unsigned char *field => array variable used to store received data//------------------------------------------------------------------------------void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){ TI_receive_field = field; if ( byteCount == 1 ){ byteCtr = 0 ; __disable_interrupt(); UCB0CTL1 |= UCTXSTT; // I2C start condition while (UCB0CTL1 & UCTXSTT); // Start condition sent? UCB0CTL1 |= UCTXSTP; // I2C stop condition __enable_interrupt(); } else if ( byteCount > 1 ) { byteCtr = byteCount - 2 ; UCB0CTL1 |= UCTXSTT; // I2C start condition } else while (1); // illegal parameter}
//------------------------------------------------------------------------------// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)//// This function is used to start an I2C commuincation in master-transmit mode.//// IN: unsigned char byteCount => number of bytes that should be transmitted// unsigned char *field => array variable. Its content will be sent.//------------------------------------------------------------------------------void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){ TI_transmit_field = field; byteCtr = byteCount; UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition}
//------------------------------------------------------------------------------// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)//// This function is used to look for a slave address on the I2C bus.//// IN: unsigned char slave_address => Slave Address// OUT: unsigned char => 0: address was not found,// 1: address found//------------------------------------------------------------------------------unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){ unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue; ucb0i2cie = UCB0IE; // restore old UCB0I2CIE ie2_bak = UCB0IE; // store IE2 register slaveadr_bak = UCB0I2CSA; // store old slave address UCB0IE &= ~ UCNACKIE; // no NACK interrupt UCB0I2CSA = slave_address; // set slave address UCB0IE &= ~(UCTXIE + UCRXIE); // no RX or TX interrupts __disable_interrupt(); UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP; // I2C TX, start condition while (UCB0CTL1 & UCTXSTP); // wait for STOP condition
returnValue = !(UCB0STAT & UCNACKIFG); __enable_interrupt(); UCB0IE = ie2_bak; // restore IE2 UCB0I2CSA = slaveadr_bak; // restore old slave address UCB0IE = ucb0i2cie; // restore old UCB0CTL1 return returnValue; // return whether or not // a NACK occured}
//------------------------------------------------------------------------------// unsigned char TI_USCI_I2C_notready()//// This function is used to check if there is commuincation in progress.//// OUT: unsigned char => 0: I2C bus is idle,// 1: communication is in progress//------------------------------------------------------------------------------unsigned char TI_USCI_I2C_notready(){ return (UCB0STAT & UCBBUSY);}
#pragma vector = USCI_B0_VECTOR__interrupt void USCI_B0_ISR(void){ switch (__even_in_range(UCB0IV, 12)) {
case 10: q=10;// Vector 10: RXIFG -- I am not using it yet (but I'll need it) if (UCB0STAT & UCNACKIFG){ // send STOP if slave sends NACK UCB0CTL1 |= UCTXSTP; UCB0STAT &= ~UCNACKIFG; } break; case 12: q=12;// Vector 12: TXIFG if (P2IFG & UCRXIFG){ if ( byteCtr == 0 ){ UCB0CTL1 |= UCTXSTP; // I2C stop condition *TI_receive_field = UCB0RXBUF; TI_receive_field++; } else { *TI_receive_field = UCB0RXBUF; TI_receive_field++; byteCtr--; } } else { if (byteCtr == 0){ UCB0CTL1 |= UCTXSTP; // I2C stop condition P2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag } else { UCB0TXBUF = *TI_transmit_field; TI_transmit_field++; byteCtr--; } } break; default: break;
}
}
*/
Team,
Sorry it doesnt look like I attached my last approach correctly. Here it is:
/* * Here's an example using an MSP430G2553 to read/write using I2C to an 24LC512 and DS3231 RTC. * Two functions are provided for read and write. * * The code avoids any while loops, and relies completely on interrupts and low power modes of the MSP430 to reduce the power consumption to the * minimum. * * Author: Ahmed Talaat (aa_talaat@yahoo.com) * Date: 19 October 2012 */ #include "msp430f5529.h" #define ONEBYTEADDR 1 #define TWOBYTEADDR 2 #define WRITE 0 // ISR mode WRITE or READ #define READ 1 #define NOACK 2 #define EEPROM_ADDR 0x40 #define DS3231_ADDR 0x00 unsigned char txdataEEPROM[2]; unsigned char txdataDS3231[7] = {0x20, 0x30, 0x20, 0x04, 0x17, 0x10, 0x12}; unsigned char rxdata[150]; typedef struct { volatile unsigned char *data_buf; // address of tx or rx data buffer volatile unsigned char buf_size; // size of the buffer volatile unsigned char buf_index; // index in the buffer volatile unsigned char addr_index; // index of the byte address (0,1) volatile unsigned char isr_mode; // Tx or Rx affects the interrupt logic volatile unsigned char addr_high_byte; // High byte of the address to read/write to volatile unsigned char addr_low_byte; // Low byte of the address to read/write to volatile unsigned char addr_type; // two bytes like eeprom or 1 byte like RTC for example } i2c_t; i2c_t i2c_packet; void i2c_init(void); void i2c_tx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char); void i2c_rx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char); void usdelay(int); void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT i2c_init(); // Initialize I2C txdataEEPROM[0]=0x61; txdataEEPROM[1]=0x3F; i2c_tx(EEPROM_ADDR, txdataEEPROM, sizeof(txdataEEPROM)-1,ONEBYTEADDR,0x00,0x00);//i2c TX 115 bytes starting @ address 01:00 i2c_rx(EEPROM_ADDR, rxdata, 2,ONEBYTEADDR,0x00,0x00);//i2c RX 115 bytes from EEPROM starting @ address 01:00 LPM0; // Enter LPM0 w/ interrupts } void i2c_init(void){ P3SEL |= BIT0 + BIT1; //Set I2C pins //P1SEL2|= BIT6 + BIT7; UCB0CTL1 |= UCSWRST; //Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; //I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; //Use SMCLK, keep SW reset UCB0BR0 = 10; //fSCL = SMCLK/11 = ~100kHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; //Clear SW reset, resume operation UCB0IE |= UCTXIE; //Enable TX interrupt UCB0IE |= UCRXIE; //Enable RX interrupt UCB0IE |= UCNACKIE; //Need to enable the status change interrupt __enable_interrupt(); //Enable global interrupt } void i2c_tx(unsigned char slave_addr, unsigned char *txdata, unsigned char bufSize, unsigned char addr_size, unsigned char high_byte_addr, unsigned char low_byte_addr) { i2c_packet.isr_mode=WRITE; i2c_packet.data_buf=txdata; i2c_packet.buf_size=bufSize; i2c_packet.buf_index=0; i2c_packet.addr_type=addr_size; i2c_packet.addr_high_byte=high_byte_addr; i2c_packet.addr_low_byte=low_byte_addr; i2c_packet.addr_index=0; UCB0I2CSA = slave_addr; //Slave Address while (1) { UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition LPM0; // Enter LPM0 // and remain until all data is TX'd if (i2c_packet.isr_mode == NOACK){ // If no ack received, then sleep for 0.5ms and try again i2c_packet.isr_mode = WRITE; i2c_packet.addr_index=0; // Reset the address index for the next write operation usdelay(500); } else { break; // Successful write, then quit } } } /* * This functions reads from any I2C device. It takes as parameters: * - The slave address (7 bits) * - Pointer to the data buffer to fill with data read. * - Size of the buffer * - Size of the address location to start writing at. Being 2 bytes for some of the EEPROMs and single byte * for other devices. Please note that the ISR of this function assumes that the address bytes are written high * byte first, then low byte second. * In case of single byte address device, only the high byte will be used to set the address. * - The high byte and low byte address for the location to start reading at. * * The function starts with a write operation to specify the address at which the read operation with start * In case the start condition of the write operation is not ack (for example EEPROM busy with a a previous write cycle), * the corresponding interrupts detects this condition, generates a stop signal, and a Timer A1 (not Timer A0) * is activated for 0.5 ms, then the trial for writing is repeated. * * Once the write address is successful, the functions switch to read mode, and fills the buffer provided * */ void i2c_rx(unsigned char slave_addr, unsigned char *rxdata, unsigned char bufSize, unsigned char addr_size, unsigned char high_byte_addr, unsigned char low_byte_addr) { i2c_packet.isr_mode=READ; // The ISR will send the address bytes, then wake CPU. i2c_packet.addr_type=addr_size; i2c_packet.addr_high_byte=high_byte_addr; i2c_packet.addr_low_byte=low_byte_addr; i2c_packet.addr_index=0; UCB0I2CSA = slave_addr; // Slave Address while (1) { UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition LPM0; // Enter LPM0 // and remain until all data is TX'd if (i2c_packet.isr_mode == NOACK){ // If no ack received, then sleep for 0.5ms and try again i2c_packet.isr_mode = READ; i2c_packet.addr_index=0; // Reset the address index for the next write operation usdelay(500); } else { break; // Successful write, then quit } } // We wrote already the address, so now read only data. i2c_packet.addr_index=i2c_packet.addr_type; i2c_packet.data_buf=rxdata; i2c_packet.buf_size=bufSize; i2c_packet.buf_index=0; UCB0CTL1 &= ~UCTR; // I2C RX UCB0CTL1 |= UCTXSTT; // I2C re-start condition LPM0; // Enter LPM0 // and remain until all data is received } //interrupt(USCIAB0RX_VECTOR) state change to trap the no_Ack from slave case /* * This interrupt is called each time the UCSI_B module is either ready to get a new byte in UCB0TXBUF to send to the I2C device, or * a new byte is read into UCB0RXBUF and we should pick it up. * The interrupt is called as both UCB0TXIE and UCB0RXIE are enabled. To stop this interrupt being called indefinitely, the corresponding * interrupt flag should be cleared. * These flags are automatically clearly by the USCI_B module if the UCB0XXBUF is access. However, if we are to do something different than reading * or writing a byte to/from the UCB0XXBUF, we need to clear the corresponding flag by ourselves or the ISR will be called for ever, * and the whole program will hang. */ #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) { switch (__even_in_range(UCB0IV, 12)) { case 10: RXByteCtr--; // Decrement RX byte counter if (RXByteCtr) { *PRxData++ = UCB0RXBUF; // Move RX data to address PRxData if (RXByteCtr == 1) // Only one byte left? UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition } else { *PRxData = UCB0RXBUF; // Move final RX data to PRxData __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU } case 12: // Transmit address bytes irrespective of send or receive mode.*/ if (i2c_packet.addr_index==0){ UCB0TXBUF = i2c_packet.addr_high_byte; i2c_packet.addr_index++; } else if (i2c_packet.addr_index==1 && i2c_packet.addr_type==TWOBYTEADDR){ UCB0TXBUF = i2c_packet.addr_low_byte; i2c_packet.addr_index++; } else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==READ) { // USCI_B is ready to get a new data byte to transmit it, and we are in READ mode. // So, we should not continue writing, but should exit to the calling function to // switch the USCI_B into read mode P2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF LPM0_EXIT; // Exit LPM0 } else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==WRITE){// USCI_B is ready to get a new data byte to transmit it, and we are in write mode. if(i2c_packet.buf_index == i2c_packet.buf_size){ // If no more data to transmit, then issue stop condition and wake CPU. P2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF UCB0CTL1 |= UCTXSTP; // I2C stop condition LPM0_EXIT; // Exit LPM0 } else { UCB0TXBUF = i2c_packet.data_buf[i2c_packet.buf_index]; i2c_packet.buf_index++; // Increment TX byte counter } } else if (UCRXIFG & P2IFG && i2c_packet.addr_index==i2c_packet.addr_type) { // Read mode, and we already completed writing the address i2c_packet.data_buf[i2c_packet.buf_index]= UCB0RXBUF; i2c_packet.buf_index++; // Increment RX byte counter if(i2c_packet.buf_index == i2c_packet.buf_size){ // If last byte to receive, then issue stop condition and wake CPU. P2IFG &= ~UCRXIFG; // Clear USCI_B0 RX int flag UCB0CTL1 |= UCTXSTP; // I2C stop condition here to avoid reading any extra bytes LPM0_EXIT; // Exit LPM0 } } /* break; default: break; */ } } //------------------------------------------------------------------------------ // micro seconds delays // void usdelay(int interval){ // Setup TimerA TA1CCTL0 = CCIE; // interrupt enabled TA1CCR0 = TA1R + interval; // micro secs @ 1Mhz Clock TA1CTL = TASSEL_2 + MC_2; // SMCLK, continuous mode. LPM0; // suspend CPU } // Timer A1 interrupt service routine. TIMERx_Ay_VECTOR.(x being the index of the timer, y of the vector for this timer) #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer1_A0 (void) { TA1CTL = 0; // Stop Timer_A1 LPM0_EXIT; // Return active }
Hi,
sorry but this is too much code for me to look at :)
Why do not you take the examples in "Resource Explorer"? They seem easier to me.
Or you can just try to do it with ENERGIA.
What I usually do is to merge the Writing example with the Reading example.
This is the code for MSP430F55xx_uscib0_i2c_08.c:
/* --COPYRIGHT--,BSD_EX * Copyright (c) 2012, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************* * * MSP430 CODE EXAMPLE DISCLAIMER * * MSP430 code examples are self-contained low-level programs that typically * demonstrate a single peripheral function or device feature in a highly * concise manner. For this the code may rely on the device's power-on default * register values and settings such as the clock configuration and care must * be taken when combining code from several examples to avoid potential side * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware * for an API functional library-approach to peripheral configuration. * * --/COPYRIGHT--*/ //****************************************************************************** // MSP430F552x Demo - USCI_B0 I2C Master TX multiple bytes to MSP430 Slave // // Description: This demo connects two MSP430's via the I2C bus. The master // transmits to the slave. This is the MASTER CODE. It cntinuously // transmits an array of data and demonstrates how to implement an I2C // master transmitter sending multiple bytes using the USCI_B0 TX interrupt. // ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.045MHz // // ***to be used with "MSP430F55xx_uscib0_i2c_09.c" *** // // /|\ /|\ // MSP430F5529 10k 10k MSP430F5529 // slave | | master // ----------------- | | ----------------- // -|XIN P3.0/UCB0SDA|<-|----+->|P3.0/UCB0SDA XIN|- // | | | | | // -|XOUT | | | XOUT|- // | P3.1/UCB0SCL|<-+------>|P3.1/UCB0SCL | // | | | | // // Bhargavi Nisarga // Texas Instruments Inc. // April 2009 // Built with CCSv4 and IAR Embedded Workbench Version: 4.21 //****************************************************************************** #include <msp430.h> unsigned char *PTxData; // Pointer to TX data unsigned char TXByteCtr; const unsigned char TxData[] = // Table of data to transmit { 0x11, 0x22, 0x33, 0x44, 0x55 }; int main(void) { unsigned int i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT P3SEL |= 0x03; // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz UCB0BR1 = 0; UCB0I2CSA = 0x48; // Slave Address is 048h UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE |= UCTXIE; // Enable TX interrupt while (1) { for(i=0;i<10;i++); // Delay required between transaction PTxData = (unsigned char *)TxData; // TX array start address // Place breakpoint here to see each // transmit operation. TXByteCtr = sizeof TxData; // Load TX byte counter UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts __no_operation(); // Remain in LPM0 until all data // is TX'd while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent } } //------------------------------------------------------------------------------ // The USCIAB0TX_ISR is structured such that it can be used to transmit any // number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData // points to the next byte to transmit. //------------------------------------------------------------------------------ #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void) #else #error Compiler not supported! #endif { switch(__even_in_range(UCB0IV,12)) { case 0: break; // Vector 0: No interrupts case 2: break; // Vector 2: ALIFG case 4: break; // Vector 4: NACKIFG case 6: break; // Vector 6: STTIFG case 8: break; // Vector 8: STPIFG case 10: break; // Vector 10: RXIFG case 12: // Vector 12: TXIFG if (TXByteCtr) // Check TX byte counter { UCB0TXBUF = *PTxData++; // Load TX buffer TXByteCtr--; // Decrement TX byte counter } else { UCB0CTL1 |= UCTXSTP; // I2C stop condition UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } default: break; } }
Hello Luke,
It's generally not a good practice to post large portions of code expecting the community to review it all. Instead, I would recommend breaking up your larger issue into smaller, more manageable questions, which are easier to provide targeted feedback and elicit feedback from our community.
As kazola correctly pointed out, our code examples in Resource Explorer are the best starting point on the coding side. Another starting point we recommend is the Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430™ MCUs app note (see Section 5). Also, when working with I2C, a logic analyzer should be required, since it will show you exactly what is and isn't getting transmitted.
Hopefully this helps your development!
Regards,
James
MSP Customer Applications
**Attention** This is a public forum