Hi,
I'm trying to use I2C on an MSP430BT5190 (master) to read a MLX90620 IR sensor (slave) and I'm having trouble. I'm following the "MSP430F541xA, MSP430F543xA Code Examples" but they seem to be incomplete for what I want to do. All I2C commands follow the specification, and consist of master transmission of 1 or more bytes, followed by either a stop or a repeated start receive of 2 or more bytes (up to 256). My EEPROM read works find but some of the read commands don't produce the expected data (verified using I2C from an arduino). I didn't particularly want to use mspware because my EEPROM read command blew up to over 40 lines (if I ignore the ISR code) - is that normal? Below I've listed my code, MLX90620_read_EEPROM() gives the expected values from the receive command, but the MLX90620_read_TA() command does not. I suspect there is a problem with the I2C receive code because I've used my arduino to slowly build up the I2C o-scope like view and its hard to tell but it looks like the 8th bit of each receieve byte comes only after an STT is set, and I get an extra byte at the end of my receive on the read_TA command. Is there any I2C code examples explicitly for the MSP430F5xx series that encompasses a transmit X bytes+receive X bytes without a stop condition in between them? Thanks, I'm pretty sure I'm not the only person looking for more complete code examples specific to this proc. There was the previous bluetooth lib (mindtree's ethermind) released with the ez430-rf256x that used I2C to comm with the accelerometer for this chip, but they yanked the library and I can't find it anywhere despite having bought one.
Erik
//code functions:
static unsigned char IR_EEPROM_DATA[256];
static unsigned int IR_RAW_TA;
static unsigned char i2c_buffer[IR_ARRAY_LEN_2X];
signed char byteCtr;
unsigned char I2C_byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;
unsigned char i2c_txrx = 0;
void MLX90620_read_EEPROM(void)
{
while ( TI_USCI_I2C_notready() ); // wait for bus to be free
TI_USCI_I2C_transmitinit(EEPROM_Addr,I2C_PRESCALER);
i2c_buffer[0]=0x0;
i2c_txrx=1; // don't send stop after transmit, turn into a receiver like repeated start
TI_USCI_I2C_transmit(1, i2c_buffer);
TI_USCI_I2C_receive(256,IR_EEPROM_DATA);
}
signed int MLX90620_read_TA(void)
{
i2c_buffer[0]=0x02;
i2c_buffer[1]=0x90; // set addr of subsequent read
i2c_buffer[2]=0x00; // addr step = 0
i2c_buffer[3]=0x01; // number of reads = 1
i2c_txrx=1;
while ( TI_USCI_I2C_notready() ); // wait for bus to be free
TI_USCI_I2C_transmitinit(ARRAY_Addr,I2C_PRESCALER);
TI_USCI_I2C_transmit(4, i2c_buffer);
TI_USCI_I2C_receive(2,i2c_buffer);
signed int ta_data = (256*i2c_buffer[1]) + i2c_buffer[0];
return ta_data;
}
void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale){
if (i2c_txrx)
return;
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 |= UCRXIE + UCNACKIE; // 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 |= UCTXIE + UCNACKIE; // Enable TX interrupt, EBB
}
void TI_USCI_I2C_receive(unsigned int byteCount, unsigned char *field){
TI_receive_field = field;
if ( byteCount == 1 ){
I2C_byteCtr = 1 ;
__disable_interrupt();
UCB0CTL1 |= UCTXSTT; // I2C start condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts
} else if ( byteCount > 1 ) {
I2C_byteCtr = byteCount;
UCB0CTL1 |= UCTXSTT; // I2C start condition // TODO10 in read_PTAT, this causes the device to send back two bytes, but now SCL low
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts
}
}
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
TI_transmit_field = field;
I2C_byteCtr = byteCount;
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition (UCTR = Tx/Rx flag, UCTXSTT=start), address byte sent at this point in time.
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts
if (i2c_txrx==0)
{
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
}
else
{
while (i2c_txrx); // this gets cleared by my ISR when done transmitting
}
}
#pragma vector=USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
switch(__even_in_range(UCB0IV,12))
{
case 0: break; // Vector 0: No interrupts
case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG
case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG
// error handling, set flags
break;
case USCI_I2C_UCSTTIFG: // Vector 6: USCI_I2C_UCSTTIFG start int flag, used in slave mode only
break; // end Vector 6: STTIFG
case USCI_I2C_UCSTPIFG: // Vector 8: STPIFG stop int flag, used in slave mode only
break; // end Vector 8: STPIFG stop int flag
case USCI_I2C_UCRXIFG: // Vector 10: RXIFG, set when receive buffer is filled with a char
I2C_byteCtr--; // Decrement RX byte counter
if (I2C_byteCtr>2)
{
*TI_receive_field++ = UCB0RXBUF; // Move RX data to address TI_receive_field
}
else
{
*TI_receive_field = UCB0RXBUF; // Move final RX data to TI_receive_field
//UCB0CTL1 |= UCTXNACK; // first send a NACK before the STOP in master rx mode (pg 972 of MSP4305xx family guide)
UCB0CTL1 |= UCTXSTP; // for MLX90620, no NACK is necessary, just ACK when rxing two bytes from PTAT or otherwise
__bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
}
break;
case USCI_I2C_UCTXIFG: // Vector 12: TXIFG, set when TX buffer is empty
if (I2C_byteCtr) // Check TX byte counter
{
UCB0TXBUF = *TI_transmit_field++; // Load TX buffer: sends 8+ACK clock.
I2C_byteCtr--; // Decrement TX byte counter
}
else
{
if (i2c_txrx) // use this flag for reading immed after writing, so we only send stop if not about to do a read
{
i2c_txrx=0;
// turn it into receiver, but otherwise don't do much else
UCB0CTL1 &= ~UCTR;
UCB0IE |= UCRXIE + UCNACKIE;
}
else
{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
}
UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
//UCB0TXBUF = *TI_transmit_field++;
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
default: break;
}
}