Part Number:MSP430F5529
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;
}
}
*/