Skyward boardcore
Loading...
Searching...
No Matches
L3GD20.h
Go to the documentation of this file.
1
2/* Copyright (c) 2019 Skyward Experimental Rocketry
3 * Author: Luca Erbetta
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#pragma once
25
28#include <miosix.h>
29#include <sensors/Sensor.h>
30
31#include <Eigen/Core>
32#include <array>
33
34#include "L3GD20Data.h"
35
36namespace Boardcore
37{
38
39static constexpr uint32_t L3GD20_FIFO_SIZE = 32;
40
41class L3GD20 : public SensorFIFO<L3GD20Data, L3GD20_FIFO_SIZE>
42{
43public:
44 enum class FullScaleRange
45 {
46 FS_250 = 250,
47 FS_500 = 500,
48 FS_2000 = 2000
49 };
50
51 enum class OutPutDataRate
52 {
53 ODR_95 = 95,
54 ODR_190 = 190,
55 ODR_380 = 380,
56 ODR_760 = 760
57 };
58
68 L3GD20(SPIBusInterface& bus, miosix::GpioPin cs,
71 uint8_t cutoffFreq = 0x03)
72 : L3GD20(bus, cs, {}, range, odr, cutoffFreq)
73 {
74 // Configure SPI
76 }
77
88 L3GD20(SPIBusInterface& bus, miosix::GpioPin cs, SPIBusConfig cfg,
91 uint8_t cutoffFreq = 0x03)
92 : spislave(bus, cs, cfg), fs(range), odr(odr), cutoffFreq(cutoffFreq)
93 {
94 switch (fs)
95 {
97 sensitivity = SENSITIVITY_250;
98 break;
100 sensitivity = SENSITIVITY_500;
101 break;
103 sensitivity = SENSITIVITY_2000;
104 break;
105 }
106 }
107
114 void enableFifo(unsigned int fifoWatermark)
115 {
116 fifoEnabled = true;
117 this->fifoWatermark = fifoWatermark;
118 }
119
120 bool init()
121 {
122 SPITransaction spi(spislave);
123
124 uint8_t whoami = spi.readRegister(REG_WHO_AM_I);
125
126 if (whoami != WHO_AM_I_VAL)
127 {
129 return false;
130 }
131
132 switch (fs)
133 {
135 spi.writeRegister(REG_CTRL4, 0);
136 break;
138 spi.writeRegister(REG_CTRL4, (uint8_t)(1 << 4));
139 break;
141 spi.writeRegister(REG_CTRL4, (uint8_t)(2 << 4));
142 break;
143 default:
144 break;
145 }
146
147 if (fifoEnabled)
148 {
149 // Enable fifo
150 spi.writeRegister(REG_CTRL5, 1 << 6);
151
152 // Set watermark level to fifoWatermark samples
153 uint8_t fifoCtrl = fifoWatermark;
154
155 // Set fifo to STREAM mode
156 fifoCtrl |= 0x02 << 5;
157
158 spi.writeRegister(REG_FIFO_CTRL, fifoCtrl);
159
160 // Enable FIFO watermark interrupt on INT2
161 spi.writeRegister(REG_CTRL3, 0x04);
162 }
163 else
164 {
165 // Enable DRDY interrupt on INT2
166 spi.writeRegister(REG_CTRL3, 0x08);
167 }
168
169 // Enter normal mode, enable output
170 uint8_t ctrl1 = 0x0F;
171
172 // Configure cutoff frequency
173 ctrl1 |= (cutoffFreq & 0x03) << 4;
174
175 // Configure ODR
176 switch (odr)
177 {
179 break;
181 ctrl1 |= 1 << 6;
182 break;
184 ctrl1 |= 2 << 6;
185 break;
187 ctrl1 |= 3 << 6;
188 break;
189 }
190
191 spi.writeRegister(REG_CTRL1, ctrl1);
192
193 return true;
194 }
195
196 bool selfTest() { return true; }
197
199 {
200 if (!fifoEnabled) // FIFO not enabled
201 {
202 // Timestamp of the last sample
203 uint64_t lastSampleTimestamp;
204
205 // Read output data registers (X, Y, Z)
206 {
207 SPITransaction spi(spislave);
208 spi.readRegisters(REG_OUT_X_L | 0x40, buf, 6);
209 }
210
211 {
212 // Disable interrupts and copy the last sample locally, as a new
213 // interrupt may come just as we are reading it and causing a
214 // race condition.
215 miosix::FastInterruptDisableLock dLock;
216 lastSampleTimestamp = lastInterruptTimestamp;
217 }
218
219 int16_t x = buf[0] | buf[1] << 8;
220 int16_t y = buf[2] | buf[3] << 8;
221 int16_t z = buf[4] | buf[5] << 8;
222
223 Eigen::Vector3f rads = toRadiansPerSecond(x, y, z);
224 return {lastSampleTimestamp, rads(0), rads(1), rads(2)};
225 }
226 else // FIFO is enabled
227 {
228 // Lock mutex for thread safe Fifo reading
229 miosix::Lock<miosix::FastMutex> l(mutex);
230
231 SPITransaction spi(spislave);
232 // Read last fifo level
233 uint8_t fifoSrc = spi.readRegister(REG_FIFO_SRC);
234 uint8_t ovr = (fifoSrc & 0x40) >> 7; // Overrun bit
235 uint8_t fifoLevel = (fifoSrc & 0x1F) + ovr;
236
237 // Read fifo
238 spi.readRegisters(REG_OUT_X_L | 0x40, buf, fifoLevel * 6);
239
241
242 uint8_t duplicates = 0;
243 for (uint8_t i = 0; i < fifoLevel; ++i)
244 {
245 bool rmv;
246 // Check for duplicates: there seems to be a bug where the
247 // sensor occasionally shifts out the same sample two times in a
248 // row: discard one
249 if (i < fifoLevel - 1)
250 {
251 rmv = true;
252 for (uint8_t j = 0; j < 6; ++j)
253 {
254 if (buf[i * 6 + j] != buf[(i + 1) * 6 + j])
255 {
256 rmv = false;
257 break;
258 }
259 }
260 }
261 else
262 {
263 rmv = false;
264 }
265
266 if (rmv)
267 {
268 // Skip this sample;
269 ++duplicates;
270 continue;
271 }
272
273 // Assign a timestamp to each sample in the FIFO based of the
274 // timestamp of the FIFO_WATERMARKth sample and the delta
275 // between the watermark interrupts (evenly distribute the
276 // timestamp between the two times)
277 // Ignoring possible duplicates, the timestamp of the ith sample
278 // in the fifo is:
279 // ts(i) = ts(fifoWatermark) + (i - fifoWatermark)*dt;
280 Eigen::Vector3f rads =
281 toRadiansPerSecond(buf[i * 6] | buf[i * 6 + 1] << 8,
282 buf[i * 6 + 2] | buf[i * 6 + 3] << 8,
283 buf[i * 6 + 4] | buf[i * 6 + 5] << 8);
284
285 lastFifo[i - duplicates] = L3GD20Data{
287 ((int)i - (int)fifoWatermark - (int)duplicates) * dt,
288 rads(0), rads(1), rads(2)};
289 }
290
291 lastFifoLevel = fifoLevel - duplicates;
292 return lastFifo[lastFifoLevel - 1];
293 }
294 }
295
296private:
297 Eigen::Vector3f toRadiansPerSecond(int16_t x, int16_t y, int16_t z)
298 {
299 return Eigen::Vector3f(x * sensitivity, y * sensitivity,
300 z * sensitivity);
301 }
302
303 static constexpr float SENSITIVITY_250 = 0.00875f;
304 static constexpr float SENSITIVITY_500 = 0.0175f;
305 static constexpr float SENSITIVITY_2000 = 0.070f;
306
307 SPISlave spislave;
308
311 uint8_t cutoffFreq = 0x03;
312
313 bool fifoEnabled = false;
314 unsigned int fifoWatermark = 24;
315
316 float sensitivity = SENSITIVITY_250;
317
318 uint8_t buf[192];
319
320 constexpr static uint8_t WHO_AM_I_VAL = 212;
321
322 enum RegMap
323 {
324 REG_WHO_AM_I = 0x0F,
325
326 REG_CTRL1 = 0x20,
327 REG_CTRL2 = 0x21,
328 REG_CTRL3 = 0x22,
329 REG_CTRL4 = 0x23,
330 REG_CTRL5 = 0x24,
331
332 REG_REFERENCE = 0x25,
333 REG_OUT_TEMP = 0x26,
334 REG_STATUS = 0x27,
335
336 REG_OUT_X_L = 0x28,
337 REG_OUT_X_H = 0x29,
338
339 REG_OUT_Y_L = 0x2A,
340 REG_OUT_Y_H = 0x2B,
341
342 REG_OUT_Z_L = 0x2C,
343 REG_OUT_Z_H = 0x2D,
344
345 REG_FIFO_CTRL = 0x2E,
346 REG_FIFO_SRC = 0x2F
347 };
348};
349
350} // namespace Boardcore
SensorErrors lastError
Definition Sensor.h:54
L3GD20(SPIBusInterface &bus, miosix::GpioPin cs, SPIBusConfig cfg, FullScaleRange range=FullScaleRange::FS_250, OutPutDataRate odr=OutPutDataRate::ODR_95, uint8_t cutoffFreq=0x03)
Creates an instance of an L3GD20 sensor.
Definition L3GD20.h:88
L3GD20(SPIBusInterface &bus, miosix::GpioPin cs, FullScaleRange range=FullScaleRange::FS_250, OutPutDataRate odr=OutPutDataRate::ODR_95, uint8_t cutoffFreq=0x03)
Creates an instance of an L3GD20 sensor.
Definition L3GD20.h:68
bool init()
Initialize the sensor.
Definition L3GD20.h:120
L3GD20Data sampleImpl()
Read a data sample from the sensor. In case of errors, the method should return the last available co...
Definition L3GD20.h:198
bool selfTest()
Check if the sensor is working.
Definition L3GD20.h:196
void enableFifo(unsigned int fifoWatermark)
Enables storing samples in a FIFO, must be called before init().
Definition L3GD20.h:114
Interface for low level access of a SPI bus as a master.
Provides high-level access to the SPI Bus for a single transaction.
uint8_t readRegister(uint8_t reg)
Reads an 8 bit register.
void readRegisters(uint8_t reg, uint8_t *data, size_t size)
Reads multiple bytes starting from the specified register.
void writeRegister(uint8_t reg, uint8_t data)
Writes an 8 bit register.
Interface for sensor that implement a FIFO.
Definition Sensor.h:149
std::array< L3GD20Data, FifoSize > lastFifo
Definition Sensor.h:153
miosix::FastMutex mutex
Definition Sensor.h:107
This file includes all the types the logdecoder script will decode.
@ INVALID_WHOAMI
Definition SensorData.h:40
SPI Bus configuration for a specific slave.
SPI::ClockDivider clockDivider
< Peripheral clock division