📄 i2c.c
字号:
// write slave address
rIICDS = (UCHAR)SlaveAddr;
rIICSTAT = MTX_START;
// IST writes the slave word address & data
if (WAIT_OBJECT_0 != SyncIst(pI2C, TX_TIMEOUT)) {
DEBUGMSG(ZONE_WRITE|ZONE_ERR,(TEXT("TX_TIMEOUT.1\r\n")));
goto _done;
}
// LJY, 20040724, commented out
#if 0
// get ACK
while(1)
{
pI2C->State = WRITE_ACK;
pI2C->Status = INVALID_IICSTAT;
rIICDS = (UCHAR)SlaveAddr;
rIICSTAT = MTX_START;
rIICCON = RESUME_ACK;
while ( pI2C->Status == INVALID_IICSTAT ) {
if (WAIT_OBJECT_0 != SyncIst(pI2C, TX_TIMEOUT)) {
DEBUGMSG(ZONE_WRITE|ZONE_ERR,(TEXT("TX_TIMEOUT.2\r\n")));
break;
}
}
// done when ACK received
if ( !(pI2C->Status & 0x1))
break;
}
#endif
_done:
rIICSTAT = MTX_STOP;
rIICCON = RESUME_ACK;
rIICSTAT = M_IDLE; // disable Rx/Tx
pI2C->State = IDLE;
pI2C->Data = NULL;
pI2C->DataCount = INVALID_DATA_COUNT;
dwErr = pI2C->LastError;
LeaveCriticalSection(&pI2C->RegCS);
DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("-I2C_Write: %u \r\n"), dwErr));
return dwErr;
}
static DWORD
I2C_IST(
LPVOID Context
)
{
PI2C_CONTEXT pI2C = (PI2C_CONTEXT)Context;
DWORD i2cSt;
BOOL bDone = FALSE;
#ifdef DEBUG
DWORD r = 0;
#endif
if ( !pI2C ) {
TEST_TRAP;
return ERROR_INVALID_PARAMETER;
}
//DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("+I2C_IST[%u, %u, %d] \r\n"), pI2C->Mode, pI2C->State, pI2C->DataCount));
do {
if (pI2C->Mode == INTERRUPT) {
DWORD we;
bDone = FALSE;
we = WaitForSingleObject(pI2C->ISTEvent, INFINITE);
//DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST[%u, %d] \r\n"), pI2C->State, pI2C->DataCount));
// clear the interrupt here because we re-arm another below
InterruptDone(gIntrIIC);
//
// Ensure correct state initiated by Read/Write
//
DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST[%u, %d] \r\n"),
pI2C->State, pI2C->DataCount));
switch(pI2C->State)
{
case OFF:
DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST: ExitThread \r\n")));
ExitThread(ERROR_SUCCESS);
break;
case IDLE:
DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST: IDLE \r\n")));
continue;
break;
default:
if (pI2C->State != WRITE_ACK &&
pI2C->State != RESUME &&
pI2C->DataCount == INVALID_DATA_COUNT) {
DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST: INVALID_DATA_COUNT\r\n")));
continue;
}
break;
}
}
// EnterCriticalSection(&pI2C->RegCS);
i2cSt = rIICSTAT;
if (i2cSt & 0x8) {
DEBUGMSG(ZONE_ERR,(TEXT("I2C_IST[%u, %d]: bus arbitration failed \r\n"),
pI2C->State, pI2C->DataCount));
RETAILMSG(1, (TEXT("I2C_IST[%u, %d]: bus arbitration failed \r\n"),
pI2C->State, pI2C->DataCount));
}
if (i2cSt & 0x4) {
DEBUGMSG(ZONE_ERR,(TEXT("I2C_IST[%u, %d]: slave address matches IICADD \r\n"),
pI2C->State, pI2C->DataCount));
RETAILMSG(1, (TEXT("I2C_IST[%u, %d]: slave address matches IICADD \r\n"),
pI2C->State, pI2C->DataCount));
}
if (i2cSt & 0x2) {
DEBUGMSG(ZONE_ERR,(TEXT("I2C_IST[%u, %d]: received slave address 0x0 \r\n"),
pI2C->State, pI2C->DataCount));
RETAILMSG(1, (TEXT("I2C_IST[%u, %d]: received slave address 0x0 \r\n"),
pI2C->State, pI2C->DataCount));
}
if (i2cSt & 0x1) {
DEBUGMSG(ZONE_READ|ZONE_WRITE,(TEXT("I2C_IST[%u, %d]: ACK NOT received \r\n"),
pI2C->State, pI2C->DataCount));
RETAILMSG(1, (TEXT("I2C_IST[%u, %d]: ACK NOT received \r\n"),
pI2C->State, pI2C->DataCount));
}
__try {
switch(pI2C->State)
{
case IDLE:
case SUSPEND:
continue;
break;
case RESUME:
DEBUGMSG(ZONE_WRN, (TEXT("I2C_IST: RESUME \r\n")));
RETAILMSG(1, (TEXT("I2C_IST: RESUME \r\n")));
InitRegs(pI2C);
pI2C->LastError = ERROR_OPERATION_ABORTED;
SetEvent(pI2C->DoneEvent);
break;
case SET_READ_ADDR:
if ( (pI2C->DataCount--) == 0 )
{
DEBUGMSG(ZONE_READ|ZONE_TRACE, (TEXT("A2[%d] \r\n"),
pI2C->DataCount ));
RETAILMSG(1, (TEXT("A2[%d] \r\n"),
pI2C->DataCount ));
bDone = TRUE;
break;
}
DEBUGMSG(ZONE_READ|ZONE_TRACE, (TEXT("A1[%d]: 0x%X \r\n"),
pI2C->DataCount, pI2C->WordAddr));
RETAILMSG(1, (TEXT("A1[%d]: 0x%X \r\n"),
pI2C->DataCount, pI2C->WordAddr));
// write word address
// For setup time of SDA before SCL rising edge, rIICDS must be written
// before clearing the interrupt pending bit.
if (pI2C->Flags.WordAddr) {
rIICDS = pI2C->WordAddr;
// clear interrupt pending bit (resume)
rIICCON = RESUME_ACK;
pI2C->Flags.WordAddr = FALSE;
}
break;
case READ_DATA:
ASSERT(pI2C->Data);
if ( (pI2C->DataCount--) == 0 )
{
bDone = TRUE;
*pI2C->Data = (UCHAR)rIICDS;
#ifdef DEBUG
r = *pI2C->Data;
//RETAILMSG(1,(TEXT("R3_1:0x%X, pI2C->Data(0x%X) \r\n"), r, pI2C->Data));
//RETAILMSG(1,(_T("pI2C->Data(0x%X)\r\n"), pI2C->Data));
#endif
pI2C->Data++;
rIICSTAT = MRX_STOP;
rIICCON = RESUME_ACK; // resume operation.
//RETAILMSG(1,(_T("pI2C->Data(0x%X)\r\n"), pI2C->Data));
//RETAILMSG(1,(TEXT("R3_2:0x%X, pI2C->Data(0x%X) \r\n"), r, pI2C->Data));
//DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("R3:0x%X \r\n"), r));
//The pending bit will not be set after issuing stop condition.
break;
}
// Drop the returned Slave WordAddr?
if ( pI2C->Flags.DropRxAddr )
{
pI2C->RxRetAddr = (UCHAR)rIICDS;
pI2C->Flags.DropRxAddr = FALSE;
DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("Drop: 0x%X \r\n"),
pI2C->RxRetAddr));
} else {
*pI2C->Data = (UCHAR)rIICDS;
#ifdef DEBUG
r = *pI2C->Data;
#endif
pI2C->Data++;
}
//RETAILMSG(1,(TEXT("R3_3:0x%X, pI2C->Data(0x%X) \r\n"), r, pI2C->Data));
// The last data is read with no ack.
if ( pI2C->DataCount == 0 ) {
rIICCON = RESUME_NO_ACK; // resume operation with NOACK.
DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("R1:0x%X \r\n"), r));
} else {
rIICCON = RESUME_ACK; // resume operation with ACK
DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("R2:0x%X \r\n"), r));
}
break;
case WRITE_DATA:
ASSERT(pI2C->Data);
if ( (pI2C->DataCount--) == 0 )
{
DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("W3[%d] \r\n"), pI2C->DataCount));
//RETAILMSG(1,(TEXT("W3[%d] \r\n"), pI2C->DataCount));
bDone = TRUE;
rIICSTAT = MTX_STOP;
rIICCON = RESUME_ACK; // resume operation.
//The pending bit will not be set after issuing stop condition.
break;
}
if (pI2C->Flags.WordAddr) {
rIICDS = pI2C->WordAddr;
DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("W1[%d]: 0x%X \r\n"),
pI2C->DataCount, pI2C->WordAddr));
pI2C->Flags.WordAddr = FALSE;
} else {
DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("W2[%d]: 0x%X \r\n"),
pI2C->DataCount, *pI2C->Data));
rIICDS = (UCHAR)*pI2C->Data;
pI2C->Data++;
}
rIICCON = RESUME_ACK; // resume operation.
break;
case WRITE_ACK:
DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("WRITE_ACK \r\n") ));
//RETAILMSG(1,(TEXT("WRITE_ACK \r\n") ));
pI2C->Status = i2cSt;
bDone = TRUE;
break;
case IO_COMPLETE:
DEBUGMSG(ZONE_IST, (TEXT("IO_COMPLETE \r\n")));
bDone = TRUE;
break;
case IO_ABANDONED:
DEBUGMSG(ZONE_ERR|ZONE_WRN,(TEXT("IO_ABANDONED \r\n") ));
bDone = TRUE;
break;
default:
DEBUGMSG(ZONE_ERR,(TEXT("!!! I2C_IST ERROR: Invalid State: %u !!!\r\n"),
pI2C->State));
bDone = TRUE;
break;
}
} _except(EXCEPTION_EXECUTE_HANDLER) {
rIICSTAT = (pI2C->State == READ_DATA) ? MRX_STOP : MTX_STOP;
rIICCON = RESUME_ACK;
pI2C->DataCount = INVALID_DATA_COUNT;
pI2C->LastError = GetExceptionCode();
RETAILMSG(1,(TEXT("!!! I2C_IST EXCEPTION: 0x%X !!!\r\n"), pI2C->LastError ));
}
if (bDone) {
DEBUGMSG(ZONE_IST, (TEXT("SetEvent DONE\r\n")));
SetEvent(pI2C->DoneEvent);
}
// LeaveCriticalSection(&pI2C->RegCS);
} while (pI2C->Mode == INTERRUPT);
//DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("-I2C_IST[%u] \r\n"), pI2C->Mode));
return ERROR_SUCCESS;
}
BOOL
HW_PowerUp(
PI2C_CONTEXT pI2C
)
{
pI2C->State = RESUME;
SetInterruptEvent(gIntrIIC);
return TRUE;
}
BOOL
HW_PowerDown(
PI2C_CONTEXT pI2C
)
{
// set idle
rIICSTAT = M_IDLE;
// turn off our clock
pI2C->pCLKPWRReg->CLKCON &= ~I2C_POWER_ON;
pI2C->State = SUSPEND;
return TRUE;
}
BOOL
HW_PowerCapabilities(
PI2C_CONTEXT pI2C,
PPOWER_CAPABILITIES ppc
)
{
memset(ppc, 0, sizeof(*ppc));
//
// SPECIAL CASE: support D0 only.
// If we power off outside of system state Suspend then the PCF50606
// will no longer work, which means the whole system could be forced off
// by an internal PCF transition. The Battery driver would not work either.
//
// If we knew we did not have to support the PCF50606,
// or didn't know what I2C Client drivers we could have,
// then we should support D0 and D4. In this case you would use
// RegisterPowerRelationship and serve as the Bus driver (parent/proxy)
// to forward power transitions to all the I2C Client drivers.
//
ppc->DeviceDx = 0x1; // D0
// no wake
// no inrush
// Report our power consumption in uAmps rather than mWatts.
ppc->Flags = POWER_CAP_PREFIX_MICRO | POWER_CAP_UNIT_AMPS;
ppc->Power[D0] = 600; // 0.6 mA or 600 uA @ 200 MHz
// no latency issues
return TRUE;
}
BOOL
HW_PowerSet(
PI2C_CONTEXT pI2C,
PCEDEVICE_POWER_STATE pDx // IN, OUT
)
{
CEDEVICE_POWER_STATE NewDx = *pDx;
if ( VALID_DX(NewDx) )
{
// We only support D0, so do nothing.
// Just return current state.
pI2C->Dx = *pDx = D0;
DEBUGMSG(ZONE_POWER, (TEXT("I2C: IOCTL_POWER_SET: D%u => D%u \r\n"),
NewDx, pI2C->Dx));
return TRUE;
}
return FALSE;
}
BOOL
HW_PowerGet(
PI2C_CONTEXT pI2C,
PCEDEVICE_POWER_STATE pDx
)
{
// return our Current Dx value
*pDx = pI2C->Dx;
DEBUGMSG(ZONE_POWER, (TEXT("I2C: IOCTL_POWER_GET: D%u \r\n"), pI2C->Dx));
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -