/* * I2CONSET * 0x04 AA * 0x08 SI * 0x10 STOP * 0x20 START * 0x40 ENABLE * * I2CONCLR * 0x04 AA * 0x08 SI * 0x20 START * 0x40 ENABLE */ I2C_Base::mI2CStateMachineStatusType I2C_Base::i2cStateMachine() { enum I2CStatus{ busError=0, start=0x08, repeatStart=0x10, arbitrationLost=0x38, // Master Transmitter States: slaveAddressAcked=0x18, slaveAddressNacked=0x20, dataAckedBySlave=0x28, dataNackedBySlave=0x30, // Master Receiver States: readAckedBySlave=0x40, readModeNackedBySlave=0x48, dataAvailableAckSent=0x50, dataAvailableNackSent=0x58 }; mI2CStateMachineStatusType state = busy; /* *********************************************************************************************************** * Write-mode state transition : * start --> slaveAddressAcked --> dataAckedBySlave --> ... (dataAckedBySlave) --> (stop) * * Read-mode state transition : * start --> slaveAddressAcked --> dataAcked --> repeatStart --> readAckedBySlave * For 2+ bytes: dataAvailableAckSent --> ... (dataAvailableAckSent) --> dataAvailableNackSent --> (stop) * For 1 byte : dataAvailableNackSent --> (stop) *********************************************************************************************************** */ #define clearSIFlag() mpI2CRegs->I2CONCLR = (1<<3) #define setSTARTFlag() mpI2CRegs->I2CONSET = (1<<5) #define clearSTARTFlag() mpI2CRegs->I2CONCLR = (1<<5) // busInUse is only set to 0 for write operation since read operation should set to 0 itself #define setStop() clearSTARTFlag(); \ mpI2CRegs->I2CONSET = (1<<4); \ clearSIFlag(); \ while((mpI2CRegs->I2CONSET&(1<<4))); \ if(i2cRead == mI2CIOFrame.mode) \ state = readComplete; \ else \ state = writeComplete; switch (mpI2CRegs->I2STAT) { case start: mpI2CRegs->I2DAT = mI2CIOFrame.slaveAddress; clearSIFlag(); break; case repeatStart: mpI2CRegs->I2DAT = mI2CIOFrame.slaveAddress | 0x01; clearSIFlag(); break; case slaveAddressAcked: clearSTARTFlag(); if(0 == mI2CIOFrame.bytesToTransfer) { setStop(); } else { mpI2CRegs->I2DAT = mI2CIOFrame.firstRegister; clearSIFlag(); } break; case slaveAddressNacked: mI2CIOFrame.error = mpI2CRegs->I2STAT; setStop(); break; case dataAckedBySlave: if (i2cRead == mI2CIOFrame.mode) { setSTARTFlag(); // Send Repeat-start for read-mode clearSIFlag(); } else { if(mI2CIOFrame.bytePointer >= mI2CIOFrame.bytesToTransfer) { setStop(); } else { mpI2CRegs->I2DAT = mI2CIOFrame.rwBuffer[mI2CIOFrame.bytePointer++]; clearSIFlag(); } } break; case dataNackedBySlave: mI2CIOFrame.error = mpI2CRegs->I2STAT; setStop(); break; case readAckedBySlave: clearSTARTFlag(); if(mI2CIOFrame.bytesToTransfer > 1) mpI2CRegs->I2CONSET = 0x04; // Send ACK to receive a byte and transition to dataAvailableAckSent else mpI2CRegs->I2CONCLR = 0x04; // NACK next byte to go to dataAvailableNackSent for 1-byte read. clearSIFlag(); break; case readModeNackedBySlave: mI2CIOFrame.error = mpI2CRegs->I2STAT; setStop(); break; case dataAvailableAckSent: mI2CIOFrame.rwBuffer[mI2CIOFrame.bytePointer++] = mpI2CRegs->I2DAT; if(mI2CIOFrame.bytePointer >= (mI2CIOFrame.bytesToTransfer-1)) { // Only 1 more byte remaining mpI2CRegs->I2CONCLR = 0x04; // NACK next byte --> Next state: dataAvailableNackSent } else { mpI2CRegs->I2CONSET = 0x04; // ACK next byte --> Next state: dataAvailableAckSent(back to this state) } clearSIFlag(); break; case dataAvailableNackSent: // Read last-byte from Slave mI2CIOFrame.rwBuffer[mI2CIOFrame.bytePointer++] = mpI2CRegs->I2DAT; setStop(); break; case busError: mI2CIOFrame.error = mpI2CRegs->I2STAT; setStop(); break; case arbitrationLost: // We should not issue stop() in this condition, but we still need to end our // i2c transaction. state = mI2CIOFrame.mode == i2cRead ? readComplete : writeComplete; mI2CIOFrame.error = mpI2CRegs->I2STAT; break; default: mI2CIOFrame.error = mpI2CRegs->I2STAT; setStop(); break; } return state; }
/* * I2CONSET bits * 0x04 AA * 0x08 SI * 0x10 STOP * 0x20 START * 0x40 ENABLE * * I2CONCLR bits * 0x04 AA * 0x08 SI * 0x20 START * 0x40 ENABLE */ I2C_Base::mStateMachineStatus_t I2C_Base::i2cStateMachine() { enum { // General states : busError = 0x00, start = 0x08, repeatStart = 0x10, arbitrationLost = 0x38, // Master Transmitter States: slaveAddressAcked = 0x18, slaveAddressNacked = 0x20, dataAckedBySlave = 0x28, dataNackedBySlave = 0x30, // Master Receiver States: readAckedBySlave = 0x40, readModeNackedBySlave = 0x48, dataAvailableAckSent = 0x50, dataAvailableNackSent = 0x58, }; mStateMachineStatus_t state = busy; /* *********************************************************************************************************** * Write-mode state transition : * start --> slaveAddressAcked --> dataAckedBySlave --> ... (dataAckedBySlave) --> (stop) * * Read-mode state transition : * start --> slaveAddressAcked --> dataAcked --> repeatStart --> readAckedBySlave * For 2+ bytes: dataAvailableAckSent --> ... (dataAvailableAckSent) --> dataAvailableNackSent --> (stop) * For 1 byte : dataAvailableNackSent --> (stop) *********************************************************************************************************** */ /* Me being lazy and using #defines instead of inline functions :( */ #define clearSIFlag() mpI2CRegs->I2CONCLR = (1<<3) #define setSTARTFlag() mpI2CRegs->I2CONSET = (1<<5) #define clearSTARTFlag() mpI2CRegs->I2CONCLR = (1<<5) #define setAckFlag() mpI2CRegs->I2CONSET = (1<<2) #define setNackFlag() mpI2CRegs->I2CONCLR = (1<<2) /* yep ... lazy again */ #define setStop() clearSTARTFlag(); \ mpI2CRegs->I2CONSET = (1<<4); \ clearSIFlag(); \ while((mpI2CRegs->I2CONSET&(1<<4))); \ if(I2C_READ_MODE(mTransaction.slaveAddr)) \ state = readComplete; \ else \ state = writeComplete; switch (mpI2CRegs->I2STAT) { case start: mpI2CRegs->I2DAT = I2C_WRITE_ADDR(mTransaction.slaveAddr); clearSIFlag(); break; case repeatStart: mpI2CRegs->I2DAT = I2C_READ_ADDR(mTransaction.slaveAddr); clearSIFlag(); break; case slaveAddressAcked: clearSTARTFlag(); // No data to transfer, this is used just to test if the slave responds if(0 == mTransaction.trxSize) { setStop(); } else { mpI2CRegs->I2DAT = mTransaction.firstReg; clearSIFlag(); } break; case dataAckedBySlave: if (I2C_READ_MODE(mTransaction.slaveAddr)) { setSTARTFlag(); // Send Repeat-start for read-mode clearSIFlag(); } else { if(0 == mTransaction.trxSize) { setStop(); } else { mpI2CRegs->I2DAT = *(mTransaction.pMasterData); ++mTransaction.pMasterData; --mTransaction.trxSize; clearSIFlag(); } } break; /* In this state, we are about to initiate the transfer of data from slave to us * so we are just setting the ACK or NACK that we'll do AFTER the byte is received. */ case readAckedBySlave: clearSTARTFlag(); if(mTransaction.trxSize > 1) { setAckFlag(); // 1+ bytes: Send ACK to receive a byte and transition to dataAvailableAckSent } else { setNackFlag(); // 1 byte : NACK next byte to go to dataAvailableNackSent for 1-byte read. } clearSIFlag(); break; case dataAvailableAckSent: *mTransaction.pMasterData = mpI2CRegs->I2DAT; ++mTransaction.pMasterData; --mTransaction.trxSize; if(1 == mTransaction.trxSize) { // Only 1 more byte remaining setNackFlag();// NACK next byte --> Next state: dataAvailableNackSent } else { setAckFlag(); // ACK next byte --> Next state: dataAvailableAckSent(back to this state) } clearSIFlag(); break; case dataAvailableNackSent: // Read last-byte from Slave *mTransaction.pMasterData = mpI2CRegs->I2DAT; setStop(); break; case arbitrationLost: // We should not issue stop() in this condition, but we still need to end our transaction. state = I2C_READ_MODE(mTransaction.slaveAddr) ? readComplete : writeComplete; mTransaction.error = mpI2CRegs->I2STAT; break; case slaveAddressNacked: // no break case dataNackedBySlave: // no break case readModeNackedBySlave: // no break case busError: // no break default: mTransaction.error = mpI2CRegs->I2STAT; setStop(); break; } return state; }