📄 i2cclass.cpp
字号:
// Must gain ownership to bus lock mutex
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Waiting for Bus Lock CS \r\n")));
EnterCriticalSection(&gcsI2CBusLock);
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket(): Acquired Bus Lock CS! \r\n")));
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket():BSPI2CEnableClock(): Enabling I2C Clock! \r\n")));
if (!bSlaveInUse)
{
// 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;
}
}
else
{
UINT16 i2sr;
i2sr = INREG16(&pI2CReg->I2SR);
while ( /*(CSP_BITFEXT(i2sr, I2C_I2SR_ICF)==I2C_I2SR_ICF_IN_PROGRESS)
||*/(CSP_BITFEXT(i2sr, I2C_I2SR_IBB) == I2C_I2SR_IBB_BUSY) )
{
// Intentional polling loop.
Sleep(0);
i2sr = INREG16(&pI2CReg->I2SR);
}
byInUseSlaveAddr = (BYTE)INREG16(&pI2CReg->IADR);
}
// 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")));
// Well, if every thing is ok, and all error exits clean their pending interrupt
// this shall never need. After all the check adds cost to every i2c xfer call.
// Actually, only failure xfer need do it.
// if ( CleanupPendingInterrupt() )
// {
// DEBUGMSG(ZONE_FUNCTION, (_T("Warning: There is Pending interrupt before process packets\r\n")));
// }
HANDLE hCurrentThread = GetCurrentThread ();
DWORD dwOrigThreadQuant = CeGetThreadQuantum ( hCurrentThread);
CeSetThreadQuantum ( hCurrentThread, dwOrigThreadQuant * 3 );
DWORD dwOrigThreadPrior = CeGetThreadPriority( hCurrentThread );
CeSetThreadPriority(hCurrentThread, CE_THREAD_PRIO_256_TIME_CRITICAL);
// For each I2C packet, transfer data as specified
bRSTACycleComplete = FALSE;
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")));
*(packets[i].lpiResult) = I2C_ERR_STATEMENT_CORRUPT;
// Send a START signal if this is our first packet
if (i == 0)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket():Issuing START command.\r\n")));
if (!GenerateStart(&packets[i]))
{
retVal = FALSE;
goto __exit;
}
bAddrCycleComplete = TRUE;
}
// Send a REPEATED START signal if the address
// changed or the transfer direction changed.
else
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("I2CClass::ProcessPacket():Issuing REPEATED START command.\r\n")));
if (!GenerateRepeatedStart(&packets[i], bRSTACycleComplete))
{
retVal = FALSE;
goto __exit;
}
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;
}
bRSTACycleComplete = FALSE;
}
// I2C Receiving?
else
{
if (!ReadPacket(&packets[i],
(i + 1 == numPackets),
bAddrCycleComplete,
&bRSTACycleComplete))
{
retVal = FALSE;
goto __exit;
}
}
*(packets[i].lpiResult) = I2C_NO_ERROR;
}
}
__exit:
CeSetThreadQuantum ( hCurrentThread, dwOrigThreadQuant );
CeSetThreadPriority( hCurrentThread, dwOrigThreadPrior);
if (!bSlaveInUse)
{
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 ProcessPkt\r\n")));
}
// 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);
}
else
{
UINT16 i2cr;
// Disable I2C Module
OUTREG16(&pI2CReg->I2CR, 0);
OUTREG16(&pI2CReg->IADR, byInUseSlaveAddr);
// Init I2CR
i2cr = CSP_BITFVAL(I2C_I2CR_IEN, 1);
OUTREG16(&pI2CReg->I2CR, i2cr);
i2cr = CSP_BITFVAL(I2C_I2CR_IEN, 1)|CSP_BITFVAL(I2C_I2CR_IIEN, 1);
OUTREG16(&pI2CReg->I2CR, i2cr);
OUTREG16(&pI2CReg->I2SR, 0);
}
// On completion, release bus lock mutex
LeaveCriticalSection(&gcsI2CBusLock);
return retVal;
}
//------------------------------------------------------------------------------
//
// Function: I2CIST
//
// This function is the IPU IST thread.
//
// Parameters:
// None
//
// Returns:
// None
//
//-----------------------------------------------------------------------------
void WINAPI I2CClass::I2CIST(LPVOID lpParameter)
{
I2CClass *pI2C = (I2CClass *)lpParameter;
pI2C->I2CInterruptHandler(INFINITE);
// Should only ever get here with bTerminateISTThread == TRUE. Simply
// returning here will gracefully terminate the IST handler thread.
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)
{
UINT16 i2sr;
UINT16 i2cr;
INT i;
INT iIdleCount;
// Loop here until signal to terminate the IST thread is received.
__loop:
while(!bTerminateISTThread)
{
DEBUGMSG (ZONE_FUNCTION, (TEXT("%s: In the loop\r\n"), __WFUNCTION__));
if (WaitForSingleObject(hInterrupted, timeout) == WAIT_OBJECT_0)
{
// Check if we woke up because of a terminate IST thread request.
if (bTerminateISTThread)
{
break;
}
DEBUGMSG (ZONE_FUNCTION, (TEXT("%s: Interrupt received\r\n"), __WFUNCTION__));
i2cr =INREG16(&pI2CReg->I2CR);
i2sr= INREG16(&pI2CReg->I2SR);
// if receive unexpected IIF
// we discard the data in I2DR
// and
// give NO ACK signal to master
// and release SCL line
if ((CSP_BITFEXT(i2cr, I2C_I2CR_MSTA)==I2C_I2CR_MSTA_SLAVE)
&& (CSP_BITFEXT(i2sr, I2C_I2SR_IAAS)==I2C_I2SR_IAAS_NOT_ADDRESSED)
&& (CSP_BITFEXT(i2sr, I2C_I2SR_IAL)==I2C_I2SR_IAL_NOT_LOST)
&& (CSP_BITFEXT(i2sr, I2C_I2SR_IIF)==I2C_I2SR_IIF_PENDING))
{
CSP_BITFCLR(i2cr, I2C_I2CR_MTX);
i2cr|=CSP_BITFVAL(I2C_I2CR_TXAK, 1);
OUTREG16(&pI2CReg->I2CR, i2cr);
INREG16(&pI2CReg->I2DR);
CSP_BITFCLR(i2sr, I2C_I2SR_IAL);
CSP_BITFCLR(i2sr, I2C_I2SR_IIF);
OUTREG16(&pI2CReg->I2SR, i2sr);
InterruptDone(dwSysIntr);
continue;
}
if ((CSP_BITFEXT(i2cr, I2C_I2CR_MSTA)==I2C_I2CR_MSTA_SLAVE)
&& (CSP_BITFEXT(i2sr, I2C_I2SR_IAAS)==I2C_I2SR_IAAS_ADDRESSED)
&& (CSP_BITFEXT(i2sr, I2C_I2SR_IIF)==I2C_I2SR_IIF_PENDING))
{
i2cr= INREG16(&pI2CReg->I2CR);
CSP_BITFCLR(i2cr, I2C_I2CR_IIEN);
OUTREG16(&pI2CReg->I2CR, i2cr);
InterruptDone(dwSysIntr);
iaas_slave:
// iaas_slave flag:
// software can't get STOP/RESTART signal from i2c hardware
// whenever we find IAAS is set,
// treat it as the slave is selected again
while(CSP_BITFEXT(i2sr, I2C_I2SR_IIF)!=1)
{
i2sr= INREG16(&pI2CReg->I2SR);
}
i2cr= INREG16(&pI2CReg->I2CR);
CSP_BITFCLR(i2sr, I2C_I2SR_IAL);
CSP_BITFCLR(i2sr, I2C_I2SR_IIF);
OUTREG16(&pI2CReg->I2SR, i2sr);
if (CSP_BITFEXT(i2sr, I2C_I2SR_SRW)==I2C_I2SR_SRW_TRANSMIT)
{
// i2c is in slave transmit mode
if(pSBuf->iBufSize<=1)
{
i2cr|=CSP_BITFVAL(I2C_I2CR_MTX, 1);
i2cr|=CSP_BITFVAL(I2C_I2CR_TXAK, 1);
OUTREG16(&pI2CReg->I2CR, i2cr);
OUTREG16(&pI2CReg->I2DR, pSBuf->byBuf[0]);
iIdleCount=I2C_TRANSMIT_WAIT;
i2sr= INREG16(&pI2CReg->I2SR);
while (CSP_BITFEXT(i2sr, I2C_I2SR_IIF)!=1)
{
--iIdleCount;
if( iIdleCount<=0 )
{
goto end_transmit;
}
i2sr= INREG16(&pI2CReg->I2SR);
if (CSP_BITFEXT(i2sr, I2C_I2SR_IAL)==1)
{
goto end_transmit;
}
if (CSP_BITFEXT(i2sr, I2C_I2SR_IBB)==0)
{
goto end_transmit;
}
if (CSP_BITFEXT(i2sr, I2C_I2SR_IAAS)==1)
{
goto iaas_slave;
}
i2cr= INREG16(&pI2CReg->I2CR);
if (CSP_BITFEXT(i2cr, I2C_I2CR_IIEN)==1)
{
// the interface is preempted by master mode
goto __loop;
}
}
}
else
{
i2cr|=CSP_BITFVAL(I2C_I2CR_MTX, 1);
CSP_BITFCLR(i2cr, I2C_I2CR_TXAK);
OUTREG16(&pI2CReg->I2CR, i2cr);
for (i=0; i<pSBuf->iBufSize; ++i)
{
if (i>=pSBuf->iBufSize-1)
{
i2cr|=CSP_BITFVAL(I2C_I2CR_TXAK, 1);
OUTREG16(&pI2CReg->I2CR, i2cr);
}
OUTREG16(&pI2CReg->I2DR, pSBuf->byBuf[i]);
i2sr= INREG16(&pI2CReg->I2SR);
iIdleCount=I2C_TRANSMIT_WAIT;
while (CSP_BITFEXT(i2sr, I2C_I2SR_IIF)!=1)
{
--iIdleCount;
if( iIdleCount<=0 )
{
goto end_transmit;
}
i2sr= INREG16(&pI2CReg->I2SR);
if (CSP_BITFEXT(i2sr, I2C_I2SR_IAL)==1)
{
goto end_transmit;
}
if (CSP_BITFEXT(i2sr, I2C_I2SR_IBB)==0)
{
goto end_transmit;
}
if (CSP_BITFEXT(i2sr, I2C_I2SR_IAAS)==1)
{
goto iaas_slave;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -