Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
5 years, 10 months ago.
SPI Communication with L3G4200D Digital Gyroscope Sensor
I am using LPC1768 and L3G4200D digital gyroscope sensor. I need them to communicate through SPI where Mbed (Master) able to read the data from the gyroscope sensor (Slave). Can anyone help out?
SPI gyroscope
#include "mbed.h" SPI spi(p5, p6, p7); // mosi, miso, sclk DigitalOut cs(p8); Serial pc(USBTX, USBRX); int main() { // Slave select disabled // cs = 1; // Setup the spi for 8 bit data, high steady state clock, // Second edge capture, with a 1MHz clock rate spi.format(8,3); spi.frequency(500000); // Slave select enabled, it is active low // cs = 0; // Send 0x8F, the command to read the WHO_AM_I register // // 0x8F 1000 1111, MSB = 0 means write and MSB = 1 means read // spi.write(0x8F); // Send a dummy byte to receive the contents of the WHO_AM_I register // // The default response 1101 0011 // int whoami = spi.write(0x00); pc.printf("WHOAMI register = 0x%X\n", whoami); // Slave select disabled // cs = 1; while(1) { cs = 0 ; // Register address for OUT_X_L of the gyroscope // spi.write(0x28 & ~0x8F); int data = spi.write(0x00); pc.printf("data output 0x%X\n", data); wait(0.5); cs = 1; } }
2 Answers
5 years, 10 months ago.
You have a number of issues with your code.
Going by the datasheet here the default startup mode for the device is in power down mode. You need to set the PD bit in CRTL_REG1 to 1 to enable things. There could well be some other startup that you need to do, check the register descriptions for any defaults that aren't what you want.
Secondly you look like you are trying to read the low byte of the X axis at address 0x28 however
0x28 = 0010 1000 0x8F = 10001111 ~0x8F = 01110000 0x28 & ~0x8F = 0x00100000 = 0x20
So you will in fact be writing to the control register. Given the next transaction you are writing a 0.
If you want to perform a read by setting the most significant bit then you want spi.write(0x28 | 0x80)
Even better use some defines e.g.
#define READ 0x80 #define WRITE 0x00 // not really needed but lets you explicitly say READ or WRITE on every transfer, it makes for clearer code. #define AUTO_ADDRESS 0x40 // auto increment address when reading/writing multiple bytes. #define REG_OUT_X_LOW 0x28 ... spi.write(REG_OUT_X_LOW | READ | AUTO_ADDRESS ); lowByte = spi.write(0); highByte = spi.write(0);
Make sure you do read both the high and low registers for the axis and combine them, just reading the low byte will result in a bit of a random number generator.
Hey Andy, thanks for your explanation and appreciate your effort of trying to make things clearer for me. By the way, do you know how to combine the data from high and low registers and convert it to a decimal value? Why is there both high and low registers or what is the difference between them?
posted by 10 Aug 2018There are two registers because the sensor has a 16 bit output but only 8 bits per register. The high register holds the top 8 bits, the low register the bottom 8 bits.
Combining them is easy, just shift the high byte left by 8 places and then or them together.
spi.write(REG_OUT_X_LOW | READ | AUTO_ADDRESS ); lowByte = spi.write(0); highByte = spi.write(0); int16_t combinedValue = (int16_t)highByte<<8 | lowByte;
Mathematically this is identical to saying int16_t combinedValue = highByte * 256 + lowByte;
but you will normally see this sort of thing done using the logical / bitwise operators. This is because logical operators are faster than arithmetic ones. However these days a good compiler should be able to figure out that it could make that change itself and the benefits are fairly small so feel free to use the second version if you find it makes things clearer for you.
Converting from the combined value to a decimal number depends on how you configure it. CTRL_REG4 lets you set the full scale value to either 250, 500 or 2000 degrees per second. The default is 250. Table 2.1 of the datasheet then tells you the scale factor to apply for each setting in terms of millidegrees per second.
If it is 250 then you need to multiply the combined value by (8.75 / 1000) to get a rate of turn in degrees per second. For 500 you use 17.5/1000 and for 2000 you use 70.0/1000 (70.0 not 70 so that the compiler knows this is a floating point operation not an integer one)
posted by 10 Aug 20185 years, 10 months ago.
Hello huiying,
Can you tell us the problem you are experiencing? It seems like you might not be reading the data correctly.
Please let me know if you have any questions!
- Peter, team Mbed
If this solved your question, please make sure to click the "Thanks" link below!