i2cloader.c
来自「This driver supports both master mode, s」· C语言 代码 · 共 1,758 行 · 第 1/5 页
C
1,758 行
OpenPtr->InUse = FALSE;
OpenPtr->CtrlBlkPtr = NULL;
OpenPtr->Next = NULL;
}
return( OpenPtr );
}
#ifndef STI2C_MASTER_ONLY
/******************************************************************************
Name : RegisterEvents
Description : Called from STI2C_Init() when driver has to operate in slave
mode. Opens the specified Event Handler & registers the
events which can be notified in slave mode.
Parameters :
******************************************************************************/
static ST_ErrorCode_t RegisterEvents (const ST_DeviceName_t EvtHandlerName,
i2c_param_block_s *InitBlock)
{
STEVT_OpenParams_t EVTOpenParams;
/* First open the specified event handler */
if (STEVT_Open (EvtHandlerName, &EVTOpenParams,
&InitBlock->EVTHandle) != ST_NO_ERROR)
return STI2C_ERROR_EVT_REGISTER;
if (STEVT_Register (InitBlock->EVTHandle, STI2C_TRANSMIT_NOTIFY_EVT,
&InitBlock->TxNotifyId) != ST_NO_ERROR)
return STI2C_ERROR_EVT_REGISTER;
if (STEVT_Register (InitBlock->EVTHandle, STI2C_RECEIVE_NOTIFY_EVT,
&InitBlock->RxNotifyId) != ST_NO_ERROR)
return STI2C_ERROR_EVT_REGISTER;
if (STEVT_Register (InitBlock->EVTHandle, STI2C_TRANSMIT_BYTE_EVT,
&InitBlock->TxByteId) != ST_NO_ERROR)
return STI2C_ERROR_EVT_REGISTER;
if (STEVT_Register (InitBlock->EVTHandle, STI2C_RECEIVE_BYTE_EVT,
&InitBlock->RxByteId) != ST_NO_ERROR)
return STI2C_ERROR_EVT_REGISTER;
if (STEVT_Register (InitBlock->EVTHandle, STI2C_TRANSMIT_COMPLETE_EVT,
&InitBlock->TxCompleteId) != ST_NO_ERROR)
return STI2C_ERROR_EVT_REGISTER;
if (STEVT_Register (InitBlock->EVTHandle, STI2C_RECEIVE_COMPLETE_EVT,
&InitBlock->RxCompleteId) != ST_NO_ERROR)
return STI2C_ERROR_EVT_REGISTER;
return ST_NO_ERROR;
}
#endif /* STI2C_MASTER_ONLY */
/******************************************************************************
Name : STI2C_Init
Description : Initialises an i2c device and its control structure
Parameters : 1) A pointer to the devicename
2) A pointer to an initialisation parameter block
******************************************************************************/
ST_ErrorCode_t STI2C_Init( const ST_DeviceName_t Name,
const STI2C_InitParams_t *InitParams)
{
DU16 *I2cRegPtr = NULL;
ST_ErrorCode_t ReturnCode = ST_NO_ERROR;
i2c_param_block_s *InitBlock;
U32 DeadData;
S32 IntReturn;
S32 PIOPin1, PIOPin2;
S32 i;
i2c_open_block_s *OpenPtr = NULL;
STI2C_TermParams_t TermParams;
STPIO_OpenParams_t PIOOpenParams;
ST_ErrorCode_t PIOReturnCode;
STPIO_Handle_t PIOHandle;
const U32 StartStopDelay = ST_GetClocksPerSecond()/770;
/* First check partition has been specified */
if (InitParams->DriverPartition == NULL)
return ST_ERROR_BAD_PARAMETER;
/* Test parameters are valid */
if ( isInitialised ( Name, InitParams ) == TRUE )
return ST_ERROR_ALREADY_INITIALIZED;
/* Extra checks for Slave mode... */
if ( InitParams->MasterSlave != STI2C_MASTER )
{
#ifdef STI2C_MASTER_ONLY
return ST_ERROR_FEATURE_NOT_SUPPORTED;
#else
/* Check slave address valid */
if (InitParams->SlaveAddress < 2)
return ST_ERROR_BAD_PARAMETER;
#endif /* STI2C_MASTER_ONLY */
}
/* Check PIO Pin values are valid */
PIOPin1 = GetPioPin (InitParams->PIOforSDA.BitMask);
PIOPin2 = GetPioPin (InitParams->PIOforSCL.BitMask);
if ( (PIOPin1 >= UCHAR_MAX) || (PIOPin2 >= UCHAR_MAX) )
return ST_ERROR_BAD_PARAMETER;
/* Try to allocate a new control block */
InitBlock = AllocateI2cCtrlBlock (InitParams->DriverPartition);
if ( InitBlock == NULL )
return ST_ERROR_NO_MEMORY;
/* NB: From this point on, we can't just abort on fail, as we need to
deallocate the InitBlock. So initialize the semaphores 1st as we may
need these during the abort procedure. */
semaphore_init_fifo_timeout ( &InitBlock->IOSemaphore, 0 );
semaphore_init_priority_timeout ( &InitBlock->HandleAccessSemaphore, 1);
semaphore_init_priority_timeout ( &InitBlock->BusAccessSemaphore, 1);
/* strncpy() not used as it doesn't work properly */
strcpy( InitBlock->Name, Name );
/* Set up the control structures */
InitBlock->I2cBase = InitParams->BaseAddress;
InitBlock->I2cInterruptNum = InitParams->InterruptNumber;
InitBlock->I2cInterruptLevel = InitParams->InterruptLevel;
InitBlock->MasterSlave = InitParams->MasterSlave;
InitBlock->OpenCnt = 0;
InitBlock->LastTransferHadStop= TRUE;
InitBlock->BaudRate = InitParams->BaudRate;
InitBlock->InterruptMask = DEFAULT_ENABLES;
InitBlock->State = STI2C_IDLE;
InitBlock->Buffer = NULL;
InitBlock->BufferLen = 0;
InitBlock->BufferCnt = 0;
InitBlock->Next = NULL;
InitBlock->ClockFreq = InitParams->ClockFrequency;
InitBlock->PIOforSDA.BitMask = InitParams->PIOforSDA.BitMask;
InitBlock->PIOforSCL.BitMask = InitParams->PIOforSCL.BitMask;
InitBlock->MaxHandles = InitParams->MaxHandles;
InitBlock->Partition = InitParams->DriverPartition;
InitBlock->WaitingForStop = FALSE;
InitBlock->StopOccurred = FALSE;
strcpy (InitBlock->PIOforSDA.PortName, InitParams->PIOforSDA.PortName );
strcpy (InitBlock->PIOforSCL.PortName, InitParams->PIOforSCL.PortName );
#ifndef STI2C_MASTER_ONLY
InitBlock->SlaveAddress = InitParams->SlaveAddress;
/* Extra setup for Slave mode.... */
if ( InitParams->MasterSlave != STI2C_MASTER )
ReturnCode = RegisterEvents (InitParams->EvtHandlerName, InitBlock);
#endif /* STI2C_MASTER_ONLY */
if (ReturnCode == ST_NO_ERROR)
{
#ifdef STI2C_SW_START_STOP
/* Get physical addresses of PIO ports so we can do s/w
START & STOP sequences without using PIO API */
PIOReturnCode = STPIO_GetBaseAddress (InitBlock->PIOforSDA.PortName,
&InitBlock->BaseAddressforSDA);
if (PIOReturnCode != ST_NO_ERROR)
ReturnCode = STI2C_ERROR_PIO;
PIOReturnCode = STPIO_GetBaseAddress (InitBlock->PIOforSCL.PortName,
&InitBlock->BaseAddressforSCL);
if (PIOReturnCode != ST_NO_ERROR)
ReturnCode = STI2C_ERROR_PIO;
#endif /* STI2C_SW_START_STOP */
/* Reset I2C Control block */
I2cRegPtr = (DU16*) InitBlock->I2cBase ;
I2cRegPtr[SSC_I2C] = 0;
/* Initialise PIO for setup NB It is assumed all port names are the same */
PIOOpenParams.ReservedBits = InitBlock->PIOforSDA.BitMask |
InitBlock->PIOforSCL.BitMask ;
PIOOpenParams.BitConfigure[PIOPin1] = STPIO_BIT_BIDIRECTIONAL;
PIOOpenParams.BitConfigure[PIOPin2] = STPIO_BIT_BIDIRECTIONAL;
PIOOpenParams.IntHandler = NULL;
PIOReturnCode = STPIO_Open ( InitBlock->PIOforSDA.PortName,
&PIOOpenParams, &PIOHandle );
/* NB: From this point on, if we abort need to close the PIO port*/
/* Make sure the PIO_open worked */
if ( PIOReturnCode == ST_NO_ERROR )
{
/* Try to set the bus idle, then test it */
PIOReturnCode = STPIO_Write( PIOHandle,
( InitParams->PIOforSDA.BitMask |
InitParams->PIOforSCL.BitMask ) );
if ( PIOReturnCode == ST_NO_ERROR )
{
/* Copy PIO handle into control structure */
InitBlock->PIOHandle = PIOHandle;
/* Test bus but allow initialisation to continue if it fails */
if ( BusStuck ( InitBlock ) )
ReturnCode = STI2C_ERROR_LINE_STATE;
/* Try to register and enable the interrupt handler */
IntReturn = interrupt_install ( InitBlock->I2cInterruptNum,
InitBlock->I2cInterruptLevel,
I2cHandler, InitBlock );
if ( IntReturn == 0 )
{
IntReturn = interrupt_enable(InitBlock->I2cInterruptLevel);
if ( IntReturn == 0 )
{
/* At this point, the driver used to enable the I2C
Control Block, i.e. :
I2cRegPtr[SSC_I2C] = SSC_I2C_ENABLE |
SSC_I2C_GENERATE_ACKS;
However this was found to cause problems with
certain devices such as the CI Daughter Board.
This could have something to do with the fiddling
with PIO pins which is done later. Removing this
line cured the problems. The I2C Control Block will
get enabled later on. */
/* Calculate baud rate generator value */
I2cRegPtr[SSC_BAUD_RATE] = (InitBlock->ClockFreq /
(2*InitBlock->BaudRate));
/* Initialise the SSC Control block */
I2cRegPtr[SSC_CONTROL] = DEFAULT_CONTROL;
#ifndef STI2C_MASTER_ONLY
/* Set Slave Address, if appropriate */
if ( InitParams->MasterSlave != STI2C_MASTER )
I2cRegPtr[SSC_SLAD] = InitParams->SlaveAddress>>1;
#endif /* STI2C_MASTER_ONLY */
/* Add the correct number of open blocks to the list */
i = 0;
do
{
/* Allocate automatically adds the block to the
end of the list */
OpenPtr = (i2c_open_block_s*)AllocateI2cOpenBlock (
InitParams->DriverPartition);
i++;
}
while ( (i < InitBlock->MaxHandles) &&
(OpenPtr != NULL) );
/* If pointer value not NULL the allocate suceeded */
if ( OpenPtr != NULL )
{
/* Change PIO mode for I2C usage */
#ifdef STI2C_SW_START_STOP
/* Set to birectional open drain */
PIOOpenParams.BitConfigure[PIOPin1] = 3;
PIOOpenParams.BitConfigure[PIOPin2] = 3;
#else
PIOOpenParams.BitConfigure[PIOPin1] =
STPIO_BIT_ALTERNATE_BIDIRECTIONAL;
PIOOpenParams.BitConfigure[PIOPin2] =
STPIO_BIT_ALTERNATE_BIDIRECTIONAL;
#endif /* STI2C_SW_START_STOP */
PIOReturnCode = STPIO_SetConfig( PIOHandle,
PIOOpenParams.BitConfigure );
if ( PIOReturnCode == ST_NO_ERROR )
{
/* perform start/stop to reset attached
devices */
I2cStop (InitBlock);
task_delay (StartStopDelay);
I2cStart (InitBlock);
task_delay (StartStopDelay);
I2cStop (InitBlock);
task_delay (StartStopDelay);
/* Read i2c buffer to clear spurious data */
DeadData = I2cRegPtr[SSC_RX_BUFFER];
/* Set Tx data high to avoid bus corruption */
I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
/* enable interrupts from I2C registers */
I2cRegPtr[SSC_INT_ENABLE] =
InitBlock->InterruptMask;
}
else
ReturnCode = STI2C_ERROR_PIO;
}
else /* Allocate open block failed */
ReturnCode = ST_ERROR_NO_MEMORY;
}
else /* Interrupt enable failed */
ReturnCode = ST_ERROR_BAD_PARAMETER;
}
else /* Interrupt install failed */
ReturnCode = ST_ERROR_INTERRUPT_INSTALL;
}
else /* PIO write failed */
ReturnCode = STI2C_ERROR_PIO;
}
else /* PIO open failed */
ReturnCode = STI2C_ERROR_PIO;
}
/* If init was not successful call term to ensure memory is deallocated */
if ( ReturnCode != ST_NO_ERROR )
{
TermParams.ForceTerminate = TRUE;
/* Dont care about the term return code */
STI2C_Term( Name, &TermParams );
}
return ( ReturnCode );
}
/******************************************************************************
Name : AssignI2cOpenBlock
Description : Returns a pointer to an open block that is currently free or
NULL if none are free.
Parameters : None
******************************************************************************/
static i2c_open_block_s *AssignI2cOpenBlock()
{
i2c_open_block_s *ListPtr = NULL;
BOOL Match = FALSE;
/* Walk the list of open blocks */
if ( g_OpenHead != NULL )
{
ListPtr = g_OpenHead;
do
{
if ( ListPtr->InUse == FALSE )
Match = TRUE;
else
ListPtr = (i2c_open_block_s*)ListPtr->Next;
}
while ( (Match == FALSE) && (ListPtr != NULL) );
}
return( ListPtr );
}
/******************************************************************************
Name : STI2C_Open
Description : Create and return a handle to an initialised i2c device.
Parameters : 1) A pointer to the name of a device control block
2) A pointer to parameter block
3) A pointer to an empty handle
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?