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