📄 i2cclass.cpp
字号:
//-----------------------------------------------------------------------------
//
// 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 + -