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.
Hello everyone,
I am a newbie to MSP430 and SPI protocol. I read a lot about SPI online and also in the User Guide of MCU. The problem I am facing is described below;
I am interfacing ADXL345 Accelerometer with MSP430F2274 via 3 wire SPI. I think I am doing all the initializing correctly, but I am not getting any useful data back.
I am trying to read the device ID of ADXL345 but I keep on getting 0xF2 instead of 0xE5.
This is the data sheet for ADXL345; http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf
ADXL345 takes 16 bits of data at one time but the MCU can only clock out 8 bits in one transmission, I think this creates a timing difference in the communication and hence
I don’t get what I want. Below is the code I am trying to use:
#include "msp430x22x4.h"
volatile unsigned char Data;
volatile int i;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P3SEL |= 0x31; // P3.0,P3.4,P3.5 USCI_A0 option select
P3DIR |= 0x40; // P3.6 output direction
P4DIR |= BIT3; // Used to provide power to the Accelerometer
P4OUT &= ~BIT3;
// SPI initialization
UCA0CTL0 |= UCCKPH + UCCKPL + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
UCA0CTL1 |= UCSSEL_2; // Select SMCLK as CLK
UCA0BR0 |= 0x02;
UCA0BR1 = 0;
UCA0MCTL = 0;
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
P4OUT |= BIT3; // Turn the Accelerometer on
while(1)
{
P3OUT &= ~0x40; // Chip select active low
for(i = 0xFFFF; i > 0; i--); // Delay
IFG2 &= ~UCA0RXIFG; // Clear int flag
while ((IFG2 & UCA0TXIFG) == 0);
UCA0TXBUF = 0xC0; // Read Dev ID
IFG2 &= ~UCA0RXIFG;
//while ((IFG2 & UCA0TXIFG) == 0); // TXBUF ready?
UCA0TXBUF = 0x45;
while ((IFG2 & UCA0TXIFG) == 0); // TXBUF ready?
P3OUT |= 0x40; // End Transmission
while ((IFG2 & UCA0RXIFG) == 0); // RXBUF ready?
Data = UCA0RXBUF; // Move value
}
}
Somebody please help me on this.
Thanks.
Satbir Sekhon said:I keep on getting 0xF2 instead of 0xE5
So what you expect is
11100101
and what you get is
11110010
Looks like you're getting a superfluous '1' as the first bit and miss the last. This may be caused by a wrong clock edge setting. Or because the time between setting the chip select low and clocking the first byte is too short, so the first clock pulse is ignored.
Satbir Sekhon said:for(i = 0xFFFF; i > 0; i--); // Delay
Also, don't deselect CS before the last byte has been received. The slave might immediately stop sending and you'll get only half of the last byte. If TXBUF is empty, this does NOT mean that the transmission is complete. It rather means that the last byte has started being sent. Only after RXIFG has been flagged, you can be almost sure that the transmission is complete (at least the reception of the byte). To be entirely sure that even the sending is complete and the slave has got the last bit, check the UCBUSY bit. It is set until the last bit has been really sent and the SPI hardware is in idle state.
use TXIFG only if you want to know whether the next byte may be put into TXBUF, and nonly if you either read teh RX byte from the last transfer (so rather wait for RXIFG) or don't care for the incoming byte(s). If an ISR kicks in after you put something into TXBUF but before you read RXBUF, you might lose the received byte. TXIFG is always one byte ahead of RXIFG.
Thanks for the great advice Jens-Michael Gross.
Below is the code that i m using now, i made two fucntions one for reading data and other for writting to the SPI slave.
#include "msp430x22x4.h"
#define spi_on P3OUT &= ~0x40; // Select the slave device
#define spi_off P3OUT |= 0x40; // Release the slave device
#define wait_tx while (!(IFG2 & UCA0TXIFG)); // TXBUF ready?
#define wait_rx while (!(IFG2 & UCA0RXIFG)); // RXBUF ready?
#define wait_tm while (!(UCA0STAT & UCBUSY)); // Transmission Done?
#define delay_1 __delay_cycles(20); // required delay is minimum 10ns
#define delay_2 __delay_cycles(50); // required delay is minimum 250ns
int i,k;
char read_byte(char byte)
{
IFG2 &= ~UCA0RXIFG;
UCA0TXBUF = byte; // Adress to be read
wait_tm; // TXBUF ready?
UCA0TXBUF = 0xff; // Dummy write
wait_tm;
return UCA0RXBUF;
}
void write_byte(char addr,char data)
{
IFG2 &= ~UCA0RXIFG;
UCA0TXBUF = addr; // Read Dev ID
wait_tx; // TXBUF ready?
UCA0TXBUF = data; // write
wait_rx;
}
char devid,dataform;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_8MHZ; // Set DCO to 8MHz
DCOCTL = CALDCO_8MHZ;
BCSCTL2 |=0x52; // Set MCLK to 4 MHz and SMCLK to 4Mhz
P3SEL |= 0x31; // P3.0,P3.4,P3.5 USCI_A0 option select
P3DIR |= 0x40; // P3.6 output direction
P4DIR |= BIT3; // Power Set P4.3 to be output
P4OUT &= ~BIT3;
P1DIR |= BIT7; //LED Set P1.7 to be output
P1OUT &= ~BIT7;
P4OUT |= BIT3;
// SPI Definations
UCA0CTL1 = UCSWRST; // **Put state machine in reset**
UCA0CTL0 |= UCCKPL + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
UCA0CTL0 &= ~UC7BIT;
UCA0CTL1 |= UCSSEL_2; // Select SMCLK as CLK
UCA0BR0 |= 0x02;
UCA0BR1 = 0;
UCA0MCTL = 0;
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
// Read the ID//
spi_on;
delay_1;
devid = read_byte(0x80);
delay_1;
spi_off;
delay_2;
spi_on;
delay_1;
write_byte(0x31,0x0b);
delay_1;
spi_off;
delay_2;
spi_on;
delay_1;
dataform = read_byte(0xB1); // reading address 0x31
delay_1;
spi_off;
delay_2;
}
After running this code, devid which is E5 gets copied to the other variable called dataform, or the values get switched .
Can you please look into it and advice .
Thanks.
Satbir Sekhon said:#define wait_tx while (!(IFG2 & UCA0TXIFG)); // TXBUF ready?
keep in mind that when this function returns, the second byte is still sending (you just waited for TXBUF to be emptied into the shift register, but not for the shift register emptied).Satbir Sekhon said:void write_byte(char addr,char data)
Satbir Sekhon said:#define delay_1 __delay_cycles(20); // required delay is minimum 10ns
#define delay_2 __delay_cycles(50); // required delay is minimum 250ns
I tried your suggested method, but still no luck.
I checked the UCBUSY bit as #define wait_tm() while (UCBUSY==0) // Transmission Done?, while debugging i didnt see this bit changing, may be it changes so fast that i am unable to see it. I was trying to use the following read function:
char read_byte(char byte)
{
IFG2 &= ~UCA0RXIFG;
UCA0TXBUF = byte; // Adress to be read
wait_tx(); // TXBUF ready?
UCA0TXBUF = 0xff; // Dummy write
wait_tm();
return UCA0RXBUF;
}
by calling it as;
spi_on;
devid = read_byte(0x80);
spi_off;
It only works if i reset the target board using IAR.
It will be very helpful if you can provide me a good example of spi read, write and wait functions.
Your read_byte funciton is still faulty.
What you want is to send a command to the slave, then get its response, right?
But what do you do?
You clear RXIFG, fine. You could as well make a dummy read from RXBUF, but either way you're discarding anything in the RC buffer.
BUT now you're assuming that nothing else is still in the receiving process. It's quite possible that there's still a byte in transfer and you'd end up with a superfluous byte.
If this is the only function ever used, this is no problem, as you wait at the end for all transfers finished. And after all, you are the master. But it might decrease maximum throughput if you want to send or receive larger portions of data in a row. Anyway, just let's make this thing work and let the rest for later :)
Now you're putting teh command byte into TXBUF. Since the SPI is (assumedly) idle, this byte is moved into the shift register immediately and TXIFG is set immediately again.
wait_tx() does not wait asn TXIFG is already set again.
Now you put a dummy byte into TXBUF to request your response byte.
At this point, the (dummy) response to the command byte hasn't been received as the command byte is still being sent. Normally, this wouldn't be a problem.
Then you wait for the SPI being idle.
If the SPI is idle, this means, that the command byte has been sent (and the dummy byte was received), then the dummy byte was sent and the response byte received. You received two bytes, yet you didn't read the first causing a buffer overflow. If you ignore it (at least bad style to write code that causes errors by default), things would be still fine, IF your wait_tm would do what it is intended to.
Unfortunately it doesn't:
What happens is that while the command byte still hasn't been sent, you wait as long as UCBUSY==0. Unfortunately, UCBUSY is a bit value constant and always !=0. So you don't wait at all.Satbir Sekhon said:#define wait_tm() while (UCBUSY==0)
The correct definition of the wait_TM macro would be:
#define wait_tm() while(UCA0STAT&UCBUSY)
And note that when the SPI is BUSY, the bit is SET. Other than the IFG flags, the UCBUSY bit is cleared when the SPI is done. (else it would be an UCIDLE bit :) )
Thanks for being patient here.
Yes, you are right, I am sending the command which is the address to be read and the bit which tells that it is a read operation.
Now I think my read function is working good, as it is giving me expected results every time. It is as shown below;
#define wait_tx while (!(IFG2 & UCA0TXIFG)); // TXBUF ready?
#define wait_rx while (!(IFG2 & UCA0RXIFG)); // RXBUF ready?
#define wait_tm while ((UCA0STAT & UCBUSY)); // Transmission Done?
char read_byte(char byte)
{
IFG2 &= ~UCA0RXIFG;
UCA0TXBUF = byte; // Address to be read
wait_tm; // TXBUF ready?
UCA0TXBUF = 0xff; // Dummy write
wait_tm;
return UCA0RXBUF;
}
and it is called as;
spi_on;
devid = read_byte(0x80);
spi_off;
Now I am having trouble with the write function, I want to write to a register in the ADXL345
current write function is.....
void write_byte(char addr,char data)
{
UCA0TXBUF = addr; // Address to be written to
wait_tx; // TXBUF ready?
UCA0TXBUF = data; // write the data
wait_tm;
}
Sometimes it works and sometime it wont. But reset always helps, or changing the data byte makes it work too.
It be great if you can advice on this or if there is anything wrong in the read function.
Also if you don't mind can you write the functions too?
You could use wait_tx here. if you do wait_tm, you'll wait until the SPi is busy, then you'll put the next byte in. This introduces a small delay between the writes. Just the few MCLK cycles for doing the test (comapre, branch) and loading the next data byte. As the second byte is just -1, and UCBUSY bit is 1 these are only few MCLK cycles (values from constant generator) which is unimportant for slower SPI clocks. If you use an SPI clock near to MCLK, this unnecessary delay is in the range of a whole byte transmission, slowing you down by 33%. This is why TXBUF and the shift register are double buffered.Satbir Sekhon said:UCA0TXBUF = byte; // Address to be read
wait_tm; // TXBUF ready?
UCA0TXBUF = 0xff; // Dummy write
About the write function, it looks okay. it should work. You do not check whether the SPI is busy, but since you do so at the end of your two functions, it will be idle for sure.
So either your other code (in main) has a problem or something in the slave specs slipped your attention. Maybe it requires a delay between address and data greater than the plain transmission time? Or it needs a delay after one write before you can access it again? Maybe you may not do spi_off for some time after writing or you have to between two writes?
The SD card specification (in SPI mode) requires the master to send some dummy bytes after deselecting the card (!) for some operations. I don't have your slave's datasheet, so I cannot check.
Here is the link to the datasheet http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf .
I am going crazy over here man, this thing works some time and then it wont work. Can you please check the datasheet as you have more experience you will certainly find something that I missed.
I appreciate all your help.
Thanks Again.
Hello everyone,
Sorry for my poor english.
I am trying to communicate a MSP430 with an AD7792 using SPI. I to begin only it wants to read Device ID of the AD7792.
For first it it is necessary to write in the AD and wait for a register of response.
Do you have some routines of communication with this type of AD?. It is to say of the type question / response.
Thank you
The code that i used for my ADXL345 for SPI is in this thread.
MSP430 MCU,s have built in ADC's, may be you don't need an external ADC.
Any ways first you will need to find out, which SPI mode is supported by your device. The common one is 4 wire mode, in this mode 4 pins are used for communication.
CS usually active low
SIMO Slave in master out
SOMI Slave out master in
SCLK Clock
SPI is a bidirectional protocol so when you send a byte at the same time you receive a byte.
This is the code I used to read the device id of ADXL345
#define spi_on P3OUT &= ~0x40; // Select the slave device
#define spi_off P3OUT |= 0x40; // Release the slave device
#define wait_tx while (!(IFG2 & UCA0TXIFG)); // TXBUF ready?
#define wait_rx while (!(IFG2 & UCA0RXIFG)); // RXBUF ready?
#define wait_tm while ((UCA0STAT & UCBUSY)); // Transmission Done?
char read_byte(char byte)
{
IFG2 &= ~UCA0RXIFG;
UCA0TXBUF = byte; // Address to be read
wait_tm; // TXBUF ready?
UCA0TXBUF = 0xff; // Dummy write
wait_tm;
return UCA0RXBUF;
}
and it is called as;
spi_on;
devid = read_byte(0x80);
spi_off;
Hope it helps.
Thank you for your response it is very nice.
Please read the datasheet in http://www.analog.com/static/imported-files/data_sheets/AD7792_7793.pdf
I probe the following code:
#include "msp430x21x2.h"
//#include "math.h"
#define spi_on P3OUT &= ~0x40; // Select the slave device
#define spi_off P3OUT |= 0x40; // Release the slave device
#define wait_tx while (!(IFG2 & UCA0TXIFG)); // TXBUF ready?
#define wait_rx while (!(IFG2 & UCA0RXIFG)); // RXBUF ready?
#define wait_tm while ((UCA0STAT & UCBUSY)); // Transmission Done?
char read_byte(char byte)
{
IFG2 &= ~UCA0RXIFG;
UCA0TXBUF = byte; // Address to be read
wait_tm; // TXBUF ready?
UCA0TXBUF = 0xFF; // Dummy write
wait_tm;
return UCA0RXBUF;
}
unsigned char devid;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
//Definimos la salida P1.0 como salida para utilizar el led de la maquina
P1DIR |= 0x01; //
P1OUT = 0x00;
P3DIR |= 0x40; //P3.6 Como salida para manejar la habilitacion del AD
P3OUT = 0x40; // Set slave reset
//Configuramos el puerto 3 para utilizar las siguientes salidas
//P3.0 SCLK -> Serial Clock Out (Salida)
//P3.4 UCAOTXD -> Master Out (Salida)
//P3.5 UCAORXD -> Master In (Entrada)
P3SEL |= 0x31; // P3.0,4,5 USCI_A0 option select
UCA0CTL0 |= UCCKPL + UCCKPH + + UCMSB + UCMST + UCSYNC;
//Definimos el segundo registro de control: Fuente de Reloj SMCLK
UCA0CTL1 |= UCSSEL_2; // SMCLK
//Pre-escalamos el Clk a SMCLK/2 = 1.2Mhz/2
UCA0BR0 = 0x02; // /2
UCA0BR1 = 0; //
UCA0MCTL = 0; // No modulation
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
spi_on;
devid = read_byte(0x60);
spi_off;
while(1);
}
The value of go that it should obtain is 4A but I obtain 00.
Trying with another code similar to this one I obtained 4B. It is to say that I am having communication between the AD7792 and the MS430F2132.
I cannot achieve an efficient communication and neither write a record in the AD
Who is the ideal freucencia to use in SCLK?
Is it necessary in my case the "dummy write" in the function read_byte?
I have a evaluation board http://www.analog.com/static/imported-files/eval_boards/EVAL-AD7792.pdf.
Thanks a lot.
Thanks a lot Michael, for directing me in right direction.
Today I accidentally discovered that whenever I connect the ground of ADXL345 to the ground of MSP430 target board it introduces some sort of noise which messes up the SPI.
I am using the the GPIO pin as the supply for the Adxl345. Vcc connected to GPIO and a floating ground always gives me correct result.
May be I need to use separate supply for adxl345......
Any comments?
The output voltage of the IO pins depends on the current. If the current consumption changes, the voltage changes.
I wonder how it is workign at all with floating ground. Without ground, there is no 'supply voltage' at all. But since it works, there is, so there must be a groudn connection of some sort.
It might be, however, that doing a direct goround connection introduces a ground loop, which might catch potential differences and result in different kinds of noise. Well-known as the humming 100/120Hz in ill-connected sound systems.
Diego diac said:The value of go that it should obtain is 4A but I obtain 00.
From the datasheet:
Following a reset, the user should allow a period of 500 μs before addressing the serial interface.
I doubt that a sufficient time has passed after power-on with your code above. The code almost instantly (below 100 MCLK cycles) tries to access the AD7792. This might be waaay too fast.
Also, the AD7792 abuses the SOMI line in a very unusualy way for an SPI.
Normally, if the slave is busy, it will just send out 0xff until it is ready. The first non-0xff byte is either the first dat abyte, or a token indicating that the operation was successful and data bytes follow, or indicating an error.
The AD7792, however, abuses the SOMI line as a status signal line. It will alter its level without any clock when the dat ais ready. To detect this, you'll need to read the port pin with the SOMI line manually (by software) after you sent the data read command. THis requires either busy-waiting on this line, or connecting it with an interrupt-capable port pin, so you'll get an interrupt when the line goes low. Both is ugly, and is not conforming with the SPI specification.
So, this all makes sense, but how does the MSP430F2274 differentiate between the CC2500 and any other device on the SPI bus?
I am using the EZ430 RF2500 kit and as far as I understand, the MSP430F2274 board has the following SPI setup:
Pin 3.0 - Chip Select. mapped to GPIO Pin 17
Pin 3.3 - Clock. mapped to GPIO Pin 16
Pin 3.2 - SOMI. mapped to GPIO Pin 15
Pin 3.1 - SIMO . mapped to GPIO Pin 18
So supposing the F2274 is always the master, in order to communicate with, say, a random custom external MCU that supports SPI via GPIO pins, the F2274 would raise the ChipSelect for the CC2500, which is internally memory-mapped, and lower the ChipSelect for the custom MCU on the GPIO pin...?
As I write this, it seems apparent that the CC2500 CS wire is mapped to Pin3.0/GPIO17 and any other SPI slaves would have to have a free GPIO pin designated as its CS. But the other slaves would still use GPIO Pins 15,16 and 18 for SPI? Is this correct?
>>P3OUT &= ~0x40; // Chip select active low
GPIO Pin 3 - Chip Select,
shouldn't this be enabling the CC2500? If not, then it is enabling accelerometer. Then, where did the CC2500 get disabled?
CS pin on F2274 is not preconfigured, user can configure any GPIO pin as CS.
Secondly yes any number of SPI device can share the same Clock,SOMI and SIMO line, and they will have different CS pins.
So supposing the F2274 is always the master, in order to communicate with, say, a random custom external MCU that supports SPI via GPIO pins, the F2274 would raise the ChipSelect for the CC2500, which is internally memory-mapped, and lower the ChipSelect for the custom MCU on the GPIO pin...?
Yes thats is how it will be done. But make sure when you intialize the SPI all the slave devices are deslected, and then you can select the device you want to communicate with.
>>P3OUT &= ~0x40; // Chip select active low
GPIO Pin 3 - Chip Select,
shouldn't this be enabling the CC2500? If not, then it is enabling accelerometer. Then, where did the CC2500 get disabled?
This will enable any device which is connected to that CS pin.
Hope that helps.
You alread figured out most of the answer.Andrew Thornton said:how does the MSP430F2274 differentiate between the CC2500 and any other device on the SPI bus
SPI uses a bus (SOMI, SIMO,CLK) for the plain data trannsfer. Since it is a synchroneous bidirectional transmission, only one slave my respond at one time (unless it is a 'silent' slave). Also, there is no bus arbitration or slave selection mechanism.
So SPI uses another signal, CS, to tell the slave to
Depending on the slave, the CS signal may also reset the communicarion protocol completely .
If the MSP is the SPi master, the CS signal can come from any GPIO pin. There can be almost any number (limited by wire length and the strength of the output drivers and the desired clock frequency) of slaves connected to SOMI, SIMO and CLK. But each of them needs its own CS signal.
If the MSP is acting as SPI slave, then P3.0, STE, can be used (4-wire slave mode). It does not exactly do what CS does. But it will enable/disable the otuput driver (most important, so the bus is immediately free for the next transfer, even if your MCU is currently busy) and the clock input. It will not, however, reset the shift register to a byte border (you'll need to set SWRST to do so) and of course it will not reset any protocol in transmission. You have to connect the incoming CS signal to an (interrupt-capable) port pin too, so you can react.
It allows, however, just suspending a transfer, even in the middle of a byte, and resume it later.
SPI does not enable/disable devices by itself. It just enables/disables the bus transfer. I don't know whether the CC2500 is enabled/disabled by a signal at all. I guess it is rather activated/deactivated by SPI commands. It is, however, possible that it will signal the availability of new data by a GPIO signal, so the SPi master knows that it has to poll new data. I don't know the CC2500 at all, so I cannot help with details here.Andrew Thornton said:Then, where did the CC2500 get disabled
Hi Satbir,
How did you connect the pins between MCU and ADXL345 in your circuit please? Here you explained 4 pin SPI, but in your code you set 3 pin SPI master mode, you also selected the second function of pin3.0, 3.4, 3.5. I am a little confused about this, could you help me to make this clear please?
Thanks with regards
Hello Lijun,
I am setting 3 PIN SPI master mode, that is correct. The forth PIN of ADXL345 CS(Chip Select) or SS(Slave Select) can be connected to any GPIO of MSP430, when configured in output mode. The CS pin is active low,so when ADXL345 is not in use the CS pin should be driven HIGH. And before sending any commands to ADXL345, you will need to drive the CS pin low.
Hopefully it will clear up some of your doubts.
Satbir
Hi Satbir,
Thanks for quick reply! it makes sense now.
Actually, I used msp430f2132 to read adxl346 via I2C bus before, but I cannot get acknowledge from adxl346. So now I want to try SPI bus, but I am still not lucky.
However, I can observe the UCB0RXIFG is set after write the address to UCB0TXBUF, but the data in UCB0RXBUF is 0x00, not 0xe6. Here is my code, could you give me more advice please? Thanks!
int main(void)
{
char data;
//*******************************Timer setup**********************************
WDTCTL = WDTPW + WDTHOLD; // Stop Watchdog Timer
P3DIR |= BIT0; // P3.0 output direction, /CS
P3OUT |= BIT0;
P3SEL |= 0x0e; // pin 3.1,3.2, 3.3 to USCI_B0
// SPI Definations
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 |= UCCKPL + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
UCB0CTL1 = UCSSEL_2; // Use SMCLK, keep SW reset
UCB0BR0 = 0x02; // fSCL = SMCLK/2
UCB0BR1 = 0;
// UCB0MCTL = 0;
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
// Read the ID//
P3OUT &= ~BIT0; // Enable ADXL346, /CS reset
UCB0TXBUF = 0x80; // Write address 0x00
while (!(IFG2 & UCB0RXIFG)); // USCI_B0 RX buffer ready?
data = UCB0RXBUF; // data
P3OUT |= BIT0; // Disable ADXL346, /CS set
}
Here is the waveform of SCLK, I don't know why there are only 7 cycles and the last one is much narrower than others, tm=50us while ts=500us. Moreover, the fsclk is much slower than SMCLK/2, how does this situation happen? When I tested I2C bus, the fsclk is also very slow. It seems that the USCI always makes the cycles much slower than expected SMCLK/2. Could anyone help me to check the waveform is correct or not? Thanks!
Lijun,
The waveform does not look like it is of SMCLK. I would expect SMCLK to look like a (near)perfect square wave.
Satbir
Hi Satbir,
Thanks for reply!
I am very confuse about the waveform, because I select the DCOCLK as the source MCLK and SMCLK, and set the DCO to 8MHz or 16MHz, but the waveforms of of USCI_B are always the same, i.e. the output of MSP430F2132 Pin3.3. The code are shown following:
BCSCTL1 = CALBC1_8MHZ;
DCOCTL = CALDCO_8MHZ;
BCSCTL2 |=0x52;
OR
BCSCTL1 =RSEL3 + RSEL2 + RSEL1+ RSEL0;
DCOCTL =DCO2 + DCO1 + DCO0;
BCSCTL2 |=0x52;
Could you capture a waveform of your USCI SCLK, SDI and SDO please if it is convenient for you.
Thanks with kind regards!
Lijun,
I did not have the ADXL345 setup, so I just ran the my code without anything connected to the MSP430F2274 and captured wave forms from SDO and SCLK Pins.
The first waveform is of the data being sent to the SPI. I sent 0xAA(10101010)
The following waveform is of the SCLK (SPI Clock). SPI was being clocked by SMCLK at 4 MHz, I verified the frequency of SCLK and it was in fact 4MHz.
Also in your read the ID part, you need to send a Dummy Byte to receive the Device ID. So it should be:
// Read the ID//
P3OUT &= ~BIT0; // Enable ADXL346, /CS reset
while ((UCA0STAT & UCBUSY)); // Wait if Busy
UCB0TXBUF = 0x80; // Write address 0x00
while ((UCA0STAT & UCBUSY)); // Wait if Busy
UCB0TXBUF = 0xFF // Write Dummy byte 0xFF
while (!(IFG2 & UCB0RXIFG)); // USCI_B0 RX buffer ready?
data = UCB0RXBUF; // data
P3OUT |= BIT0; // Disable ADXL346, /CS set
Hope this helps.
Satbir
Hi Satbir,
Thanks a lot.
Considering the 3-wire SPI or 4-wire SPI, your explanation before is a little different from the datasheet of ADXL345, see the snapshot
How to distinguish 3-wire or 4-wire? If /CS pin is controlled by any other GPIO, should the 3-wire SPI diagram above be called '2-wire SPI'? In figure 35, 4 wires are connect to MSP430 here, it is still recognized as 3-wire SPI by MSP430, so we have set 3 PIN SPI in the code. Am I right? Because I have to build a new design to test, so I should better make it clear, and I am sorry to trouble you on this issue.
How did you power the ADXL345 please? Single-power supply or dual-power supply? Seperated external power supply or powered by MSP430? And what about the supply voltage, 2.5V or 3.3V please? Forgive me so many questions, I have spent lots time on the communication between MSP430F2132 and ADXL346, but I still cannot read the ID. I don't know what the problem is, so I plan to build a new board which just has MSP430F2132, ADXL345 and ADXL346 to test.
Thanks for your pictures again, and I'll test my board again on Monday, as I cannot access to our lab at weekend.
Kind regards,
Lijun
Liljun,
Don't get confused with the naming conventions. Check the following link:
http://www.atomicrhubarb.com/filebrowser/download/1451
3 Wire or 4 Wire are two modes available on MSP430. On MSP430 3 wire mode uses SDO,SDI and SCLK signals, hence 3 wire, but in reality you will need an other wire for the chip select line (GPIO Pin can be used). So even in 3 pin mode you be using 4 wires.
You should be using the mode shown in Figure 35.
I powered it with a separate single 3.3V power supply and i used a breakout board from Sparkfun for the ADXL345. Just make sure that you have the correct clock and data polarity settings on MSP430.
When you try to read the ID, do you get any data at all?
Satbir
Hi Satbir,
Thanks for your further explanation! Now I am clear.
When I tried to read the ID, I can only get 0x00.
And today I got the following waveform occasionally, it seems better, but just once. And I tried to redo it again, but I can only get the wave as before. I don't know how it happened and why it disappeared?
It seems there are much noise, is it introduced by these wires jumped? For this PCB, it is power by the debugger, 2.6V.
So I plan to rebuild a new prototype and buy a breakout board as well, so I don't need to consider the soldering issue. Thanks!
Kind regards,
Lijun
Hey Lijun,
Were you able to fix the problem?
In this thread i have posted some basic code for ADXL345 with MSP430F2274, that i wrote about 2 years ago.
See if it could of any help to you.
Satbir
Hi Satbir,
Thanks a lot! I am testing a new board just with MSP430F2132 on it and an ADXL345 breakout board. With your help I can successfully read the ID 0xE5 each time, it gives me much more encouragement, and thanks you again.
And also a little confuse about the write function which you wrote 2 years ago, http://e2e.ti.com/support/microcontrollers/msp43016-bit_ultra-low_power_mcus/f/166/p/221110/782579.aspx#782579. How did you check it was correctly written please? Such as
// write to the data format//
spi_on;
write_byte(0x31,0x07);
spi_off;
delay_2;
// make sure write worked//
spi_on;
dataform = read_byte(0xb1);
spi_off;
delay_2;
You wrote data 0x07 to address 0x31, but when you check it you read the address 0xb1. why did you read 0xb1, not 0x31? Where is the address 0xb1? Did I miss some information on the datasheet?
Also if it is successfully written in above example, what the correct value of dataform should be please? Is it 0x07 which you just wrote in?
Sorry about so much questions.
Kind regards,
Lijun
That's good that you are able to read the device ID correctly!!
You did miss some information from the data sheet:
ADXL345 uses a 6 Bit register address(Bit5-Bit0). The Bit7 and Bit6 are there as command inputs.
When the Bit7 is set it tells ADXL345 that the address is being read, and when it is not set it is being written to.
So to read from address 0x31, you need to actually send 0xB1.
If correctly written then the value read should be equal to value written.
Hope this clears some doubts.
Satbir
Hi Satbir,
Thanks a lot! It makes sense.
Today when I woke up, I suddenly realized why you wrote 0xB1, not 0x31, Just like your explanation above, that's also why write 0x80 to read ID, not 0x00. I don't know what I was thinking yesterday, sorry about that.
It seems there is some trouble to write, as the value read is not the value written, It seems only the lower 4 bits is correct. I'll try to find the reason, if i cannot fix it then I seek your help.
Best Regards,
Lijunj
Hi Satbir,
Really thank you very much!
Now I can correctly read and write ADXL345, I cannot get this without your patient and long-time help.
I could not write correctly days ago, and it was caused by a poor wire connection.
Thanks again!
Regards,
Lijun
I am glad that you got it working.
I was in the same boat when I was doing my project and this Community helped me out.
Cheers,
Satbir
Hi! I am trying to connect the MSP430F5438A wit the ADXL345. I started to build the SPI communication and I want to connect the devices together.
My goal is to put the Accelerator in some operations by sending commands and then I want to receive
informations about the position of the axes of x, y and z. First I started building the communication with all sending commands I want to (also with a interrupt handler, but I had compiling problems.
Now I reduced the code (commanded all the rest) and I just want to test the communiacation in a simpler way with one sending information and one receiving information.
Still I cannot compile the code without errors. Can somebody give some advices?
Thanks.
#include "msp430x54x.h" // einfügen der Mikroprozessordaten
#include "EHAL\hal_board.h"
void main (void) // Hauptprogramm starten
{
halBoardInit();
halBoardStartXT1();
halBoardSetSystemClock(SYSCLK_1MHZ);
halBoardOutputSystemClock();
// init_uart();
while (1)
{
WDTCTL=WDTPW+WDTHOLD; // ausschalten des Watchdogs
P10SEL=0x0F; // PSEL, SPI Konfiguration auswählen, 0b00001111
UCB0CTL1|=UCSWRST; // **Put state machine in reset** !!!
P10DIR=0x0B ; // SCLK ist 1 auf P10.3 ; MOSI ist 1 auf P10.1 ; SOMI ist 0 auf P10.2, CS(low active) auf 1 am P10.0, 0b00001011
// P10REN= 0b00000100;// CS quer dauerhaft auf low gesetzt, um die Kommunikation zu bewerkstelligen, keine gute Idee
UCB3CTL0|=UCSYNC | UCMODE1 | UCMST | UCMSB; // synchroner Modus, 4 pin SPI einstellen , Master Modus eingestellt, MSB zuerst
UCB3CTL0|=UCSSEL_2;// Zeitgeber auswählen, SMCLK
// UCB3BR0 = 0x02; // Zeitgeber einstellen, UCA3BR0 und UCA3BR1, (UCAxBR0 + UCAxBR1 × 256)
// UCB3BR1 = 0; // später ncoh einmal die Berechnung bedenken und mit den Angaben im Datenblatt vergleichen
__bis_SR_register(GIE);// globales Interrupt zulassen
// ?Polarität und Phase der seriellen clock definieren? nur Zusatz
UCB3CTL1&=~UCSWRST; // Initialisierung der State machine
UCB3IE|=UCRXIE;// Interrupt zulassen
spi_senden(0x31,0x4E);
unsigned char spi_empfang(unsigned char receive_byte);
return;
}
} // beenden des Hauptprogrammes
void spi_senden(unsigned char addr,unsigned char data) //
{
P10OUT&=~BIT0; // CSquer auf low setzen, um die Übertragung anzufangen, nicht P10REN benutzen!
while(!(IFG3&UCB3TXIFG)); // nicht UCB3IFG benutzen, sondern IFG3
// eventuell das Flag löschen
UCB3TXBUF=addr; // Addresse, 0x31;
delay(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz
while(!(IFG3&UCA3TXIFG)); // nicht UCB3IFG benutzen, sondern IFG3
UCB3TXBUF=data; // SELF_TEST | SPI | INT_INVERT | 0 | FULL_RES | Justify | Range data sozusagen, Manipulierung, 0b01001110, 0x4E;
delay(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz
P10OUT|=BIT0; // CSquer auf high setzen, um die Übertragung zu beenden}
};
unsigned char spi_empfang(unsigned char receive_byte) // für x Empfangsmetode erstellen, UCA3RXBUF-Inhalt soll empfangenen Daten gefüllt werden
{
P10OUT&=~BIT0; // CSquer auf low setzen, um die Übertragung anzufangen
// Register 0x32- DATAX0 least significant byte X-axes
while(!(IFG3&UCA3RXIFG)); // nicht UCB3IFG benutzen, sondern IFG3
receive_byte=UCB3RXBUF; // Addresse
delay(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz
IFG3=~UCB3IFG; // Flag löschen
P10OUT|=BIT0; // CSquer auf high setzen, um die Übertragung zu beenden}
};
Yes, you could post the exact compiler error messages (and mark their line numbers in the code you posted)Roko Sobar said:Still I cannot compile the code without errors. Can somebody give some advices?
Hi!
The Code is compiled now, but the content of the RXBUF is always 0x00. My goal is to receive the information of the x-, y- and z-axes in
a stream mode. Is mybe the configuration of the sensor wrong?
// Basiskommentare f�r die SPI Kommunikation // #define delay_2 __delay_cycles(10); // eine andere M�glichkeit ein Delay zu definieren #include "msp430F5438A.h" // einf�gen der Mikroprozessordaten #include "stdint.h" //Variablen char addr; char data; char receive_byte; char receive_data; //Funktionen void spi_senden(); uint8_t spi_empfang(); uint8_t leseschreib(); //Testmethode f�r den ID-Empfang uint8_t koordinatenleseschreib(); //Einstellunmgen ADXL345 void spi_senden_DATA_FORMAT(); void spi_senden_BW_RATE(); void spi_senden_FIFO_CTL(); void spi_senden_POWER_CTL(); // in diesem Register das Measure Bit setzen um eine Messung zu starten //void spi_senden_FIFO_STATUS(); void spi_beenden_POWER_CTL(); // Messung wieder beenden und in den Standby-Modus wieder zur�ckkehren //Koordinatenachsen x,y,z uint8_t DATAX0leseschreib(); uint8_t DATAX1leseschreib(); uint8_t DATAY0leseschreib(); uint8_t DATAY1leseschreib(); uint8_t DATAZ0leseschreib(); uint8_t DATAZ1leseschreib(); void main (void) // Hauptprogramm starten { WDTCTL=WDTPW+WDTHOLD; // ausschalten des Watchdogs P10SEL|= BIT1 + BIT2 + BIT3; //P10SEL|=0x0F; // PSEL, SPI Konfiguration ausw�hlen, 0b00001111 UCB3CTL1|=UCSWRST; // **Put state machine in reset** !!! P10DIR|= BIT0; //P10DIR|=0x0D; // SCLK ist 1 auf P10.3 ; MOSI ist 1 auf P10.1 ; SOMI ist 0 auf P10.2, CS(low active) auf 1 am P10.0, 0b00001101 // P10REN= 0b00000100;// CS quer dauerhaft auf low gesetzt, um die Kommunikation zu bewerkstelligen, keine gute Idee UCB3CTL0|=UCSYNC | UCMST | UCMSB | UCCKPL; //| UCMODE0; // synchroner Modus, 4 pin SPI einstellen , Master Modus eingestellt, MSB zuerst UCB3CTL1|=UCSSEL_2; // Zeitgeber ausw�hlen, SMCLK UCB3BR0=0x02; //Zeitgeber einstellen, UCA3BR0 und UCA3BR1, (UCAxBR0 + UCAxBR1 ? 256) UCB3BR1=0; // spaeter ncoh einmal die Berechnung bedenken und mit den Angaben im Datenblatt vergleichen UCB3CTL1&=~UCSWRST; // Initialisierung der State machine UCB3IE|=UCRXIE + UCTXIE;// Interrupt zulassen while (1) { //leseschreib(); // als Test soll die ID gesendet werden //Einstellungen ADXL345 im Standby-Modus // spi_beenden_POWER_CTL(); // Measure Bit auf 0 setzen // leseschreib(); spi_senden_DATA_FORMAT(); spi_senden_BW_RATE(); spi_senden_FIFO_CTL(); spi_senden_POWER_CTL(); // hier die Messung starten //spi_senden_FIFO_STATUS(); // Koordinatenachsen x,y,z DATAX0leseschreib(); // LSb X-Achse DATAX1leseschreib(); // MSb X-Achse DATAY0leseschreib(); // LSb X-Achse DATAY1leseschreib(); // MSb X-Achse DATAZ0leseschreib(); // LSb Z-Achse DATAZ1leseschreib(); // MSb Z-Achse spi_beenden_POWER_CTL(); // hier die Messung wieder beenden und in den Standby-Modus setzen // Measure Bit auf 0 setzen // spi_senden(); } } // beenden des Hauptprogrammes // Register 0x31- DATA_FORMAT (DATA format control) void spi_senden_DATA_FORMAT() { // P10OUT&=~BIT0; // CSquer auf low setzen, um die �bertragung anzufangen, bei 4 wire while(!(UCB3IFG&UCTXIFG)); // nicht UCB3IFG benutzen, sondern IFG3, wieder zur�ck ge�ndert // eventuell das Flag l�schen UCB3TXBUF=0x31; // Addresse, 0x31; __delay_cycles(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz while(!(UCB3IFG&UCTXIFG)); // nicht UCB3IFG benutzen, sondern IFG3 UCB3TXBUF=0x4E; // SELF_TEST | SPI | INT_INVERT | 0 | FULL_RES | Justify | Range data sozusagen, Manipulierung, 0b01001110, 0x4E; __delay_cycles(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz }; //--------------------------------------------------------------------------------------------------- // Register 0x2C BW_RATE (Data rate and power mode control) void spi_senden_BW_RATE() { while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen UCB3TXBUF=0x2C; // Addresse __delay_cycles(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen, sondern IFG3 UCB3TXBUF = 0x0A; // 0 | 0 | 0 | LOW_POWER | Rate | Rate , Rate auf 100 Hz,data, Manipulierung, 0b00001010 __delay_cycles(10); // Wartezeit definieren, 10 Zyklen }; //---------------------------------------------------------------------------------------------------------- // Register 0x38- FIFO_CTL void spi_senden_FIFO_CTL() { while (!(UCB3IFG & UCTXIFG)); // UCB3IFG benutzen UCB3TXBUF = 0x38; // Addresse // __delay_cycles(10); // Wartezeit definieren while (!(UCB3IFG & UCTXIFG)); // nicht UCB3IFG benutzen, sondern IFG3 UCB3TXBUF = 0x80 ; // FIFO_MODE | FIFO_MODE | Trigger | Samples | Samples | Samples | Samples | Samples data sozusagen, Manipulierung, 0b10000000 __delay_cycles(10); // Wartezeit definieren, 10 Zyklen }; // Register 0x2D- POWER_CTL void spi_senden_POWER_CTL() { while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen UCB3TXBUF=0x2D; // Addresse __delay_cycles(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0x04 ; // 0 | 0 | Link | AUTO_SLEEP | Measure | Sleep | Wakeup data sozusagen, Manipulierung, 0b0000100 __delay_cycles(10); // Wartezeit definieren, 10 Zyklen }; // Messung beenden und wieder in den Standby-Modus zur�ckkehren void spi_beenden_POWER_CTL() { while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen UCB3TXBUF=0x2D; // Addresse __delay_cycles(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0x00; // 0 | 0 | Link | AUTO_SLEEP | Measure | Sleep | Wakeup data sozusagen, Manipulierung, 0b0000100 __delay_cycles(10); // Wartezeit definieren, 10 Zyklen }; // Register 0x39- FIFO_STATUS //void spi_senden_FIFO_STATUS() // // //{ while (!(UCB3IFG&UCTXIFG)); // nicht UCB3IFG benutzen // // // UCB3TXBUF=0x39; // Addresse // // __delay_cycles(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz // // while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen // // UCB3TXBUF=; // // // __delay_cycles(10); // Wartezeit definieren, 10 Zyklen //}; // //--------------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------- // Testmethode zum einlesen der ID //uint8_t leseschreib() // //{ // Beginn der Funktion // // P10OUT &= ~BIT0; // // while (!(UCB3IFG&UCTXIFG)); // // UCB3TXBUF = 0x00; // 0x41 // Test mit 0x80; // // // __delay_cycles(10); // // // while(!(UCB3IFG&UCRXIFG)); // // // return(UCB3RXBUF); // //}; //------------------------------------------------------------------------------- // Methode zum einlesen der Koordinatenwerte DATAX0 uint8_t DATAX0leseschreib() // Register 0x32- DATAX0 least significant byte X-axes { P10OUT &= ~BIT0; while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF = 0x32; // Register 0x32- DATAX0 least significant byte X-axes __delay_cycles(10); while(!(UCB3IFG&UCRXIFG)); __delay_cycles(10); UCB3IFG&=~UCRXIFG; return(UCB3RXBUF); }; //------------------------------------------------------------------------------- // Methode zum einlesen der Koordinatenwerte DATAX1 uint8_t DATAX1leseschreib() // Register 0x33- DATAX1 most significant byte X-axes { while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen UCB3TXBUF=0x33; // Addresse __delay_cycles(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz while (!(UCB3IFG&UCRXIFG)); // nicht UCB3IFG benutzen __delay_cycles(10); return(UCB3RXBUF); }; //--------------------------------------------------------------------------------------------------------- // Methode zum einlesen der Koordinatenwerte DATAY0 uint8_t DATAY0leseschreib() // Register 0x34- DATAY0 least significant byte Y-axes { while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0x34; // Addresse __delay_cycles(10); // Wartezeit definieren, 10 Zyklen, eventuell zu kurz while (!(UCB3IFG&UCRXIFG)); // nicht UCB3IFG benutzen, sondern IFG3 __delay_cycles(10); // Wartezeit definieren, 10 Zyklen return(UCB3RXBUF); }; //--------------------------------------------------------------------------------------------------------- // Methode zum einlesen der Koordinatenwerte DATAY1 uint8_t DATAY1leseschreib() // Register 0x35- DATAY1 moct significant byte Y-axes { while (!(UCB3IFG&UCTXIFG)); // nicht UCB3IFG benutzen UCB3TXBUF=0x35; // Addresse __delay_cycles(10); while (!(UCB3IFG&UCTXIFG)); // nicht UCB3IFG benutzen __delay_cycles(10); return(UCB3RXBUF); }; // --------------------------------------------------------------------------------------------------------- // Methode zum einlesen der Koordinatenwerte DATAZ0 // Register 0x36- DATAZ0 least significant byte Z-axes uint8_t DATAZ0leseschreib() { while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen UCB3TXBUF=0x36; // Addresse __delay_cycles(10); // Wartezeit definieren while (!(UCB3IFG&UCTXIFG)); // nicht UCB3IFG benutzen __delay_cycles(10); // Wartezeit definieren return(UCB3RXBUF); }; //--------------------------------------------------------------------------------------------------------- // Methode zum einlesen der Koordinatenwerte DATAZ1 // Register 0x37- DATAZ1 most significant byte Z-axes uint8_t DATAZ1leseschreib() { while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen UCB3TXBUF=0x37; __delay_cycles(10); while (!(UCB3IFG&UCTXIFG)); // UCB3IFG benutzen __delay_cycles(10); // Wartezeit definieren return(UCB3RXBUF); }; //--------------------------------------------------------------------------------------------------------- // IFG3=~UCB3IFG; // Flag l�schen // P10OUT |= BIT0; // CSquer auf high setzen, um die �bertragung zu beenden} //// 3 verschiedene Felder f�r die �bertragung definieren, Informationen f�r die x-,y-,z-Achsen //} // Beenden der Methode
Thanks and greetings.
I see many delays that aren't necessary. You check for TXIFG which is sufficient.
You only need delays at two points: after asserting CS (see the ADXL datasheet for minimum delay between CS_>0 and first clock pulse) and before de-asserting CS (again, see datasheet). And, before the delay at de-asserting CS, ensure that UCBUSY is clear, that means, everyhtign you stuffe dinto TXBUF has been sent.
Anothe rproblem: each time you sent a byte to the ADXL, you also received a byte. So when you really want to receive something, you already have in RXBUF what you received while sending the last command. Also, after sending a command, what you received is received whiel the slave hasn't seen your command. it is NOT the answer. The answer comes with the next (dummy) byte you send.
uint8_t DATAX0leseschreib()
{
P10OUT &= ~BIT0; // after setting CS to 0, you should insert a delay, depending on the slave specs.
while (!(UCB3IFG&UCTXIFG)); // this only means RXBUF is empty. But whatever you may have sent before might still be sending
// you should wait for UCBUSY=0
UCB3TXBUF = 0x32; // send 0x32
__delay_cycles(10); // superfluous
while(!(UCB3IFG&UCRXIFG)); // here you're waiting for what has been received while the byte before the 0x32 was sent.
// After you waited for UCBUSY=0 above, you need to clear RXIFG, then wait for thee byte received during
// sending 0x32, clear RXIFG, then send a dummy byte in order to reeive your result.
__delay_cycles(10); // superfluous
UCB3IFG&=~UCRXIFG; // superfluous, reading UCB3RXBUF in teh resturn statement will already clear the RXIFG bit
return(UCB3RXBUF); // what about CS? Shouldn't it be set to 1 after communication?
};
Thanks for the critic and the helping comments.
I reduced the code and I tried to improve it, but it is still not working correctly. No correct data in the Receive buffer.
Maybe Jens you can give me some support.
I tried to figure out the correct number for the delay cycles, but I must admit I do not know how to figure out the right constant for the function.
t delay is about 5 ns and tquiet also about 5 ns. Shold the function be then __delay_cycles(5); ?
Thanks and Greetings!
// SPI Communication #include "msp430F5438A.h" // einf�gen der Mikroprozessordaten #include "stdint.h" //Variables uint8_t addr; uint8_t data; uint8_t Test; uint8_t receive_byte; uint8_t receive_data; //Settings of the ADXL345 uint8_t testreadwrite(); //void spi_senden_CONFG(); //Coordinate axes x,y,z //uint8_t DATAX0readwrite(); // DATAX0 void main (void) // Starting main program { WDTCTL=WDTPW+WDTHOLD; // turn of the Watchdogs P10SEL|= BIT0 + BIT1 + BIT2 + BIT3; //P10SEL|=0x0F; // SCLK, BIT3, P10.3 ; MOSI ist 1 auf P10.1 ; SOMI ist 0 auf P10.2, CS(low active) auf 1 am P10.0, 0b00001101 // PSEL, SPI Konfiguration ausw�hlen, 0b00001111 P10DIR|=0x40; //P10DIR|=0x0D; //GPIO-Pin 10.6, defining the direction, output UCB3CTL1|=UCSWRST; // **Put state machine in reset** !!! UCB3CTL0|= UCSYNC | UCMST | UCMSB | UCCKPL | UCMODE1; // synchronous Mode,3 pin SPI, (4 pin SPI, old), Master Mode, MSB first UCB3CTL1|=UCSSEL_2; // SMCLK UCB3BR0|=0x02; // Rate, UCA3BR0 and UCA3BR1, (UCAxBR0 + UCAxBR1 ? 256) UCB3BR1=0; UCB3IE|=UCRXIE + UCTXIE; // Interrupts enable UCB3CTL1&=~UCSWRST; // Initialising of the State machine // spi_senden_CONFG(); while (1) { //spi_senden_CONFG(); testreadwrite(); //DATAX0readwrite(); // DATAX0 __delay_cycles(5); P10OUT|=BIT6; // putting CS to 1 to end transmission } } // end main program //// Testfunction for SPI, receiving ID of the ADXL345 uint8_t testreadwrite() // Testfunction { P10OUT &= ~BIT6; // CS putting to low to start transmission __delay_cycles(5); // inserting a delay while (!(UCA0STAT & UCBUSY)==0); // while (UCBUSY!=0)); UCB3TXBUF = 0x80; // sending UCB3IFG &=~UCTXIFG; // clearing the flag while (!(UCA0STAT & UCBUSY)==0); UCB3TXBUF=0xFF; // sending dummy byte UCB3IFG &=~UCTXIFG; return(UCB3RXBUF); // putting CS to 1 in the while loop outside of the function }; //Configuration //void spi_senden_CONFG() //{ // P10OUT &= ~BIT6; // CSquer to low setzen, starting configuration // // while (!(UCA0STAT & UCBUSY)==0); // waiting // // UCB3TXBUF=0x31; // Addresse, 0x31; // UCB3IFG &=~UCTXIFG; // while (!(UCA0STAT & UCBUSY)==0); // waiting // UCB3TXBUF=0x4E; //SELF_TEST | SPI | INT_INVERT | 0 | FULL_RES | Justify | Range data sozusagen, Manipulierung, 0b01001110, 0x4E; // UCB3IFG &=~UCTXIFG; // // while (!(UCA0STAT & UCBUSY)==0); // waiting // UCB3TXBUF=0x2C; // Addresse // UCB3IFG &=~UCTXIFG; // while (!(UCA0STAT & UCBUSY)==0); // finished? // UCB3TXBUF = 0x0A; // UCB3IFG &=~UCTXIFG; // // while (!(UCA0STAT & UCBUSY)==0); // waiting // UCB3TXBUF = 0x38; // Addresse // UCB3IFG &=~UCTXIFG; // while (!(UCA0STAT & UCBUSY)==0); // waiting // UCB3TXBUF = 0x80 ; // FIFO_MODE | FIFO_MODE | Trigger | Samples | Samples | Samples | Samples | Samples data sozusagen, Manipulierung, 0b10000000 // UCB3IFG &=~UCTXIFG; // // while (!(UCA0STAT & UCBUSY)==0); // waiting // UCB3TXBUF=0x2D; // Addresse // UCB3IFG &=~UCTXIFG; // while (!(UCA0STAT & UCBUSY)==0); // waiting // UCB3TXBUF=0x04 ; // 0 | 0 | Link | AUTO_SLEEP | Measure | Sleep | Wakeup data sozusagen, Manipulierung, 0b0000100 // UCB3IFG &=~UCTXIFG; // // // __delay_cycles(5); // // P10OUT|=BIT6; // //}; //uint8_t DATAX0readwrite() // DATAX0 //{ // P10OUT &= ~BIT6; // CS putting to low to start transmission // __delay_cycles(5); // inserting a delay // // while (!(UCA0STAT & UCBUSY)==0); // while (UCBUSY!=0)); // UCB3TXBUF = 0x32; // sending // UCB3IFG &=~UCTXIFG; // clearing the flag // while (!(UCA0STAT & UCBUSY)==0); // UCB3TXBUF=0xFF; // sending dummy byte // data= UCB3RXBUF // UCB3IFG &=~UCTXIFG; // // return(data); // // putting CS to 1 in the while loop outside of the function //};
I forgot to add the code to my comment. I tried to read the ID and I set a Breakpoint. Most of the times I ran the program it worked ok, but sometimes not.
Could the Delay be a problem? I Tried it with __delay_cycles(5). I have putted a configuration method in the code. Is the method ok like this?
Later (if the testread-function is ok I want to replace it by reading the value of the coordinates( at the bottom of the code there is a commented example for X0).
Could it work out like this? Advices?
Greetings
5ns is the cycle time of a 200MHz CPU. It is impossible to not have at least 120ns between CS going low and the first clock edge, even if you write 0x00 to TXBUF, using the constant generator (which still would take three MCLK cycles, which are 3*40ns @25MHz). So that isn't a problem.Roko Sobar said:t delay is about 5 ns and tquiet also about 5 ns. Shold the function be then __delay_cycles(5); ?
Some things about your code:
UCB3IE|=UCRXIE + UCTXIE; // Interrupts enable
UCB3CTL1&=~UCSWRST; // Initialising of the State machine
while UCSWRST is set, you can't set the IE bits. I guess this is intentionally, since SWRST sets UCTXIFG, and with UCTXIE set too but the stat emachine in reset, this would lead to an eternal itnerrupt loop.
But luckily your setting of these bits has noeffect, because you don#t have any ISR edfined to handle the interrupts. THis would crash your MSP if the bits were set.
UCB3TXBUF = 0x80; // sending
UCB3IFG &=~UCTXIFG; // clearing the flag
Clearing the flag is superfluous, as writing to TXBUF automatically clears it.
UCB3TXBUF=0xFF; // sending dummy byte
UCB3IFG &=~UCTXIFG;
return(UCB3RXBUF);
After writing to TXBUF, you'll have to wait until the dummy 0xff is sent before you can read the answer from RXBUF. You return what was received somewhen sooner.
Put another while loop before you return.
Also, you may replace the second while loop from waiting for UCBUSY to waiting for RXIFG. This speeds up the transfer a little bit.
Hi Jens!
/// SPI Communication #include "msp430F5438A.h" // microprozessor #include "stdint.h" //Variables uint8_t addr; uint8_t dataX0; uint8_t dataX1; uint8_t dataY0; uint8_t dataY1; uint8_t dataZ0; uint8_t dataZ1; uint8_t Test; uint8_t receive_byte; uint8_t receive_data; //Settings of the ADXL345 uint8_t testreadwrite(); void spi_senden_CONFG(); void main (void) // Starting main program { WDTCTL=WDTPW+WDTHOLD; // turn of the Watchdogs P10SEL|= BIT0 + BIT1 + BIT2 + BIT3; //P10SEL|=0x0F; // SCLK, BIT3, P10.3 ; MOSI ist 1 auf P10.1 ; SOMI ist 0 auf P10.2, CS(low active) auf 1 am P10.0, 0b00001101 // PSEL, SPI Konfiguration ausw�hlen, 0b00001111 P10DIR|=0x40; //P10DIR|=0x0D; //GPIO-Pin 10.6, defining the direction, output UCB3CTL1|=UCSWRST; // **Put state machine in reset** !!! UCB3CTL0|=UCSYNC | UCMST | UCMSB | UCCKPL | UCCKPH | UCMODE1; // synchronous Mode,3 pin SPI, (4 pin SPI, old), Master Mode, MSB first UCB3CTL1|=UCSSEL_2; // SMCLK UCB3BR0|=0x02; // Rate, UCA3BR0 and UCA3BR1, (UCAxBR0 + UCAxBR1 ? 256) UCB3BR1=0; UCB3CTL1&=~UCSWRST; // Initialising of the State machine while (1) { testreadwrite(); } uint8_t testreadwrite() // Testfunction { P10OUT&=~BIT6; // CS putting to low to start transmission __delay_cycles(1); // inserting a delay while (!(UCB3STAT&UCBUSY)==0); // while (UCBUSY!==0)); UCB3TXBUF=0x80; // sending while (!(UCB3STAT&UCBUSY)==0); // while( (UCB3IFG&UCRXIFG) == 0); // receive_data=UCB3RXBUF; //eingebaut UCB3TXBUF=0xFF; // sending dummy byte //while (!(UCB3IFG&UCRXIFG)); while (!(UCRXIFG)); receive_data=UCB3RXBUF; //erg�nzt __delay_cycles(1); P10OUT|=BIT6; return(receive_data); // putting CS to 1 in the while loop outside of the function };
Thanks for the comments and help! I changed parts of the code and now I am receiving 0xC7 instead of the right ID. Also in the first run I can just see 0x00 in the variable.
I removed the interrupt stuff. Thanks.
What is the differenz between UCB3CTL1|=UCSSEL_2;and UCB3CTL1|=UCSSEL_3; ? Both refer to the SMCLK.
Greetings!
Hi Jens!
Can you take a look on this Code.
/// SPI Communication #include "msp430F5438A.h" // einf�gen der Mikroprozessordaten #include "stdint.h" //Variables uint8_t addr; uint8_t dataX0; uint8_t dataX1; uint8_t dataY0; uint8_t dataY1; uint8_t dataZ0; uint8_t dataZ1; uint8_t Test; uint8_t receive_byte; uint8_t receive_data; uint8_t data; //uint8_t config = 0xFF & ~BIT6; //Settings of the ADXL345 uint8_t testreadwrite(); void spi_senden_CONFG(); //Coordinate axes x,y,z //uint8_t DATAX0readwrite(); // DATAX0 //uint8_t DATAX1readwrite(); // DATAX1 //uint8_t DATAY0readwrite(); // DATAY0 //uint8_t DATAY1readwrite(); // DATAY1 //uint8_t DATAZ0readwrite(); // DATAZ0 //uint8_t DATAZ1readwrite(); // DATAZ1 void main (void) // Starting main program { WDTCTL=WDTPW+WDTHOLD; // turn of the Watchdogs P10SEL|= BIT0 + BIT1 + BIT2 + BIT3; //P10SEL|=0x0F; // SCLK, BIT3, P10.3 ; MOSI ist 1 auf P10.1 ; SOMI ist 0 auf P10.2 // PSEL, SPI Konfiguration ausw�hlen, 0b00001111 P10DIR|=0x40; //P10DIR|=0x0D; //GPIO-Pin 10.6, defining the direction, output UCB3CTL1|=UCSWRST; // **Put state machine in reset** !!! UCB3CTL0|=UCSYNC | UCMST | UCMSB | UCCKPL | UCCKPH | UCMODE1; // synchronous Mode,3 pin SPI, (4 pin SPI, old), Master Mode, MSB first UCB3CTL1|=UCSSEL_2; // SMCLK UCB3BR0|=0x02; //0x02; // 10; // Rate, UCA3BR0 and UCA3BR1, (UCAxBR0 + UCAxBR1 ? 256) UCB3BR1=0; UCB3CTL1&=~UCSWRST; // Initialising of the State machine // spi_senden_CONFG(); while (1) { // spi_senden_CONFG(); testreadwrite(); // DATAX0readwrite(); // DATAX0 //DATAX1readwrite(); // DATAX1 //DATAY0readwrite(); // DATAY0 //DATAY1readwrite(); // DATAY1 //DATAZ0readwrite(); // DATAZ0 //DATAZ1readwrite(); // DATAZ1 // //Testarea // // in Standby Mode // UCB3TXBUF=0x31; // Addresse, 0x31; DATA_FORMAT, wake up from standby // UCB3IFG &=~UCTXIFG; // while (!(UCB3STAT & UCBUSY)==0); // waiting // UCB3TXBUF=0x4E; //SELF_TEST | SPI | INT_INVERT | 0 | FULL_RES | Justify | Range data sozusagen, Manipulierung, 0b01001110, 0x4E; // UCB3IFG &=~UCTXIFG; // // // Ending Meassurement // // while (!(UCB3STAT & UCBUSY)==0); // waiting // UCB3TXBUF=0x2D; // Addresse POWER_CTRL, switch to measurement // UCB3IFG &=~UCTXIFG; // while (!(UCB3STAT & UCBUSY)==0); // waiting // UCB3TXBUF=0x04 ; // 0 | 0 | Link | AUTO_SLEEP | Measure | Sleep | Wakeup data sozusagen, Manipulierung, 0b0000100 // UCB3IFG &=~UCTXIFG; // // // // // // // // // // // __delay_cycles(10); // P10OUT|=BIT6; // // putting CS to 1 to end transmission // // // } } // end main program //------------------------------------------------------------------------------------------------------------------------ uint8_t testreadwrite() // Testfunction { P10OUT&=~BIT6; // CS putting to low to start transmission // __delay_cycles(10); // inserting a delay while (!(UCB3STAT&UCBUSY)==0); // while (UCBUSY!==0)); UCB3TXBUF=0x31; // DATA Format Register adress while (!(UCB3STAT&UCBUSY)==0); UCB3TXBUF=0x00; // setting every BIT to 0, BIT=0 means 4 wire communication, sending while (!(UCB3STAT&UCBUSY)==0); // while (UCBUSY!==0)); UCB3TXBUF=0x80; // sending while (!(UCB3STAT&UCBUSY)==0); // while( (UCB3IFG&UCRXIFG) == 0); // receive_data=UCB3RXBUF; //eingebaut UCB3TXBUF=0xFF; // sending dummy byte //while (!(UCB3IFG&UCRXIFG)); while (!(UCTXIFG)); receive_data=UCB3RXBUF; //erg�nzt // __delay_cycles(2); P10OUT|=BIT6; // P10OUT&=~BIT6; return(receive_data); // return (UCB3RXBUF); // putting CS to 1 in the while loop outside of the function };
Thanks and Greetings
what do you expect as 'right ID'?Roko Sobar said:now I am receiving 0xC7 instead of the right ID
In your latest code, are you sure about UCCKPH and UCCKPL? There are four possible combinations of the two. Picking the wrong one will cause partially failure, shifted bits (in both write and read) or no success at all.
UCCKPL but not UCCKPH is a common combination. Note that the meaning of UCCKPL is inverse to the often used motorola SPI notation.
Roko Sobar said:from your code:
uint8_t testreadwrite() // Testfunction
{
P10OUT&=~BIT6; // CS putting to low to start transmission
// __delay_cycles(10); // inserting a delay
while (!(UCB3STAT&UCBUSY)==0); // while (UCBUSY!==0));
UCB3TXBUF=0x31; // DATA Format Register adress
while (!(UCB3STAT&UCBUSY)==0);
UCB3TXBUF=0x00; // setting every BIT to 0, BIT=0 means 4 wire communication, sending
while (!(UCB3STAT&UCBUSY)==0); // while (UCBUSY!==0));
UCB3TXBUF=0x80; // sending
while (!(UCB3STAT&UCBUSY)==0);
// while( (UCB3IFG&UCRXIFG) == 0);
// receive_data=UCB3RXBUF; //eingebaut
UCB3TXBUF=0xFF; // sending dummy byte
//while (!(UCB3IFG&UCRXIFG));
while (!(UCTXIFG));
receive_data=UCB3RXBUF; //ergänzt
P10OUT|=BIT6; // P10OUT&=~BIT6;
return(receive_data); // return (UCB3RXBUF); // putting CS to 1 in the while loop outside of the function
};
This code flow is still not correct. The last whiel still doesn't wait until the answer is received. Also, the first lines are not logical. You lower CS but then you wait for SPI going idle. If it weren't already, CS would be low already and you wouldn't need to check for busy, or it might be busy, then you'll have to do more than waiting.
Also, "while(!UCTXIFG)" is always false, since UCTXIFG is a constant and != 0.
Try this:
uint8_t testreadwrite() // Testfunction
{
if(UCB3STAT&UCBUSY){ // for some reason, the SPI is still busy. Normally, it shouldn't, so this whole IF block might be superfluous
while(UCB3STAT&UCBUSY); // wait until SPI is idle
P10OUT |= BIT6; // de-assert CS, ending ht eprevious transfer
__delay_cycles(10); // give the slave some time (see datasheet how much is required between raising and next falling CS)
}
P10OUT&=~BIT6; // CS putting to low to start transmission
UCB3TXBUF=0x31; // DATA Format Register adress (if the USCI was idle, it now still is, and TXBUF can be written to)
while (!(UCB3IFG&UCTXIFG)); // is TXBUF empty (previous byte is sending) yet? On high SPI clock, it would, as teh USCI was idle and should start sending the previous byte immediately, leavign TXBUF empty. But be safe...
UCB3TXBUF=0x00; // setting every BIT to 0, BIT=0 means 4 wire communication, sending
while (!(UCB3IFG&UCTXIFG)); // is TXBUF empty (previous byte is sending) yet?
UCB3TXBUF=0x80; // sending
while (!(UCB3IFG&UCTXIFG)); // is TXBUF empty (previous byte is sending) yet?
UCB3TXBUF=0xFF; // sending dummy byte
while (!(UCB3STAT&UCBUSY)==0); // wait until all sending and receiving is complete
P10OUT|=BIT6; // de-assert CS
return(UCB3RXBUF); // return (UCB3RXBUF);
};
Hi Jens!
Thanks for the critic and help again. I will follow your proposals and try to improve the code.
In fact it is not necessary to config the DATA_FORMAT Register for SPI 4 wire. It is per default in 4 wire.
In the meantime a new code was developed which was able to receive constantly the right ID of 0xE5.
#include "msp430x54xA.h" #include "hal_MSP-EXP430F5438.h" #include "hal_lcd.h" #include <stdint.h> #include "hal_pmm.h" #define SYSTEM_CLOCK 23986176 #define USB_PORT_OUT P5OUT #define USB_PORT_SEL P5SEL #define USB_PORT_DIR P5DIR #define USB_PORT_REN P5REN #define USB_PIN_TXD BIT6 #define USB_PIN_RXD BIT7 #define USB_PORT_BAUDRATE 57600 #define UART_A3_PSEL P10SEL #define UART_A3_PDIR P10DIR #define UART_A3_TXD_MASK BIT4 #define UART_A3_RXD_MASK BIT5 #define UART_A3_BAUDRATE 57600 char rxBuffer[256]; //Buffer to keep received messages/responses/events from module char rxReadIndex = 0; char rxWriteIndex = 0; volatile char dataReady = 0; //variable to declare is message is completely received (to be implemented) volatile unsigned int i; // volatile to prevent optimization unsigned int SetVCore (unsigned char level); void initSystemClock(); //unsigned char contrast = 0x66; //unsigned char backlight = 8; void lcdStart(); void portsInit(); /************************************** MAIN *****************************************/ /********************** sends command and keeps idle - stop **************************/ /********************** debugging and check memory contents **************************/ /********************** rxBuffer[] should contain response **************************/ unsigned char MST_Data = 0x80; // Initialize data values unsigned char MST_Data2 = 0xFF; unsigned char SLV_Data = 0xE5; unsigned char tempvar; int j = 0; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer //initSystemClock(); // It's 4 wires, but in reality 3-wire mode for MSP430, since the CS is manually controlled. Still full duplex (and not half) P10DIR |= 0x40; // CS pin. P10SEL |= 0x0E; // or BIT1 + BIT2 + BIT3; UCB3CTL1 |= UCSWRST; // **Put state machine in reset** !!! UCB3CTL0 |= UCMST + UCSYNC + UCCKPL + UCMSB;// + UCCKPH; // 3-pin, 8-bit SPI master //UCB3CTL1 |= UCSSEL_1; // ACLK = ~32.768kHz, UCB3CTL1 |= UCSSEL_2; // SMCLK //UCB3BR0 = 0; // UCB3BR0 = 0x02; // UCB3BR1 = 0; // UCB3CTL1 &= ~UCSWRST; // **Initialize USCI state machine** UCB3IE |= UCRXIE; // Enable USCI_B3 RX interrupt P10OUT |= 0x40; //set high (CS active low) __delay_cycles(100); // Wait for slave to initialize //******* ROUTINE TO SEND P10OUT &= ~0x40; //select slave while (!(UCB3IFG&UCTXIFG)); // USCI_A0 TX buffer ready? UCB3TXBUF = MST_Data; // Transmit first character __bis_SR_register(GIE); // enable interrupts ???????? while(1){}; } #pragma vector=USCI_B3_VECTOR __interrupt void USCI_B3_ISR(void) { switch(__even_in_range(UCB3IV,12)) { case 0: break; // Vector 0 - no interrupt case 2: // Vector 2 - RXIFG while (!(UCB3IFG&UCTXIFG)); // USCI_A0 TX buffer ready? tempvar = UCB3RXBUF; if (tempvar == SLV_Data) // Test for correct character RX'd tempvar = 0xAA; else UCB3TXBUF = MST_Data2; // Send next value j++; __delay_cycles(40); // Add time between transmissions to // make sure slave can process information if(j==2) tempvar++; break; case 4: break; // Vector 4 - TXIFG default: break; } }
Now I want to configure the registers in the right way to receive the data of the axes.
#include "msp430x54xA.h" #include "hal_MSP-EXP430F5438.h" #include "hal_lcd.h" #include <stdint.h> #include "hal_pmm.h" #define SYSTEM_CLOCK 23986176 #define USB_PORT_OUT P5OUT #define USB_PORT_SEL P5SEL #define USB_PORT_DIR P5DIR #define USB_PORT_REN P5REN #define USB_PIN_TXD BIT6 #define USB_PIN_RXD BIT7 #define USB_PORT_BAUDRATE 57600 #define UART_A3_PSEL P10SEL #define UART_A3_PDIR P10DIR #define UART_A3_TXD_MASK BIT4 #define UART_A3_RXD_MASK BIT5 #define UART_A3_BAUDRATE 57600 char rxBuffer[256]; //Buffer to keep received messages/responses/events from module char rxReadIndex = 0; char rxWriteIndex = 0; volatile char dataReady = 0; //variable to declare is message is completely received (to be implemented) volatile unsigned int i; // volatile to prevent optimization unsigned int SetVCore (unsigned char level); void initSystemClock(); //unsigned char contrast = 0x66; //unsigned char backlight = 8; void lcdStart(); void portsInit(); /************************************** MAIN *****************************************/ /********************** sends command and keeps idle - stop **************************/ /********************** debugging and check memory contents **************************/ /********************** rxBuffer[] should contain response **************************/ unsigned char MST_Data = 0x80; // Initialize data values unsigned char MST_Data2 = 0xFF; unsigned char SLV_Data = 0xE5; // Slave-Data, Roko unsigned char tempvar; int j = 0; // SPI-Configurationfunction void spi_init (); // Code added by Roko uint8_t ADRESS_DATA_FORMAT=0x31; uint8_t ADRESS_BW_RATE=0x2C; uint8_t ADRESS_FIFO_CTL=0x80; uint8_t ADRESS_POWER_CTRL=0x2D; // Code added by Roko uint8_t DATA_FORMAT=0x0A; // 100 Hz output rate uint8_t BW_RATE=0x0A; // uint8_t FIFO_CTL=0x80; // uint8_t POWER_CTRL=0x08; // // Variables for measurement uint8_t DATAX0=0x32; // adress uint8_t DATAX1=0x33; // adress uint8_t DATAY0=0x34; // adress uint8_t DATAY1=0x35; // adress uint8_t DATAZ0=0x36; // adress uint8_t DATAZ1=0x37; // adress // Results measurements uint8_t X0; uint8_t X1; uint8_t Y0; uint8_t Y1; uint8_t Z0; uint8_t Z1; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer //initSystemClock(); // It's 4 wires, but in reality 3-wire mode for MSP430, since the CS is manually controlled. Still full duplex (and not half) P10DIR |= 0x40; // CS pin. P10SEL |= 0x0E; // or BIT1 + BIT2 + BIT3; UCB3CTL1 |= UCSWRST; // **Put state machine in reset** !!! UCB3CTL0 |= UCMST + UCSYNC + UCCKPL + UCMSB;// + UCCKPH; // 3-pin, 8-bit SPI master //UCB3CTL1 |= UCSSEL_1; // ACLK = ~32.768kHz, UCB3CTL1 |= UCSSEL_2; // SMCLK //UCB3BR0 = 0; // UCB3BR0 = 0x02; // UCB3BR1 = 0; // UCB3CTL1 &= ~UCSWRST; // **Initialize USCI state machine** UCB3IE |= UCRXIE; // Enable USCI_B3 RX interrupt P10OUT |= 0x40; //set high (CS active low) __delay_cycles(100); // Wait for slave to initialize //******* ROUTINE TO SEND //TEST_ID // P10OUT &= ~0x40; //select slave // // while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? // UCB3TXBUF = MST_Data; // Transmit first character // // spi_init(); __bis_SR_register(GIE); // enable global interrupts while(1) { } } #pragma vector=USCI_B3_VECTOR __interrupt void USCI_B3_ISR(void) { switch(__even_in_range(UCB3IV,12)) { case 0: break; // Vector 0 - no interrupt case 2: // Vector 2 - RXIFG P10OUT&=~0x40; //****Measurements*************** UCB3TXBUF=DATAX0; // USCI_B0 TX buffer ready? while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready? X0=UCB3RXBUF; while (!(UCB3STAT&UCBUSY)==0); // UCB3TXBUF = MST_Data2; // Transmit first character, Address(ROKO) UCB3TXBUF=DATAX1; // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready?? X1=UCB3RXBUF; while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=DATAY0; // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 TX buffer ready? Y0=UCB3RXBUF; while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=DATAY1; while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready? Y1=UCB3RXBUF; while (!(UCB3STAT&UCBUSY)==0); // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=DATAZ0; // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready? Z0=UCB3RXBUF; while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=DATAZ1; // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready? Z1=UCB3RXBUF; while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; // while (!(UCB3IFG&UCTXIFG)); // USCI_A0 TX buffer ready? // tempvar = UCB3RXBUF; // if (tempvar == SLV_Data) // Test for correct character RX'd // tempvar = 0xAA; //tempvar=0xAA; // else // UCB3TXBUF = MST_Data2; // Send next value (Roko, sending Dummy byte) // j++; // Zeile zum Debuggen __delay_cycles(40); // Add time between transmissions to // make sure slave can process information (seems to avoid putting CS to high) // if(j==2) // tempvar++; break; case 4: break; // Vector 4 - TXIFG default: break; } } void spi_init () { //******** Configuration ***** Roko while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_DATA_FORMAT; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=DATA_FORMAT; // Transmit second character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //------------------------------- P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_BW_RATE; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=BW_RATE; // Transmit second character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //-------------------------------- P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_FIFO_CTL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=FIFO_CTL; // Transmit second character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //--------------------------------- P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_POWER_CTRL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //--------------------------------------- P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=POWER_CTRL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //---------------------------------------- };
Every axes receive the same data in the moment. I am working on that.
Line 179 while (!(UCB3STAT&UCBUSY)==0);
Line 181 while (!(UCB3IFG&UCTXIFG));
Maybe this is unnecessary. Can you give me advices for the measurement section in the interupt vector? I am trying to put CS low and high after every measurement
Greetings
Hi Jens!
Here is my actual code. Also based on the Arduino sample code for the ADXL345. What can be improved? Should I change the variable definitions to
preprocessor statements?
Thanks and Greetings
#include "msp430x54xA.h" #include "hal_MSP-EXP430F5438.h" #include "hal_lcd.h" #include <stdint.h> #include "hal_pmm.h" #define SYSTEM_CLOCK 23986176 #define USB_PORT_OUT P5OUT #define USB_PORT_SEL P5SEL #define USB_PORT_DIR P5DIR #define USB_PORT_REN P5REN #define USB_PIN_TXD BIT6 #define USB_PIN_RXD BIT7 #define USB_PORT_BAUDRATE 57600 #define UART_A3_PSEL P10SEL #define UART_A3_PDIR P10DIR #define UART_A3_TXD_MASK BIT4 #define UART_A3_RXD_MASK BIT5 #define UART_A3_BAUDRATE 57600 char rxBuffer[256]; //Buffer to keep received messages/responses/events from module char rxReadIndex = 0; char rxWriteIndex = 0; volatile char dataReady = 0; //variable to declare is message is completely received (to be implemented) volatile unsigned int i; // volatile to prevent optimization unsigned int SetVCore (unsigned char level); void initSystemClock(); //unsigned char contrast = 0x66; //unsigned char backlight = 8; void lcdStart(); void portsInit(); /****************** HCI - RF module commands: ******************/ // Example commands present in the readme.docx char command[] = {"\xA5\x01\x01\x00"}; // 4 bytes char command2[] = {"\xA5\x01\x13\x01\x01"}; // 5 bytes char command3[] = {"\xA5\x01\x13\x01\x02"}; // 5 bytes char command4[] = {"\xA5\x01\x13\x01\x03"}; // 5 bytes char command5[] = {"\xA5\x01\x13\x01\x04"}; // 5 bytes char command6[] = {"\xA5\x01\x13\x01\x05"}; // 5 bytes char command7[] = {"\xA5\x02\x04\x05\x30\x31\x32\x33\x34"}; // 9 // Command sent by the Functional Test Tool app char command8[] = {"\xA5\x82\x01\x16\x00\x00\x00\x97\x00\x7F\x36\x01\xF1\x01\x02\x03\x00\x33\x30\x5D\x05\x41\x1F\x86\x15\xAA\x6E\x08"}; // 28 bytes /************************************** MAIN *****************************************/ /********************** sends command and keeps idle - stop **************************/ /********************** debugging and check memory contents **************************/ /********************** rxBuffer[] should contain response **************************/ unsigned char MST_Data = 0x80; // Initialize data values unsigned char MST_Data2 = 0xFF; unsigned char SLV_Data = 0xE5; // Slave-Data, Roko unsigned char tempvar; int j = 0; // SPI-Configurationfunction void spi_init (); // multiread function uint8_t multiread (void); // Code added by Roko uint8_t ADRESS_DATA_FORMAT=0x31; // 0x31; DATA_FORMAT, wake up from standby uint8_t ADRESS_BW_RATE=0x2C; // Address uint8_t ADRESS_FIFO_CTL=0x80; // Address uint8_t ADRESS_POWER_CTRL=0x2D; // Address // Code added by Roko uint8_t DATA_FORMAT=0x08; // 100 Hz output rate // 0x0A //SELF_TEST | SPI | INT_INVERT | 0 | FULL_RES | Justify | Range uint8_t BW_RATE=0x0A; // 0 | 0 | 0 | LOW_POWER | Rate | Rate | Rate Rate uint8_t FIFO_CTL=0x80; // FIFO_MODE | FIFO_MODE | Tigger | Samples | Samples | Samples | Samples | Samples uint8_t POWER_CTRL=0x08; // 0 | 0 | Link | AUTO_SLEEP | Measure | Sleep | Wakeup unint8_t POWER_CTRLstop=0x00; // setting Measurement Bit to 0 to stop measurement // Variables for measurement uint8_t DATAX0=0x32; // adress uint8_t DATAX1=0x33; // adress uint8_t DATAY0=0x34; // adress uint8_t DATAY1=0x35; // adress uint8_t DATAZ0=0x36; // adress uint8_t DATAZ1=0x37; // adress // Results measurements uint8_t X0; uint8_t X1; uint8_t Y0; uint8_t Y1; uint8_t Z0; uint8_t Z1; uint8_t x; uint8_t y; uint_8t z; // buffer for DATA unint8_t [10]; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer //initSystemClock(); // It's 4 wires, but in reality 3-wire mode for MSP430, since the CS is manually controlled. Still full duplex (and not half) P10DIR |= 0x40; // CS pin. P10SEL |= 0x0E; // or BIT1 + BIT2 + BIT3; UCB3CTL1 |= UCSWRST; // **Put state machine in reset** !!! UCB3CTL0 |= UCMST + UCSYNC + UCCKPL + UCMSB;// + UCCKPH; // 3-pin, 8-bit SPI master //UCB3CTL1 |= UCSSEL_1; // ACLK = ~32.768kHz, UCB3CTL1 |= UCSSEL_2; // SMCLK //UCB3BR0 = 0; // UCB3BR0 = 0x02; // UCB3BR1 = 0; // UCB3CTL1 &= ~UCSWRST; // **Initialize USCI state machine** UCB3IE |= UCRXIE; // Enable USCI_B3 RX interrupt P10OUT |= 0x40; //set high (CS active low) __delay_cycles(100); // Wait for slave to initialize //******* ROUTINE TO SEND //TEST_ID // P10OUT &= ~0x40; //select slave // // while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? // UCB3TXBUF = MST_Data; // Transmit first character // // spi_init(); multiread (void); __bis_SR_register(GIE); // enable global interrupts while(1) { } } #pragma vector=USCI_B3_VECTOR __interrupt void USCI_B3_ISR(void) { switch(__even_in_range(UCB3IV,12)) { case 0: break; // Vector 0 - no interrupt case 2: // Vector 2 - RXIFG P10OUT&=~0x40; // sending the adress to start conversation with POWER_CTL while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_POWER_CTRL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //--------------------------------------- // sending 0x08 to the POWER_CTL Register to start the measurement P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=POWER_CTRL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //****Measurements*************** UCB3TXBUF=DATAX0; // USCI_B0 TX buffer ready? while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready? X0=UCB3RXBUF; buffer[0]=X0; // Putting Data from Variable X0 into the buffer while (!(UCB3STAT&UCBUSY)==0); // P10OUT|=0x40; // // __delay_cycles(40); // P10OUT&=~0x40; // UCB3TXBUF = MST_Data2; // Transmit first character, Address(ROKO) UCB3TXBUF=DATAX1; // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready?? X1=UCB3RXBUF; buffer[1]=X1; // Putting Data from Variable X1 into the buffer while (!(UCB3STAT&UCBUSY)==0); // // P10OUT&=~0x40; // // __delay_cycles(40); // P10OUT|=0x40; while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=DATAY0; // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 TX buffer ready? Y0=UCB3RXBUF; buffer[2]=Y0; // Putting Data from Variable Y0 into the buffer while (!(UCB3STAT&UCBUSY)==0); // // P10OUT&=~0x40; // // __delay_cycles(40); // P10OUT|=0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=DATAY1; while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready? Y1=UCB3RXBUF; buffer[3]=Y1; // Putting Data from Variable Y1 into the buffer while (!(UCB3STAT&UCBUSY)==0); // Transmit first character, Address(ROKO) // // P10OUT&=~0x40; // // __delay_cycles(40); // P10OUT|=0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=DATAZ0; // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready? Z0=UCB3RXBUF; buffer[4]=Z0; // Putting Data from Variable Z0 into the buffer while (!(UCB3STAT&UCBUSY)==0); // P10OUT|=0x40; // P10OUT&=~0x40; // __delay_cycles(40); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=DATAZ1; // Transmit first character, Address(ROKO) while (!(UCB3IFG&UCTXIFG)); UCB3TXBUF=0xFF; // Dummy-Byte while (!(UCB3IFG&UCRXIFG)); // USCI_B0 RX buffer ready? Z1=UCB3RXBUF; buffer[5]=Z1; // Putting Data from Variable Z1 into the buffer while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; // while (!(UCB3IFG&UCTXIFG)); // USCI_A0 TX buffer ready? // tempvar = UCB3RXBUF; // if (tempvar == SLV_Data) // Test for correct character RX'd // tempvar = 0xAA; //tempvar=0xAA; // else // UCB3TXBUF = MST_Data2; // Send next value (Roko, sending Dummy byte) // j++; // Zeile zum Debuggen // sending the adress to start conversation with POWER_CTL while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_POWER_CTRL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //--------------------------------------- // sending 0x08 to the POWER_CTL Register to start the measurement P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=POWER_CTRLstop; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); // Add time between transmissions to // make sure slave can process information (seems to avoid putting CS to high) // if(j==2) // tempvar++; break; case 4: break; // Vector 4 - TXIFG default: break; } } void spi_init () { //******** Configuration ***** Roko while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_DATA_FORMAT; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=DATA_FORMAT; // Transmit second character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //------------------------------- P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_BW_RATE; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=BW_RATE; // Transmit second character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //-------------------------------- P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_FIFO_CTL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=FIFO_CTL; // Transmit second character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //--------------------------------- P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=ADRESS_POWER_CTRL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //--------------------------------------- P10OUT&=~0x40; while (!(UCB3IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB3TXBUF=POWER_CTRL; // Transmit first character, Address(ROKO) while (!(UCB3STAT&UCBUSY)==0); P10OUT|=0x40; __delay_cycles(40); //---------------------------------------- }; uint8_t multiread (void) { x = ((int)values[1]<<8)|(int)values[0]; y = ((int)values[3]<<8)|(int)values[2]; z = ((int)values[5]<<8)|(int)values[4]; } /******************************** UART Interrupt for response from RF module ***************/ #pragma vector=USCI_A3_VECTOR __interrupt void USCI_A3_ISR(void) { unsigned char data = UCA3RXBUF; rxBuffer[rxWriteIndex++] = data; // while (!(UCA1IFG&UCTXIFG)){ // UCA1TXBUF = data; // } if(data == 0x02) dataReady=1; // to signalize end of command received, but does not always work, because only a few end with 0x02 // so the best way to debug is Break operation and check memory registers, and variable "rxBuffer" } /************ Function to initialize system clock ***********/ /************ taken from steering wheel code ****************/ void initSystemClock (void) { SetVCore(PMMCOREV_3); // Set VCore to level3 (ca 1.9V) for 25MHz UCSCTL3 |= SELREF_2; // Set DCO FLL reference = REFO UCSCTL4 |= SELA_2; // Set ACLK = REFO __bis_SR_register(SCG0); // Disable the FLL control loop UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx UCSCTL1 = DCORSEL_6; // Select DCO range 48MHz operation UCSCTL2 = FLLD_1 + 731; // Set DCO Multiplier for 24MHz // (N + 1) * FLLRef = Fdco // (731 + 1) * 32768 = 24MHz // Set FLL Div = fDCOCLK/2 __bic_SR_register(SCG0); // Enable the FLL control loop // Worst-case settling time for the DCO when the DCO range bits have been // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx // UG for optimization. // 32 x 32 x 24 MHz / 32,768 Hz = 750000 = MCLK cycles for DCO to settle __delay_cycles(750000); // Loop until XT1,XT2 & DCO fault flag is cleared do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags SFRIFG1 &= ~OFIFG; // Clear fault flags }while (SFRIFG1&OFIFG); // Test oscillator fault flag } /************ Function to initialize ports (UART3 and UART-USB) ***********/ void portsInit(void) { UART_A3_PSEL |= 0x30; // or |= BIT4 + BIT5; P3.4,5 = USCI_A0 TXD/RXD // YOU DON'T MESS WITH DIRECTION WHEN USING UART //UART_A3_PDIR &= ~UART_A3_RXD_MASK; //CHECK THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! and also in system.c //UART_A3_PDIR |= UART_A3_TXD_MASK; //WHY? because I think you don't mess with PxDIR when you want to receive and possibly send UCA3CTL1 |= UCSWRST; // 8-bit character UCA3CTL1 |= UCSSEL_2; // UCLK = SMCLK UCA3BR0 = (uint8_t)(SYSTEM_CLOCK / UART_A3_BAUDRATE); UCA3BR1 = (uint8_t)((SYSTEM_CLOCK / UART_A3_BAUDRATE) >> 8); UCA3MCTL = (uint8_t)((SYSTEM_CLOCK / UART_A3_BAUDRATE - (uint16_t)(SYSTEM_CLOCK / UART_A3_BAUDRATE))*8 + 0.5) << 1; // manually start reading of data UCA3CTL1 &= ~UCSWRST; // Initialize USART state machine UCA3IE |= UCRXIE; // Enable only USART0 RX interrupt (only possible if not in reset!!!) // GUERRA usb-serial port for debugging init(): USB_PORT_SEL |= USB_PIN_RXD + USB_PIN_TXD; USB_PORT_DIR |= USB_PIN_TXD; USB_PORT_DIR &= ~USB_PIN_RXD; UCA1CTL1 |= UCSWRST; //Reset State UCA1CTL0 = UCMODE_0; UCA1CTL0 &= ~UC7BIT; // 8bit char UCA1CTL1 |= UCSSEL_2; UCA1BR0 = (uint8_t)(SYSTEM_CLOCK / USB_PORT_BAUDRATE); // clock/57600=? UCA1BR1 = (uint8_t)((SYSTEM_CLOCK / USB_PORT_BAUDRATE) >> 8); UCA1MCTL = (uint8_t)((SYSTEM_CLOCK / USB_PORT_BAUDRATE - (uint16_t)(SYSTEM_CLOCK / USB_PORT_BAUDRATE))*8 + 0.5) << 1; UCA1CTL1 &= ~UCSWRST; UCA1IE |= UCRXIE; __bis_SR_register(GIE); } /************ Function to initialize LCD and backlight ***********/ /************ taken from user experience program by TI ***********/ void lcdStart(void) { halLcdInit(); halLcdBackLightInit(); halLcdSetBackLight(halLcdGetBackLight()); halLcdSetContrast(halLcdGetContrast()-6); halLcdClearScreen(); halLcdPrintLine("Hello world.", 0, 0); } /************ USB echo test ********************/ /* #pragma vector=USCI_A1_VECTOR __interrupt void USCI_A1_ISR(void) { UCA1TXBUF = UCA1RXBUF; //echoes _NOP(); } */
Hi Guys, do not drown in so much detail. There is no need to include UCBUSY in SPI communication for basic reading and writing. The code below works perfectly fine for reading device ID of ADXL345 with MSP430G2553;
#include <msp430g2553.h>
volatile char received_byte1 = 0;
volatile char received_byte2 = 0;
volatile char received_byte3 = 0;
volatile char received_byte4 = 0;
volatile char received_byte5 = 0;
unsigned int i;
void spi_conf(void);
void general_clock_cong(void);
void spi_read(void);
void main(void){
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= BIT0;
general_clock_cong();
spi_conf();
spi_read();
P1OUT &= ~BIT0;
}
void general_clock_cong(void){
DCOCTL = CAL_DCO_16MHZ;
BCSCTL1 = CAL_BC1_16MHZ;
}
void spi_conf(void){
UCA0CTL1 = UCSWRST; // Reset
UCA0CTL0 = UCCKPL + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
UCA0CTL1 |= UCSSEL_2 ; // USCI clock source select. (SMCLK)
UCA0BR0 = 128; // Baud Rate
UCA0BR1 = 0; // Baud Rate
//UCA0CTL1 &= ~UCCKPH; // phase 0
//UCA0CTL1 |= UCCKPL; // polarity 1
//UC0IE = (UCA0RXIE + UCA0TXIE); // enable interrrupt
//UCA0CTL1 |= UCSWRST; // reset usci
UCA0CTL1 &= ~UCSWRST; // clear reset
P1SEL = (BIT1 + BIT2 + BIT4); // Set SPI CLK, MOSI and MISO
P1SEL2 = (BIT1 + BIT2 + BIT4);
P1DIR = BIT5 + BIT0; // BIT 5 SPI EN, BIT0 LED
}
void spi_read(void){
P1OUT |= BIT5;
P1OUT &= ~BIT5; // BIT 5 is CS
for(i=1000;i>0;i--){
}
while (!(IFG2&UCA0TXIFG)); // Wait for TXBUF ready
UCA0TXBUF = 0x80; // Send address
while(!(IFG2 & UCA0RXIFG)); // Wait for RXBUF ready
received_byte1 = UCA0RXBUF;
while (!(IFG2&UCA0TXIFG)); // Wait for TXBUF ready
UCA0TXBUF = 0xFF; // Send address
while(!(IFG2 & UCA0RXIFG)); // Wait for RXBUF ready
received_byte2 = UCA0RXBUF;
P1OUT |= BIT5;
//P1OUT &= ~BIT5;
}
You can configure for your pins of the chip you re using. When you read the datasheet of ADXL carefully, you will see you need to set MSB as 1 for reading and 0 for Writting. And the rest is pretty standart for SPI communication. I hope I can help. Take care!
I'm not familiar with the ADXL sensor, but in its data sheet it reads "To read or write multiple bytes in a single transmission, the multiple-byte bit, located after the R/W bit in the first byte transfer (MB in Figure 37 to Figure 39), must be set"
Your code sends address 0x32, which means the next byte transfer writes 0xff to register 0x32 (which is read-only), then the next byte transfer is interpreted as another address. As this is 0xff (the dummy byte), this results in a multi-byte read from register 0x3f on (which doesn't exist, and maybe wraps to 0x00).
You should use register address 0xf2 instead, to indicate subsequent reads until CS is set high again.
Without the multiple-byte bit set, the transfers are always one address, one data byte and can live without toggling CS at all.
Besides this, I'd recommend some changes in the way you define your macros.
You shouldn't include a semicolon to them. Instead, add it adter the macro name in the code.
Worst case this might happen:
if(x)
if(y)
macro;
else
...;
If the macro already contains a semicolon, the else belongs to the first if, even if it was meant to belong to the second. And from looking at the code, you can't see this.
This also applies to your while macro. Use two curled brackets instead of the semicolon. This makes the use of the macro transparent no matter where you use it. Also, if your macro is more than just an expression, you should define it with brackets. This way, it can be used as if it were an inline function.
If it contains more than one instruction, it should be also put into curled brackets, so it appears as one monolithic code block at the point where it is used.
Expressions should also put into brackets, to avoid ambiguity of the resulting code.
Imagine what heppens if you write
"x = y * z", where z was defined as "#define z 1+1"
Remember, the macros are plain text search&replace operations, done before the compiler even sees the code. The compiler doesn't know which part of the code once was a macro and was considered by you to be monolithic.
**Attention** This is a public forum