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

I don't know where are the definitions of the mentioned functions l3gd20h_dev_reset_set, l3gd20h_gy_data_rate_set (in order to call them)!

I wrote in REG4 manually instead of calling the functions l3gd20h_block_data_update_set, l3gd20h_gy_full_scale_set as follows:

GYRO_IO_Read(&tmp, L3GD20_CTRL_REG4_ADDR, 1);

tmp |= 0xB0;

GYRO_IO_Write(&tmp, L3GD20_CTRL_REG4_ADDR, 1);

But still I get one single reading from L3GD20_ReadXYZAngRate, which doesnt change as I moving the board.

One more question, once I succeed to continuously read the gyroscope values, then would these readings be current anglereates relative to zero state or relative to the previous reading?

In other words, if I read the following:

  • time t1: AngleRateX = 40
  • time t2 = t1 + 10ms: AngleRateX = 60

Would this mean that within 10ms there is a change of 20 on X Axis (or change of 60)?

Ala1980
Associate II

I added the following lines for initializing the Gyro, but got also unexpected readings:

ctrl1 = (uint8_t) (L3GD20_MODE_ACTIVE | L3GD20_OUTPUT_DATARATE_4 |

L3GD20_AXES_ENABLE | L3GD20_BANDWIDTH_4);

ctrl4 = (uint8_t) (L3GD20_BlockDataUpdate_Single | L3GD20_BLE_LSB | L3GD20_FULLSCALE_250);

GYRO_IO_Write(&ctrl1, L3GD20_CTRL_REG1_ADDR, 1);

GYRO_IO_Write(&ctrl4, L3GD20_CTRL_REG4_ADDR, 1);

The problem is now, I read varying values on the axes even if the board is completely stable (and the readings vary in a very big range (-300 -> +300).

Is there any declaration for this?

Thanks in advance

Hi @Ala1980โ€‹ ,

glad to hear you did some progress.

Are you correctly interpreting the received data? The following one is the conversion formula (see l3gd20h_reg.c:(

float_t l3gd20h_from_fs245_to_mdps(int16_t lsb)
{
  return ((float_t)lsb * 8.75f);
}

Let me please know.

-Eleon

But multiplying the readings by 8 will increase the problem!

So, my problem was that as if the sensor is too much sensitive.

Even when the board is stable on a table, I see that the reading is varying too much (between -300 -> +300).

@Eleon BORLINIโ€‹ Could you please explain why you want me to multiply the reading by 8.75?

Hi @Ala1980โ€‹ ,

please note that the sensitivity So at FS 245dps is 8.45 mdps/digit (as described in the datasheet at p.10), so the data conversion from LSB to milli dps must take into account that sensitivity).

Can you please share the binary / hexadecimal data? Are you following these steps for data conversion?

  1. Concatenate, for example, OUT_X_H (29h) and OUT_X_L (28h) in this order
  2. Convert the 16bit value in decimal two's complement.
  3. Multiply the value by 8.45 /1000 dps

Can you please also try to shake your board and see if the values are increasing significantly?

-Eleon

@Eleon Berlini Thanks for your reply, I use the function L3GD20_ReadXYZAngRate which in truns take care about concatenating, multiplying by 8.45, but I don't see anywhere the two's complement conversion! neither I see dividing by 1000!

The problem is, even when I don't shake the board, then the reading is changing very quickly (but I notice also that when I change it and when the shake is strong, then the reading is also much bigger, which means that it works somehow)

void L3GD20_ReadXYZAngRate(float *pfData)
{
  uint8_t tmpbuffer[6] ={0};
  int16_t RawData[3] = {0};
  uint8_t tmpreg = 0;
  float sensitivity = 0;
  int i =0; 
  GYRO_IO_Read(&tmpreg,L3GD20_CTRL_REG4_ADDR,1); 
  GYRO_IO_Read(tmpbuffer,L3GD20_OUT_X_L_ADDR,6); 
  /* check in the control register 4 the data alignment (Big Endian or Little Endian)*/
  if(!(tmpreg & L3GD20_BLE_MSB))
  {
    for(i=0; i<3; i++)
    {
      RawData[i]=(int16_t)(((uint16_t)tmpbuffer[2*i+1] << 8) + tmpbuffer[2*i]);
    }
  }
  else
  {
    for(i=0; i<3; i++)
    {
      RawData[i]=(int16_t)(((uint16_t)tmpbuffer[2*i] << 8) + tmpbuffer[2*i+1]);
    }
  } 
  /* Switch the sensitivity value set in the CRTL4 */
  switch(tmpreg & L3GD20_FULLSCALE_SELECTION)
  {
  case L3GD20_FULLSCALE_250:
    sensitivity=L3GD20_SENSITIVITY_250DPS;
    break;   
  case L3GD20_FULLSCALE_500:
    sensitivity=L3GD20_SENSITIVITY_500DPS;
    break;   
  case L3GD20_FULLSCALE_2000:
    sensitivity=L3GD20_SENSITIVITY_2000DPS;
    break;
  }
  /* Divide by sensitivity */
  for(i=0; i<3; i++)
  {
    pfData[i]=(float)(RawData[i] * sensitivity);
  }
}

Hi @Ala1980โ€‹ ,

you have to divide by 1000 to get dps instead of milli - dps (which is the unit of measure of the sensitivity). 300 LSB *8.45 means about 2500 mdps, i.e. 2.5 dps, which is the typical noise you have to expect from L3GD20 device, as you can see from the zero rate level parameter values in the datasheet, p. 9:

0693W000004JNhRQAW.png 

I can say you that the L3GD20 is not the best-in-class gyroscope for the noise purpose: you should switch to more recent products such as LSM6DSO family IMUs, to reduce noise by a 10 factor...

However, to reduce the noise in L3GD20 device, you may enable the high pass filter by setting 1 the HPen bit of CTRL_REG5 (24h) register and configuring the appropriate bits in CTRL_REG2 (21h) register.

-Eleon

Thank you very much, actually after dividing by 1000 I get so plausible readings (maybe with some noise).

Yes I will activate the high pass filter too in order to get better results.

My next question is, when I get a reading from Gyro (on time T) then this is the change of the angelrate between (T-1 =>T), am I correct?

If yes, then what happens if I pass the reading on T and start my reading on T+1, then would the reading correspond the anglerate between (T-1 => T) or (T-1 => T+1).

Please accept my primitive question but this is for me very important to have further steps (fusing the readings with Accelerometer).

Hi @Ala1980โ€‹ ,

>> My next question is, when I get a reading from Gyro (on time T) then this is the change of the angle rate between (T-1 =>T), am I correct?

The output of the gyroscope at time T is the value of the angular velocity at time T, or, better, the average of the angular velocity value between T-1 and T (sampled by the internal clock, which runs higher than ODR), where T-1 and T are defined by the chosen ODR (output data rate). For example, if ODR = 100Hz, the T step is 1/100 s = 10ms.

So, defining the angular velocity as the rate of change of an angle in time, basically you are right.

The answer to your other question is that, even if you miss a reading (e.g. at time T), the gyroscope will keep outputting the angular variation internally calculated in the last 1/ODR timeframe, so will output the variation between the angle at T and at T+1 (even if angle at T has not been actually read by the user).

-Eleon

Ala1980
Associate II

I understand that the gyroscope measures the change in angle on each axis, in other words it measures the angular speed in deg/sec (or in other scale).

My question is, in case the gyroscope was rotating with 5 deg/sec on T0 and then with 3 deg/sec on T1 and then stopped rotating (i.e. on T2 was is rotating 0 deg/sec).

So in my application if my sampling rate is equal to T2-T0 and if my first measurement was at time T0 = 5 deg/sec then what would I read at next sample (on T2), would I read 0?

Acutally this is not so drastic if I average the speed values.

More drastic if the rotation is only between my samples, so in the example above if it was rotating 0 deg/sec on T0, 5 deg/sec on T1 and 0 deg/sec on T2, then the readings will tell me that it is stationary but it rotates actually!!

Is there any explanation pleas? Or maybe I don't understand the whole issue!!