How to use SPI with ADXL345 accelerometer and PSoC 5 board

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable
        Hi everyone! I'm trying to get data out of a ADXL345 accelerometer and display it on the LCD of the PSoC5. I'm having difficulties trying to display the results. At this point, I'm only trying to get the x and y axis results, one for each line of the LCD. I'm currently a student at a university and have asked my professors if they have any idea how to use SPI, but none have been able to help with the PSoC related stuff. I've looked at other threads in this forum but none have really solved the problem and I've pretty much exhausted the internet searching for answers. I did find some code (AccelSPI_test.c) that I spliced and added into my code. It wasn't meant for the PSoC5 though, so I had to change some things. I think I only need an SPI Master in the top design, and not a slave. I've attached the main c file for anyone to look at with the AccelSPI_test.c file under it. If anyone can help or has any ideas how to do this it would be great. If you need more information, like TopDesign, or pin assignments, I can post this too, but I think those are ok right now.   
0 Likes
15 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Since the ADXL345 has got an I2C-interface (I am not a friend of SPI), why don't you use this? With the basic APIs of I2C-master (start, restart read etc) you can setup your connection byte-by-byte easily.

   

In your routine task() you initialize your device and get data, better is to separate initialization and reading off data.

   

You do not tell us where your program runs into troubles. Debugging the code will reveill that.

   

Best is to upload a complete project archive here (use Creator -> File -> Create Workspace Bundle (minimal) and upload the resulting .zip here), so we can check not only the code but all the settings.

   

 

   

Bob

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

A complete project helps to see where your hardware might be configured wrong.

   

Things to look for:

   
        
  • SPI clock too fast (then the slave select output might go high inbetween the bytes)
  •     
  • each write to the SPI also does a read - and this will fill up the buffer, so you might read wrong values afterwards. So clear the read buffer after each write
  •     
  • wrong SPI mode (must be 1/1)
  •     
  • when reading the registers, *1 must be shifted, as its the higher byte, and *0 is the lower byte
  •    
   

You should attach a logic analyzer and see whats going over the wire, and see whether it is what you expect. Then you can look at the software...

0 Likes
Anonymous
Not applicable

I think the code is very well written, here is some suggestions

   
     1.       I think you should read all the data first into an array and then process the whole array; in that case you can check that value immediate after the reading.   
   
        
   
     2.       I would avoid use any names with leading underscore such as _POWER_CTL, as that normal are used for system usage   
   
        
   
     3.       Try not to mix // and /* */ together such as   
   
                     /*LCD_Position(0,9);       //Initialize string position 9   
   
                     LCD_PrintString(point); //Prints . at 0,9, may not need?   
   
                     LCD_Position(0,12);      //Initialize string position 12   
   
                     LCD_PrintString(G);      //Prints G at 0,12*/   
   
        
   
    I prefer to use   
   
        
   
    #if 0   
   
    LCD_Position(0,9);            //Initialize string position 9   
   
                     LCD_PrintString(point); //Prints . at 0,9, may not need?   
   
                     LCD_Position(0,12);      //Initialize string position 12   
   
                     LCD_PrintString(G);      //Prints G at 0,12   
   
    #endif   
   
        
   
    Or   
   
        
   
    #ifndef  NO_PRINT   
   
    LCD_Position(0,9);            //Initialize string position 9   
   
                     LCD_PrintString(point); //Prints . at 0,9, may not need?   
   
                     LCD_Position(0,12);      //Initialize string position 12   
   
                     LCD_PrintString(G);      //Prints G at 0,12   
   
    #endif   
   
         
   
    And define that at the beginning of the file like this.   
   
    #define NO_PRINT   
   
    You then can check your setting in one place and no need to check the code   
   
        
   
     4.       I think PSoC5 does not have bit variables. That is why sbit would not work   
   
        
   
     5.       I normally control the CS of SPI directly and not using the output from the SPI component. You can change it back to use the output of the component. But directly controlling it save a lot of headache during debugging.   
   
        
   
     6.        It would also help if you use more defines such as   
   
        
   
    #define CARRAGE_RETURN  (13)   
   
    #define X_READING (0)   
   
    #define Y_READING (0)   
   
        
   
    UART1_Write(CARRAGE_RETURN );   
   
    readings[X_READING] = ADXL345_Read(SENSOR_DATAX0) << 8;   
   
    readings[Y_READING] = ADXL345_Read(SENSOR_DATAY0) << 8;   
   
        
   
     7.       As mentioned, it would be easier if you post the complete project.   
   
        
   
    8. I would debug one portion of code a time, IE made sure the UART part works first by write something the the array direcly and send it out to the UART. Once it can display correctly then start doing   
   

my 2cents

0 Likes
Anonymous
Not applicable
    My bad!!   
   
        
   
    8. I would debug one portion of code a time, IE made sure the UART part works first by write something the the array direcly and send it out to the UART. Once it can display correctly then start doing the reading of the sensor.   
0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable
        Thanks for the suggestions everyone. Hopefully this zip file will contain everything you need to look at, I've never used that feature before. As for the problem that I'm running into, I can display the title of the axis(X and Y) on the LCD but it won't display the data if should be getting from the accelerometer. I think the 2 problems are getting the accelerometer data and converting that data into a string to print on the LCD. One of my profs thought maybe that the LCD could only hold so much data so it wouldn't print something that was really long, but I don't think that is the case as I've shortened it to the first 6 values. I didn't know about the sbit stuff so thank you for that. I couldn't figure out why that wasn't working. I currently don't use UART anywhere (it's in there, just commented out), is it something I should be using? As for using SPI over I2C, I've been working on the project with many different accelerometers and boards over the past year and this just seems like the one that has been making the most progress. If I can't make it work with SPI, I'll switch over to I2C. I'm really not too picky on which I'll end up using, at this point I'd use whatever made it work. Sorry to keep you guys waiting for a few days, I was out of town and couldn't work on this then.   
0 Likes
lock attach
Attachments are accessible only for community members.
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

The easy way to convert data to formatted data is sprintf(), basically printf() that

   

outputs to a character buffer for printing on LCD.

   

 

   

Attached the format specifications useful for sprintf(). If you are using character

   

LCD there is an API f() call in datasheet for printing a character buffer/array to the

   

LCD, as well as f()'s for moving the cursor to the position where you want the

   

formatted data to be written on LCD.

   

 

   

Regards, Dana.,

0 Likes
Anonymous
Not applicable

1. You have a while loop in your task() function. it will never come out so it won't run the Updatedisplay function().

   

2. You should be able to step and break within creator to debug your project.

   

3. For some simply test. I would suggest to added a 1second delay inside the main loop and also increment and x and y counter every loop and shown it on the LCD. So you can see the change of the counters updated on the LCD.

   

4. One step a time is actually quicker to the finish line.

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable
        I've changed a few things around and got actual numbers to be outputted on the LCD, but they only update when the accelerometer is unplugged. These numbers that change are from noise in the air we believe. Once the ADXL is plugged back in, the numbers stop changing. If the ADXL is plugged in when the PSoC board is programmed, it displays a single 0 on each line. We expected this but when I would change the default readings at the start of the code, the 0's would still be displayed. I've cleaned up some stuff that I don't think I'll need and am no longer using a printf() as LCD_PrintNumber() seems to be giving us data. I also fixed the while loop in task() and spilt task() into ADXLReady() and GetData(). Any ideas how I can get data from the ADXL? I know the registers are correct and I've tried different ADXL's and PSoC boards so it's not a hardware issue.   
0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

First thing to note is that the SPI master is configured wrong. Its set to CPOL=0/CPHA=0, but the data sheet says it needs to be 1/1.

   

Can you attach a scope or logic analyzer to the SPI bus and check what goes over the wire, and whether the ADXL345 actually responds to the commands? Only if you can make sure that it answers it makes sense to look for other problems.

   

Also, your read logic is wrong. You only send the address byte to the ADXL345, but you never receive any data. For that, you need to send a second (dummy) byte, during which the ADXL345 will send your data back (see data sheet, page 16). Don't forget to skip the first byte you get from the read buffer, and you also need to wait for the transmission to finish (readRxStatus / readTXStatus).

   

I suggest you start reading the SPI master component data sheet, at least the API and the functional descriptions, and the ADXL345 data sheet, the part about SPI. Look at especially at the timing diagrams in both data sheets.

   

Btw: you still mix high and low bytes (DATAX0 is low, DATAX1 is high).

0 Likes
Anonymous
Not applicable

1. ADXL345 use the CS pin to switch between I2C and SPI mode, did you follow suggestion from the data sheet "Preventing bus traffic errors"?

   


2. SPI uses the CS pin to restart. It was mentioned by others that the line switches to high if the TX buffer is not filled up fast enough.
 I would suggest to control the CS line via a control register. Or use I2C mode as other suggested.

   


3. Try to read the ID register( which is a constant) first to make sure the SPI and the related circuit is working correctly.

   


4. There are different setting for all the registers, make sure the default reset value is what your wants.
 if not you need to set it up for your application.

   


5. I would suggest to read the values (6 bytes in one go).

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

The SPI clock is set to 150kHz, so I suppose that the PSoC is fast enough to fill the transmit buffer. The real problem is that only a single byte is send, so the ADXL345 never gets a chance to send its data back.

0 Likes
Anonymous
Not applicable
        Thanks for all the suggestions so far, this is my first time working with SPI or I2C so a lot of this is new to me. I tried going the I2C route until I figured out how to get actual numbers displayed (I was getting greek letters, numbers, and random symbols at first) so I continued with the SPI. I won't be able to get into the lab until Tuesday so hopefully I can figure the signal stuff out after that because if I can't it'll be another week because the university will be shut down for the holiday. I've taken a look at the various data sheets involved, but having never used it before it's difficult to know what's used for what and its purpose. Thank you guys for your patience, you're an awesome group of people!   
0 Likes
Anonymous
Not applicable

 how did u do with the sbit?

0 Likes
moro_1580446
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

Hi friends.could u runing adxl345 with spi or i2c?because i cant solved this problem!!!

   

If you solved this problem please give me your project to understanding how i can to do?

   

tanks...

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

So you switched from I2C (the easier interface) to SPI.

   

For every bit (byte) the SPI interface gets one bit (byte) is returned immediately. When the very first byte is sent, the interface does not "know" yet what to answer, so a dummy byte is returned which must be skipped.
SPI has no read command, so you must send dummy bytes to retrieve the information wanted.
A pitfall is the select line which is automatically taken low when a byte is sent. When the buffer is empty it is taken high again. This can lead to interface errors when the byte sequence is not provided fast enough resulting in ss-line glitches.

   

As I said: I2C is easier to handle.

   

 

   

Bob

0 Likes