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 NUnit.Framework; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure; 11 using Antmicro.Renode.Peripherals.I2C; 12 using System.Threading; 13 using System.Diagnostics; 14 using System.Collections.Generic; 15 using Antmicro.Renode.Peripherals.Mocks; 16 using Antmicro.Renode.Peripherals.Bus; 17 using Antmicro.Renode.Peripherals.Sensors; 18 19 namespace Antmicro.Renode.PeripheralsTests 20 { 21 [TestFixture] 22 public class EFR32_I2CControllerTests 23 { 24 [SetUp] SetupController()25 public void SetupController() 26 { 27 machine = new Machine(); 28 controller = new EFR32_I2CController(machine); 29 readTestPeripheral = new DummyI2CSlave(); 30 writeTestPeripheral = new EchoI2CDevice(); 31 32 controller.Reset(); 33 readTestPeripheral.Reset(); 34 // Enable the controller 35 // Also enable autoack, which will automatically acknowledge all incoming bytes 36 // so we don't have to do it manually. 37 controller.WriteDoubleWord(0x0, 0x1 | (1 << 2)); 38 // Enable all interrupts 39 controller.WriteDoubleWord(0x40, 0x7FFFF); 40 41 machine.SystemBus.Register(controller, new BusRangeRegistration(0x4A010000, 0x400)); 42 controller.Register(readTestPeripheral, new NumberRegistrationPoint<int>(readTestPeripheralAddress)); 43 controller.Register(writeTestPeripheral, new NumberRegistrationPoint<int>(writeTestPeripheralAddress)); 44 } 45 46 [Test] WriteToSlaveUsingSingleByteTransfer()47 public void WriteToSlaveUsingSingleByteTransfer() 48 { 49 BeginTransmission(writeTestPeripheralAddress, TransmissionType.Write); 50 // Send some magic bytes to the device 51 foreach(var b in testMagicSequence) 52 { 53 // Write the byte to send 54 controller.WriteDoubleWord(0x2C, b); 55 } 56 EndTransmission(); 57 58 Assert.AreEqual(testMagicSequence, writeTestPeripheral.Read(testMagicSequence.Length)); 59 } 60 61 [Test, Timeout(2000)] ReadFromSlaveUsingSingleByteTransfer()62 public void ReadFromSlaveUsingSingleByteTransfer() 63 { 64 // Write some data that will be mirrored back to the controller 65 EnqueueDummyBytes(testMagicSequence); 66 67 BeginTransmission(readTestPeripheralAddress, TransmissionType.Read); 68 var bytes = ReadBytes(testMagicSequence.Length); 69 EndTransmission(); 70 71 Assert.AreEqual(testMagicSequence, bytes); 72 } 73 74 [Test] PeekSingleByte()75 public void PeekSingleByte() 76 { 77 // Write some data that will be mirrored back to the controller 78 EnqueueDummyBytes(testMagicSequence); 79 80 BeginTransmission(readTestPeripheralAddress, TransmissionType.Read); 81 Assert.AreEqual(testMagicSequence[0], PeekRxByte()); 82 EndTransmission(); 83 } 84 85 [Test] WriteToSlaveUsingDoubleByteTransfer()86 public void WriteToSlaveUsingDoubleByteTransfer() 87 { 88 BeginTransmission(writeTestPeripheralAddress, TransmissionType.Write); 89 // Send some magic bytes to the device, two bytes at a time 90 for(var i = 0; i < testMagicSequence.Length; i += 2) 91 { 92 uint value = (uint)testMagicSequence[i] | ((uint)testMagicSequence[i + 1] << 8); 93 controller.WriteDoubleWord(0x30, value); 94 } 95 EndTransmission(); 96 97 Assert.AreEqual(testMagicSequence, writeTestPeripheral.Read(testMagicSequence.Length)); 98 } 99 100 [Test, Timeout(2000)] ReadFromSlaveUsingDoubleByteTransfer()101 public void ReadFromSlaveUsingDoubleByteTransfer() 102 { 103 // Write some data that will be mirrored back to the controller 104 EnqueueDummyBytes(testMagicSequence); 105 106 BeginTransmission(readTestPeripheralAddress, TransmissionType.Read); 107 var bytes = ReadBytesDouble(testMagicSequence.Length); 108 EndTransmission(); 109 110 Assert.AreEqual(testMagicSequence, bytes); 111 } 112 113 [Test] PeekDoubleByte()114 public void PeekDoubleByte() 115 { 116 // Write some data that will be mirrored back to the controller 117 EnqueueDummyBytes(testMagicSequence); 118 119 BeginTransmission(readTestPeripheralAddress, TransmissionType.Read); 120 121 var value = PeekRxDoubleByte(); 122 Assert.AreEqual(testMagicSequence[0], (byte)value); 123 Assert.AreEqual(testMagicSequence[1], (byte)(value >> 8)); 124 125 EndTransmission(); 126 } 127 128 [Test] InterruptReadUnderflow()129 public void InterruptReadUnderflow() 130 { 131 ReadRxByte(); // we only care about the IRQ flags afterwards 132 133 AssertInterrupt(irqRxUnderflow); 134 } 135 136 [Test] InterruptMasterStop()137 public void InterruptMasterStop() 138 { 139 // Send stop command 140 controller.WriteDoubleWord(0x04, 0x2); 141 142 AssertInterrupt(irqMasterStop); 143 } 144 145 [Test] InterruptStart()146 public void InterruptStart() 147 { 148 // Send start command 149 controller.WriteDoubleWord(0x4, 0x1); 150 // Start should have fired 151 AssertInterrupt(irqStart); 152 } 153 154 [Test] InterruptAck()155 public void InterruptAck() 156 { 157 BeginTransmission(readTestPeripheralAddress, TransmissionType.Read); 158 // As there is a peripheral connected at that address, this should be ACK'd 159 AssertInterrupt(irqAck); 160 } 161 162 [Test] InterruptNack()163 public void InterruptNack() 164 { 165 BeginTransmission(0x40, TransmissionType.Read); 166 // No peripheral at that address, this should be NACK'd 167 AssertInterrupt(irqNack); 168 } 169 170 [Test] InterruptBusHold()171 public void InterruptBusHold() 172 { 173 // On HW, the controller can lose bus arbitration at any time during the transmission 174 // For simulation purposes, the bus is "virtually" held by the controller for the entire duration of the transmission 175 BeginTransmission(readTestPeripheralAddress, TransmissionType.Read); 176 AssertInterrupt(irqBusHold); 177 EndTransmission(); 178 } 179 180 [Test] InterruptTransmitBufferLevel()181 public void InterruptTransmitBufferLevel() 182 { 183 BeginTransmission(writeTestPeripheralAddress, TransmissionType.Write); 184 // Write test byte 185 controller.WriteDoubleWord(0x2C, 0x42); 186 EndTransmission(); 187 188 // TXBL should have fired 189 AssertInterrupt(irqTxBufferLevel); 190 191 // Write a test byte to the transmit buffer 192 controller.WriteDoubleWord(0x2C, 0x42); 193 // This should have cleared the TXBL condition 194 AssertInterruptCleared(irqTxBufferLevel); 195 } 196 197 [Test] InterruptTransferCompleted()198 public void InterruptTransferCompleted() 199 { 200 BeginTransmission(writeTestPeripheralAddress, TransmissionType.Write); 201 // Write test byte 202 controller.WriteDoubleWord(0x2C, 0x42); 203 EndTransmission(); 204 205 // TXC should have fired 206 AssertInterrupt(irqTransferCompleted); 207 } 208 209 [Test] TestWithBMP180()210 public void TestWithBMP180() 211 { 212 var sensor = new BMP180(); 213 sensor.Reset(); 214 controller.Register(sensor, new NumberRegistrationPoint<int>(0x77)); 215 216 // Send the register address to start reading from (0xF6 - OutMSB) 217 BeginTransmission(0x77, TransmissionType.Write); 218 controller.WriteDoubleWord(0x2c, 0xF6); 219 EndTransmission(); 220 221 // Now, read from the sensor 222 BeginTransmission(0x77, TransmissionType.Read); 223 var bytes = ReadBytes(8); 224 EndTransmission(); 225 226 // The reset value for OutMSB is 0x80 227 Assert.NotZero(bytes.Length); 228 Assert.AreEqual(0x80, bytes[0]); 229 } 230 BeginTransmission(int address, TransmissionType type)231 private void BeginTransmission(int address, TransmissionType type) 232 { 233 // Start transmission 234 controller.WriteDoubleWord(0x4, 0x1); 235 236 // Write address of peripheral, with LSB cleared (direction: write) 237 var data = (address << 1) | (type == TransmissionType.Read ? 0x1 : 0x0); 238 controller.WriteDoubleWord(0x2C, (uint)data); 239 } 240 EndTransmission()241 private void EndTransmission() 242 { 243 // Stop transmission 244 controller.WriteDoubleWord(0x4, 0x2); 245 } 246 EnqueueDummyBytes(IEnumerable<byte> response)247 private void EnqueueDummyBytes(IEnumerable<byte> response) 248 { 249 foreach (var @byte in response) 250 { 251 readTestPeripheral.EnqueueResponseByte(@byte); 252 } 253 } 254 ReadStatus()255 private uint ReadStatus() 256 { 257 return controller.ReadDoubleWord(0xC); 258 } 259 ReadInterruptStatus()260 private uint ReadInterruptStatus() 261 { 262 return controller.ReadDoubleWord(0x34); 263 } 264 ReadRxByte()265 private byte ReadRxByte() 266 { 267 return (byte)controller.ReadDoubleWord(0x1C); 268 } 269 ReadRxDoubleByte()270 private ushort ReadRxDoubleByte() 271 { 272 return (ushort)controller.ReadDoubleWord(0x20); 273 } 274 PeekRxByte()275 private byte PeekRxByte() 276 { 277 return (byte)controller.ReadDoubleWord(0x24); 278 } 279 PeekRxDoubleByte()280 private ushort PeekRxDoubleByte() 281 { 282 return (ushort)controller.ReadDoubleWord(0x28); 283 } 284 ReadBytes(int count)285 private byte[] ReadBytes(int count) 286 { 287 var bytes = new Queue<byte>(); 288 289 // Read bytes while data is still available in the Rx buffer 290 var received = 0; 291 while(received < count && (ReadStatus() & 0x100) != 0) 292 { 293 // Make sure there's actually a byte waiting in the Rx buffer 294 Assert.AreEqual(irqMasterStop, ReadStatus() & irqMasterStop); 295 bytes.Enqueue(ReadRxByte()); 296 received += 1; 297 } 298 299 return bytes.ToArray(); 300 } 301 ReadBytesDouble(int count)302 private byte[] ReadBytesDouble(int count) 303 { 304 var bytes = new Queue<byte>(); 305 306 var received = 0; 307 // Read bytes while data is still available in the Rx buffer 308 while(received < count && (ReadStatus() & 0x100) != 0) 309 { 310 // Make sure the rx buffer actually contains two bytes to read; 311 // reading from it is otherwise undefined behavior 312 Assert.AreEqual((1 << 9), ReadStatus() & (1 << 9)); 313 // Reading is done two bytes at a time (RXDOUBLE) 314 var value = ReadRxDoubleByte(); 315 bytes.Enqueue((byte)value); 316 bytes.Enqueue((byte)(value >> 8)); 317 received += 2; 318 } 319 320 return bytes.ToArray(); 321 } 322 AssertInterrupt(uint irqMask)323 private void AssertInterrupt(uint irqMask) 324 { 325 Assert.AreEqual(irqMask, ReadInterruptStatus() & irqMask); 326 } 327 AssertInterruptCleared(uint irqMask)328 private void AssertInterruptCleared(uint irqMask) 329 { 330 Assert.AreEqual(0, ReadInterruptStatus() & irqMask); 331 } 332 333 private enum TransmissionType 334 { 335 Read, 336 Write 337 } 338 339 private IMachine machine; 340 private EFR32_I2CController controller; 341 private EchoI2CDevice writeTestPeripheral; 342 private DummyI2CSlave readTestPeripheral; 343 private const int readTestPeripheralAddress = 0x10; 344 private const int writeTestPeripheralAddress = 0x20; 345 private const int irqRxUnderflow = 1 << 13; 346 private const int irqMasterStop = 1 << 8; 347 private const int irqStart = 1 << 0; 348 private const int irqAck = 1 << 6; 349 private const int irqNack = 1 << 7; 350 private const int irqBusHold = 1 << 11; 351 private const int irqTxBufferLevel = 1 << 4; 352 private const int irqTransferCompleted = 1 << 3; 353 // The length of the below sequence needs to be a multiple of 2 for double-width transfer tests to work 354 private static byte[] testMagicSequence = { 0x11, 0x22, 0x33, 0x44, 0xFF, 0xEE, 0xDD, 0xCC, 0x11, 0x22, 0x33, 0x44, 0xFF, 0xEE, 0xDD, 0xCC }; 355 } 356 }