i2cloader.c
来自「This driver supports both master mode, s」· C语言 代码 · 共 1,758 行 · 第 1/5 页
C
1,758 行
******************************************************************************/
ST_ErrorCode_t STI2C_Open( const ST_DeviceName_t Name,
const STI2C_OpenParams_t *OpenParams,
STI2C_Handle_t *Handle)
{
i2c_param_block_s *ListPtr = NULL;
BOOL Match = FALSE;
i2c_open_block_s *OpenPtr = NULL;
clock_t Time;
if (OpenParams->AddressType != STI2C_ADDRESS_7_BITS)
return ST_ERROR_BAD_PARAMETER;
/* Check for init()ed devices */
if ( g_CtrlHead == NULL )
return ST_ERROR_UNKNOWN_DEVICE;
/* Walk the list of Ctrl blocks until we find the right name */
ListPtr = g_CtrlHead;
do
{
if ( strcmp( ListPtr->Name, Name ) == 0 )
Match = TRUE;
else
ListPtr = (i2c_param_block_s*)(ListPtr->Next);
}
while ( (ListPtr != NULL) && (Match == FALSE) );
/* If no match was found, this device name has not been init'ed */
if ( ListPtr == NULL )
return ST_ERROR_UNKNOWN_DEVICE;
/* Check OpenCnt is less than MaxHandles */
if ( ListPtr->OpenCnt >= ListPtr->MaxHandles )
return ST_ERROR_NO_FREE_HANDLES;
/* Generate a new handle and wait 1 tick to ensure handle uniqueness */
Time = clock();
task_delay (1);
/* Assign the open block */
OpenPtr = AssignI2cOpenBlock();
if ( OpenPtr == NULL )
return ST_ERROR_NO_FREE_HANDLES; /* Should never get this! */
/* Everything checked & OK - so get exclusive access to driver data,
then copy in parameters. */
semaphore_wait ( &ListPtr->BusAccessSemaphore );
/* Change the open count in the control block */
ListPtr->OpenCnt++;
/* Store the open parameters */
/* Bottom bit is R/W bit - remove for now */
OpenPtr->I2cAddress = OpenParams->I2cAddress & 0xFFFE;
OpenPtr->Handle = (STI2C_Handle_t)Time;
OpenPtr->InUse = TRUE;
OpenPtr->AddressType = OpenParams->AddressType;
OpenPtr->BusAccessTimeOut = OpenParams->BusAccessTimeOut;
OpenPtr->CtrlBlkPtr = (void*)ListPtr;
/* Set the handle pointer for the calling function */
*Handle = OpenPtr->Handle;
/* Release the access semaphore */
semaphore_signal( &ListPtr->BusAccessSemaphore );
return ST_NO_ERROR;
}
/******************************************************************************
Name : ResolveHandleToOpenPointer
Description : Walk the linked list until the open block with this handle is
found and return a pointer to it, else return a null pointer.
Parameters : The handle of the open device to be found
******************************************************************************/
static i2c_open_block_s *ResolveHandleToOpenPointer( STI2C_Handle_t Handle )
{
i2c_open_block_s *ListPtr = g_OpenHead;
BOOL Match = FALSE;
while ( (ListPtr != NULL) && (Match == FALSE) )
{
if ( (Handle == ListPtr->Handle) && (ListPtr->InUse == TRUE) )
{
Match = TRUE;
}
else
{
ListPtr = (i2c_open_block_s*)(ListPtr->Next);
}
}
return( ListPtr );
}
/******************************************************************************
Name : ConvertMStoTicks
Description : Converts a timeout in milliseconds to the appropiate number of
clock ticks. Returns a pointer to the result. Takes care of
special case 'infinity'. Also takes care of overflow by treating
as infinity.
Parameters : 1) The number of milliseconds to convert to ticks
2) The number of clock ticks per second
3) Pointer to result (not used if returns infinity)
Returns : Pointer to result. This will either be pResult or
TIMEOUT_INFINITY.
******************************************************************************/
static clock_t * ConvertMStoTicks (U32 TimeOutMS, U32 TicksPerSec,
clock_t *pResult)
{
int Div = 0;
clock_t Timeout;
/* Deal with Infinity as special case */
if (TimeOutMS == STI2C_TIMEOUT_INFINITY)
return (clock_t *)(TIMEOUT_INFINITY);
/* Make sure the conversion will not overflow */
while (TimeOutMS > INT_MAX/TicksPerSec)
{
Div++;
TimeOutMS /= 10;
}
/* Convert from ms to clock ticks, with rounding */
Timeout = (TimeOutMS * TicksPerSec + 500) / 1000;
/* Now multiply up again, but if overflow giving infinity */
while (Div > 0)
{
if (Timeout > INT_MAX/10)
return (clock_t *)(TIMEOUT_INFINITY);
Div--;
Timeout *= 10;
}
*pResult = Timeout;
return pResult;
}
/******************************************************************************
Name : TakeBus
Description : Take control of the I2C bus. Only the
handle with control of the bus may call BusAccess
Parameters : 1) Handle - open connection to STI2C
2) *AlreadyLocked - Returns TRUE if this handle already
has control of the bus.
Returns : ST_NO_ERROR - This handle now has control of the bus
ST_ERROR_INVALID_HANDLE - Self explanatory
ST_ERROR_DEVICE_BUSY - BusAccessTimeout expired
******************************************************************************/
static ST_ErrorCode_t TakeBus( STI2C_Handle_t Handle, BOOL *AlreadyLocked )
{
const U32 TicksPerSec = ST_GetClocksPerSecond();
U32 SemReturn;
clock_t BusTimeOut;
clock_t *pBusTimeOut;
i2c_param_block_s *CtrlBlkPtr;
i2c_open_block_s *OpenBlkPtr;
BOOL LocalAlreadyLocked;
ST_ErrorCode_t ErrorCode = ST_NO_ERROR;
/* Default return value for already locked flag */
LocalAlreadyLocked = FALSE;
/* Set up the pointers to the control block and the open block */
OpenBlkPtr = ResolveHandleToOpenPointer (Handle);
if ( OpenBlkPtr == NULL )
{
*AlreadyLocked = LocalAlreadyLocked;
return ST_ERROR_INVALID_HANDLE;
}
CtrlBlkPtr = OpenBlkPtr->CtrlBlkPtr;
/* Set bus access timeout */
pBusTimeOut = ConvertMStoTicks( OpenBlkPtr->BusAccessTimeOut,
TicksPerSec, &BusTimeOut );
if (pBusTimeOut != TIMEOUT_INFINITY)
*pBusTimeOut = time_plus (*pBusTimeOut, time_now());
/* Test if I2C bus has already been locked */
SemReturn = semaphore_wait_timeout( &(CtrlBlkPtr->HandleAccessSemaphore),
TIMEOUT_IMMEDIATE );
if( SemReturn == 0 )
{
/* SUCCESS: I2C bus is now locked to this handle */
CtrlBlkPtr->LockedHandle = Handle;
/* Check bus access has not been claimed already */
SemReturn = semaphore_wait_timeout ( &(CtrlBlkPtr->BusAccessSemaphore),
pBusTimeOut );
if( SemReturn != 0 )
{
/* Failed to claim bus access */
ErrorCode = ST_ERROR_DEVICE_BUSY;
}
}
else
{
/* FAILURE: Bus is already locked */
/* Test if this handle has the bus locked */
if( CtrlBlkPtr->LockedHandle == Handle )
{
/* SUCCESS: This handle already has the bus locked */
/* Check bus access has not been claimed already */
SemReturn = semaphore_wait_timeout ( &(CtrlBlkPtr->BusAccessSemaphore),
pBusTimeOut );
if (SemReturn != 0)
{
/* Failed to claim bus access */
ErrorCode = ST_ERROR_DEVICE_BUSY;
}
else
{
LocalAlreadyLocked = TRUE;
}
}
else
{
/* FAILURE: The bus is currently locked by another handle */
/* Wait for the bus to become unlocked */
SemReturn = semaphore_wait_timeout ( &(CtrlBlkPtr->HandleAccessSemaphore),
pBusTimeOut );
if (SemReturn != 0)
{
/* Failed to claim bus lock */
ErrorCode = ST_ERROR_DEVICE_BUSY;
}
else
{
/* SUCCESS: Bus is now locked to this handle */
CtrlBlkPtr->LockedHandle = Handle;
/* Check bus access has not been claimed already */
SemReturn = semaphore_wait_timeout ( &(CtrlBlkPtr->BusAccessSemaphore),
pBusTimeOut );
if (SemReturn != 0)
{
/* Failed to claim bus access */
ErrorCode = ST_ERROR_DEVICE_BUSY;
}
}
}
}
*AlreadyLocked = LocalAlreadyLocked;
return( ErrorCode );
}
/******************************************************************************
Name : ReleaseBus
Description : Releases control of the I2C bus.
Parameters : 1) Handle - open connection to STI2C
Returns : ST_NO_ERROR - This handle now has control of the bus
ST_ERROR_INVALID_HANDLE - Self explanatory
******************************************************************************/
static ST_ErrorCode_t ReleaseBus( STI2C_Handle_t Handle )
{
ST_ErrorCode_t ErrorCode = ST_NO_ERROR;
i2c_param_block_s *CtrlBlkPtr;
i2c_open_block_s *OpenBlkPtr;
/* Set up the pointers to the control block and the open block */
OpenBlkPtr = ResolveHandleToOpenPointer (Handle);
if ( OpenBlkPtr == NULL )
{
ErrorCode = ST_ERROR_INVALID_HANDLE;
}
else
{
CtrlBlkPtr = OpenBlkPtr->CtrlBlkPtr;
/* Release the access semaphore */
semaphore_signal( &CtrlBlkPtr->HandleAccessSemaphore );
}
return( ErrorCode );
}
/******************************************************************************
Name : STI2C_Reset
Description : Resets the I2C h/w device associated with the given handle.
Also sets the s/w state back to Idle. Does not reset the I2C bus.
This is designed as a recovery aid when things go badly wrong.
Note this function does not get exclusive access by claiming the
bus access semaphore.
Currently, this is a hidden function not visible in the API.
Parameters : 1) The handle to a device being used
******************************************************************************/
ST_ErrorCode_t STI2C_Reset (STI2C_Handle_t Handle)
{
DU16 *I2cRegPtr;
i2c_param_block_s *CtrlBlkPtr;
i2c_open_block_s *OpenBlkPtr = ResolveHandleToOpenPointer (Handle);
if ( OpenBlkPtr == NULL )
return ST_ERROR_INVALID_HANDLE;
CtrlBlkPtr = OpenBlkPtr->CtrlBlkPtr;
I2cRegPtr = (DU16*) CtrlBlkPtr->I2cBase;
I2C_TRACE_LOCK(CtrlBlkPtr,0xD000,(U32)I2cRegPtr);
CtrlBlkPtr->State = STI2C_IDLE;
I2cRegPtr [SSC_INT_ENABLE] = 0;
I2cRegPtr [SSC_CONTROL] = DEFAULT_CONTROL | SSC_CON_RESET;
I2cRegPtr [SSC_CONTROL] = DEFAULT_CONTROL;
/* Set Tx data high to avoid bus corruption */
I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
I2cRegPtr [SSC_INT_ENABLE] = CtrlBlkPtr->InterruptMask = DEFAULT_ENABLES;
return ST_NO_ERROR;
}
/******************************************************************************
Name : BusAccess
Description : Initiates all master mode bus activity by reading or writing the
first byte in a bus transfer. The ISR does the rest, signalling
via a semaphore when the operation is complete or aborted.
Caters for the possibility of the bus being in use by another
master device (but see comments on h/w bugs in module header).
If a transfer fails due to 'Bus In Use', the function will keep
retrying until the bus access timeout expires. As a partial
workaround the h/w bugs, the function will also retry after
other errors up to a maximum of STI2C_MAX_RETRIES times.
Parameters : 1) The handle
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?