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 + -
显示快捷键?