i2c Hanging on Write to 9150 - Code included (CC430)

By miogui , 10 September 2014

Please help SoulPedal live. To get your interest here, I'm attempting to track foot motion (virtual pedals) using the Accel and Magnet sensors, then potentially work with Boogio with their foot sensors. Accel is not enough - you need to know when the foot is moving in pure XY vs rotating. I'm assuming the Magnetometer can track where the earth is (let me know if this is not the case - never worked with a MEMs compass before). Gryo would require integration on the data therefore more errors with time. So... Compass?

Thanks in advance,
John

Here's what happens, code simplified below. This really should work and did work with a different accelerometer on the i2c bus.
1. After the Start process, the address is set in the TXBuffer, and i2c.slave_reg_written = 1 as expected.
msp430_i2c_write (0x68, 0x6B, 0x01, 0x00); // write 0 to reg 6B to wake up device
2. Still WAITING, it re-enters LPM0 again, but then hangs in LPM. (It never re-enters the ISR to send the data).
3. There is never a NoAck bit set ever and the IE flag is enabled. (Very strange!)

i2c data rate is reduced to only 100K. Their msp430_i2c.h is unchanged. This same board was able to write i2c to another device using very similar code which I tried (clear the interrupt flag at the end of the Case 12 vs beginning, and remove the while loop after Start - still no luck). I'm using the Sparkfun breakout (quick proto testing only) for the 9150, and wires are only about 2 cm long for data/clock/Pwr/Gnd. AD0 comes soldered to ground. If it works, we'll embed into our design. Also notice some of Invensense code is commented - this is bare bones.

INIT: (what applies)
PMAPPWD = 0x02D52;
P1MAP3 = PM_UCB0SDA; // Map UCB0SDA to P1.3
P1MAP2 = PM_UCB0SCL; // Map UCB0SCL to P1.2
P1SEL |= BIT2 + BIT3; // Select P1.2 & P1.3 to I2C function
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 = 0x68; // Slave is 68 FOR THE GYRO 9150
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0IE |= UCTXIE + UCRXIE + UCNACKIE; // Enable TX/RX interrupt, monitor for NACK (No Acknowledge)
PMAPPWD = 0; // Lock port mapping registers


#include "cc430x513x.h"
#include "soulUtil.h"

// 9150
#include "msp430_i2c.h"

MAIN:
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer to prevent time out reset
HAL::SetVCore(2);

/* Initialize struct. */
i2c.state = STATE_WAITING;
i2c.slave_reg = 0;
i2c.slave_reg_written = 0;
i2c.data = 0;
i2c.length = 0;
i2c.enabled = 1;

// static msp430_i2c_info i2c = {
// .enabled = 0
// };

while( true ) {
msp430_i2c_write (0x68, 0x6B, 0x01, 0x00);
__no_operation();
}

int msp430_i2c_write(unsigned char slave_addr,
unsigned char reg_addr,
unsigned char length,
unsigned char const *data)
{
// unsigned long start, cur;
if (!i2c.enabled)
return -1;
if (!length)
return 0;

/* Populate struct. */
i2c.state = STATE_WRITING;
i2c.slave_reg = reg_addr;
i2c.slave_reg_written = 0;
i2c.data = (unsigned char*)data;
i2c.length = length;

UCB0I2CSA = slave_addr;
UCB0CTL1 |= UCTR | UCTXSTT;
while (i2c.state != STATE_WAITING)
__bis_SR_register(LPM0_bits + GIE);
// while (UCB0CTL1 & UCTXSTP);

__no_operation();

// msp430_get_clock_ms(&start);
// while (i2c.state != STATE_WAITING) {
// __bis_SR_register(LPM0_bits + GIE);
// msp430_get_clock_ms(&cur);
// if (cur >= (start + I2C_TIMEOUT_MS)) {
// CTL1 |= UCTXSTP;
// i2c.state = STATE_WAITING;
// msp430_i2c_disable();
// msp430_delay_ms(1);
// CLEAR_SCL();
// CLEAR_SDA();
// msp430_delay_ms(1);
// SET_SCL();
// SET_SDA();
// msp430_i2c_enable();
// return -1;
// }
// }
return 0;
}

int msp430_i2c_read(unsigned char slave_addr,
unsigned char reg_addr,
unsigned char length,
unsigned char *data)
{
// unsigned long start, cur;
if (!i2c.enabled)
return -1;
if (!length)
return 0;

/* Populate struct. */
i2c.state = STATE_READING;
i2c.slave_reg = reg_addr;
i2c.slave_reg_written = 0;
i2c.data = data;
i2c.length = length;

UCB0I2CSA = slave_addr;
UCB0CTL1 |= UCTR | UCTXSTT;
while (i2c.state != STATE_WAITING)
__bis_SR_register(LPM0_bits + GIE);

// msp430_get_clock_ms(&start);
// while (i2c.state != STATE_WAITING) {
// __bis_SR_register(LPM0_bits + GIE);
// msp430_get_clock_ms(&cur);
// if (cur >= (start + I2C_TIMEOUT_MS)) {
// CTL1 |= UCTXSTP;
// i2c.state = STATE_WAITING;
// msp430_i2c_disable();
// msp430_delay_ms(1);
// CLEAR_SCL();
// CLEAR_SDA();
// msp430_delay_ms(1);
// SET_SCL();
// SET_SDA();
// msp430_i2c_enable();
// return -1;
// }
// }
return 0;
}

#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
switch(__even_in_range(UCB0IV,12)) {
case 4: /* NAK interrupt. */
i2c.state = STATE_WAITING;
UCB0CTL1 |= UCTXSTP;
break;
case 10: /* RX interrupt. */
UCB0IFG &= ~UCRXIFG;
if (--i2c.length) {
/* If only one byte left, prepare stop signal. */
if (i2c.length == 1)
UCB0CTL1 |= UCTXSTP;
} else
i2c.state = STATE_WAITING;
/* Read RXBUF last because we don't want to release SCL until we're
* sure we're ready.
*/
*i2c.data++ = UCB0RXBUF;
break;
case 12: /* TX interrupt. */
UCB0IFG &= ~UCTXIFG;
switch (i2c.state) {
case STATE_WRITING:
if (!i2c.slave_reg_written) {
i2c.slave_reg_written = 1;
UCB0TXBUF = i2c.slave_reg;
} else if (i2c.length) {
/* Send next byte, increment pointer. */
char next = i2c.data[0];
i2c.data++;
i2c.length--;
/* Writing to TXBUF must always be the final operation. */
UCB0TXBUF = next;
} else {
i2c.state = STATE_WAITING;
UCB0CTL1 |= UCTXSTP;
//UCB0IFG &= ~UCTXIFG; // clear after all done
}
break;
case STATE_READING:
if (!i2c.slave_reg_written) {
i2c.slave_reg_written = 1;
UCB0TXBUF = i2c.slave_reg;
} else {
/* Repeated start, switch to RX mode. */
UCB0CTL1 &= ~UCTR;
UCB0CTL1 |= UCTXSTT;

/* If single byte, prepare stop signal immediately. */
if (i2c.length == 1) {
/* Well, not IMMEDIATELY. First we need to make sure
* the start signal got sent.
*/
while (UCB0CTL1 & UCTXSTT);
UCB0CTL1 |= UCTXSTP;
}
}
break;
case STATE_WAITING:
default:
break;
}
break;
case 0: /* No interrupt. */
case 2: /* Arbitration lost interrupt. */
case 6: /* Start condition interrupt. */
case 8: /* Stop condition interrupt. */
default:
break;
}
__bic_SR_register_on_exit(LPM0_bits);
}

phpbb Topic ID
16593