Hi,
I am having some major difficulty with my SPI interface to the LIS331DLH Accelerometer (at this point I think that part is cursed). Basically I"m having the following problems
- When I attempt to write 0x01 to the accelerometer's 4th register and read the value back, I get 0xFF (I hover over the variable in CCS and I get /255 which I'm taking as 0xFF).
- The while loop in my initAccelerometer() function turns into a forever loop. I always read back 0xFF. However, When I let the micro idle for 0.5 seconds, when I read that same register, I get 0x00 (Which is what I'm expecting). Just to clarify, this register that I"m reading in the accelerometer has a "boot" flag. If the boot flag is up, it will not be recording data correctly.
- I did at one point have this communication protocol working before. I changed no portion of the firmware that interacts with Accelerometer (or hardware) and then this code suddenly broke. Since then I've had to add the flag UCCKPH or UCCKPL in order to get anything but 0xFF from the accelerometer. I'm finding this to be very strange.
- I should note that I am reading the Who_AM_I register and getting the correct result for the accelerometer. I can read and write to most registers and get the correct result back (except point number 1).
If anyone has any suggestions or ideas please let me know. This is a very frustrating problem.
Thanks for the help,
Jec
The datasheet for the accelerometer is located here: http://www.st.com/stonline/products/literature/ds/15094.pdf
/**
* Configures the SPI port to be used.
* @param newMode The new mode for the SPI port.
*/
void SPIConfig(SPI_MODES newMode)
{
switch (newMode)
{
case SPI_MODE_OFF:
UCA0CTL0 |= UCSWRST; // Set bit before configurations
P3SEL = 0x00; // Port3 = standard I/O port
UCA0CTL0 &= ( ~ UCSWRST ); // Clear bit now - ready
break;
case SPI_MODE_MASTER:
default:
{
// Reconfiguring Process
// 1. Set UCSWRST in the UCXCTL1 register
// 2. Initialize all USCI registers with UCSWRST = 1 (Including UCxCTL1)
// 3. Configure Ports.
// 4. Clear UCSWRST via software.
// Enable Interrupts via UCxRXIE and UCxTXIE.
UCA0CTL1 |= UCSWRST; // Disabling SPI bus while reconfiguration is occuring.
UCA0CTL0 = (UCMSB | UCCKPL
| UCMST | UCSYNC); // Data Cap on First Edge, MSB, Clock Polarity (Inactive High), Master SPI, 3-wire SPI, synchronous.
UCA0CTL1 |= UCSSEL_2; // SMCLK.
// 16 bit baud rate register
UCA0BR0 |= 0x08; // LSB: SMCLK / 2
UCA0BR1 |= 0x00; // MSB:
UCA0MCTL = 0x00; // no modulation
// Configuring Ports
P3SEL |= ( MOSI | MISO | SCLK ); // Port3 = SPI peripheral
P3DIR |= ( MOSI | SCLK | ACCEL_EN | FLASH_EN);
P3OUT |= ( MOSI | SCLK );
UCA0CTL1 &= ~(UCSWRST); // Clear bit now - ready
break;
}
}
}
/**
* Transfer a byte from the microcontroller to another device.
* @param spiOutput The output data to be sent from the microcontroller.
* @return The data received by the microcontroller.
*/
unsigned char SPIByteTransfer(unsigned char spiOutput)
{
// Clearing received interrupt flag.
IFG2 &= ~(UCA0RXIFG);
// Starting Transfer.
UCA0TXBUF = spiOutput;
// Poll Interrupt flag for completion
while ((IFG2 & UCA0RXIFG) != UCA0RXIFG);
return (UCA0RXBUF);
}
/**
* Transfers a byte of data to accelerometer at the specified address.
* @param commMode The communication mode used to talk with the accelerometer.
* @param address The address of the accelerometer's register.
* @param data The data being sent to the accelerometer.
* @return The byte of data the accelerometer transmitted.
*/
unsigned char accelTransfer(unsigned char commMode, unsigned char address, unsigned char data)
{
// This is a simple function to communicate with the accelerometer. If data is expected to
// be transmitted from the accelerometer, the return statement is used.
unsigned char dataIn;
// Enabling the accelerometer's SPI control signal.
P3OUT &= ~(ACCEL_EN);
SPIByteTransfer(commMode | address);
dataIn = SPIByteTransfer(data);
// Disabling the accelerometer's SPI control signal.
P3OUT |= ACCEL_EN;
return dataIn;
}
/**
* Starts up the accelerometer and sets it to standard settings.
*/
void initAccelerometer()
{
// This method starts up the accelerometer.
// Reconmended Startup Sequence:
// 1. Write CTRL_REG1.
// 2. Write CTRL_REG2.
// 3. Write CTRL_REG3.
// 4. Write CTRL_REG4.
// 5. Write Reference.
// 6. Write INT1_THS.
// 7. Write INT1_DUR.
// 8. Write INT2_THS.
// 9. Write INT2_DUR.
// 10. Read HP_FILTER_RESET (If filter is enabled).
// 11. Write INT1_CFG
// 12. Write INT2_CFG
// 13. Write CTRL_REG5
unsigned char testus1, testus2;
SPIConfig(SPI_MODE_MASTER);
// Must wait 5ms for the accelerometer to warm up.
timeDelay(5000);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_CTRL_REG1, ACCEL_PM0 | ACCEL_DR1 | ACCEL_DR0 | ACCEL_Xen | ACCEL_Yen | ACCEL_Zen);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_CTRL_REG2, ACCEL_BOOT);
timeDelay(500000);
while ((accelTransfer(ACCEL_READ_NOINCREMENT, ACCEL_CTRL_REG2, 0x00) & ACCEL_BOOT) == ACCEL_BOOT);
testus1 = accelTransfer(ACCEL_READ_NOINCREMENT, ACCEL_CTRL_REG2, 0x00);
testus2 = accelTransfer(ACCEL_READ_NOINCREMENT, ACCEL_CTRL_REG1, 0x00);
//accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_CTRL_REG3, ACCEL_I1_CFG1);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_CTRL_REG3, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_CTRL_REG4, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_REFERENCE, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_INT1_THS, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_INT1_DURATION, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_INT2_THS, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_INT2_DURATION, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_HP_FILTER_RESET, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_INT1_CFG, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_INT2_CFG, 0x00);
accelTransfer(ACCEL_WRITE_NOINCREMENT, ACCEL_CTRL_REG5, 0x00);
// Must wait 5ms for the accelerometer to boot.
timeDelay(5000);
}
/**
* Converts the acceleration read from the accelerometer into standard
* binary format. This is necessary because the accelerometer represents
* 1 gravity with 1024. The acceleration from the accelerometer is also
* in 2's complement.
* @param accel The acceleration from the accelerometer.
* @return The binary formatted accelerometer data.
*/
int accelIntConversion(unsigned int accel)
{
// This method converts the 2's complement integers from the accelerometer into normally
// formatted signed integers.
// Testing for negative number (bit 15 is high)
if ((accel & 0x8000) == 0x8000)
{
accel = ~(accel) + 1; // Performing 2's complement.
// Checking for 2g measured
if ((accel & 0x0800) == (0x0800))
{
accel = 2000; // 2g is the greatest value possible.
}
else if ((accel & 0x0400) == (0x0400))
{
// Checking for 1g measured.
accel = (accel & ~(0x0400)); // Removing the 1g indicator bit.
accel += 1000; // Adding the 1000 back in.
}
return (-accel); // Taking negative value of the 2's complement result.
}
else
{
// The number was positive.
// Checking for 2g measured.
if ((accel & 0x0800) == (0x0800))
{
accel = 2000; // 2g is the greatest value possible.
}
else if ((accel & 0x0400) == (0x0400))
{
// Checking for 1g measured.
accel = (accel & ~(0x0400)); // Removing the 1g indicator bit.
accel += 1000; // Adding the 1000 back in.
}
return(accel);
}
}