📄 iic.cpp
字号:
if (WAIT_OBJECT_0 != SyncIst(pI2C, TX_TIMEOUT))
{
DEBUGMSG(ZONE_WRITE|ZONE_ERR,(TEXT("TX_TIMEOUT.1\r\n")));
goto _done;
}
// 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 )
{
Sleep(20);
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;
}
_done:
rIICSTAT = MTX_STOP;
rIICCON = RESUME_ACK;
pI2C->State = IDLE;
pI2C->pData = 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;
}
//--------------------------------------------------------------------------------------------
// When you execute code in kernel mode, in contrast to user mode, you must have access
// to the entire physical memory. Because an interrupt service thread (IST) runs in user
// mode and could need access to a block of physical memory to communicate with a device,
// you must map this block of memory to the address space in which the IST runs.
// If a device driver creates a thread, and in that thread you call MapPtrToProcess, you
// must use GetCurrentPermissions and SetProcPermissions to retrieve and reset process
// permissions.
//--------------------------------------------------------------------------------------------
static DWORD I2C_IST(LPVOID Context)
{
PI2C_CONTEXT pI2C = (PI2C_CONTEXT)Context;
DWORD i2cSt,dwRight;
BOOL bDone = FALSE;
volatile int i,j = 0;
if ( !pI2C )
{
TEST_TRAP;
return ERROR_INVALID_PARAMETER;
}
do
{
if (pI2C->Mode == INTERRUPT) //中断处理方式
{
DWORD we;
bDone = FALSE;
we = WaitForSingleObject(pI2C->ISTEvent, INFINITE); //等中断到来
// 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));
}
if (i2cSt & 0x4) //地址不相符
{
//DEBUGMSG(ZONE_ERR,(TEXT("I2C_IST[%u, %d]: slave address matches IICADD \r\n"), pI2C->State, pI2C->DataCount));
}
if (i2cSt & 0x2) //接收到0地址
{
//DEBUGMSG(ZONE_ERR,(TEXT("I2C_IST[%u, %d]: received slave address 0x0 \r\n"),pI2C->State, pI2C->DataCount));
}
if (i2cSt & 0x1) //ACK没有接收到
{
//DEBUGMSG(ZONE_READ|ZONE_WRITE,(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")));
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 ));
bDone = TRUE;
break;
}
//DEBUGMSG(ZONE_READ|ZONE_TRACE, (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;
for(i=0;i<10;i++); //For setup time until rising edge of IICSCL
// clear interrupt pending bit (resume)
rIICCON = RESUME_ACK;
pI2C->Flags.WordAddr = FALSE;
}
break;
case READ_DATA:
ASSERT(pI2C->pData);
dwRight=GetCurrentPermissions(); //获得当前进程的权限
SetProcPermissions(0xFFFFFFFF); //设置当前的权限为最高权限
if ( (pI2C->DataCount--) == 0 ) //if reciver over data
{
bDone = TRUE;
*pI2C->pData = (UCHAR)rIICDS;
pI2C->pData++;
rIICSTAT = MRX_STOP;
rIICCON = RESUME_ACK; // resume operation.
//Sleep(100); //for setup time until rising edge of IICSCL
//The pending bit will not be set after issuing stop condition.
SetProcPermissions(dwRight); //恢复原来的权限
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->pData = (UCHAR)rIICDS;
pI2C->pData++;
}
// The last data is read with no ack.
if ( pI2C->DataCount == 0 )
rIICCON = RESUME_NO_ACK; // resume operation with NOACK.
else
rIICCON = RESUME_ACK; // resume operation with ACK
SetProcPermissions(dwRight);
break;
case WRITE_DATA:
ASSERT(pI2C->pData);
dwRight=GetCurrentPermissions(); //获得当前进程的权限
SetProcPermissions(0xFFFFFFFF); //设置当前的权限为最高权限
if ( (pI2C->DataCount--) == 0 )
{
//DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("W3[%d] \r\n"), pI2C->DataCount));
bDone = TRUE;
rIICSTAT = MTX_STOP;
rIICCON = RESUME_ACK; // resume operation.
//Sleep(100); //for setup time until rising edge of IICSCL
//The pending bit will not be set after issuing stop condition.
SetProcPermissions(dwRight); //恢复原来的权限
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->pData));
rIICDS = (UCHAR)*pI2C->pData;
pI2C->pData++;
}
for(i=0;i<10;i++); //For setup time until rising edge of IICSCL
rIICCON = RESUME_ACK; // resume operation.
SetProcPermissions(dwRight); //恢复原来的权限
break;
case WRITE_ACK:
//DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(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();
SetProcPermissions(dwRight);
}
if (bDone)
{
pI2C->pData=(LPBYTE)UnMapPtr(pI2C->pData);
//DEBUGMSG(ZONE_IST, (TEXT("SetEvent DONE\r\n")));
SetEvent(pI2C->DoneEvent);
}
//LeaveCriticalSection(&pI2C->RegCS);
} while (pI2C->Mode == INTERRUPT);
return ERROR_SUCCESS;
}
BOOL HW_PowerUp(PI2C_CONTEXT pI2C)
{
pI2C->State = RESUME;
InitRegs(pI2C);
return TRUE;
}
BOOL HW_PowerDown(PI2C_CONTEXT pI2C)
{
// set idle
rIICSTAT = M_IDLE;
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)
{
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 + -