Needing high level advice please. Goal is to read Gyros at set time intervals for an accurate calculation of angle and let the 9250 interrupt line drive the ship (plenty of time to do everything else in between, removed for now but still no luck). It goes to sleep and stays there without firing Port 1 ISR?
I used the MSP430 ISR to wake up, then immediately read the sensor data which should clear the interrupt (as configured). Not sure if I understand RAW_DATA_RDY_INT correctly, or maybe I should use CYCLE instead (assuming Gyro data is ready when Accel data is also ready).
Here's my code, I have just finally got the Interrupt wire to jiggle, but my ISR is still not firing and so it won't wake up. I have no trouble reading (verified) or writing for sensor data. Just need the 9250 to wake then do a read.
No expert here, so thanks in advance for any thoughts to try!
CC430F513x <-> Invensense 9250
P1.1 <-> INT
P1.2 <-> CLK (10K to Vcc)
P1.3 <-> SDA (10K to Vcc)
int main( void ) {
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer to prevent time out
HAL::SetVCore(2);
accel->configAccelerometer(); // Configure Port Maps
msp430_i2c_write (MPU9250_ADDRESS, PWR_MGMT_1, 1, &InitCMP0); // 00 6B Wake up!
__delay_cycles(100);
msp430_i2c_write (MPU9250_ADDRESS, PWR_MGMT_1, 1, &InitCMP1); // 01 Stable PLL Clock Source
__delay_cycles(200);
msp430_i2c_write (MPU9250_ADDRESS, CONFIG, 1, &InitCMP3); // 03 DLPF_CFG = bits 2:0 = 011; 1K Hz internally
msp430_i2c_write (MPU9250_ADDRESS, GYRO_CONFIG, 1, &InitCMP3); // 03 Set accelerometer rate to 1 kHz and bandwidth to 41 Hz
msp430_i2c_write (MPU9250_ADDRESS, SMPLRT_DIV, 1, &InitCMP3); // 0x07 is very slow sampling for now
msp430_i2c_write (MPU9250_ADDRESS, INT_PIN_CFG, 1, &InitCMP30); // 10 INT_Status is cleared on any read of the device
// Also tried 0x00 requiring Int_Status read, and 70 w/o pullup, no luck...
msp430_i2c_write (MPU9250_ADDRESS, INT_ENABLE, 1, &InitCMP11); // 11 Raw Ready Enable and FIFO to Interrupt (just to force the INT line to fire)
P1IFG &= ~0x01; // P1.1 IFG cleared (I do this in the ISR too)
while (true) {
P1IE |= BIT1; // P1.1 interrupt enabled
__bis_SR_register(LPM0_bits + GIE); // Also tried LPM4 to all clocks
P1IE &= ~BIT1; // P1.1 interrupt disabled
// Read Accel and Gyro
msp430_i2c_read (MPU9250_ADDRESS, 0x3B, 0x06, &AccelXYZ[0]); // 3B Read Accelerometers
msp430_i2c_read (MPU9250_ADDRESS, 0x43, 0x06, &GyroXYZ[0]); // 43 Read Gyros
// Do other stuff here, but doesn't work even if commented out!
}
}
// Port 1 Interrupt
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void) {
switch(__even_in_range(P1IV, 0x06)){
case 0x00: break; // pin 0
case 0x02: P1IFG &= ~0x01; // P1-Pin 1
break;
case 0x04: break; // pin 2
case 0x06: break; // pin 3
default: break;
}}
#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;
NoAck = 4;
break;
case 10: /* RX interrupt. */
NoAck = 0;
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);
}
void Accelerometer::configAccelerometer( void )
{
// Disable all interrupts
PMAPPWD = 0x02D52; // Get write-access to port mapping regs
P2SEL |= 0x01; // Enable A/D channel A0
/* Initialize ADC12_A */
ADC12CTL0 = ADC12ON+ADC12SHT0_8+ADC12MSC; // Turn on ADC12, set sampling time
// Need this to be 12 bits for accuracy
ADC12CTL2 &= ~0x30; // Clear out only bits 4 and 5
ADC12CTL2 |= 0x20; // Set only bit 5 (put in 12-bit mode)
ADC12CTL1 = ADC12SHP+ADC12CONSEQ_0; // Use sampling timer, Single Channel converted once
ADC12CTL0 |= ADC12ENC; // Enable conversions ENC = 1
// 9250 Interrupt on Port 1.1 input
P1DIR &= ~BIT1; // for the motion interrupt on P1.1 input to CPU
P1IES &= ~BIT1; // P1.1 Lo/Hi edge
P1IFG &= ~BIT1; // P1.1 IFG cleared
// 9250 Data and Clock to I2C
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;
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
return;
}