1 // 2 // Copyright (c) 2010-2020 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.SPI; 13 using Antmicro.Renode.Peripherals.Sensor; 14 using Antmicro.Renode.Utilities; 15 using Antmicro.Renode.Peripherals.I2C; 16 17 namespace Antmicro.Renode.Peripherals.Sensors 18 { 19 public class ADXL372 : ISPIPeripheral, II2CPeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, IGPIOReceiver, ISensor 20 { ADXL372()21 public ADXL372() 22 { 23 RegistersCollection = new ByteRegisterCollection(this); 24 DefineRegisters(); 25 } 26 OnGPIO(int number, bool value)27 public void OnGPIO(int number, bool value) 28 { 29 if(number != 0) 30 { 31 this.Log(LogLevel.Warning, "This model supports only CS on pin 0, but got signal on pin {0}", number); 32 return; 33 } 34 35 // value is the negated CS 36 if(chipSelected && value) 37 { 38 FinishTransmission(); 39 } 40 chipSelected = !value; 41 } 42 Write(byte[] bytes)43 public void Write(byte[] bytes) 44 { 45 foreach(var b in bytes) 46 { 47 WriteByte(b); 48 } 49 } 50 WriteByte(byte b)51 public void WriteByte(byte b) 52 { 53 switch(state) 54 { 55 case State.Idle: 56 address = b; 57 state = State.Processing; 58 break; 59 60 case State.Processing: 61 RegistersCollection.Write(address, b); 62 address++; 63 break; 64 65 default: 66 throw new ArgumentException($"Unexpected state: {state}"); 67 } 68 } 69 Read(int count = 1)70 public byte[] Read(int count = 1) 71 { 72 byte[] result = null; 73 74 switch(state) 75 { 76 case State.Idle: 77 this.Log(LogLevel.Noisy, "Unexpected reading in Idle state"); 78 result = new byte[] { }; 79 break; 80 81 case State.Processing: 82 result = new byte[] { RegistersCollection.Read(address) }; 83 address++; 84 break; 85 86 default: 87 throw new ArgumentException($"Unexpected state: {state}"); 88 } 89 90 return result; 91 } 92 Transmit(byte b)93 public byte Transmit(byte b) 94 { 95 if(!chipSelected) 96 { 97 this.Log(LogLevel.Warning, "Received transmission, but CS pin is not selected"); 98 return 0; 99 } 100 101 byte result = 0; 102 switch(state) 103 { 104 case State.Idle: 105 result = HandleIdle(b); 106 break; 107 108 case State.Reading: 109 this.NoisyLog("Reading register {0} (0x{0:X})", (Registers)address); 110 result = RegistersCollection.Read(address); 111 address++; 112 break; 113 114 case State.Writing: 115 this.NoisyLog("Writing 0x{0:X} to register {1} (0x{1:X})", b, (Registers)address); 116 RegistersCollection.Write(address, b); 117 address++; 118 break; 119 120 default: 121 this.Log(LogLevel.Error, "Received byte in an unexpected state!"); 122 break; 123 } 124 125 this.Log(LogLevel.Noisy, "Transmitting - received 0x{0:X}, sending 0x{1:X} back", b, result); 126 return result; 127 } 128 FinishTransmission()129 public void FinishTransmission() 130 { 131 this.NoisyLog("Finishing transmission, going to the Idle state"); 132 state = State.Idle; 133 } 134 Reset()135 public void Reset() 136 { 137 RegistersCollection.Reset(); 138 state = State.Idle; 139 address = 0; 140 chipSelected = false; 141 142 AccelerationX = 0; 143 AccelerationY = 0; 144 AccelerationZ = 0; 145 } 146 147 public double AccelerationX { get; set; } 148 public double AccelerationY { get; set; } 149 public double AccelerationZ { get; set; } 150 151 public ByteRegisterCollection RegistersCollection { get; } 152 DefineRegisters()153 private void DefineRegisters() 154 { 155 Registers.DeviceID.Define(this) 156 .WithValueField(0, 8, FieldMode.Read, name: "DEVID_AD", valueProviderCallback: _ => 0xAD); 157 158 Registers.PartID.Define(this) 159 .WithValueField(0, 8, FieldMode.Read, name: "DEVID_PRODUCT", valueProviderCallback: _ => 0xFA); 160 161 Registers.Status.Define(this) 162 .WithFlag(0, FieldMode.Read, name: "DATA_RDY", valueProviderCallback: _ => true) 163 .WithTag("FIFO_RDY", 1, 1) 164 .WithTag("FIFO_FULL", 2, 1) 165 .WithTag("FIFO_OVR", 3, 1) 166 .WithReservedBits(4, 1) 167 .WithTag("USER_NVM_BUSY", 5, 1) 168 .WithTag("AWAKE", 6, 1) 169 .WithTag("ERR_USER_REGS", 7, 1); 170 171 Registers.MaxPeakXHigh.Define(this) 172 .WithValueField(0, 8, FieldMode.Read, name: "MAXPEAK_X[11:4]", valueProviderCallback: _ => Convert(AccelerationX, upperByte: true)); 173 174 Registers.MaxPeakXLow.Define(this) 175 .WithReservedBits(0, 4) 176 .WithValueField(4, 4, FieldMode.Read, name: "MAXPEAK_X[3:0]", valueProviderCallback: _ => Convert(AccelerationX, upperByte: false)); 177 178 Registers.MaxPeakYHigh.Define(this) 179 .WithValueField(0, 8, FieldMode.Read, name: "MAXPEAK_Y[11:4]", valueProviderCallback: _ => Convert(AccelerationY, upperByte: true)); 180 181 Registers.MaxPeakYLow.Define(this) 182 .WithReservedBits(0, 4) 183 .WithValueField(4, 4, FieldMode.Read, name: "MAXPEAK_Y[3:0]", valueProviderCallback: _ => Convert(AccelerationY, upperByte: false)); 184 185 Registers.MaxPeakZHigh.Define(this) 186 .WithValueField(0, 8, FieldMode.Read, name: "MAXPEAK_Z[11:4]", valueProviderCallback: _ => Convert(AccelerationZ, upperByte: true)); 187 188 Registers.MaxPeakZLow.Define(this) 189 .WithReservedBits(0, 4) 190 .WithValueField(4, 4, FieldMode.Read, name: "MAXPEAK_Z[3:0]", valueProviderCallback: _ => Convert(AccelerationZ, upperByte: false)); 191 } 192 Convert(double value, bool upperByte)193 private byte Convert(double value, bool upperByte) 194 { 195 var v = (uint)(value * 160); 196 197 // lower byte contains only 4 bits that are left-shifted 198 var result = upperByte 199 ? (byte)(v >> 8) 200 : (byte)(v >> 4); 201 202 return result; 203 } 204 HandleIdle(byte b)205 private byte HandleIdle(byte b) 206 { 207 address = (byte)(b >> 1); 208 209 if(BitHelper.IsBitSet(b, 0)) 210 { 211 state = State.Reading; 212 } 213 else 214 { 215 state = State.Writing; 216 } 217 218 return 0; 219 } 220 221 private byte address; 222 223 private State state; 224 225 private bool chipSelected; 226 227 private enum State 228 { 229 Idle, 230 // those two states are used in SPI mode 231 Reading, 232 Writing, 233 // this state is used in I2C mode 234 Processing 235 } 236 237 private enum Registers 238 { 239 DeviceID = 0x00, 240 PartID = 0x02, 241 Status = 0x04, 242 243 MaxPeakXHigh = 0x15, 244 MaxPeakXLow = 0x16, 245 MaxPeakYHigh = 0x17, 246 MaxPeakYLow = 0x18, 247 MaxPeakZHigh = 0x19, 248 MaxPeakZLow = 0x1A 249 } 250 } 251 } 252