Пример #1
0
/*
 * 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;
}
Пример #2
0
/*
 * 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;
}