cancel
Showing results for 
Search instead for 
Did you mean: 

Reading data from L3GD20 (SPI)

Ala1980
Associate II

Hi,

did anyone try to connect to the gyro (L3GD20) on F303Discovery board over SPI?

I have a problem even with reading the WHO_AM_I register:

My code is generated with Cube and I added the following lines:

𝐮𝐢𝐧𝐭𝟖_𝐭 𝐝𝐚𝐭𝐚_𝐰𝐡𝐨𝐚𝐦𝐢, 𝐚𝐝𝐝𝐫𝐞𝐬𝐬_𝐰𝐡𝐨𝐚𝐦𝐢;

𝐚𝐝𝐝𝐫𝐞𝐬𝐬_𝐰𝐡𝐨𝐚𝐦𝐢 = 𝟎𝐱𝟎𝐟 | 𝟎𝐱𝟖𝟎; -- set RW

𝐇𝐀𝐋_𝐆𝐏𝐈𝐎_𝐖𝐫𝐢𝐭𝐞𝐏𝐢𝐧(𝐆𝐏𝐈𝐎𝐄,𝐆𝐏𝐈𝐎_𝐏𝐈𝐍_𝟑, 𝐆𝐏𝐈𝐎_𝐏𝐈𝐍_𝐑𝐄𝐒𝐄𝐓);--reset CS on SPI

𝐇𝐀𝐋_𝐒𝐏𝐈_𝐓𝐫𝐚𝐧𝐬𝐦𝐢𝐭𝐑𝐞𝐜𝐞𝐢𝐯𝐞(&𝐡𝐬𝐩𝐢𝟏, &𝐚𝐝𝐝𝐫𝐞𝐬𝐬_𝐰𝐡𝐨𝐚𝐦𝐢,&𝐝𝐚𝐭𝐚_𝐰𝐡𝐨𝐚𝐦𝐢,𝟐,𝟓𝟎);

𝐇𝐀𝐋_𝐆𝐏𝐈𝐎_𝐖𝐫𝐢𝐭𝐞𝐏𝐢𝐧(𝐆𝐏𝐈𝐎𝐄,𝐆𝐏𝐈𝐎_𝐏𝐈𝐍_𝟑, 𝐆𝐏𝐈𝐎_𝐏𝐈𝐍_𝐒𝐄𝐓);--set CS on SPI

Having that the 𝐌𝐗_𝐒𝐏𝐈𝟏_𝐈𝐧𝐢𝐭() is called before so that the SPI should be initialized correctly, but the problem I can't read the expected WHO_AM_I value (D4)

29 REPLIES 29

Hi @Ala1980​ ,

To obtain degrees from deg/sec you correctly have to integrate the angular speed on time. It is suggested that T1-T0 = 1/ODR.

How to do this, it depend on a number of condition. The simplest way could be -for example- integrating 5 deg/s from T0 to T1 (so you calculate the area of the rectangle with sides T1-T0 and 5deg/s), and then you sum all the ; or you can linearly interpolate and average the T0 and T1 angular speed value, in this case 4 deg/s, and again integrate it in the T1-T0 time. For the sign, if you are not changing the rotational direction (i.e. you are not crossing the line of 0deg/s), you have to sum the areas with the same sign, the one of the output.

As important side note, you should also run periodical calibration of the gyroscope, and for this scope you could use the MotionGC library described here.

-Eleon

Thanks for the reply, I understand that I need to integrate the speed in order to get the angular position (degree).

From your reply I can understand that the gyroscope delivers really the current angular speed (exactly on the moment of reading), and it doesn't care whether the previous angular speed has been read or not!

Maybe I should enlarge the time span in order to convey my idea: So if my sampling rate is 1 minute, and my initial degree is 90°. So I read the gyro once at 13:05:00 (HH:MM:SS) and once at 13:06:00 but the object was only rotating in the time range 13:05:10 till 13:05:50, then, according to my understanding my both readings will give me 0 deg/sec, and as a result I will integrate the 0 value, consequently my calculation will tell me that the object is still on 90° (which is incorrect because I missed the rotation between 13:05:10 till 13:05:50.

Is the goal of MotionGC just to overcome the bias problem of gyro or it does also fusing the sensor data of Acc + Gyro? (Something like Kalman filter)?

Is there any alternative for MotionGC for STM32F3 Discovery? Or at least another software/way for continuously reading of gyro data into my PC?

Hi @Ala1980​ ,

Yes, maybe you should increase the timestamp granularity to get a less ambiguous output of gyroscope integration, especially if you are performing movements that can vary more times during the time of 1 minute...

>> Is the goal of MotionGC just to overcome the bias problem of gyro or it does also fusing the sensor data of Acc + Gyro? (Something like Kalman filter)?

There are other libraries for the sensors' calibration (and fusion, embedding the Kalman Filter), that are part of the X-CUBE-MEMS1 firmware package (folder: \Middlewares\ST) anc can be called from your main project. For example, there are:

  • MotionAC, for the accelerometer calibration;
  • MotionGC, for the gyroscope calibration;
  • MotionFX library, for the sensor fusion, implementing a Kalman filter.

>> Is there any alternative for MotionGC for STM32F3 Discovery? Or at least another software/way for continuously reading of gyro data into my PC?

There should not be problem in running the libraries , since these libraries is designed to be used on STM32 micro-controllers based on the ARM Cortex-M3 (and M4 and M7).

-Eleon

@Eleon BORLINI Thank you again for your help and explanation.

I think I can do further and of course the only means is by increasing my sampling rate, but of course there is always a chance to loose some rotation info in case the vibration of the board is faster than my sampling rate.

Can you also please tell me what is the minimum sampling rate so that I don't worry about missing any info? (having that my application is a small multirotor drone).

BTW, I also read about the FIFO mechanism in L3GD20, but this will be also helpless if my sampling rate is not fast enough.

It is really worth making use of MotionFX for fusing the sensor information, but I didn't find the library under the installation path of my Keil_v5! Can I import the library from anywhere else?

Do you mean that I can use the Unicleo-GUI.exe to transfer the sensor data to my PC?

@Eleon BORLINI

I am using the HAL driver to read the gyor values, I think there is a mistake in the file l3gd20.c on line 396.

Here the raw data should be divided by the sensitivity, but it is multiplied.

Is this a mistake or I don't understand it well?

However, I corrected the l3gd20.c so that I divide by the sensitivity and I get somehow reasonable values, but I still cant read 0 as the output of gyroscope even when the board is completely stationary!

Is this normal? Is this because the gyroscope is too much sensitive, and because the board is not absolutely stationary?

One more question, what are the units of the values being read from the function L3GD20_ReadXYZAngRate? Is it degree per second? in the datasheet of the sensor I see often the abbreviation DPS, but does it mean degree per second?

@Eleon BORLINI could you please help me?

I am really confused about how to correctly read the angular velocity using the function L3GD20_ReadXYZAngRate!!

First If I let the line 396 in l3gd20.c without any change, then angular velocity on X=[-1100, 2300], on Y= [-500, 500], on Z= [-500, 500] (board is stationary)

Then when I change the line 396 so that I divide through the sensitivity, then the angular velocity on X=[14, 27], on Y= [-6, 6], on Z= [-8, 8] (board is stationary).

So my question, is it correct to multiply with the sensitivity? What is then the unit of measurement? It is sure not Degree Per Second!!

Hi @Ala1980​ ,

the correct LSB to physical units (mdps, milli-dps) conversion functions are these ones:

float_t l3gd20h_from_fs245_to_mdps(int16_t lsb)
{
  return ((float_t)lsb * 8.75f);
}
 
float_t l3gd20h_from_fs500_to_mdps(int16_t lsb)
{
  return ((float_t)lsb * 17.50f);
}
 
float_t l3gd20h_from_fs2000_to_mdps(int16_t lsb)
{
  return ((float_t)lsb * 70.0f);
}

You can find them in the Github repository for C drivers for L3GD20 (l3gd20h_reg.c).

Please use these formulas (where "int16" to "float" casting is the usual two's complement conversion).

In you case, supposing FS = 245dps:

LSB(dec): X=[-1100, 2300], on Y= [-500, 500], on Z= [-500, 500] --> milli-dps: X=[-9625, 20125], on Y= [-4375, 4375], on Z= [-4375, 4375] --> dps: X=[-9.625, 20.125], on Y= [-4.375, 4.375], on Z= [-4.375, 4.375].

(why there are two values for the angular rate for each axis?)

Consider that the typical Zero rate level is ±25dps for the F = 2000dps case, so the stationary values are not so far from a reasonable value, especially if your stationary level is actually not fully stationary...

-Eleon

Thanks for the reply, with the 2 values I was meaning the range of the readings.

So even if the board is stationary, then the reading on Y is continuously changing between 500 & -500.

Do you mean then the physical reading should be exactly as follows:

1- reading raw data from OUT_X_L & OUT_X_H (having that CTRL_REG4 is configured for LSB).

2- Pass the reading to the function l3gd20h_from_fs245_to_mdps (having that CTRL_REG4 is configured for 250dps).

3- Then the output of the function l3gd20h_from_fs245_to_mdps will be the angular velocity (in milli degrees per second).

Hi @Ala1980​ ,

you are right, you have to concatenate the OUT_X_H (MSB) and the OUT_X_L (LSB) (step1). This is an integer value in binary format. You cast it with int16 passing the LSB value to the l3gd20h_from_fs245_to_mdps function, so that you convert the binary word into a decimal number with sign through two's complement conversion (step2) and after multiplying it for the sensitivity (8.75 mdps/LSB in the FS = 245dps case) you'll get the data in physical units, i.e. milli-dps (step3)

-Eleon

So I did exactly as explained, and I get some plausible readings, the only problem is with the scale!

My sampling rate is 1/2500us = 1/2.5 ms, so I should multiply each gyro reading by this time interval and then accumulate the value to get the current angle value.

The point which I don't understand is: Assuming that the output of l3gd20h_from_fs245_to_mdps corresponds the physical angle rate in milli degrees per second, then I should multiply this output by 1,000 in order to get the reading in degrees per second.

From other side, since my time interval is 2.5 milli second (I should multiply by 2.5 * 1,000).

As a result, theoretically I can get the angle in degrees by: output of (l3gd20h_from_fs245_to_mdps) * 1,000 * 2.5 * 1,000 (Am I correct)?

In reality I can get plausible values only if I divide through 1,000,000 instead of multiplying by 1,000,000.

So Final angle in degrees can only be obtained using = output of (l3gd20h_from_fs245_to_mdps) * 2.5 / 1,000,000

IS there any explanation for this scale? Or I am missing some point?