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