i2cclass.cpp

来自「i.mx27 soc for wince 6.0」· C++ 代码 · 共 935 行 · 第 1/3 页

CPP
935
字号
//-----------------------------------------------------------------------------
BOOL I2CClass::ProcessPackets(I2C_PACKET packets[], INT32 numPackets)
{
    BOOL retVal = TRUE;
    // Flag to signal if address cycle just completed
    BOOL bAddrCycleComplete;

    // Must gain ownership to bus lock mutex
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): + \r\n")));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Waiting for Bus Lock CS \r\n")));
    EnterCriticalSection(&m_csI2CBusLock);
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Acquired Bus Lock CS! \r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket():BSPI2CEnableClock(): Enabling I2C Clock! \r\n")));

    // Enabling I2C Clock
    if (!BSPI2CEnableClock(m_iModuleIndex, TRUE))
    {
        DEBUGMSG(ZONE_FUNCTION | ZONE_ERROR, (TEXT("I2CClass::ProcessPacket():BSPI2CEnableClock(): I2C Clock cannot be enabled! \r\n")));
        retVal = FALSE;
        goto __exit;
    }

    // Reset I2CR
    OUTREG16(&pI2CReg->I2CR, 0x0);
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Resetting I2CR \r\n")));

    // Try resetting I2DR = 0x0
    OUTREG16(&pI2CReg->I2DR, 0x0);
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Resetting I2DR \r\n")));

    // Configure data sampling rate
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Trying to set IFDR->0x%x! \r\n"), wLastClkRate));
    OUTREG16(&pI2CReg->IFDR, CSP_BITFVAL(I2C_IFDR_IC, wLastClkRate));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Set IFDR->0x%x! \r\n"), INREG16(&pI2CReg->IFDR)));

    // Configure slave address
    OUTREG16(&pI2CReg->IADR, CSP_BITFVAL(I2C_IADR_ADR, byLastSelfAddr));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Configure Self Address->0x%x \r\n"), INREG16(&pI2CReg->IADR)));

    // Enable I2C
    INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_IEN), CSP_BITFVAL(I2C_I2CR_IEN, I2C_I2CR_IEN_ENABLE));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Enable I2C \r\n")));

    // Enable I2C Interrupt
    INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_IIEN), CSP_BITFVAL(I2C_I2CR_IIEN, I2C_I2CR_IIEN_ENABLE));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Enable I2C Interrupt \r\n")));

    // For each I2C packet, transfer data as specified
    for (int i = 0; i < numPackets; i++)
    {
        bAddrCycleComplete = FALSE;

        // Initialize Tx/Rx buffer navigator
        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Setting up Tx/Rx Buffer Navigator \r\n")));
        PBYTE pbyBufPtr = packets[i].pbyBuf;
        PBYTE pbyBufEnd = pbyBufPtr + packets[i].wLen;

        // Send a START signal if this is our first packet
        if (i == 0)
        {
            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket():Issuing START command.\r\n")));
            GenerateStart(&packets[i]);

            InterruptDone(dwSysIntr);

            // Wait for interrupt event
            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Waiting for incoming interrupt! \r\n")));
            if (WaitForSingleObject(m_hI2CIntrEvent, iIntrWaitTimeout) == WAIT_TIMEOUT)
            {
                DEBUGMSG(ZONE_ERROR, (TEXT("I2CClass::ProcessPacket(): Timed out waiting for interrupt!  Aborting I2C transfer.\r\n")));

                // Send stop signal to abort
                INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MSTA), CSP_BITFVAL(I2C_I2CR_MSTA, I2C_I2CR_MSTA_SLAVE));
                retVal = FALSE;
                goto __exit;
            }

            if (EXTREG16BF(&pI2CReg->I2SR, I2C_I2SR_IAL))
            {
                // Arbitration lost.  An error has occurred, likely due to a bad
                // slave I2C address.
                *(packets[i].lpiResult) = I2C_ERR_ARBITRATION_LOST;

                // Clear IAL bit (we are already put into Stop)
                INSREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IAL), I2C_I2SR_IAL_NOT_LOST);
                retVal = FALSE;
                goto __exit;
            }

            // Clear Interrupt Signal
            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Clear Interrupt! \r\n")));
            INSREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IIF), CSP_BITFVAL(I2C_I2SR_IIF, 0));

            bAddrCycleComplete = TRUE;
        }
        // Send a REPEATED START signal if the address
        // changed or the transfer direction changed.
        else if ((packets[i].byAddr != packets[i - 1].byAddr) ||
                   (packets[i].byRW != packets[i - 1].byRW))
        {
            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket():Issuing REPEATED START command.\r\n")));
            GenerateRepeatedStart(&packets[i]);

            InterruptDone(dwSysIntr);

            // Wait for interrupt event
            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Waiting for incoming interrupt! \r\n")));
            if (WaitForSingleObject(m_hI2CIntrEvent, iIntrWaitTimeout) == WAIT_TIMEOUT)
            {
                DEBUGMSG(ZONE_ERROR, (TEXT("I2CClass::ProcessPacket(): Timed out waiting for interrupt!  Aborting I2C transfer.\r\n")));

                // Send stop signal to abort
                INSREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IAL), I2C_I2SR_IAL_NOT_LOST);
                retVal = FALSE;
                goto __exit;
            }

            if (EXTREG16BF(&pI2CReg->I2SR, I2C_I2SR_IAL))
            {
                // Arbitration lost.  An error has occurred, likely due to a bad
                // slave I2C address.
                *(packets[i].lpiResult) = I2C_ERR_ARBITRATION_LOST;

                // Clear IAL bit (we are already put into Stop)
                INSREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IAL), I2C_I2SR_IAL_NOT_LOST);
                retVal = FALSE;
                goto __exit;
            }

            // Clear Interrupt Signal
            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Clear Interrupt! \r\n")));
            INSREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IIF), CSP_BITFVAL(I2C_I2SR_IIF, 0));

            bAddrCycleComplete = TRUE;
        }

        // Is I2C in master mode?
        if (byLastMode == I2C_MASTER_MODE)
        {

            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): I2C In Master Mode! \r\n")));
            // I2C Transmitting?
            if (packets[i].byRW == I2C_RW_WRITE)
            {
                if (!WritePacket(&packets[i], (i + 1 == numPackets)))
                {
                    retVal = FALSE;
                    goto __exit;
                }
            }
            // I2C Receiving?
            else
            {
                if (!ReadPacket(&packets[i], (i + 1 == numPackets), bAddrCycleComplete))
                {
                    retVal = FALSE;
                    goto __exit;
                }
            }
                
        }
        else
        {
            // TODO: Is slave mode support needed?
        }
    }
	
__exit:
    // Disable I2C Module
    OUTREG16(&pI2CReg->I2CR, 0);

    // Disable I2C Clock
    DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Disabling I2C Clock! \r\n")));                

    BSPI2CEnableClock(m_iModuleIndex, FALSE);

    // On completion, release bus lock mutex
    LeaveCriticalSection(&m_csI2CBusLock);

    // Return success
    return retVal;
}


//------------------------------------------------------------------------------
//
// Function: I2CIST
//
// This function is the IPU IST thread.
//
// Parameters:
//      None
//
// Returns:
//      None
//
//-----------------------------------------------------------------------------
void I2CClass::I2CIST(LPVOID lpParameter)
{
    I2CClass *pI2C = (I2CClass *)lpParameter;

    pI2C->I2CInterruptHandler(INFINITE);

    return;
}



//-----------------------------------------------------------------------------
//
// Function: I2CInterruptHandler
//
// This function is the interrupt handler for the I2C.
// It waits for an I2C interrupt, and signals
// the event to the driver.  This additional layer of 
// event signalling is required to prevent priority inversion bugs.
//
// Parameters:
//      timeout
//          [in] Timeout value while waiting for EOF interrupt.
//
// Returns:
//      None
//
//-----------------------------------------------------------------------------
void I2CClass::I2CInterruptHandler(UINT32 timeout)
{
    // loop here
    while(TRUE)
    {
        DEBUGMSG (ZONE_FUNCTION, (TEXT("%s: In the loop\r\n"), __WFUNCTION__));

        if (WaitForSingleObject(hInterrupted, timeout) == WAIT_OBJECT_0)
        {
            DEBUGMSG (ZONE_FUNCTION, (TEXT("%s: Interrupt received\r\n"), __WFUNCTION__));

            SetEvent(m_hI2CIntrEvent);

            // Kernel call to unmask the interrupt so that it can be signalled again
//            InterruptDone(dwSysIntr);
        }
        else
        {
            DEBUGMSG (ZONE_ERROR, (TEXT("%s: Time out\r\n"), __WFUNCTION__));
        }

    }
    return;
}


//-----------------------------------------------------------------------------
//
// Function:  I2CGetBaseRegAddr
//
// This function returns the physical base address for the
// I2C registers based on the device index requested.
//
// Parameters:
//      index
//          [in] Index of the I2C device requested.
//
// Returns:
//      Physical base address for I2C registers, or 0 if an
//      invalid index was passed.
//
//-----------------------------------------------------------------------------
UINT32 I2CClass::I2CGetBaseRegAddr(UINT32 index)
{
    switch (index)
    {
        case 1:
            return CSP_BASE_REG_PA_I2C1;
        case 2:
            return CSP_BASE_REG_PA_I2C2;
        default:
            return 0;
    }
}


//-----------------------------------------------------------------------------
//
// Function:  I2CGetIRQ
//
// This function returns the IRQ number for the
// I2C based on the device index requested.
//
// Parameters:
//      index
//          [in] Index of the I2C device requested.
//
// Returns:
//      IRQ number for I2C, or 0 if an
//      invalid index was passed.
//
//-----------------------------------------------------------------------------
UINT32 I2CClass::I2CGetIRQ(UINT32 index)
{
    switch (index)
    {
        case 1:
            return IRQ_I2C1;
        case 2:
            return IRQ_I2C2;
        default:
            return 0;
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?