1 //
2 // Copyright (c) 2010-2024 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;
9 using Antmicro.Renode.Logging;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Peripherals.I2C;
13 using Antmicro.Renode.Peripherals.Sensor;
14 
15 namespace Antmicro.Renode.Peripherals.Sensors
16 {
17     public partial class ICM20948
18     {
TryGetI2CPeripherial(out II2CPeripheral pheriperial)19         private bool TryGetI2CPeripherial(out II2CPeripheral pheriperial)
20         {
21             if(!i2cContainer.TryGetByAddress((int)slaveAddress0.Value, out pheriperial))
22             {
23                 this.WarningLog("Selecting unconnected IIC slave address: 0x{0:X}", slaveAddress0.Value);
24                 return false;
25             }
26             this.DebugLog("Selected slave address 0x{0:X}", slaveAddress0.Value);
27             return true;
28         }
29 
WriteI2CPeripherial(II2CPeripheral selectedI2CSlave, byte[] data)30         private void WriteI2CPeripherial(II2CPeripheral selectedI2CSlave, byte[] data)
31         {
32             selectedI2CSlave.Write(data);
33             selectedI2CSlave.FinishTransmission();
34         }
35 
ReadI2CPeripherial(II2CPeripheral selectedI2CSlave, int length)36         private void ReadI2CPeripherial(II2CPeripheral selectedI2CSlave, int length)
37         {
38             if(length > externalSlaveSensorData.Length)
39             {
40                 this.Log(LogLevel.Warning, "Requested read length is greater than the number of available external sensor data registers. Clamping to the maximum available length.");
41                 length = externalSlaveSensorData.Length;
42             }
43             byte[] data = selectedI2CSlave.Read(length);
44             selectedI2CSlave.FinishTransmission();
45             for(int i = 0; i < data.Length; i++)
46             {
47                 externalSlaveSensorData[i].Value = data[i];
48             }
49         }
50 
ReadSensorData()51         private void ReadSensorData()
52         {
53             if(!TryGetI2CPeripherial(out var selectedI2CSlave))
54             {
55                 return;
56             }
57             WriteI2CPeripherial(selectedI2CSlave, new byte[] { (byte)slaveTransactionRegisterAddress0.Value } );
58             ReadI2CPeripherial(selectedI2CSlave, (int)slaveTransferLength0.Value );
59         }
60 
DefineGyroAccelUserBank3Registers()61         private void DefineGyroAccelUserBank3Registers()
62         {
63             GyroAccelUserBank3Registers.I2CIDRMasterConfig.Define(gyroAccelUserBank3Registers)
64                 .WithReservedBits(4, 4)
65                 .WithTag("I2C_MST_ODR_CONFIG", 0, 4)
66             ;
67 
68             GyroAccelUserBank3Registers.I2CMasterControl.Define(gyroAccelUserBank3Registers)
69                 .WithTag("MULT_MST_EN", 7, 1)
70                 .WithReservedBits(5, 2)
71                 .WithTag("I2C_MST_P_NSR", 4, 1)
72                 .WithTag("I2C_MST_CLK", 0, 4)
73             ;
74 
75             GyroAccelUserBank3Registers.I2CMasterDelayControl.Define(gyroAccelUserBank3Registers)
76                 .WithTag("DELAY_ES_SHADOW", 7, 1)
77                 .WithReservedBits(5, 2)
78                 .WithTag("I2C_SLV4_DELAY_EN", 4, 1)
79                 .WithTag("I2C_SLV3_DELAY_EN", 3, 1)
80                 .WithTag("I2C_SLV2_DELAY_EN", 2, 1)
81                 .WithTag("I2C_SLV1_DELAY_EN", 1, 1)
82                 .WithTag("I2C_SLV0_DELAY_EN", 0, 1)
83             ;
84 
85             GyroAccelUserBank3Registers.I2CSlave0Address.Define(gyroAccelUserBank3Registers)
86                 .WithFlag(7, out slaveRWBit0, name: "I2C_SLV0_RNW")
87                 .WithValueField(0, 7, out slaveAddress0, name: "I2C_ID_0")
88             ;
89 
90             GyroAccelUserBank3Registers.I2CSlave0Register.Define(gyroAccelUserBank3Registers)
91                 .WithValueField(0, 8, out slaveTransactionRegisterAddress0, name: "I2C_SLV0_REG")
92             ;
93 
94             GyroAccelUserBank3Registers.I2CSlave0Control.Define(gyroAccelUserBank3Registers)
95                 .WithFlag(7, out var slaveEnable0, name: "I2C_SLV0_EN",
96                         writeCallback: (_, value) =>
97                         {
98                             if(!value)
99                             {
100                                 magFeederThread?.Stop();
101                                 return;
102                             }
103                             magFeederThread?.Stop();
104                             var machine = this.GetMachine();
105                             Action feedSample = () =>
106                             {
107                                 ReadSensorData();
108                             };
109                             Func<bool> stopCondition = () => false;
110                             magFeederThread = machine.ObtainManagedThread(feedSample, (uint)InternalSampleRateHz, "Magnetometer stream thread", this, stopCondition);
111                             this.Log(LogLevel.Debug, "Starting reading magnetometer samples at frequency {0}Hz", InternalSampleRateHz);
112                             magFeederThread.Start();
113                         })
114                 .WithTag("I2C_SLV0_BYTE_SW", 6, 1)
115                 .WithTag("I2C_SLV0_REG_DIS", 5, 1)
116                 .WithTag("I2C_SLV0_GRP", 4, 1)
117                 .WithValueField(0, 4, out slaveTransferLength0, name: "I2C_SLV0_LENG")
118             ;
119 
120             GyroAccelUserBank3Registers.I2CSlave0DataOut.Define(gyroAccelUserBank3Registers)
121                 .WithValueField(0, 8, out slaveDataOut0, name: "I2C_SLV0_DO",
122                     writeCallback: (_, val) =>
123                     {
124                         if(!TryGetI2CPeripherial(out var selectedI2CSlave))
125                         {
126                             return;
127                         }
128                         WriteI2CPeripherial(selectedI2CSlave, new byte[] { (byte)slaveTransactionRegisterAddress0.Value, (byte)val } );
129                     })
130             ;
131 
132             GyroAccelUserBank3Registers.I2CSlave1Address.Define(gyroAccelUserBank3Registers)
133                 .WithTag("I2C_SLV1_RNW", 7, 1)
134                 .WithTag("I2C_ID_1", 0, 7)
135             ;
136 
137             GyroAccelUserBank3Registers.I2CSlave1Register.Define(gyroAccelUserBank3Registers)
138                 .WithTag("I2C_SLV1_REG", 0, 8)
139             ;
140 
141             GyroAccelUserBank3Registers.I2CSlave1Control.Define(gyroAccelUserBank3Registers)
142                 .WithTag("I2C_SLV1_EN", 7, 1)
143                 .WithTag("I2C_SLV1_BYTE_SW", 6, 1)
144                 .WithTag("I2C_SLV1_REG_DIS", 5, 1)
145                 .WithTag("I2C_SLV1_GRP", 4, 1)
146                 .WithTag("I2C_SLV1_LENG", 0, 4)
147             ;
148 
149             GyroAccelUserBank3Registers.I2CSlave1DataOut.Define(gyroAccelUserBank3Registers)
150                 .WithTag("I2C_SLV1_DO", 0, 8)
151             ;
152 
153             GyroAccelUserBank3Registers.I2CSlave2Address.Define(gyroAccelUserBank3Registers)
154                 .WithTag("I2C_SLV2_RNW", 7, 1)
155                 .WithTag("I2C_ID_2", 0, 7)
156             ;
157 
158             GyroAccelUserBank3Registers.I2CSlave2Register.Define(gyroAccelUserBank3Registers)
159                 .WithTag("I2C_SLV2_REG", 0, 8)
160             ;
161 
162             GyroAccelUserBank3Registers.I2CSlave2Control.Define(gyroAccelUserBank3Registers)
163                 .WithTag("I2C_SLV2_EN", 7, 1)
164                 .WithTag("I2C_SLV2_BYTE_SW", 6, 1)
165                 .WithTag("I2C_SLV2_REG_DIS", 5, 1)
166                 .WithTag("I2C_SLV2_GRP", 4, 1)
167                 .WithTag("I2C_SLV2_LENG", 0, 4)
168             ;
169 
170             GyroAccelUserBank3Registers.I2CSlave2DataOut.Define(gyroAccelUserBank3Registers)
171                 .WithTag("I2C_SLV2_DO", 0, 8)
172             ;
173 
174             GyroAccelUserBank3Registers.I2CSlave3Address.Define(gyroAccelUserBank3Registers)
175                 .WithTag("I2C_SLV3_RNW", 7, 1)
176                 .WithTag("I2C_ID_3", 0, 7)
177             ;
178 
179             GyroAccelUserBank3Registers.I2CSlave3Register.Define(gyroAccelUserBank3Registers)
180                 .WithTag("I2C_SLV3_REG", 0, 8)
181             ;
182 
183             GyroAccelUserBank3Registers.I2CSlave3Control.Define(gyroAccelUserBank3Registers)
184                 .WithTag("I2C_SLV3_EN", 7, 1)
185                 .WithTag("I2C_SLV3_BYTE_SW", 6, 1)
186                 .WithTag("I2C_SLV3_REG_DIS", 5, 1)
187                 .WithTag("I2C_SLV3_GRP", 4, 1)
188                 .WithTag("I2C_SLV3_LENG", 0, 4)
189             ;
190 
191             GyroAccelUserBank3Registers.I2CSlave3DataOut.Define(gyroAccelUserBank3Registers)
192                 .WithTag("I2C_SLV3_DO", 0, 8)
193             ;
194 
195             GyroAccelUserBank3Registers.I2CSlave4Address.Define(gyroAccelUserBank3Registers)
196                 .WithTag("I2C_SLV4_RNW", 7, 1)
197                 .WithTag("I2C_ID_4", 0, 7)
198             ;
199 
200             GyroAccelUserBank3Registers.I2CSlave4Register.Define(gyroAccelUserBank3Registers)
201                 .WithTag("I2C_SLV4_REG", 0, 8)
202             ;
203 
204             GyroAccelUserBank3Registers.I2CSlave4Control.Define(gyroAccelUserBank3Registers)
205                 .WithTag("I2C_SLV4_EN", 7, 1)
206                 .WithTag("I2C_SLV4_BYTE_SW", 6, 1)
207                 .WithTag("I2C_SLV4_REG_DIS", 5, 1)
208                 .WithTag("I2C_SLV4_DLY", 0, 5)
209             ;
210 
211             GyroAccelUserBank3Registers.I2CSlave4DataOut.Define(gyroAccelUserBank3Registers)
212                 .WithTag("I2C_SLV4_DO", 0, 8)
213             ;
214 
215             GyroAccelUserBank3Registers.I2CSlave4DataIn.Define(gyroAccelUserBank3Registers)
216                 .WithTag("I2C_SLV4_DI", 0, 8)
217             ;
218 
219             DefineBankSelectRegister(gyroAccelUserBank3Registers);
220         }
221 
222         private IManagedThread magFeederThread;
223 
224         private IValueRegisterField slaveAddress0;
225         private IFlagRegisterField slaveRWBit0;
226         private IValueRegisterField slaveTransactionRegisterAddress0;
227         private IValueRegisterField slaveTransferLength0;
228         private IValueRegisterField slaveDataOut0;
229 
230         private enum GyroAccelUserBank3Registers : byte
231         {
232             I2CIDRMasterConfig = 0x0,
233             I2CMasterControl = 0x1,
234             I2CMasterDelayControl = 0x2,
235             I2CSlave0Address = 0x3,
236             I2CSlave0Register = 0x4,
237             I2CSlave0Control = 0x5,
238             I2CSlave0DataOut = 0x6,
239             I2CSlave1Address = 0x7,
240             I2CSlave1Register = 0x8,
241             I2CSlave1Control = 0x9,
242             I2CSlave1DataOut = 0xA,
243             I2CSlave2Address = 0xB,
244             I2CSlave2Register = 0xC,
245             I2CSlave2Control = 0xD,
246             I2CSlave2DataOut = 0xE,
247             I2CSlave3Address = 0xF,
248             I2CSlave3Register = 0x10,
249             I2CSlave3Control = 0x11,
250             I2CSlave3DataOut = 0x12,
251             I2CSlave4Address = 0x13,
252             I2CSlave4Register = 0x14,
253             I2CSlave4Control = 0x15,
254             I2CSlave4DataOut = 0x16,
255             I2CSlave4DataIn = 0x17,
256         }
257 
258         private enum I2CTransactionDirection
259         {
260             Unset,
261             Read,
262             Write,
263         }
264     }
265 }
266