1 // 2 // Copyright (c) 2010-2018 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using System.Linq; 10 using System.Collections.Generic; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Logging; 15 using Antmicro.Renode.Exceptions; 16 17 namespace Antmicro.Renode.Peripherals.I2C 18 { 19 public class EFM32GGI2CController : SimpleContainer<II2CPeripheral>, IDoubleWordPeripheral 20 { 21 EFM32GGI2CController(IMachine machine)22 public EFM32GGI2CController(IMachine machine) : base(machine) 23 { 24 IRQ = new GPIO(); 25 } 26 27 // TODO: Implement checks on if the controller is enabled where needed, ie if bit 0 in i2cn_trl is set 28 // TODO: Implment all interrupt handling p 419 EFM32GG Ref Man 29 // TODO: handle and send ack/nack 30 ReadDoubleWord(long offset)31 public virtual uint ReadDoubleWord(long offset) 32 { 33 this.Log(LogLevel.Noisy, "read {0}", (Registers)offset); 34 35 switch((Registers)offset) 36 { 37 case Registers.I2Cn_CTRL: 38 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_ctrl); 39 return i2cn_ctrl; 40 case Registers.I2Cn_CMD: 41 return 0; 42 case Registers.I2Cn_STATE: 43 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_state); 44 return i2cn_state; 45 case Registers.I2Cn_STATUS: 46 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_status); 47 return i2cn_status; 48 case Registers.I2Cn_CLKDIV: 49 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_clkdiv); 50 return i2cn_clkdiv; 51 case Registers.I2Cn_SADDR: 52 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_saddr); 53 return i2cn_saddr; 54 case Registers.I2Cn_RXDATA: 55 // Set underflow flag if buffer is empty 56 uint i2cn_rxdata = 0; 57 if(!rxBufferFull) 58 { 59 SetInterrupt(1 << (int)Interrupts.RXUF); 60 } 61 else 62 { 63 i2cn_rxdata = rxBuffer; 64 rxBuffer = 0; 65 rxBufferFull = false; 66 ShiftRxData(); 67 } 68 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_rxdata); 69 return i2cn_rxdata; 70 case Registers.I2Cn_RXDATAP: 71 this.Log(LogLevel.Noisy, "register value = {0}", rxBuffer); 72 return rxBuffer; 73 case Registers.I2Cn_TXDATA: 74 return 0; 75 case Registers.I2Cn_IF: 76 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_if); 77 return i2cn_if; 78 case Registers.I2Cn_IFS: 79 return 0; 80 case Registers.I2Cn_IFC: 81 return 0; 82 case Registers.I2Cn_IEN: 83 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_ien); 84 return i2cn_ien; 85 case Registers.I2Cn_ROUTE: 86 this.Log(LogLevel.Noisy, "register value = {0}", i2cn_route); 87 return i2cn_route; 88 default: 89 this.Log(LogLevel.Warning, "Unexpected read at 0x{0:X}.", offset); 90 return 0; 91 } 92 } 93 WriteDoubleWord(long offset, uint value)94 public virtual void WriteDoubleWord(long offset, uint value) 95 { 96 this.Log(LogLevel.Noisy, "write {0}, value 0x{1:X}", (Registers)offset, value); 97 98 switch((Registers)offset) 99 { 100 case Registers.I2Cn_CTRL: 101 HandleCtrl(value); 102 break; 103 case Registers.I2Cn_CMD: 104 HandleCommand(value); 105 break; 106 case Registers.I2Cn_STATE: 107 break; 108 case Registers.I2Cn_STATUS: 109 break; 110 case Registers.I2Cn_CLKDIV: 111 i2cn_clkdiv = value; 112 break; 113 case Registers.I2Cn_SADDR: 114 i2cn_saddr = value; 115 break; 116 case Registers.I2Cn_RXDATA: 117 break; 118 case Registers.I2Cn_RXDATAP: 119 break; 120 case Registers.I2Cn_TXDATA: 121 LoadTxData(value); 122 break; 123 case Registers.I2Cn_IF: 124 break; 125 case Registers.I2Cn_IFS: 126 SetInterrupt(value); 127 break; 128 case Registers.I2Cn_IFC: 129 ClearInterrupt(value); 130 break; 131 case Registers.I2Cn_IEN: 132 EnableInterrupt(value); 133 break; 134 case Registers.I2Cn_ROUTE: 135 i2cn_route = value; 136 break; 137 default: 138 this.Log(LogLevel.Warning, "Unexpected write at 0x{0:X}, value 0x{1:X}.", offset, value); 139 break; 140 } 141 } 142 Reset()143 public override void Reset() 144 { 145 this.Log(LogLevel.Noisy, "Reset"); 146 i2cn_ctrl = 0; 147 i2cn_cmd = 0; 148 i2cn_state = 0; 149 i2cn_status = 0; 150 i2cn_clkdiv = 0; 151 i2cn_saddr = 0; 152 i2cn_if = 0; 153 i2cn_ien = 0; 154 i2cn_route = 0; 155 rxBuffer = 0; 156 rxBufferFull = false; 157 txBuffer = 0; 158 txBufferFull = false; 159 rxShiftRegister = 0; 160 rxShiftRegisterFull = false; 161 txShiftRegister = 0; 162 txShiftRegisterFull = false; 163 transferState = TransferState.Idle; 164 txpacket.Clear(); 165 rxpacket.Clear(); 166 } 167 HandleCtrl(uint value)168 private void HandleCtrl(uint value) 169 { 170 if(i2cn_ctrl == value) 171 { 172 this.Log(LogLevel.Noisy, "Received Ctrl register update but value is same as current {0}", (Commands)i2cn_ctrl); 173 return; 174 } 175 // If EN bit in I2Cn_CTRL is cleared then reset internal state and terminate any ongoing transfers 176 if(((i2cn_ctrl & 0x1) == 0x1) && ((~value & 0x1) == 1)) 177 { 178 // TODO: Abort ongoing transfers. 179 Reset(); 180 } 181 // If EN bit is set, i2c controller is to be enabled. Set TXBL flag if tx buffer is empty 182 if(((value & 0x1) == 0x1) && ((~i2cn_ctrl & 0x1) == 1)) 183 { 184 if(!txBufferFull && txShiftRegisterFull) 185 { 186 SetStatus(Status.TXBL); 187 SetInterrupt(1 << (int)Interrupts.TXBL); 188 } 189 } 190 i2cn_ctrl = value; 191 this.Log(LogLevel.Noisy, "Changed Ctrl register to {0}", (Commands)i2cn_ctrl); 192 } 193 HandleCommand(uint value)194 private void HandleCommand(uint value) 195 { 196 // I2Cn_CMD register is W1, ie write-only and only write of 1 has any action 197 i2cn_cmd = value & 0xFF; //Only bits 0-7 used in I2Cn_CMD register 198 199 if((i2cn_cmd & (uint)(Commands.START)) == (uint)(Commands.START)) 200 { 201 // SDA line pulled low while SCL line is high 202 SetInterrupt(1 << (int)Interrupts.START); 203 // Since we send a packet list a restart means we should send the present list and start on a new 204 if(((int)transferState & (int)TransferState.StartTrans) == (int)TransferState.StartTrans) 205 { 206 transferState = TransferState.RestartTrans; 207 } 208 else 209 { 210 transferState = TransferState.StartTrans; 211 } 212 this.Log(LogLevel.Noisy, "Received START Command"); 213 HandleTransfer(); 214 } 215 if((i2cn_cmd & (uint)(Commands.STOP)) == (uint)(Commands.STOP)) 216 { 217 // SDA line pulled high while SCL line is high 218 SetInterrupt(1 << (int)Interrupts.MSTOP); 219 transferState = TransferState.StopTrans; 220 this.Log(LogLevel.Noisy, "Received STOP Command"); 221 HandleTransfer(); 222 } 223 if((i2cn_cmd & (uint)(Commands.ACK)) == (uint)(Commands.ACK)) 224 { 225 // TODO: set an internal variable to track and possibly use this, now slave does not expect ACK/NACK 226 this.Log(LogLevel.Noisy, "Received ACK Command"); 227 } 228 if((i2cn_cmd & (uint)(Commands.NACK)) == (uint)(Commands.NACK)) 229 { 230 // TODO: set an internal variable to track and possibly use this, now slave does not expect ACK/NACK 231 this.Log(LogLevel.Noisy, "Received NACK Command"); 232 } 233 if((i2cn_cmd & (uint)(Commands.CONT)) == (uint)(Commands.CONT)) 234 { 235 // TODO: Not implemented yet, set internal variable 236 this.Log(LogLevel.Noisy, "Received CONT Command"); 237 } 238 if((i2cn_cmd & (uint)(Commands.ABORT)) == (uint)(Commands.ABORT)) 239 { 240 // TODO: Not implemented yet 241 this.Log(LogLevel.Noisy, "Received ABORT Command"); 242 } 243 if((i2cn_cmd & (uint)(Commands.CLEARTX)) == (uint)(Commands.CLEARTX)) 244 { 245 // Clear transmit buffer and shift register, and TXBL flags in status register and interrupt flag register 246 txBuffer = 0; 247 txBufferFull = false; 248 txShiftRegister = 0; 249 txShiftRegisterFull = false; 250 txpacket.Clear(); 251 ClearStatus(Status.TXBL); 252 ClearInterrupt((uint)Interrupts.TXBL); 253 this.Log(LogLevel.Noisy, "Received CLEARTX Command"); 254 } 255 if((i2cn_cmd & (uint)(Commands.CLEARPC)) == (uint)(Commands.CLEARPC)) 256 { 257 // TODO: Not implemented yet 258 this.Log(LogLevel.Noisy, "Received CLEARPC Command"); 259 } 260 } 261 LoadTxData(uint value)262 private void LoadTxData(uint value) 263 { 264 // Check TXBL flags in status register and interrupt flag register to see if there is room for data in transmit buffer 265 // If not then set TXOF flag in status register and return without loading data. 266 this.Log(LogLevel.Noisy, "LoadTxData - status reg = {0}", i2cn_status); 267 if(CheckStatus(Status.TXBL) || (!txBufferFull && !txShiftRegisterFull)) 268 { 269 this.Log(LogLevel.Noisy, "Loaded transmit buffer with data {0}", value); 270 txBuffer = value; 271 txBufferFull = true; 272 if(CheckStatus(Status.TXBL)) 273 { 274 ClearStatus(Status.TXBL); 275 ClearInterrupt((uint)Interrupts.TXBL); 276 } 277 ShiftTxData(); 278 } 279 else 280 { 281 this.Log(LogLevel.Noisy, "Transmit buffer is full - overflow interrupt flag set"); 282 SetInterrupt(1 << (int)Interrupts.TXOF); 283 } 284 } 285 ShiftTxData()286 private void ShiftTxData() 287 { 288 // Only set TXC after transmission, how do we check this? Internal state? 289 if((txBufferFull == false) && (txShiftRegisterFull == false)) 290 { 291 SetStatus(Status.TXC); 292 SetInterrupt(1 << (int)Interrupts.TXC); 293 } 294 // Check if shift register is empty 295 // If so then move data to shift register and set TXBL flags in status register and interrupt flag register 296 if((txShiftRegisterFull == false) && txBufferFull) 297 { 298 txShiftRegister = txBuffer; 299 txShiftRegisterFull = true; 300 txBuffer = 0; 301 txBufferFull = false; 302 ClearStatus(Status.TXC); 303 // TXC interrupt can only be cleared by software 304 // Signal that transmit buffer is ready for receiving data 305 SetStatus(Status.TXBL); 306 SetInterrupt(1 << (int)Interrupts.TXBL); 307 HandleTransfer(); 308 } 309 // Check if BUSHOLD, then start sending slave address 310 if(txShiftRegisterFull && CheckInterrupt(Interrupts.BUSHOLD)) 311 { 312 HandleTransfer(); 313 } 314 } 315 WriteToSlave(int slaveAddress, List<byte> data)316 private void WriteToSlave(int slaveAddress, List<byte> data) 317 { 318 II2CPeripheral slave; 319 if(TryGetByAddress(slaveAddress, out slave)) 320 { 321 slave.Write(data.ToArray()); 322 } 323 else 324 { 325 this.Log(LogLevel.Warning, "Trying to write to nonexisting slave with address \"{0}\"", slaveAddress); 326 } 327 } 328 HandleTransfer()329 private void HandleTransfer() 330 { 331 // If transmit shift register contains data, package it and handle TXBL flags in status register and interrupt flag register 332 // TODO: see section 16.3.7.4 in EFM32GG Ref manual for master transmitter 333 // TODO: controller acting as slave 334 this.Log(LogLevel.Noisy, "HandleTransfer - txShiftRegister = {0}", txShiftRegister); 335 switch((TransferState)transferState) 336 { 337 case TransferState.Idle: 338 break; 339 case TransferState.StartTrans: 340 // Check if data is available in txShiftRegister, if so then use it, else BUS_HOLD 341 if(txShiftRegisterFull) 342 { 343 if(txBufferFull == false) 344 { 345 // Signal that transmit buffer is ready for receiving data 346 if(CheckStatus(Status.TXBL) == false) 347 { 348 this.Log(LogLevel.Noisy, "Setting TXBL status and intr flag"); 349 SetStatus(Status.TXBL); 350 SetInterrupt(1 << (int)Interrupts.TXBL); 351 } 352 } 353 // Create the packet list with bytes for the save device 354 // Check the current status of the packet list and add whats needed 355 // TODO: currently no verification on the validity of the data 356 switch(txpacket.Count) 357 { 358 case 0: 359 this.Log(LogLevel.Noisy, "HandleTransfer - packet count = 0"); 360 // Add mode as first byte in packet list 361 // Calculate what the mode should be from the device slave address 362 // First byte in tx buffer should be the 7-bit slave device address + Read/Write bit 363 slaveAddressForPacket = (byte)((txShiftRegister >> 1) & 0x7F); 364 if((txShiftRegister & 0x1) == 1) 365 { 366 // Mode is Read data from slave 367 txpacket.Add((byte)(PacketStates.ReadData)); 368 // Since Read data is a command and not followed by address, 369 // add the stored address and change to ReadTrans 370 txpacket.Add((byte)(registerAddress)); 371 transferState = TransferState.ReadTrans; 372 } 373 else 374 { 375 // Mode is Write data to slave 376 txpacket.Add((byte)(PacketStates.SendData)); 377 } 378 // Clear to enable more data 379 txShiftRegister = 0; 380 txShiftRegisterFull = false; 381 // We need to emulate receiving an ACK for the data byte sent 382 SetInterrupt(1 << (int)Interrupts.ACK); 383 this.Log(LogLevel.Noisy, "HandleTransfer - packet count = 0 - have set ACK interrupt"); 384 break; 385 case 1: 386 this.Log(LogLevel.Noisy, "HandleTransfer - packet count = 1"); 387 // Add register address 388 // Second byte in tx buffer should be the register address 389 txpacket.Add((byte)(txShiftRegister & 0xFF)); 390 // Save the address in case of upcoming Read 391 registerAddress = (byte)txShiftRegister; 392 // Clear to enable more data 393 txShiftRegister = 0; 394 txShiftRegisterFull = false; 395 // We need to emulate receiving an ACK for the data byte sent 396 SetInterrupt(1 << (int)Interrupts.ACK); 397 break; 398 case 2: 399 this.Log(LogLevel.Noisy, "HandleTransfer - packet count = 2"); 400 // If read mode of single register then we are done and we can change to EndTransfer state 401 // If multiple reads then we could continue, how to know if this is the case? 402 // If mode is write, add value for operation 403 txpacket.Add((byte)(txShiftRegister & 0xFF)); 404 // Clear to enable more data 405 txShiftRegister = 0; 406 txShiftRegisterFull = false; 407 // We need to emulate receiving an ACK for the data byte sent 408 SetInterrupt(1 << (int)Interrupts.ACK); 409 break; 410 default: 411 this.Log(LogLevel.Noisy, "HandleTransfer - packet count = ", txpacket.Count); 412 break; 413 } 414 ShiftTxData(); 415 } 416 else 417 { 418 this.Log(LogLevel.Noisy, "Setting state and intr flag BUSHOLD"); 419 SetInterrupt(1 << (int)Interrupts.BUSHOLD); 420 i2cn_state |= (uint)StateReg.BUSHOLD; 421 } 422 // Change state to send packet list if we are finished - how do we know? 423 // TODO: determine if we are finished 424 if(((int)transferState & (int)TransferState.ReadTrans) == (int)TransferState.ReadTrans) 425 { 426 HandleTransfer(); 427 } 428 break; 429 case TransferState.RestartTrans: 430 // Restart was issued - send packet list and change transferState to StartTrans 431 // Use the registration point - ie memory address - for slave communication 432 if(txpacket.Count > 0) 433 { 434 currentAddress = (int)slaveAddressForPacket << 1; 435 WriteToSlave(currentAddress, txpacket); 436 txpacket.Clear(); 437 } 438 transferState = TransferState.StartTrans; 439 HandleTransfer(); 440 break; 441 case TransferState.ReadTrans: 442 // Read was issued - send packet list and then read 443 // Use the registration point - ie memory address - for slave communication 444 if(txpacket.Count > 0) 445 { 446 currentAddress = (int)slaveAddressForPacket << 1; 447 WriteToSlave(currentAddress, txpacket); 448 txpacket.Clear(); 449 } 450 ReadData(); 451 HandleTransfer(); 452 break; 453 case TransferState.StopTrans: 454 // STOP was issued - send packet list 455 if(txpacket.Count > 0) 456 { 457 currentAddress = (int)slaveAddressForPacket << 1; 458 WriteToSlave(currentAddress, txpacket); 459 txpacket.Clear(); 460 } 461 // If automatic stop on empty is enabled signal STOP 462 if((i2cn_ctrl & (uint)(Control.AUTOSE)) == (uint)(Control.AUTOSE)) 463 { 464 SetInterrupt(1 << (int)Interrupts.MSTOP); 465 transferState = TransferState.Idle; 466 } 467 break; 468 default: 469 break; 470 } 471 } 472 ShiftRxData()473 private void ShiftRxData() 474 { 475 // Check if the receive buffer is empty, if not then BUSHOLD 476 if(rxBufferFull && rxShiftRegisterFull) 477 { 478 SetInterrupt(1 << (int)Interrupts.BUSHOLD); 479 i2cn_state |= (uint)StateReg.BUSHOLD; 480 return; 481 } 482 if((rxBufferFull == false) && rxShiftRegisterFull) 483 { 484 rxBuffer = rxShiftRegister; 485 rxBufferFull = true; 486 rxShiftRegister = 0; 487 rxShiftRegisterFull = false; 488 SetStatus(Status.RXDATAV); 489 SetInterrupt(1 << (int)Interrupts.RXDATAV); 490 this.Log(LogLevel.Noisy, "Data byte available for reading ({0})", rxBuffer); 491 } 492 // Strip away the CRC and do not pass it through 493 // TODO: add CRC verification as well 494 if(rxpacket.Count == 1) 495 { 496 rxpacket.Clear(); 497 } 498 if(rxpacket.Count > 1) 499 { 500 AddRxData(); 501 } 502 } 503 AddRxData()504 private void AddRxData() 505 { 506 if(rxShiftRegisterFull == false) 507 { 508 // Copy first item in list to receiver shift buffer and remove it 509 rxShiftRegister = rxpacket.ElementAt(0); 510 rxShiftRegisterFull = true; 511 rxpacket.RemoveAt(0); 512 this.Log(LogLevel.Noisy, "AddRxData - rxShiftRegister = {0}", rxShiftRegister); 513 } 514 ShiftRxData(); 515 } 516 ReadData()517 private void ReadData() 518 { 519 // Fetch packet list from slave device 520 II2CPeripheral slave; 521 transferState = TransferState.Idle; 522 if(!TryGetByAddress(currentAddress, out slave)) 523 { 524 this.Log(LogLevel.Warning, "Trying to read from nonexisting slave with address \"{0}\"", currentAddress); 525 return; 526 } 527 byte[] rxArray = slave.Read(); 528 // Packet list should have a least one byte plus a CRC byte 529 if(rxArray.Length > 1) 530 { 531 rxpacket = new List<byte>(rxArray); 532 this.Log(LogLevel.Noisy, "Read data - packet length = {0}", rxpacket.Count); 533 AddRxData(); 534 } 535 } 536 CheckStatus(Status status)537 private bool CheckStatus(Status status) 538 { 539 bool result = false; 540 if((i2cn_status & (uint)(1 << (int)status)) == (uint)(1 << (int)status)) 541 { 542 result = true; 543 } 544 return result; 545 } 546 SetStatus(Status status)547 private void SetStatus(Status status) 548 { 549 i2cn_status |= (uint)(1 << (int)status); 550 } 551 ClearStatus(Status status)552 private void ClearStatus(Status status) 553 { 554 i2cn_status &= ~((uint)status); 555 } 556 557 public GPIO IRQ { get; private set; } 558 CheckInterrupt(Interrupts interrupt)559 private bool CheckInterrupt(Interrupts interrupt) 560 { 561 bool result = false; 562 if((i2cn_if & (uint)(1 << (int)interrupt)) == (uint)(1 << (int)interrupt)) 563 { 564 result = true; 565 } 566 return result; 567 } 568 UpdateInterrupt()569 private void UpdateInterrupt() 570 { 571 if((i2cn_if & i2cn_ien) > 0) 572 { 573 this.Log(LogLevel.Noisy, "UpdateInterrupt - Irq set"); 574 IRQ.Set(); 575 } 576 else 577 { 578 this.Log(LogLevel.Noisy, "UpdateInterrupt - Irq cleared"); 579 IRQ.Unset(); 580 } 581 } 582 SetInterrupt(uint interruptMask)583 private void SetInterrupt(uint interruptMask) 584 { 585 // Only act if controller is enabled and on enabled interrupts 586 uint enableInterruptMask = i2cn_ien & interruptMask; 587 this.Log(LogLevel.Noisy, "SetInterrupt - enableInterruptMask = {0}", Convert.ToString(enableInterruptMask)); 588 this.Log(LogLevel.Noisy, "SetInterrupt i2cn_ctrl = {0}", Convert.ToString(i2cn_ctrl)); 589 // TODO: enable this check again once the Bitbanding.cs issue have been resolved 590 // if ((i2cn_ctrl & 0x1) == 0x1) 591 // { 592 i2cn_if |= enableInterruptMask; 593 UpdateInterrupt(); 594 // } 595 } 596 ClearInterrupt(uint interruptMask)597 private void ClearInterrupt(uint interruptMask) 598 { 599 // Only act if controller is enabled and on enabled interrupts 600 uint enableInterruptMask = i2cn_ien & interruptMask; 601 // TODO: enable this check again once the Bitbanding.cs issue have been resolved 602 // if ((i2cn_ctrl & 0x1) == 0x1) 603 // { 604 i2cn_if &= ~enableInterruptMask; 605 this.Log(LogLevel.Noisy, "ClearInterrupt i2cn_if = {0}", Convert.ToString(i2cn_if)); 606 UpdateInterrupt(); 607 // } 608 } 609 EnableInterrupt(uint interruptMask)610 private void EnableInterrupt(uint interruptMask) 611 { 612 i2cn_ien |= interruptMask; 613 // Clear disabled interrupts 614 i2cn_if &= interruptMask; 615 UpdateInterrupt(); 616 } 617 618 private uint i2cn_ctrl; 619 private uint i2cn_cmd; 620 private uint i2cn_state; 621 private uint i2cn_status; 622 private uint i2cn_clkdiv; 623 private uint i2cn_saddr; 624 private uint i2cn_if; 625 private uint i2cn_ien; 626 private uint i2cn_route; 627 628 private uint txShiftRegister; 629 private uint rxShiftRegister; 630 private bool txShiftRegisterFull; 631 private bool rxShiftRegisterFull; 632 private uint txBuffer; 633 private uint rxBuffer; 634 private bool txBufferFull; 635 private bool rxBufferFull; 636 private TransferState transferState; 637 638 private byte slaveAddressForPacket; 639 private byte registerAddress; 640 private int currentAddress; 641 642 private List<byte> txpacket = new List<byte>(); 643 private List<byte> rxpacket = new List<byte>(); 644 645 // Source: pages 434-445 in EFM32GG Reference Manual 646 private enum Registers 647 { 648 I2Cn_CTRL = 0x000, // Control Register - Read-Write 649 I2Cn_CMD = 0x004, // Command Register - Write-1-only 650 I2Cn_STATE = 0x008, // State Register - Read-only 651 I2Cn_STATUS = 0x00C, // Status Register - Read-only 652 I2Cn_CLKDIV = 0x010, // Clock Division Register - Read-Write 653 I2Cn_SADDR = 0x014, // Slave Address Register - Read-Write 654 I2Cn_SADDRMASK = 0x018, // Slave Address Mask Register - Read-Write 655 I2Cn_RXDATA = 0x01C, // Receive Buffer Data Register - Read-only 656 I2Cn_RXDATAP = 0x020, // Receive Buffer Data Peek Register - Read-only 657 I2Cn_TXDATA = 0x024, // Transmit Buffer Data Register - Write-only 658 I2Cn_IF = 0x028, // Interrupt Flag Register - Read-only 659 I2Cn_IFS = 0x02C, // Interrupt Flag Set Register - Write-1-only 660 I2Cn_IFC = 0x030, // Interrupt Flag Clear Register - Write-1-only 661 I2Cn_IEN = 0x034, // Interrupt Enable Register - Read-Write 662 I2Cn_ROUTE = 0x038 // I/O Routing Register - Read-Write 663 } 664 665 // Bits in the Control register (0-31) 666 private enum Control 667 { 668 EN = 0x0, // I2C Enable 669 SLAVE = 0x1, // Addressable as slave 670 AUTOACK = 0x2, // Automatic acknowledge 671 AUTOSE = 0x3, // Automatic STOP when empty 672 AUTOSN = 0x4, // Automatic STOP on NACK 673 ARBDIS = 0x5, // Arbitration disable 674 GCAMEN = 0x6, // General Call Address Match Enable 675 CLHR_0 = 0x8, // Clock Low High Ratio, bit 0 676 CLHR_1 = 0x9, // Clock Low High Ratio, bit 1 677 BITO_0 = 0x12, // Bus Idle Timeout, bit 0 678 BITO_1 = 0x13, // Bus Idle Timeout, bit 1 679 GIBITO = 0x15, // Go Idle on Bus Idle Timeout 680 CLTO_0 = 0x16, // Clock Low Timeout, bit 0 681 CLTO_1 = 0x17, // Clock Low Timeout, bit 1 682 CLTO_2 = 0x18 // Clock Low Timeout, bit 2 683 684 } 685 686 // Values in the Command register (Only bits 0-7 used, 8-31 reserved) 687 private enum Commands 688 { 689 START = 0x01, // Send start condition 690 STOP = 0x02, // Send stop condition 691 ACK = 0x04, // Send ACK 692 NACK = 0x08, // Send NACK 693 CONT = 0x10, // Continue transmission 694 ABORT = 0x20, // Abort transmission 695 CLEARTX = 0x40, // Clear TX 696 CLEARPC = 0x80 // Clear pending commands 697 } 698 699 // Values in the State register (0-31) - Only some states, see pages 423-424 in EFM32GG ref manual 700 private enum StateVal 701 { 702 StartTrans = 0x57, 703 AddrWAck = 0x97, 704 AddrWNack = 0x9F, 705 DataWAck = 0xD7, 706 DataWNack = 0xDF 707 } 708 709 // Bits in the State register (0-31) 710 private enum StateReg 711 { 712 BUSY = 0x0, // Bus busy 713 MASTER = 0x1, // Master 714 TRANSMIT = 0x2, // Transmitter 715 NACKED = 0x3, // Nack Received 716 BUSHOLD = 0x4, // Bus held 717 STATE_0 = 0x5, // Transmission state, bit 0 718 STATE_1 = 0x6, // Transmission state, bit 1 719 STATE_2 = 0x7 // Transmission state, bit 2 720 } 721 722 // Bits in the Status register (0-31) 723 private enum Status 724 { 725 PSTART = 0x0, // Pending start 726 PSTOP = 0x1, // Pending stop 727 PACK = 0x2, // Pending ACK 728 PNACK = 0x3, // Pending NACK 729 PCONT = 0x4, // Pending continue transmission 730 PABORT = 0x5, // Pending abort transmission 731 TXC = 0x6, // TX complete 732 TXBL = 0x7, // TX buffer level 733 RXDATAV = 0x8 // RX data valid 734 } 735 736 // Bits in the Interrupt Flag Register (0-31) 737 private enum Interrupts 738 { 739 START = 0x00, // START condition Interrupt Flag 740 RSTART = 0x01, // Repeated START condition Interrupt Flag 741 ADDR = 0x02, // Address Interrupt Flag 742 TXC = 0x03, // Transfer Completed Interrupt Flag 743 TXBL = 0x04, // Transmit Buffer Level Interrupt Flag 744 RXDATAV = 0x05, // Receive Data Valid Interrupt Flag 745 ACK = 0x06, // Acknowledge Received Interrupt Flag 746 NACK = 0x07, // Not Acknowledge Received Interrupt Flag 747 MSTOP = 0x08, // Master STOP Condition Interrupt Flag 748 ARBLOST = 0x09, // Arbitration Lost Interrupt Flag 749 BUSERR = 0x0A, // Bus Error Interrupt Flag 750 BUSHOLD = 0x0B, // Bus Held Interrupt Flag 751 TXOF = 0x0C, // Transmit Buffer Overflow Interrupt Flag 752 RXUF = 0x0D, // Receive Buffer Underflow Interrupt Flag 753 BITO = 0x0E, // Bus Idle Timeout Interrupt Flag 754 CLTO = 0x0F, // Clock Low Timeout Interrupt Flag 755 SSTOP = 0x10 // Slave STOP condition Interrupt Flag 756 } 757 758 // Transfer state enumaration 759 private enum TransferState 760 { 761 Idle = 0x0, 762 StartTrans = 0x1, 763 RestartTrans = 0x2, 764 ReadTrans = 0x3, 765 StopTrans = 0x4 766 } 767 768 private enum PacketStates 769 { 770 ReadData = 0xFC, 771 SendData = 0xFD 772 } 773 } 774 } 775 776