Pololu Zumo Shield Arduino Library
L3G.cpp
1 #include <L3G.h>
2 #include <Wire.h>
3 #include <math.h>
4 
5 // Defines ////////////////////////////////////////////////////////////////
6 
7 // The Arduino two-wire interface uses a 7-bit number for the address,
8 // and sets the last bit correctly based on reads and writes
9 #define D20_SA0_HIGH_ADDRESS 0b1101011 // also applies to D20H
10 #define D20_SA0_LOW_ADDRESS 0b1101010 // also applies to D20H
11 #define L3G4200D_SA0_HIGH_ADDRESS 0b1101001
12 #define L3G4200D_SA0_LOW_ADDRESS 0b1101000
13 
14 #define TEST_REG_ERROR -1
15 
16 #define D20H_WHO_ID 0xD7
17 #define D20_WHO_ID 0xD4
18 #define L3G4200D_WHO_ID 0xD3
19 
20 // Constructors ////////////////////////////////////////////////////////////////
21 
22 L3G::L3G(void)
23 {
24  _device = device_auto;
25 
26  io_timeout = 0; // 0 = no timeout
27  did_timeout = false;
28 }
29 
30 // Public Methods //////////////////////////////////////////////////////////////
31 
32 // Did a timeout occur in read() since the last call to timeoutOccurred()?
33 bool L3G::timeoutOccurred()
34 {
35  bool tmp = did_timeout;
36  did_timeout = false;
37  return tmp;
38 }
39 
40 void L3G::setTimeout(unsigned int timeout)
41 {
42  io_timeout = timeout;
43 }
44 
45 unsigned int L3G::getTimeout()
46 {
47  return io_timeout;
48 }
49 
50 bool L3G::init(deviceType device, sa0State sa0)
51 {
52  int id;
53 
54  // perform auto-detection unless device type and SA0 state were both specified
55  if (device == device_auto || sa0 == sa0_auto)
56  {
57  // check for L3GD20H, D20 if device is unidentified or was specified to be one of these types
58  if (device == device_auto || device == device_D20H || device == device_D20)
59  {
60  // check SA0 high address unless SA0 was specified to be low
61  if (sa0 != sa0_low && (id = testReg(D20_SA0_HIGH_ADDRESS, WHO_AM_I)) != TEST_REG_ERROR)
62  {
63  // device responds to address 1101011; it's a D20H or D20 with SA0 high
64  sa0 = sa0_high;
65  if (device == device_auto)
66  {
67  // use ID from WHO_AM_I register to determine device type
68  device = (id == D20H_WHO_ID) ? device_D20H : device_D20;
69  }
70  }
71  // check SA0 low address unless SA0 was specified to be high
72  else if (sa0 != sa0_high && (id = testReg(D20_SA0_LOW_ADDRESS, WHO_AM_I)) != TEST_REG_ERROR)
73  {
74  // device responds to address 1101010; it's a D20H or D20 with SA0 low
75  sa0 = sa0_low;
76  if (device == device_auto)
77  {
78  // use ID from WHO_AM_I register to determine device type
79  device = (id == D20H_WHO_ID) ? device_D20H : device_D20;
80  }
81  }
82  }
83 
84  // check for L3G4200D if device is still unidentified or was specified to be this type
85  if (device == device_auto || device == device_4200D)
86  {
87  if (sa0 != sa0_low && testReg(L3G4200D_SA0_HIGH_ADDRESS, WHO_AM_I) == L3G4200D_WHO_ID)
88  {
89  // device responds to address 1101001; it's a 4200D with SA0 high
90  device = device_4200D;
91  sa0 = sa0_high;
92  }
93  else if (sa0 != sa0_high && testReg(L3G4200D_SA0_LOW_ADDRESS, WHO_AM_I) == L3G4200D_WHO_ID)
94  {
95  // device responds to address 1101000; it's a 4200D with SA0 low
96  device = device_4200D;
97  sa0 = sa0_low;
98  }
99  }
100 
101  // make sure device and SA0 were successfully detected; otherwise, indicate failure
102  if (device == device_auto || sa0 == sa0_auto)
103  {
104  return false;
105  }
106  }
107 
108  _device = device;
109 
110  // set device address
111  switch (device)
112  {
113  case device_D20H:
114  case device_D20:
115  address = (sa0 == sa0_high) ? D20_SA0_HIGH_ADDRESS : D20_SA0_LOW_ADDRESS;
116  break;
117 
118  case device_4200D:
119  address = (sa0 == sa0_high) ? L3G4200D_SA0_HIGH_ADDRESS : L3G4200D_SA0_LOW_ADDRESS;
120  break;
121  }
122 
123  return true;
124 }
125 
126 /*
127 Enables the L3G's gyro. Also:
128 - Sets gyro full scale (gain) to default power-on value of +/- 250 dps
129  (specified as +/- 245 dps for L3GD20H).
130 - Selects 200 Hz ODR (output data rate). (Exact rate is specified as 189.4 Hz
131  for L3GD20H and 190 Hz for L3GD20.)
132 Note that this function will also reset other settings controlled by
133 the registers it writes to.
134 */
135 void L3G::enableDefault(void)
136 {
137  if (_device == device_D20H)
138  {
139  // 0x00 = 0b00000000
140  // Low_ODR = 0 (low speed ODR disabled)
141  writeReg(LOW_ODR, 0x00);
142  }
143 
144  // 0x00 = 0b00000000
145  // FS = 00 (+/- 250 dps full scale)
146  writeReg(CTRL_REG4, 0x00);
147 
148  // 0x6F = 0b01101111
149  // DR = 01 (200 Hz ODR); BW = 10 (50 Hz bandwidth); PD = 1 (normal mode); Zen = Yen = Xen = 1 (all axes enabled)
150  writeReg(CTRL_REG1, 0x6F);
151 }
152 
153 // Writes a gyro register
154 void L3G::writeReg(byte reg, byte value)
155 {
156  Wire.beginTransmission(address);
157  Wire.write(reg);
158  Wire.write(value);
159  last_status = Wire.endTransmission();
160 }
161 
162 // Reads a gyro register
163 byte L3G::readReg(byte reg)
164 {
165  byte value;
166 
167  Wire.beginTransmission(address);
168  Wire.write(reg);
169  last_status = Wire.endTransmission();
170  Wire.requestFrom(address, (byte)1);
171  value = Wire.read();
172  Wire.endTransmission();
173 
174  return value;
175 }
176 
177 // Reads the 3 gyro channels and stores them in vector g
178 void L3G::read()
179 {
180  Wire.beginTransmission(address);
181  // assert the MSB of the address to get the gyro
182  // to do slave-transmit subaddress updating.
183  Wire.write(OUT_X_L | (1 << 7));
184  Wire.endTransmission();
185  Wire.requestFrom(address, (byte)6);
186 
187  unsigned int millis_start = millis();
188  while (Wire.available() < 6)
189  {
190  if (io_timeout > 0 && ((unsigned int)millis() - millis_start) > io_timeout)
191  {
192  did_timeout = true;
193  return;
194  }
195  }
196 
197  uint8_t xlg = Wire.read();
198  uint8_t xhg = Wire.read();
199  uint8_t ylg = Wire.read();
200  uint8_t yhg = Wire.read();
201  uint8_t zlg = Wire.read();
202  uint8_t zhg = Wire.read();
203 
204  // combine high and low bytes
205  g.x = (int16_t)(xhg << 8 | xlg);
206  g.y = (int16_t)(yhg << 8 | ylg);
207  g.z = (int16_t)(zhg << 8 | zlg);
208 }
209 
210 void L3G::vector_normalize(vector<float> *a)
211 {
212  float mag = sqrt(vector_dot(a,a));
213  a->x /= mag;
214  a->y /= mag;
215  a->z /= mag;
216 }
217 
218 // Private Methods //////////////////////////////////////////////////////////////
219 
220 int L3G::testReg(byte address, regAddr reg)
221 {
222  Wire.beginTransmission(address);
223  Wire.write((byte)reg);
224  if (Wire.endTransmission() != 0)
225  {
226  return TEST_REG_ERROR;
227  }
228 
229  Wire.requestFrom(address, (byte)1);
230  if (Wire.available())
231  {
232  return Wire.read();
233  }
234  else
235  {
236  return TEST_REG_ERROR;
237  }
238 }