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