⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2cclass.cpp

📁 Microsoft WinCE 6.0 BSP FINAL release source code for use with the i.MX27ADS TO2 WCE600_FINAL_MX27_S
💻 CPP
📖 第 1 页 / 共 5 页
字号:


//-----------------------------------------------------------------------------
//
// Function: I2CClass::WritePacket
//
// This method performs a write operation with the data in one I2C_PACKET.
//
// Parameters:
//      pI2CPkt
//          [in] Contains all the necessary information to transmit/
//          receive from the slave device.
//
//      bLast
//          [in] Signifies if this is the last packet to be transmitted.
//
// Returns:  
//      None.
//
//-----------------------------------------------------------------------------
BOOL I2CClass::WritePacket(PI2C_PACKET pI2CPkt, BOOL bLast)
{
    int intrRetry;
    UINT16 i2sr;

    PBYTE pWriteBufPtr = pI2CPkt->pbyBuf;

    // Set MTX to switch to transmit mode
    INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MTX),
             CSP_BITFVAL(I2C_I2CR_MTX, I2C_I2CR_MTX_TRANSMIT));

    (*(pI2CPkt->lpiResult)) = I2C_NO_ERROR;

    for (int i = 0; i < pI2CPkt->wLen; i++)
    {
        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): ")
                                 TEXT("Transmitting Next Byte: %x! \r\n"),
                                 *pWriteBufPtr));

        bDispatchEvent = TRUE;

        OUTREG16(&pI2CReg->I2DR, (*pWriteBufPtr));
        pWriteBufPtr++;

        // Wait for interrupt event
        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): ")
                                 TEXT("Waiting for incoming interrupt! \r\n")));

        intrRetry=iIntrWaitTimeoutRetry;
WaitRetry:
        if (WaitForSingleObject(m_hI2CIntrEvent, iIntrWaitTimeout) == WAIT_TIMEOUT)
        {
            if (--intrRetry>0)
            {
                goto WaitRetry;
            }
            DEBUGMSG(ZONE_ERROR, (TEXT("I2CClass::ProcessPacket(): ")
                                  TEXT("Timed out waiting for interrupt! ")
                                  TEXT("Aborting I2C transfer.\r\n")));

            (*(pI2CPkt->lpiResult)) = I2C_ERR_TRANSFER_TIMEOUT;
            goto error_cleanup;
        }

        // Clear Interrupt Signal
        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): ")
                                 TEXT("Clear Interrupt! \r\n")));

        i2sr = INREG16(&pI2CReg->I2SR);

        bDispatchEvent = FALSE;
        INSREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IIF),
                 CSP_BITFVAL(I2C_I2SR_IIF, 0));
        ResetEvent(m_hI2CIntrEvent);
        InterruptDone(dwSysIntr);

        if (EXTREG16BF(&pI2CReg->I2SR, I2C_I2SR_IAL))
        {
            // Arbitration lost.  An error has occurred, likely due to a bad
            // slave I2C address.

            // Clear IAL bit (we are already put into Stop)
            INSREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IAL),
                     CSP_BITFVAL(I2C_I2SR_IAL, I2C_I2SR_IAL_NOT_LOST));

            INSREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IIF),
                     CSP_BITFVAL(I2C_I2SR_IIF, 0));

           (*(pI2CPkt->lpiResult)) = I2C_ERR_ARBITRATION_LOST;
            goto error_cleanup;
        }

        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): ")
                                 TEXT("Got Detect ACK? \r\n")));
        if ( (i<pI2CPkt->wLen -1) &&
            (EXTREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_RXAK),
                     I2C_I2SR_RXAK_LSH) == I2C_I2SR_RXAK_NO_ACK_DETECT))
        {
            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): ")
                                     TEXT("No ACK, STOP issued! -\r\n")));

            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): ")
                                     TEXT("No ACK, STOP issued! -\r\n")));

            (*(pI2CPkt->lpiResult)) = I2C_ERR_NO_ACK_ISSUED;
            goto error_cleanup;
        }   
            
    }
        
    if (EXTREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IIF), 
                 I2C_I2SR_IIF_LSH) == I2C_I2SR_IIF_PENDING)
    {
        DEBUGMSG(ZONE_FUNCTION, (_T("IIF dose not reset in WR.Pkt\r\n")));
    }

    if (bLast)
    {
        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): ")
                                 TEXT("Send STOP...this is the last packet ")
                                 TEXT("written. \r\n")));
        // Send STOP signal if this is the last packet to process
        OUTREG16(&pI2CReg->I2SR, 0);
        GenerateStop();
    }

    bDispatchEvent = FALSE;
    OUTREG16(&pI2CReg->I2SR, 0);

    return TRUE;

error_cleanup:

    bDispatchEvent = FALSE;
    OUTREG16(&pI2CReg->I2SR, 0);

    // Capture Error for debug
    if ( CleanupPendingInterrupt() )
    {
        DEBUGMSG(ZONE_FUNCTION, (_T("Warning: Event remain AFTER Write packet done\r\n")));
    }

    // Send a STOP Signal
    if (EXTREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MSTA),
                 I2C_I2CR_MSTA_LSH) == I2C_I2CR_MSTA_MASTER)
    {
        GenerateStop();
    }
    return FALSE;
}


//-----------------------------------------------------------------------------
//
// Function: I2CClass::ReadPacket
//
// This method performs a read operation with the data in one I2C_PACKET.
//
// Parameters:
//      pI2CPkt
//          [in] Contains all the necessary information to transmit/
//          receive from the slave device.
//
//      bLast
//          [in] Signifies if this is the last packet to be transmitted.
//
//      bAddrCycleComplete
//          [in] Signifies that the slave address cycle was just completed.
//
// Returns:  
//      TRUE   Success.
//      FALSE  Arbitration lost or timeout error.
//
//-----------------------------------------------------------------------------
BOOL I2CClass::ReadPacket(PI2C_PACKET pI2CPkt, BOOL bLast, BOOL bAddrCycleComplete, BOOL *pbRSTACycleComplete)
{
    UINT16 i2sr;
    int intrRetry;

    PBYTE pReadBufPtr = pI2CPkt->pbyBuf;

    // Switch to Receive Mode
    INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MTX), CSP_BITFVAL(I2C_I2CR_MTX, I2C_I2CR_MTX_RECEIVE));

    // Clear the TXAK bit to gen an ack when receiving only one byte.
    if (pI2CPkt->wLen == 1)
    {
        INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_TXAK), CSP_BITFVAL(I2C_I2CR_TXAK, I2C_I2CR_TXAK_NO_ACK_SEND));
    }
    else
    {
        INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_TXAK), CSP_BITFVAL(I2C_I2CR_TXAK, I2C_I2CR_TXAK_ACK_SEND));
    }

    if (bAddrCycleComplete)
    {
        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Dummy read to trigger I2C Read operation.\r\n")));

        // Dummy read to trigger I2C Read operation
        bDispatchEvent=TRUE;
        INREG16(&pI2CReg->I2DR);
    }

    (*(pI2CPkt->lpiResult)) = I2C_NO_ERROR;

    for (int i = 0; i < pI2CPkt->wLen; i++)
    {
        // Wait for data transmission to complete.
        // Wait for interrupt event.
        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Waiting for incoming interrupt! \r\n")));

        intrRetry=iIntrWaitTimeoutRetry;
WaitRetry:
        if (WaitForSingleObject(m_hI2CIntrEvent, iIntrWaitTimeout) == WAIT_TIMEOUT)
        {
            if (--intrRetry>0)
            {
                goto WaitRetry;
            }
            DEBUGMSG(ZONE_ERROR, (TEXT("I2CClass::ProcessPacket(): Timed out waiting for interrupt!  Aborting I2C transfer.\r\n")));                // Send STOP signal if this is the last packet to process

            (*(pI2CPkt->lpiResult)) = I2C_ERR_TRANSFER_TIMEOUT;

            goto error_cleanup;
        }

        i2sr = INREG16(&pI2CReg->I2SR);

        // Clear Interrupt Signal
        bDispatchEvent = FALSE;
        OUTREG16(&pI2CReg->I2SR, 0);
        ResetEvent(m_hI2CIntrEvent);
        InterruptDone(dwSysIntr);
        //DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Clear Interrupt! \r\n")));

        if (CSP_BITFEXT(i2sr, I2C_I2SR_IAL)==I2C_I2SR_IAL_LOST)
        {
            // Arbitration lost.  An error has occurred, likely due to a bad
            // slave I2C address. (we are already put into Stop)

            (*(pI2CPkt->lpiResult)) = I2C_ERR_ARBITRATION_LOST;
            goto error_cleanup;
        }


        // Do not generate an ACK for the last byte 
        if (i == (pI2CPkt->wLen - 2))
        {
            DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Change to No ACK for last byte. \r\n")));
            INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_TXAK), CSP_BITFVAL(I2C_I2CR_TXAK, I2C_I2CR_TXAK_NO_ACK_SEND));
        }
        else if (i == (pI2CPkt->wLen - 1))
        {
            if (bLast)
            {
                DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Send STOP...this is the last packet read. \r\n")));

                // Send STOP signal if this is the last packet to process
                GenerateStop();
                goto last_read_i2dr;
            }
            else 
            {
                // Send Repeated Start signal to initial next packet
                INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_RSTA),
                         CSP_BITFVAL(I2C_I2CR_RSTA, I2C_I2CR_RSTA_GENERATE));
                if ( pbRSTACycleComplete )
                {
                    *pbRSTACycleComplete = TRUE;
                }
                // Switch to Transmit Mode
                INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MTX), CSP_BITFVAL(I2C_I2CR_MTX, I2C_I2CR_MTX_TRANSMIT));
                goto last_read_i2dr;
            }
        }

        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Read next byte! \r\n")));
        bDispatchEvent = TRUE;

last_read_i2dr:
        (*pReadBufPtr) = (BYTE) INREG16(&pI2CReg->I2DR);
        DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Byte read: %x \r\n"), *pReadBufPtr));
        ++pReadBufPtr;
    }

    OUTREG16(&pI2CReg->I2SR, 0);
    bDispatchEvent = FALSE;

    return TRUE;

error_cleanup:

    bDispatchEvent = FALSE;
    OUTREG16(&pI2CReg->I2SR, 0);

    // Capture Error for debug
    if ( CleanupPendingInterrupt() )
    {
        DEBUGMSG(ZONE_FUNCTION, (_T("Warning: Event remain pending AFTER read packet done\r\n")));
    }

    // Send a STOP Signal
    if (EXTREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MSTA),
                 I2C_I2CR_MSTA_LSH) == I2C_I2CR_MSTA_MASTER)
    {
        GenerateStop();
    }
    return FALSE;
}

//-----------------------------------------------------------------------------
//
// Function: I2CClass::CleanupPendingInterrupt
//
// Shall not Interrupt pending before ProcessPackets does it work.
// This function ensure this condition.
//
// Parameters:
//      None. 
//
// Returns:  
//      TRUE:   Clean pending interrupt
//      FALSE:  No interrupt pending
//
//-----------------------------------------------------------------------------
BOOL I2CClass::CleanupPendingInterrupt(void)
{
    BOOL bRet;
    int count;

    bRet = FALSE;
    count=0;
    while (WaitForSingleObject(m_hI2CIntrEvent, 0) == WAIT_OBJECT_0)
    {
        ++count;
        OUTREG16(&pI2CReg->I2SR, 0);
        // Reset the event manually
        ResetEvent(m_hI2CIntrEvent);
        InterruptDone(dwSysIntr);
        bRet = TRUE;
    }
    return bRet;
}
//-----------------------------------------------------------------------------
//
// Function: I2CClass::ProcessPackets
//
// This is the main engine that transmits or receives data from I2C Bus
// Interface. This engine implements the complete I2C Bus Protocol which allows
// the calling process to interact with all I2C-compliant slave device. This
// method has built-in mechanism to prevent concurrent execution.
//
// Parameters:
//      pPacket 
//          [in] Contains all the necessary information to transmit/
//          receive from the slave device.
//
//      dwNumPackets
//          [in] Number of packets to be processed.
//
// Returns:  
//      TRUE   Success.
//      FALSE  Failed due to any one of the following conditions:
//               - failed to enable the I2C clock
//               - GenerateStart() call returned an error
//               - timed out waiting for interrupt notification
//               - arbitration lost
//               - transfer operation timed out
//
//-----------------------------------------------------------------------------
BOOL I2CClass::ProcessPackets(I2C_PACKET packets[], INT32 numPackets)
{
    BOOL retVal = TRUE;
    // Flag to signal if address cycle just completed
    BOOL bAddrCycleComplete;
    BOOL bRSTACycleComplete;

⌨️ 快捷键说明

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