1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using Antmicro.Renode.Peripherals.Bus;
9 using Antmicro.Renode.Peripherals.Sensor;
10 using Antmicro.Renode.Peripherals.I2C;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Core.Structure.Registers;
14 
15 namespace Antmicro.Renode.Peripherals.Sensors
16 {
17     public class LSM330_Accelerometer : ST_I2CSensorBase<LSM330_Accelerometer.Registers>
18     {
LSM330_Accelerometer()19         public LSM330_Accelerometer()
20         {
21             Reset();
22         }
23 
Reset()24         public override void Reset()
25         {
26             base.Reset();
27             UpdateSensitivity(0);
28         }
29 
30         public decimal AccelerationX { get; set; }
31 
32         public decimal AccelerationY { get; set; }
33 
34         public decimal AccelerationZ { get; set; }
35 
DefineRegisters()36         protected override void DefineRegisters()
37         {
38             Registers.Control6.Define(this)
39                 .WithTaggedFlag("SIM", 0)
40                 .WithReservedBits(1, 2)
41                 .WithValueField(3, 3, name: "FSCALE: Full-scale selection", writeCallback: (_, val) => UpdateSensitivity((uint)val))
42                 .WithTag("BW", 6, 2)
43             ;
44 
45             Registers.OutputXLow.Define(this)
46                 .WithValueField(0, 8, FieldMode.Read, name: "OUT_X_L_A", valueProviderCallback: _ => GetScaledValue(AccelerationX, sensitivity, false))
47             ;
48 
49             Registers.OutputXHigh.Define(this)
50                 .WithValueField(0, 8, FieldMode.Read, name: "OUT_X_H_A", valueProviderCallback: _ => GetScaledValue(AccelerationX, sensitivity, true))
51             ;
52 
53             Registers.OutputYLow.Define(this)
54                 .WithValueField(0, 8, FieldMode.Read, name: "OUT_Y_L_A", valueProviderCallback: _ => GetScaledValue(AccelerationY, sensitivity, false))
55             ;
56 
57             Registers.OutputYHigh.Define(this)
58                 .WithValueField(0, 8, FieldMode.Read, name: "OUT_Y_H_A", valueProviderCallback: _ => GetScaledValue(AccelerationY, sensitivity, true))
59             ;
60 
61             Registers.OutputZLow.Define(this)
62                 .WithValueField(0, 8, FieldMode.Read, name: "OUT_Z_L_A", valueProviderCallback: _ => GetScaledValue(AccelerationZ, sensitivity, false))
63             ;
64 
65             Registers.OutputZHigh.Define(this)
66                 .WithValueField(0, 8, FieldMode.Read, name: "OUT_Z_H_A", valueProviderCallback: _ => GetScaledValue(AccelerationZ, sensitivity, true))
67             ;
68         }
69 
UpdateSensitivity(uint val)70         private void UpdateSensitivity(uint val)
71         {
72             var range = 0;
73             switch(val)
74             {
75                 case 0:
76                     range = 2;
77                     break;
78                 case 1:
79                     range = 4;
80                     break;
81                 case 2:
82                     range = 6;
83                     break;
84                 case 3:
85                     range = 8;
86                     break;
87                 case 4:
88                     range = 16;
89                     break;
90                 default:
91                     this.Log(LogLevel.Warning, "Tried to set an unsupported sensitivity value: {0}", val);
92                     return;
93             }
94 
95             sensitivity = CalculateScale(-range, range, OutputWidth);
96         }
97 
98         private short sensitivity;
99 
100         private const int OutputWidth = 16;
101 
102         public enum Registers
103         {
104             WhoaAmI = 0x0F,
105 
106             // yes, according to the documentation those are out-of-order;
107             // don't ask
108             Control5 = 0x20,
109             Control4 = 0x23,
110             Control6 = 0x24,
111             Control7 = 0x25,
112 
113             AxisOffsetCorrectionX = 0x10,
114             AxisOffsetCorrectionY = 0x11,
115             AxisOffsetCorrectionZ = 0x12,
116 
117             ConstantShiftX = 0x13,
118             ConstantShiftY = 0x14,
119             ConstantShiftZ = 0x15,
120 
121             LongCounterLow = 0x16,
122             LongCounterHigh = 0x17,
123 
124             InterruptSync = 0x18,
125             SM1_Peak = 0x19,
126             SM2_Peak = 0x1A,
127 
128             VectorFilterCoefficient1 = 0x1B,
129             VectorFilterCoefficient2 = 0x1C,
130             VectorFilterCoefficient3 = 0x1D,
131             VectorFilterCoefficient4 = 0x1E,
132 
133             Threshold3 = 0x1F,
134 
135             Control2 = 0x21,
136             Control3 = 0x22,
137 
138             OutputXLow = 0x28,
139             OutputXHigh = 0x29,
140             OutputYLow = 0x2A,
141             OutputYHigh = 0x2B,
142             OutputZLow = 0x2C,
143             OutputZHigh = 0x2D,
144 
145             FifoControl = 0x2E,
146             FifoSource = 0x2F,
147 
148             // State machine 1 registers
149             SM1_OpCode01 = 0x40,
150             SM1_OpCode02 = 0x41,
151             SM1_OpCode03 = 0x42,
152             SM1_OpCode04 = 0x43,
153             SM1_OpCode05 = 0x44,
154             SM1_OpCode06 = 0x45,
155             SM1_OpCode07 = 0x46,
156             SM1_OpCode08 = 0x47,
157             SM1_OpCode09 = 0x48,
158             SM1_OpCode10 = 0x49,
159             SM1_OpCode11 = 0x4A,
160             SM1_OpCode12 = 0x4B,
161             SM1_OpCode13 = 0x4C,
162             SM1_OpCode14 = 0x4D,
163             SM1_OpCode15 = 0x4E,
164             SM1_OpCode16 = 0x4F,
165 
166             SM1_Timer4 = 0x50,
167             SM1_Timer3 = 0x51,
168             SM1_Timer2Low = 0x52,
169             SM1_Timer2High = 0x53,
170             SM1_Timer1Low = 0x54,
171             SM1_Timer1High = 0x55,
172 
173             SM1_Threshold2 = 0x56,
174             SM1_Threshold1 = 0x57,
175 
176             SM1_AxisSignMaskB = 0x59,
177             SM1_AxisSignMaskA = 0x5A,
178 
179             SM1_Settings = 0x5B,
180             SM1_ProgramReset = 0x5C,
181 
182             SM1_TimerCounterLow = 0x5D,
183             SM1_TimerCounterHigh = 0x5E,
184 
185             SM1_OutputFlags = 0x5F,
186 
187             // State machine 2 registers
188             SM2_OpCode01 = 0x60,
189             SM2_OpCode02 = 0x61,
190             SM2_OpCode03 = 0x62,
191             SM2_OpCode04 = 0x63,
192             SM2_OpCode05 = 0x64,
193             SM2_OpCode06 = 0x65,
194             SM2_OpCode07 = 0x66,
195             SM2_OpCode08 = 0x67,
196             SM2_OpCode09 = 0x68,
197             SM2_OpCode10 = 0x69,
198             SM2_OpCode11 = 0x6A,
199             SM2_OpCode12 = 0x6B,
200             SM2_OpCode13 = 0x6C,
201             SM2_OpCode14 = 0x6D,
202             SM2_OpCode15 = 0x6E,
203             SM2_OpCode16 = 0x6F,
204 
205             SM2_Timer4 = 0x70,
206             SM2_Timer3 = 0x71,
207             SM2_Timer2Low = 0x72,
208             SM2_Timer2High = 0x73,
209             SM2_Timer1Low = 0x74,
210             SM2_Timer1High = 0x75,
211 
212             SM2_Threshold2 = 0x76,
213             SM2_Threshold1 = 0x77,
214 
215             SM2_Decimation = 0x78,
216 
217             SM2_AxisSignMaskB = 0x79,
218             SM2_AxisSignMaskA = 0x7A,
219 
220             SM2_Settings = 0x7B,
221             SM2_ProgramReset = 0x7C,
222 
223             SM2_TimerCounterLow = 0x7D,
224             SM2_TimerCounterHigh = 0x7E,
225 
226             SM2_OutputFlags = 0x7F,
227         }
228     }
229 }
230