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 + -
显示快捷键?