This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I have been trying to get the LIS3LV02DQ accelerometer (http://www.sparkfun.com/products/758) working via SPI with my MSP430F2272 because it is faster than the way I am currently doing It with my CC430 via bit-banging. I am stuck trying to simply read the "WHO_AM_I" register because I always get 0xFF in return no matter what register I try to read.
Here is my code. Thanks in advance.
//******************************************************************************
// MSP430 Accelerometer demo
#include <msp430x22x2.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
char READ = 0;
//read a register
char read_reg(char address)
{
char rbyte;
// Need to set bit 7 to indicate a read
address |= 0x80;
// CS is active low, pull low
P3OUT &= ~0x01; // CS Low
// send the address of the register we want to read first
while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
UCB0TXBUF = address;
while (!(IFG2 & UCB0TXIFG)); // Dummy write so we can read
UCB0TXBUF = 0x00;
while (!(IFG2 & UCB0RXIFG)); // USCI_B0 RX buffer ready?
rbyte = UCB0RXBUF; // Save received byte
// deselect the device
P3OUT |= 0x01; // CS High
return rbyte;
}
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P3SEL |= 0x0F; // P3.0,1,2,3 USCI_B0 option select for UCB
P3DIR |= 0x0B; // P3.0,1,3 output direction(CS + CLK + SIMO out)
P3OUT |= 0x01; // CS High
UCB0CTL0 |= UCMSB + UCMST + UCSYNC + UCCKPH + UCMODE_2; // 4-Pin SPI active low, 8-bit SPI mstr, MSB 1st and UCCKPH graph looks like the LIS3LV02DQ manual's clock graph
UCB0CTL1 |= UCSSEL_2; // SMCLK
UCB0BR0 = 0x0F; // BRCLK = SMCLK/X
UCB0BR1 = 0x00;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCB0TXBUF = 0x00; // Dummy write to start SPI
UCB0TXBUF = 0x00;
READ = read_reg(0x0F); // Reading the WHO_AM_I register should return 0x3A
//P1DIR |= 0x04;
//P1OUT |= 0x04;
while(1)
{
}
}
Gianni Gibelli said:while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
UCB0TXBUF = address;
while (!(IFG2 & UCB0TXIFG)); // Dummy write so we can read
UCB0TXBUF = 0x00;
while (!(IFG2 & UCB0RXIFG)); // USCI_B0 RX buffer ready?
rbyte = UCB0RXBUF; // Save received byte
Your program logic has a flaw with the double buffering mechanism.
First you write to TXBUF. Fine.
Since TXBUF is empty on the first run, the byte you wrote immediately moves to the output shift register and TXBUF is empty again. YOu sense this and write the 'dummy byte', which is correct (except that the dummy bytes are ususally written as 0xff). While doing so, the first byte is still being send and the dummy return byte is being received.
Now you wait for the RXIFG bit to be set, which finally happens. But it is set because you just received the dummy response for the address. At this point the dummy byte to read the real response has just moved into theoutput shift and the response has not been received.
Remember, you send two bytes and therefore you receive two and only the second one is of interest for you. The first is a dummy, sent by the slave while it was receiving the command.
So after writing the second byte to TXBUF, you have to wait until TXBUF is clear once more, indicating that the first byte was sent and the second has started to be sent. Then clear the RXIFG bit (or make a dummy read) and wait for the real response. But if this takes too long, you still might miss it, so you can wait for the busy bit clear (indicating that the last byte was sent and nothing is being received) which means that the first, dumym respons has been overwritten by the real answer (in this case, the overflow bit should also be set) and you can read your response.
It sounds more complex than it is. Just keep in mind that both, TX and RX, are double buffered (one byte in the buffer, one in the transfer).
Thank you so much for such a complete response. I have actually just spent another 5 hours looking at every port under an oscilloscope and deduced just that, now I wish I saw your response earlier but I still learned a lot from debugging it. The other problem was however that 4-wire mode on the MSP does not = 4-wire mode for the accelerometer. I actually want 3-wire mode (SIMO MOSI CLK) on the MSP with a manual CS, and 4-wire mode on the accelerometer (SIMO MOSI CLK CS instead of (SIMO/MOSI) CLK CS = "3 wire"). Lastly, the CS had to be delayed a couple of cycles to not cut off reception early.
Thanks again.
This is a common misunderstanding. The 4th lien i 4 wire mode is only used for controlling the clock/data output, so if this line is pulled by a different master, the port pins go inactive immediately. The program won't notice (o flag/interrupt) and it ha snothing to do with controlling a slave. Controllign a slaves CS line needs to be done manually with a normal port pin.
The reason is obvious: the might be any number of slaves on the same SPI. Actually, you can individually select as many slaves as you have free GPIO lines and access them all through the same SOMI/SIMO/CLK lines.
Also, the CS line often indicates the start of a complete transmission procedure. Releasing CS ends the current connection or acknowledges the receipt or aborts a command sequence or whatever. It's use (when and how long to keep it asserted) is different for different slaves.
The documentation properly describes the SPI hardware. It does not, however, explicitely explain the SPI bus and the interaction with different slaves (including the slave selection where necessary), and leaves room for this misinterpretation.
**Attention** This is a public forum