📄 iic.cpp
字号:
// IIC.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "IIC.h"
#include "drv.h"
#include <Pkfuncs.h>
#include <nkintr.h>
#include <windev.h>
#include <Pkfuncs.h>
// I2C Registers
#define rIICCON (pI2C->pI2CReg->IICCON) // Control Register
#define rIICSTAT (pI2C->pI2CReg->IICSTAT) // Status Register
#define rIICADD (pI2C->pI2CReg->IICADD) // Address Register
#define rIICDS (pI2C->pI2CReg->IICDS) // Data Shift Register
//#define RX_TIMEOUT 3000
//#define TX_TIMEOUT 150000
#define RX_TIMEOUT 0x7FFFFFFFL
#define TX_TIMEOUT 0x7FFFFFFFL
static DWORD I2C_IST(LPVOID Context);
DWORD gIntrIIC = SYSINTR_NOP;
VOID InitRegs(PI2C_CONTEXT pI2C)
{
EnterCriticalSection(&pI2C->RegCS);
// enable the I2C Clock (PCLK)
pI2C->pIOPReg->GPECON &= ~(0x0F<<28);
pI2C->pIOPReg->GPECON |= (0x0A<<28); // GPE15:IICSDA, GPE14:IICSCL
// setup GPIO for I2C
pI2C->pIOPReg->GPEUP |= 0xC000; // Pull-up-down Disable
// config controller
rIICCON = RESUME_ACK; // =0xEF clear interrupt pending bit, ACK enabled, div=512, IICCLK=PCLK/512
rIICSTAT = M_IDLE; // =0x00 Disable Rx/Tx
pI2C->State = IDLE;
pI2C->DataCount = INVALID_DATA_COUNT; // =-1
LeaveCriticalSection(&pI2C->RegCS);
}
DWORD HW_Init(PI2C_CONTEXT pI2C)
{
DWORD dwErr = ERROR_SUCCESS;
UINT32 Irq;
if ( !pI2C )
return ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_TRACE,(TEXT("+I2C_Init: %u, 0x%x, 0x%x \r\n"),pI2C->Mode, pI2C->SlaveAddress));
InitializeCriticalSection(&pI2C->RegCS);
pI2C->Status = 0;
pI2C->pData = NULL;
pI2C->DataCount = INVALID_DATA_COUNT;
pI2C->Flags.DropRxAddr = FALSE;
pI2C->hProc = (HANDLE)GetCurrentProcessId();
InitRegs(pI2C);
// create I/O Done Event
if ( (pI2C->DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
{
dwErr = GetLastError();
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Init ERROR: Unable to create Done event: %u \r\n"), dwErr));
goto _init_error;
}
// setup Operating Mode
if ( pI2C->Mode == INTERRUPT )
{
// create IST event
if ( (pI2C->ISTEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
{
dwErr = GetLastError();
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Init ERROR: Unable to create IST event: %u \r\n"), dwErr));
goto _init_error;
}
// Obtain sysintr values from the OAL for the camera interrupt.
Irq = IRQ_IIC;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(UINT32), &gIntrIIC, sizeof(UINT32), NULL))
{
DEBUGMSG(ZONE_ERR, (TEXT("ERROR: Failed to request the IIC sysintr.\r\n")));
gIntrIIC = SYSINTR_UNDEFINED;
return(FALSE);
}
// initialize the interrupt
if( !InterruptInitialize(gIntrIIC, pI2C->ISTEvent, NULL, 0) )
{
dwErr = GetLastError();
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Init ERROR: Unable to initialize interrupt: %u\r\n"), dwErr));
goto _init_error;
}
InterruptDone(gIntrIIC);
// create the IST
if ( (pI2C->IST = CreateThread(NULL, 0, I2C_IST, (LPVOID)pI2C, 0, NULL)) == NULL)
{
dwErr = GetLastError();
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Init ERROR: Unable to create IST: %u\r\n"), dwErr));
goto _init_error;
}
// TODO: registry override
if ( !CeSetThreadPriority(pI2C->IST, THREAD_PRIORITY_ABOVE_NORMAL))
{
dwErr = GetLastError();
DEBUGMSG(ZONE_ERR, (TEXT("I2C_Init ERROR: CeSetThreadPriority ERROR:%d\n"), dwErr));
goto _init_error;
}
}
DEBUGMSG(ZONE_TRACE,(TEXT("-I2C_Init \r\n")));
return dwErr;
_init_error:
HW_Deinit(pI2C);
return dwErr;
}
DWORD HW_Deinit(PI2C_CONTEXT pI2C)
{
if ( !pI2C )
return ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_TRACE,(TEXT("I2C_Deinit: %u \r\n"), pI2C->State));
if ( pI2C->State == IDLE )
{
pI2C->State = OFF; // also signals the IST to terminate
rIICSTAT = M_IDLE;
if (pI2C->DoneEvent && CloseHandle(pI2C->DoneEvent))
pI2C->DoneEvent = NULL;
if (pI2C->Mode == INTERRUPT)
{
InterruptDisable(gIntrIIC);
if (pI2C->ISTEvent && CloseHandle(pI2C->ISTEvent))
pI2C->ISTEvent = NULL;
if (pI2C->IST && CloseHandle(pI2C->IST))
pI2C->IST = NULL;
}
pI2C->Mode = POLLING;
pI2C->pData = NULL;
pI2C->DataCount = INVALID_DATA_COUNT;
pI2C->Flags.DropRxAddr = FALSE;
DeleteCriticalSection(&pI2C->RegCS);
return ERROR_SUCCESS;
}
else
{
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Deinit ERROR: %u \r\n"), pI2C->State));
return ERROR_BUSY;
}
}
DWORD HW_Open(PI2C_CONTEXT pI2C)
{
return ERROR_SUCCESS;
}
DWORD HW_Close(PI2C_CONTEXT pI2C)
{
return ERROR_SUCCESS;
}
__inline DWORD SyncIst(PI2C_CONTEXT pI2C,DWORD dwTimeout)
{
if (pI2C->Mode == INTERRUPT) //中断方式处理
{
DEBUGMSG(ZONE_READ|ZONE_WRITE,(TEXT("SyncIst...\r\n")));
if(WaitForSingleObject(pI2C->DoneEvent, dwTimeout != WAIT_OBJECT_0 ))
{
pI2C->State = IO_ABANDONED;
if (pI2C->LastError == ERROR_SUCCESS)
pI2C->LastError = ERROR_TIMEOUT;
DEBUGMSG(ZONE_WRN|ZONE_READ|ZONE_WRITE,(TEXT("SyncIst: IO_ABANDONED\r\n")));
}
DEBUGMSG(ZONE_READ|ZONE_WRITE,(TEXT("...SyncIst: 0x%X\r\n"), pI2C->LastError));
return pI2C->LastError;
}
else //查询方式的处理
{
while(pI2C->DataCount != INVALID_DATA_COUNT)
{
// poll INT pending bit
if (pI2C->Mode == POLLING && (rIICCON & 0x10))
I2C_IST(pI2C);
}
}
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------------------------------
//RANDOM READ: A random read requires a “dummy” byte write sequence to load in the data
//word address. Once the device address word and data word address are clocked in and
//acknowledged by the EEPROM, the microcontroller must generate another start condition.
//The microcontroller now initiates a current address read by sending a device address with the
//read/write select bit high. The EEPROM acknowledges the device address and serially clocks
//out the data word.
//-----------------------------------------------------------------------------------------------------
DWORD HW_Read(PI2C_CONTEXT pI2C,
DWORD SlaveAddr, // slave address
UCHAR WordAddr, // starting word address
PUCHAR pData, // pdata
DWORD Count // bytes to read
)
{
DWORD dwErr;
if (!VALID_CONTEXT(pI2C))
return ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("+I2C_Read[%u]: 0x%X, 0x%X, 0x%X, %u\r\n"),
pI2C->State, SlaveAddr, WordAddr, pData, Count));
if ( !pData || !Count || IsBadWritePtr(pData, Count) )
{
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Read ERROR: invalid parameter \r\n")));
return ERROR_INVALID_PARAMETER;
}
EnterCriticalSection(&pI2C->RegCS);
if ( pI2C->State != IDLE)
{
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Read ERROR: i2cState: %u \r\n"), pI2C->State));
LeaveCriticalSection(&pI2C->RegCS);
return ERROR_BUSY;
}
pI2C->LastError = ERROR_SUCCESS;
ResetEvent(pI2C->DoneEvent);
rIICSTAT = M_ACTIVE; // =0x10 Enable Rx/Tx
// pre-setup word address
pI2C->pData = NULL;
pI2C->State = SET_READ_ADDR;
pI2C->WordAddr = WordAddr;
pI2C->Flags.WordAddr = TRUE;
pI2C->DataCount = 1;
// enable the slave address drop
pI2C->Flags.DropRxAddr = TRUE;
// write slave address
rIICDS = (UCHAR)SlaveAddr;
rIICSTAT = MTX_START; // =0xF0 Master Tx Start
Sleep(20);
// Wait for IST to write the word address
if (WAIT_OBJECT_0 != SyncIst(pI2C, RX_TIMEOUT))
{
DEBUGMSG(ZONE_READ|ZONE_ERR,(TEXT("RX_TIMEOUT.1\r\n")));
goto _done;
}
ResetEvent(pI2C->DoneEvent);
// get read data
pI2C->State = READ_DATA;
pI2C->pData = pData;
pI2C->DataCount = Count;
rIICDS = (UCHAR)SlaveAddr;
rIICSTAT = MRX_START; //=0xB0 Master Rx Start
rIICCON = RESUME_ACK; //=0xEF Clear interrupt pending bit, ACK enabled, div=512, IICCLK=PCLK/512
Sleep(20);
// Wait for IST to get data
if (WAIT_OBJECT_0 != SyncIst(pI2C, RX_TIMEOUT))
{
DEBUGMSG(ZONE_READ|ZONE_ERR,(TEXT("RX_TIMEOUT.2\r\n")));
goto _done;
}
_done:
rIICSTAT = M_IDLE; //=0x00 Disable Rx/Tx
rIICCON = RESUME_ACK; //=0xEF Clear interrupt pending bit, ACK enabled, div=512, IICCLK=PCLK/512
pI2C->State = IDLE;
pI2C->pData = NULL;
pI2C->DataCount = INVALID_DATA_COUNT;
//如果接收到地址不是原来发送的地址则出错
if ( !pI2C->LastError && ((SlaveAddr & ~(0x01)) != (pI2C->RxRetAddr & ~(0x01)) ) )
{
DEBUGMSG(ZONE_READ|ZONE_ERR,(TEXT("I2C_Read Invalid Return Address: 0x%X != 0x%X \r\n"),
pI2C->RxRetAddr, SlaveAddr ));
pI2C->LastError = ERROR_INCORRECT_ADDRESS;
TEST_TRAP;
}
pI2C->RxRetAddr = 0;
dwErr = pI2C->LastError;
LeaveCriticalSection(&pI2C->RegCS);
DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("-I2C_Read:%u \r\n"), dwErr ));
return dwErr;
}
DWORD HW_Write(
PI2C_CONTEXT pI2C,
DWORD SlaveAddr, // slave address
UCHAR WordAddr, // starting slave word address
PUCHAR pData, // pdata
DWORD Count // bytes to write
)
{
DWORD dwErr;
if ( !VALID_CONTEXT(pI2C) )
return ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("+I2C_Write[%u]: 0x%X, 0x%X, 0x%X, %u \r\n"), pI2C->State, SlaveAddr, WordAddr, *pData, Count));
if ( !pData || !Count || IsBadReadPtr(pData, Count) )
{
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Write ERROR: invalid parameter \r\n")));
return ERROR_INVALID_PARAMETER;
}
EnterCriticalSection(&pI2C->RegCS);
if ( pI2C->State != IDLE)
{
DEBUGMSG(ZONE_ERR,(TEXT("I2C_Write ERROR: i2cState: %u \r\n"), pI2C->State));
LeaveCriticalSection(&pI2C->RegCS);
return ERROR_BUSY;
}
pI2C->LastError = ERROR_SUCCESS;
ResetEvent(pI2C->DoneEvent);
rIICSTAT = M_ACTIVE;
// pre-setup write data
pI2C->State = WRITE_DATA;
pI2C->DataCount = 1 + Count; // slave word address + data
pI2C->WordAddr = WordAddr;
pI2C->Flags.WordAddr = TRUE;
pI2C->pData = pData;
// write slave address
rIICDS = (UCHAR)SlaveAddr;
rIICSTAT = MTX_START;
Sleep(20);
// IST writes the slave word address & data
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -