i2cloader.c

来自「This driver supports both master mode, s」· C语言 代码 · 共 1,758 行 · 第 1/5 页

C
1,758
字号
/******************************************************************************

File name   : sti2c.c

Description : Driver code for STAPI I2C interface

Reference   : 1)  STi5510 Datasheet
              2)  SSC2 Silicon Spec, UDCS No. 2001944, 22/4/98
              3)  The I2C-bus and how to use it,  Philips Semiconductors

    This driver supports both master mode, slave mode & mixed mode operation.
    Note however that the current SSC h/w contains some serious bugs which
    affect mixed mode operation - see Reference 2) section 5 & Appendix B.
    The code contains partial workarounds for the bugs, but may still behave
    upredictably occasionally under conditions of heavy bus loading.

******************************************************************************/

/* Force MASTER_ONLY mode if using software START/STOP generation */ 
#ifdef  STI2C_SW_START_STOP
#define STI2C_MASTER_ONLY
#endif

/* hcx force master_only */
#define STI2C_MASTER_ONLY

/* Includes------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include "stcommon.h"
#include "stddefs.h"
#ifndef  STI2C_MASTER_ONLY
#include "stevt.h"
#endif
#include "sti2c.h"
#include "stlite.h"
#include "stpio.h"

/* Constants ----------------------------------------------------------------*/

/* --- SSC offsets in half words (16 bits) --- */
#define SSC_BAUD_RATE   (0*2)
#define SSC_TX_BUFFER   (1*2)
#define SSC_RX_BUFFER   (2*2)
#define SSC_CONTROL     (3*2)
#define SSC_INT_ENABLE  (4*2)
#define SSC_STATUS      (5*2)
#define SSC_I2C         (6*2)
#define SSC_SLAD        (7*2)

/* --- The i2c control register bits ---  */
#define SSC_I2C_ENABLE           0x01
#define SSC_I2C_GENERATE_START   0x02
#define SSC_I2C_GENERATE_STOP    0x04
#define SSC_I2C_GENERATE_ACKS    0x08
#define SSC_I2C_10_BIT_ADDRESS   0x10

/* ---  The SSC control register bits --- */
#define SSC_CON_DATA_WIDTH_7     0x06
#define SSC_CON_DATA_WIDTH_8     0x07
#define SSC_CON_DATA_WIDTH_9     0x08
#define SSC_CON_HEAD_CONTROL     0x10
#define SSC_CON_CLOCK_PHASE      0x20
#define SSC_CON_CLOCK_POLARITY   0x40
#define SSC_CON_RESET            0x80
#define SSC_CON_MASTER_SELECT    0x100
#define SSC_CON_ENABLE           0x200
#define SSC_CON_LOOP_BACK        0x400

/* ---  The status register bits --- */
#define SSC_STAT_RX_BUFFER_FULL  0x01
#define SSC_STAT_TX_BUFFER_EMPTY 0x02
#define SSC_STAT_TX_ERROR        0x04
#define SSC_STAT_RX_ERROR        0x08
#define SSC_STAT_PHASE_ERROR     0x10
#define SSC_STAT_STRETCH         0x20
#define SSC_STAT_AAS             0x40
#define SSC_STAT_STOP            0x80
#define SSC_STAT_ARBL            0x100
#define SSC_STAT_BUSY            0x200

/* ---  The interrupt enable register bits --- */
#define SSC_IEN_RX_BUFFER_FULL   0x01
#define SSC_IEN_TX_BUFFER_EMPTY  0x02
#define SSC_IEN_RX_ERROR         0x08
#define SSC_IEN_PHASE_ERROR      0x10
#define SSC_IEN_AAS              0x40
#define SSC_IEN_STOP             0x80
#define SSC_IEN_ARBL             0x100

#define DEFAULT_ENABLES   (SSC_IEN_RX_BUFFER_FULL | SSC_IEN_AAS | SSC_IEN_ARBL)
#define DEFAULT_CONTROL   (SSC_CON_DATA_WIDTH_9  | SSC_CON_HEAD_CONTROL |  \
                           SSC_CON_MASTER_SELECT | SSC_CON_ENABLE)

#define MILLISEC_PER_SEC   1000
#define MICROSEC_PER_SEC   1000000

/* --- misc constants & defines --- */
#define ACKNOWLEDGE_BIT    0x01

#ifndef STI2C_MAX_RETRIES
#define STI2C_MAX_RETRIES  4
#endif

#ifndef STI2C_START_DELAY
#define STI2C_START_DELAY  0
#endif

#ifdef STI2C_SW_START_STOP

/* Word offsets for direct access to PIO for START/STOP generation */

#define PIO_OUT_SET        1
#define PIO_OUT_CLR        2
#define PIO_C2_SET         17
#define PIO_C2_CLR         18

#endif /* STI2C_SW_START_STOP */


/* Typedefs -----------------------------------------------------------------*/

#pragma ST_device (DU16)
typedef volatile U16       DU16;
#pragma ST_device (DU32)
typedef volatile U32       DU32;


/* Driver state - note order is important so we can do < & > comparisons */
typedef enum
{
    STI2C_SLAVE_WAIT_FOR_STOP          = 0,
    STI2C_SLAVE_ADDRESSED              = 1,
    STI2C_SLAVE_READ                   = 2,
    STI2C_SLAVE_WRITE                  = 3,
    STI2C_IDLE                         = 4,
    STI2C_MASTER_ADDRESSING_WRITE      = 5,
    STI2C_MASTER_WRITING               = 6,
    STI2C_MASTER_ADDRESSING_READ       = 7,
    STI2C_MASTER_READING               = 8
} STI2C_DriverState_t;

#define MASTER_STATE(p)      ( ((p)->State) >= STI2C_MASTER_ADDRESSING_WRITE )
#define SLAVE_STATE(p)       ( ((p)->State) <= STI2C_SLAVE_WRITE )

typedef struct
{
    U32                        *I2cBase;
    STPIO_PIOBit_t             PIOforSDA;          
    STPIO_PIOBit_t             PIOforSCL;
#ifdef STI2C_SW_START_STOP
    U32                        *BaseAddressforSDA;  /* for direct PIO access */
    U32                        *BaseAddressforSCL;  /* for direct PIO access */
#endif /* STI2C_SW_START_STOP */
    STPIO_Handle_t             PIOHandle; 
    U32                        I2cInterruptNum;
    U32                        I2cInterruptLevel;
    STI2C_MasterSlave_t        MasterSlave;   
    BOOL                       LastTransferHadStop;
    S32                        OpenCnt;
    U32                        BaudRate;
    U16                        InterruptMask;
    STI2C_Handle_t             LockedHandle;
    semaphore_t                HandleAccessSemaphore;
    semaphore_t                BusAccessSemaphore;
    semaphore_t                IOSemaphore;
    STI2C_DriverState_t        State;
    U8                         *Buffer;
    S32                        BufferLen;
    S32                        BufferCnt;
    ST_DeviceName_t            Name;
    U32                        ClockFreq;
    U32                        MaxHandles;
    U32                        HandlerCondition;
    ST_Partition_t             *Partition;
    BOOL                       WaitingForStop;
    BOOL                       StopOccurred;
#ifndef STI2C_MASTER_ONLY
    U32                        SlaveAddress;
    STEVT_Handle_t             EVTHandle;
    STEVT_EventID_t            TxNotifyId;
    STEVT_EventID_t            RxNotifyId;
    STEVT_EventID_t            TxByteId;
    STEVT_EventID_t            RxByteId;
    STEVT_EventID_t            TxCompleteId;
    STEVT_EventID_t            RxCompleteId;
#endif
    struct i2c_param_block_s   *Next;
} i2c_param_block_s;


typedef struct
{
    STI2C_Handle_t             Handle;
    U32                        BusAccessTimeOut;
    STI2C_Address_t            AddressType;
    U32                        I2cAddress;
    BOOL                       InUse;
    struct i2c_open_block_s    *Next;
    i2c_param_block_s          *CtrlBlkPtr;
} i2c_open_block_s;


typedef enum 
{
    READING,
    WRITING
} i2c_context_e;


/* Externs ------------------------------------------------------------------*/

#ifdef STI2C_SW_START_STOP

/* Direct access to PIO pins is needed for s/w START/STOP generation.
   This 'hidden' PIO function gets us the base address of the PIO port. */

extern ST_ErrorCode_t STPIO_GetBaseAddress (ST_DeviceName_t DeviceName,
                                            U32 **BaseAddress);
#endif /* STI2C_SW_START_STOP */

/* This is used by test/debug routines only */
extern void myprintf (char *format, ...);


/* Statics ------------------------------------------------------------------*/

static   i2c_param_block_s    *g_CtrlHead    = NULL;
static   i2c_open_block_s     *g_OpenHead    = NULL;
static   S32                  g_CtrlBlkCnt   = 0;
static   S32                  g_OpenBlkCnt   = 0;
static   const ST_Revision_t  g_Revision     = "STI2C-REL_1.3.4";

/* Debug facilities ---------------------------------------------------------*/

#ifdef STI2C_TRACE

/* Simple trace facility */

#define DBG_SIZE              10000
#define DBG_REC_SIZE          10

U32 I2cIntCount = 0;
U32 I2cErrCount = 0;
volatile U32 I2cIndex    = 0;
volatile U32 I2cLastIndex = 0;
U32 I2cDebug [DBG_SIZE * DBG_REC_SIZE];

#define I2C_TRACE(p,id,data)                                   \
    {                                                          \
        U32 t = I2cIndex*DBG_REC_SIZE;                         \
        if (++I2cIndex >= DBG_SIZE)                            \
            I2cIndex = 0;      /* wrap around */               \
        I2cDebug[t  ] = I2cIntCount;                           \
        I2cDebug[t+1] = (id);                                  \
        I2cDebug[t+2] = I2cErrCount;                           \
        I2cDebug[t+3] = (p)->State;                            \
        I2cDebug[t+4] = (p)->HandlerCondition;                 \
        I2cDebug[t+5] = (p)->InterruptMask;                    \
        I2cDebug[t+6] = (p)->BufferCnt;                        \
        I2cDebug[t+7] = (p)->BufferLen;                        \
        I2cDebug[t+8] = (data);                                \
        I2cDebug[t+9] = GetHpClock();                          \
    }

#define I2C_TRACE_LOCK(p,id,data)                              \
    interrupt_lock();                                          \
    I2C_TRACE(p,id,data);                                      \
    interrupt_unlock();

#define I2C_TRACE_ERR_INC            I2cErrCount++;
#define I2C_TRACE_INT_INC            I2cIntCount++;

static U32 GetHpClock (void);
#pragma ST_inline (GetHpClock)

#else     /* not STI2C_TRACE */

#define I2C_TRACE(p,id,data)
#define I2C_TRACE_LOCK(p,id,data)
#define I2C_TRACE_ERR_INC
#define I2C_TRACE_INT_INC

#endif /* STI2C_TRACE */


/* Debug Functions ----------------------------------------------------------*/

#ifdef STI2C_TRACE

static U32 GetHpClock (void)
{
    U32 temp;
    __asm { ldc 0; ldclock; st temp; }
    return temp;
}


U32 I2cPrintTrace (S32 Start, S32 Number)
{
    U32 i, n, first, last, index=I2cIndex, result=0;

    if (Start<0)     /* special case - print from last print position */
    {
        first = I2cLastIndex;
        n = (index >= first) ? index-first : (index+DBG_SIZE)-first;
        if ((Number <= 0) || (Number > n))
            last = index;
        else
        {
            last   = (first+Number) % DBG_SIZE;
            result = (index>last) ? index-last : (index+DBG_SIZE)-last;
        }
        I2cLastIndex = last;
    }
    else
    {
        first = Start;
        last  = (Number <= 0) ? index : (first + Number) % DBG_SIZE;
    }

    n = (last>first) ? last-first : (last+DBG_SIZE)-first;
    if (Number > 0)
    {
        i = first;
        while (i != last)
        {
            n = i*10;
            if( ++i >= DBG_SIZE )
                i = 0;
        }
    }
    return result;
}
#endif /* STI2C_TRACE */


/* Functions ----------------------------------------------------------------*/


/******************************************************************************
Name        : STI2C_GetRevision
Description : Returns a pointer to the string containing the version number of
              this code.
Parameters  : None
******************************************************************************/

ST_Revision_t STI2C_GetRevision (void)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?