Need SPI & Register Explication

27 Apr 2011

Hello,

I have buy an accelerometer their communicate with SPI.

I need some explication for the SPI with mbed.

How communicate with the $16 register for exemple ?

just : <<code>>mySpi.write(0x16);<</code>>

http://www.abcelectronique.com/forum/attachment.php?attachmentid=36298

For exemple if i want modifie the range of my accelerometer ( see the picture ).

How i do ??

Thanks & sorry for my english so bad !

27 Apr 2011

A couple of points:

  1. SPI target devices usually have a dedicated pin for "chip select". This would be driven by a DigitalOut pin on the mbed.
  2. The serial protocol for your specific device should explain how register addresses are encoded. Often, the address field is merged into the data field and they are sent together in, say, a 16-bit serial transfer.

Hope that helps.

28 Apr 2011

Can you help me for start, with an exemple please ?

I have find that : http://mbed.org/users/simon/libraries/LIS302/le4jy6/docs/

It's a library for Accelerometer type LIS302. I have read this librairy but i don't understand many things.

This is the datasheet of my accelerometer

http://docs-europe.electrocomponents.com/webdocs/0ef4/0900766b80ef40e7.pdf

And this is my so beginning of librairy for 7455LR1 accelerometer.

#include "mbed.h"
#include "7455LR1.h"

7455LR1 :: 7455LR1(PinName mosi, PinName miso, PinName sck, pinName cs): _SPI(mosi,miso,sck), _cs(cs){
    }

bool 7455LR1 :: range(int g){
    if( g != 2 && g!= 4 && g!= 8)
        return false;
    
    
    
    
    return true;
    }
28 Apr 2011

Your part is very similar to the LIS302, so Simon's library should make a good reference.

A few hints:

Replace the register definitions and constants in lines 26 - 55 of the LIS302 library with their equivalents for the MMA7455L (see page 21 of the data sheet). For example,

// Start with register address definitions
#define  MMA7455_XOUTL          0x00
#define  MMA7455_XOUTH          0x01
#define  MMA7455_YOUTL          0x02
...
#define  MMA7455_TW             0x1E

// Then add bit definitions as needed
#define  MMA7455_READ           0x00   // RD bit flag for serial commands
#define  MMA7455_WRITE          0x80   // WR bit flag for serial commands
#define  MMA7455_I2CAD_I2CDIS   0x80   // Mode bit "I2CDIS" is D7. Located in register "I2CAD"
#define  MMA7455_MCTL_MEASURE   0x01   // Measurement mode = 01. Located in register "MCTL"
...

Now you are ready to put in general purpose routines to read or write to the MMA7455. These routines will then be called by higher level logic in your driver.

Be sure you have set up the spi port for proper pin assignment, speed, mode, etc. Then you will need something like this:

SPI spi(p5, p6, p7); // mosi, miso, sclk
DigitalOut ncs(p8);

void devicewrite(char targetregister, char command) {
     ncs = 0;
     spi.write(MMA7455_WRITE | targetregister);
     spi.write(command);
     ncs = 1;
}

unsigned char deviceread (char targetregister) {
     unsigned char result;

     ncs = 0;
     spi.write(MMA7455_READ | targetregister);
     result = spi.write(0x00);
     ncs = 1; 
     return(result);  
}

Then you need to initialize the part. Looking over the spec quickly, it seems that the I2C port needs to be disabled, and the operational mode selected. So your init code should include:

   devicewrite(MMA7455_I2CAD, MMA7455_I2CAD_I2CDIS); // Disable I2C access
   devicewrite(MMA7455_MCTL, MMA7455_MCTL_MEASURE);  // Set mode to "Measurement"

You will need to convert the "C" code examples above into the proper form for a C++ driver. The LIS302 driver should be an excellent guide for this, and for implementing the rest of the methods.

Good luck.

29 Apr 2011

Thanks for your reply !

I have use your code in my program and I understand better now !

So, I have write that :

#include "mbed.h"

#include "7455LR1.h"

 // Commencer par vous inscrire définitions adresse
 #define MMA7455_XOUTL 0x00
 #define MMA7455_XOUTH 0x01
 #define MMA7455_YOUTL 0x02
 #define  MMA7455_I2CAD 0x0D
 #define MMA7455_MCTL 0x16
 #define MMA7455_TW 0x1E

 // Ensuite, ajouter des définitions de bits selon les besoins
 #define MMA7455_READ 0x00            // bit indicateur RD pour les commandes de série
 #define MMA7455_WRITE 0x80          // indicateur binaire WR pour les commandes de série
 #define MMA7455_I2CAD_I2CDIS  0x80 // Mode bit "I2CDIS" est D7.  Situé dans le registre "I2CAD"
 #define MMA7455_MCTL_MEASURE 0x01 // mode de mesure = 01.  Situé dans le registre "MCTL"

<</code>

<<code>>

A7455LR1 :: A7455LR1(PinName mosi, PinName miso, PinName sck, PinName cs): _spi(mosi,miso,sck), _cs(cs){
    devicewrite(MMA7455_I2CAD, MMA7455_I2CAD_I2CDIS); // desactivation mode I2C
    devicewrite(MMA7455_MCTL, MMA7455_MCTL_MEASURE);  // mettre en mode mesure
    minX = -1;
    minY = -1;
    minZ = -1;
    maxX = 1;
    maxY = 1;
    maxZ = 1;
    }
void A7455LR1 :: devicewrite(char targetregister, char command) {
     _cs = 0;
     _spi.write(MMA7455_WRITE | targetregister);
     _spi.write(command);
     _cs = 1;
}

signed char A7455LR1 :: deviceread (char targetregister) {
      signed char result;
     _cs = 0;
     _spi.write(MMA7455_READ | targetregister);
     result = _spi.write(0x00);
     _cs = 1; 
     return(result);  
}
float A7455LR1 :: x(){
    signed char value = deviceread( MMA7455_XOUTL );
    float gradient = (2.0/(maxX-minX));
    return (gradient*(float)(value)/64.0)+((-gradient*maxX)+1);
    }
    
void A7455LR1 :: calibrate(float minx,float maxx, float miny, float maxy, float minz, float maxz){
      minX = minx;
      minY = miny;
      minZ = minz;
      maxX = maxx;
      maxY = maxy;
      maxZ = maxz;
    }

As you can see, it's to many your code ! I have write the x() method.

But when I read this value on a pc.printf(..); the value is always 0, even if i move my accelerometer. Have you a idea ???

I have divide the result by 64.0 because in the datasheet I have see that :

Quote:

Sensitivity (TA=25°C, AVDD = 2.8 V)

±2g range (25°C) 8-bit |58 | 64 | 70 count/g

±4g range (25°C) 8-bit |29 | 32 | 35 count/g

±8g range (25°C) 8-bit |14.5 | 16 | 17.5 count/g

±8g range (25°C) 10-bit |58 | 64 | 70 count/g

29 Apr 2011

I think I have a bad wiring..

I call this method :

#define MMA7455_WHOAMI 0x0F

int A7455LR1 :: whoami() {
     return (int)(deviceread(MMA7455_WHOAMI));
     }

And the result it's again : 0

My cablage is :

Quote:

ACCELEROMETER => MBED

1 DVDD_IO => VOUT

2 GND => GND

3 N/C => NC

4 IADDR0 => VOUT

5 GND => GND

6 AVDD=> VCC

7 /CS => p14

8 INT1/DRDY => p16

9 INT2 => p15

10 N/C => NC

11 N/C => NC

12 SDO => p12 MISO

13 SDA/SDI/SDO => p11 MOSI

14 SCL/SCP => p13 SCK

And my object accelerometer is call :

A7455LR1 accelero(p11,p12,p13,p14);

It's ok or not ? .. I don't understand the problem ..

29 Apr 2011

Your wiring and code look OK so far. Some things to consider:

  1. The "whoami" register may not be a good test of the readback function. It looks like it returns "0" if the one-time programming links have not been blown.
  2. The chip takes a long time to do conversions (like 8 ms). Test bit DRDY in the status register to see if data is valid (see page 9).
  3. As you noted, the chip reports 16 counts/g (on the +/- 8g range). But since you are dividing by 64, you won't see anything for forces less than 4g. Try removing the division and see if you read about +/-16 on one axis when the chip is at rest.

[Edit: one more thing. Try reading XOUT8/YOUT8/ZOUT8. That will get you 8-bit data. The *OUTL/*OUTH registers are for 10-bit data, and each pair should be read in immediate succession...see the note at the bottom of page 21, for more info.]

02 May 2011

I have test that :

unsigned char  A7455LR1 :: test(){
    devicewrite(0x16, 0x01);
    return  deviceread(0x16);
    }

..............
..............
// In the main 
..............
..............
Serial pc(USBTX,USBRX);
A7455LR1 accelero(p11,p12,p13,p14);

int main() {
    while(1) {
        pc.printf("%x\n\r",accelero.test());
        wait(1);
        }
}

Normally this should return 1? No ?

But this returns 0 .. Always 0, there have a problem ?

I don't understand ..

02 May 2011

It looks like the MMA7455 requires 16 SPI clocks to perform transfers. See the top of page 18, last line of "SPI Slave Interface" section.

So try the following:

  • set the SPI format to (16,0) to get 16-bit transfers
  • change low-level read and write routines to feed the spi hardware "short" in place of chars.
  • for transmit, send the address/command byte as the MSB of the short (the LSB can be any dummy value)
  • for receive, return the LSB of the data
02 May 2011

Sorry I don't understand the 3 last points

04 May 2011

The write and read routines should look something like this:

void devicewrite(char targetregister, char command) {
     ncs = 0;
     spi.write( (MMA7455_WRITE << 8) | (targetregister << 7) | command );
     ncs = 1;
}

unsigned char deviceread (char targetregister) {
     unsigned char result;

     ncs = 0;
     result = (unsigned char) spi.write( (MMA7455_READ << 8) | (targetregister << 7) );
     result = spi.write(0x00);
     ncs = 1; 
     return(result);  
}

This should arrange the address and data values correctly for 16-bit transfers.