-
-
Notifications
You must be signed in to change notification settings - Fork 114
/
Copy pathLsm9Ds1.AccelerometerAndGyroscope.cs
121 lines (104 loc) · 4.34 KB
/
Lsm9Ds1.AccelerometerAndGyroscope.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Buffers.Binary;
using System.Device.I2c;
using System.Device.Model;
using System.Numerics;
namespace Iot.Device.Lsm9Ds1
{
/// <summary>
/// LSM9DS1 accelerometer and gyroscope
/// </summary>
[Interface("LSM9DS1 accelerometer and gyroscope")]
public class Lsm9Ds1AccelerometerAndGyroscope : IDisposable
{
private const byte ReadMask = 0x80;
private const int Max = (1 << 15);
private I2cDevice _i2c;
private AccelerationScale _accelerometerScale;
private AngularRateScale _angularRateScale;
/// <summary>
/// Lsm9Ds1 - Accelerometer and Gyroscope bus
/// </summary>
public Lsm9Ds1AccelerometerAndGyroscope(
I2cDevice i2cDevice,
AccelerationScale accelerationScale = AccelerationScale.Scale02G,
AngularRateScale angularRateScale = AngularRateScale.Scale0245Dps)
{
_i2c = i2cDevice ?? throw new ArgumentNullException(nameof(i2cDevice));
_accelerometerScale = accelerationScale;
_angularRateScale = angularRateScale;
byte accelerometerOutputDataRate = 0b011; // 119Hz, we cannot measure time accurate enough to use higher frequency
WriteByte(RegisterAG.AccelerometerControl6, (byte)((accelerometerOutputDataRate << 5) | ((byte)accelerationScale << 3)));
// enable all 3 axis of gyroscope
WriteByte(RegisterAG.Control4, 0b0011_1000);
byte angularRateOutputDataRate = 0b011; // 119Hz
WriteByte(RegisterAG.AngularRateControl1, (byte)((angularRateOutputDataRate << 5) | ((byte)angularRateScale << 3)));
}
/// <summary>
/// Acceleration measured in degrees per second (DPS)
/// </summary>
[Telemetry]
public Vector3 AngularRate => Vector3.Divide(ReadVector3(RegisterAG.AngularRateX), GetAngularRateDivisor());
/// <summary>
/// Acceleration measured in gravitational force
/// </summary>
[Telemetry]
public Vector3 Acceleration => Vector3.Divide(ReadVector3(RegisterAG.AccelerometerX), GetAccelerationDivisor());
private Vector3 ReadVector3(RegisterAG register)
{
SpanByte vec = new byte[6];
Read(register, vec);
short x = BinaryPrimitives.ReadInt16LittleEndian(vec.Slice(0, 2));
short y = BinaryPrimitives.ReadInt16LittleEndian(vec.Slice(2, 2));
short z = BinaryPrimitives.ReadInt16LittleEndian(vec.Slice(4, 2));
return new Vector3(x, y, z);
}
private void WriteByte(RegisterAG register, byte data)
{
SpanByte buff = new byte[2]
{
(byte)register,
data
};
_i2c.Write(buff);
}
private short ReadInt16(RegisterAG register)
{
SpanByte val = new byte[2];
Read(register, val);
return BinaryPrimitives.ReadInt16LittleEndian(val);
}
private void Read(RegisterAG register, SpanByte buffer)
{
_i2c.WriteByte((byte)((byte)register | ReadMask));
_i2c.Read(buffer);
}
// intentionally return float
// we have 16-bit signed number
// we can use int since our divisors are powers of 2
private float GetAccelerationDivisor() => _accelerometerScale switch
{
AccelerationScale.Scale02G => Max / 2,
AccelerationScale.Scale04G => Max / 4,
AccelerationScale.Scale08G => Max / 8,
AccelerationScale.Scale16G => Max / 16,
_ => throw new ArgumentException(nameof(_accelerometerScale), "Value is unknown."),
};
// we have 16-bit signed number
private float GetAngularRateDivisor() => _angularRateScale switch
{
AngularRateScale.Scale0245Dps => Max / 245,
AngularRateScale.Scale0500Dps => Max / 500,
AngularRateScale.Scale2000Dps => Max / 2000,
_ => throw new ArgumentException(nameof(_angularRateScale), "Value is unknown."),
};
/// <inheritdoc/>
public void Dispose()
{
_i2c?.Dispose();
_i2c = null!;
}
}
}