📄 i2cclass.cpp
字号:
// Release Interrupt Occurrence Event -
{
if (hInterrupted != NULL)
CloseHandle(hInterrupted);
DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass: Release Interrupt Occurence Event \r\n")));
}
// Release I2C Register Base Mapped Virtual Memory -
{
if (pI2CReg != NULL)
MmUnmapIoSpace((LPVOID) pI2CReg, sizeof(CSP_I2C_REG));
DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass: Release I2C Register Base Mapped Virtual Memory \r\n")));
}
DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass -\r\n")));
}
//-----------------------------------------------------------------------------
//
// Function: I2CClass::Reset
//
// This method performs a software reset on I2C internal register (I2CR). It is
// important to take note that the fields of the I2CClass are not modified in
// any way.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
VOID I2CClass::Reset(void)
{
OUTREG16(&pI2CReg->I2CR, 0x0);
iResult = I2C_NO_ERROR;
}
//-----------------------------------------------------------------------------
//
// Function: I2CClass::GenerateStart
//
// This method performs generates an I2C START signal to a slave device.
//
// Parameters:
// pI2CPkt
// [in] Contains all the necessary information to transmit/
// receive from the slave device
//
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
VOID I2CClass::GenerateStart(PI2C_PACKET pI2CPkt)
{
BYTE bySlaveAddr;
while (EXTREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_IBB), I2C_I2SR_IBB_LSH) == I2C_I2SR_IBB_BUSY);
// Grant Bus Master
INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MSTA), CSP_BITFVAL(I2C_I2CR_MSTA, I2C_I2CR_MSTA_MASTER));
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Bus Master Granted! \r\n")));
// Transmit the slave address, then change to receive mode after
// we complete the address cycle.
INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MTX), CSP_BITFVAL(I2C_I2CR_MTX, I2C_I2CR_MTX_TRANSMIT));
bySlaveAddr = (pI2CPkt->byAddr << 1) | ((pI2CPkt->byRW == I2C_RW_READ) ? 1 : 0);
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): To I2DR->0x%x (slave addr)\r\n"), bySlaveAddr));
OUTREG16(&pI2CReg->I2DR, bySlaveAddr);
}
//-----------------------------------------------------------------------------
//
// Function: I2CClass::GenerateRepeatedStart
//
// This method performs generates an I2C REPEATED START signal to a slave device.
//
// Parameters:
// pI2CPkt
// [in] Contains all the necessary information to transmit/
// receive from the slave device
//
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
VOID I2CClass::GenerateRepeatedStart(PI2C_PACKET pI2CPkt)
{
BYTE bySlaveAddr;
// Set the repeated start bit in the I2C CR.
INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_RSTA), CSP_BITFVAL(I2C_I2CR_RSTA, I2C_I2CR_RSTA_GENERATE));
// Temporary fix related to Repeated Start. Delay after repeated start for 1 PAT_REF_CLK period.
StallExecution(3);
// Append read or write bit to 7 bit slave address
bySlaveAddr = (pI2CPkt->byAddr << 1) | ((pI2CPkt->byRW == I2C_RW_READ) ? 1 : 0);
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): To I2DR->0x%x (slave addr)\r\n"), bySlaveAddr));
OUTREG16(&pI2CReg->I2DR, bySlaveAddr);
}
//-----------------------------------------------------------------------------
//
// 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)
{
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));
for (int i = 0; i < pI2CPkt->wLen; i++)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Transmitting Next Byte: %x! \r\n"), *pWriteBufPtr));
OUTREG16(&pI2CReg->I2DR, (*pWriteBufPtr));
pWriteBufPtr++;
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));
return FALSE;
}
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), I2C_I2SR_IAL_NOT_LOST);
return FALSE;
}
// 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));
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Got Detect ACK? \r\n")));
if (EXTREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_RXAK), I2C_I2SR_RXAK_LSH) == I2C_I2SR_RXAK_NO_ACK_DETECT)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): No ACK, STOP issued! -\r\n")));
// Send a STOP Signal
INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MSTA), CSP_BITFVAL(I2C_I2CR_MSTA, I2C_I2CR_MSTA_SLAVE));
(*(pI2CPkt->lpiResult)) = I2C_ERR_NO_ACK_ISSUED;
break;
} // if (EXTREG16(&pI2CReg->I2SR, CSP_BITFMASK(I2C_I2SR_RXAK), I2C_I2SR_RXAK_LSH) == I2C_I2SR_RXAK_NO_ACK_DETECT)
}
if (bLast)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Send STOP...this is the last packet written. \r\n")));
// Send STOP signal if this is the last packet to process
INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MSTA), CSP_BITFVAL(I2C_I2CR_MSTA, I2C_I2CR_MSTA_SLAVE));
// Linux code also clears MTX as part of STOP
INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MTX), CSP_BITFVAL(I2C_I2CR_MTX, I2C_I2CR_MTX_TRANSMIT));
(*(pI2CPkt->lpiResult)) = I2C_NO_ERROR;
}
return TRUE;
}
//-----------------------------------------------------------------------------
//
// 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:
// None.
//
//-----------------------------------------------------------------------------
BOOL I2CClass::ReadPacket(PI2C_PACKET pI2CPkt, BOOL bLast, BOOL bAddrCycleComplete)
{
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
INREG16(&pI2CReg->I2DR);
// TODO: Needed? If we remove, will this interfere with interrupt generation for following read op?
InterruptDone(dwSysIntr);
}
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")));
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 if this is the last packet to process
// Send stop signal to abort
INSREG16(&pI2CReg->I2CR, CSP_BITFMASK(I2C_I2CR_MSTA), CSP_BITFVAL(I2C_I2CR_MSTA, I2C_I2CR_MSTA_SLAVE));
return FALSE;
}
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), I2C_I2SR_IAL_NOT_LOST);
return FALSE;
}
// 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));
// 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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -