📄 i2c.c
字号:
/*------------------------------------------------------------------------
$Workfile: I2C.C $
$Date: 6/20/97 3:47p $
$Revision: 8 $
* Purpose:
* I2C bus read and write routines.
* Notes:
* Routines in this file are used by other routines in
* "ADV7111.C" and "SAA7111.C".
*
$History: I2C.C $
*
* ***************** Version 8 *****************
* User: Stevel Date: 6/20/97 Time: 3:47p
* Updated in $/601cman
* Add new header vlab.h.
*
* ***************** Version 7 *****************
* User: Dstarr Date: 8/26/96 Time: 10:14a
* Updated in $/601cman
* Modified to drive clock line high instead of tristating it. This fixed
* the interrmittant 7175 init failures.
*
* ***************** Version 6 *****************
* User: Dstarr Date: 7/25/96 Time: 7:40a
* Updated in $/601cman
* I2c read and write do three retries on error before giving up and
* returning FAILURE.
*
* ***************** Version 5 *****************
* User: Dstarr Date: 4/09/96 Time: 9:40a
* Updated in $/601cman
* Catch 32 fix. Clr and Set mscrbit routines converted from 32 bit to 16
* bit. the mcsr bit routines now only access the "PAL" register in the
* hi word of port 3. This prevents reading or writing the ADV601 status
* register in the low word of port 3. This fixes two problems. Writes
* of the ADv601 status register will hang (no ack) unless the ADV601 is
* out of reset. The reset bit is in the PAL, so you have to do a 16 bit
* access to take the ADV601 out of reset before you can read the ADV601
* register without getting hung. Second potential problem, Reads of the
* ADV601 status register CLEAR the status bits. Only the interrupt
* service routine (which this is NOT) should tinker with the interrupt
* status bits. We haven't actually experienced any trouble YET, but
* doing it this way will eliminate any possibilty of trouble in the
* future.
* The BIT definitions for things like reset and SDA have changed from
* 32 bit wide to 16 bit wide. Any callers (601 test.exe) should be
* recompiled using the latest version of i2c.h
*
*
* ***************** Version 4 *****************
* User: Dstarr Date: 4/04/96 Time: 11:22a
* Updated in $/601cman
* set and clr mcsrbit now do a 16 bit only write, not a 32 bit one. this
* avoids "catch32" in the eval card.
*
* ***************** Version 3 *****************
* User: Dstarr Date: 4/03/96 Time: 11:56a
* Updated in $/601cman
* clr_mcsr_bit and set mcsr_bit now return the bits they set into the
* main control and status register. This is of interest to the
* diagnostic program only.
*
* ***************** Version 2 *****************
* User: Stevel Date: 3/10/96 Time: 10:13p
* Updated in $/601cman
* Add DLLEXPORT keyword to export function in this file for diagnostic
* test.
*
* ***************** Version 1 *****************
* User: Stevel Date: 3/06/96 Time: 8:04p
* Created in $/601cman
* Initial release
This code and information is provided "as is" without warranty of any
kind, either expressed or implied, including but not limited to the
implied warranties of merchantability and/or fitness for a particular
purpose.
1996 Analog Devices, Inc.
-------------------------------------------------------------------------*/
#include <windows.h>
#include <stdio.h>
#include "globsym.h"
#include "vlab.h"
#include "i2c.h"
#define BADBIT -1
#define MAXTRY 3
static dword * pI2CReg; /* 32 bit ptr to PAL&ADV601 Stat reg*/
static word * ptr2pal; /* 16 bit ptr to just the PAL */
/////////////////////////////////////////////////////////////////////
// Define a local variable used by halfperiod() to emulate the
// I2C clock cylce timing.
/////////////////////////////////////////////////////////////////////
static long i2cbus_hperiod;
/* Declare private functions */
//=================================================================
// I2C Inline function
//=================================================================
void halfperiod();
int clockhigh ();
void clocklow();
//===================================================================
//
// Initialize the I2C Bus
//
//===================================================================
DLLEXPORT int I2CInit(dword * ptr)
{
pI2CReg = ptr;
ptr2pal = (word*) ptr;
ptr2pal +=1; /* get the hi word */
clr_mcsrbit (SCL | SDA + SCL_OE + SDA_OE);
// setup the emulate clock constant
ClockCycleCalibrate();
return SUCCESS;
}
//===================================================================
//
// Clock Cycle Calibration for I2C Bus.
//
// Return # of loops to ellase 1 usec.
//===================================================================
#define LOTTATIME 1000000L
DLLEXPORT dword ClockCycleCalibrate()
{
long runtime;
long TimeStart, TimeEnd;
i2cbus_hperiod = LOTTATIME; /* try something big */
TimeStart = GetTickCount(); /* read start time from system clock*/
halfperiod(); /* do LOTTATIME iterations */
TimeEnd = GetTickCount(); /* read stop time from system clk*/
runtime = TimeEnd - TimeStart; /* compute elapsed time in millisec */
runtime *= 1000L; /* convert runtime to microseconds */
i2cbus_hperiod = (6L * LOTTATIME) / runtime;/* 6 usec delay loop */
if (i2cbus_hperiod < 1)
i2cbus_hperiod = 1; /* safety first */
/* Gives 10 usec period in 100 Mhz Pentium */
i2cbus_hperiod = 100; /* above code no work, so fake it */
/* Gives 100 usec period in 100 Mhz Pentium */
i2cbus_hperiod = 1000; /* above code no work, so fake it */
return (i2cbus_hperiod);
}
//===================================================================
//
// Emulate one clock cycle for I2C.
// The maximum speed of I2C bus is 100 KHz. That means the fast
// is 0.01 msec (10 usec). This routine is currently hard coded to
// emulate 100 usec clock cycle.
//
//===================================================================
void halfperiod()
{
long i;
long twiddle = 0;
for (i= 0; i < i2cbus_hperiod; i++)
twiddle++; /* Optimizer might kill empty loop */
return;
}
//===================================================================
//
// Delay
//
//===================================================================
DLLEXPORT void Delay(int cycle)
{
int i;
for(i=0; i<cycle; i++)
halfperiod();
return;
}
DLLEXPORT int rite_i2c_chip(void * hisptr, int subaddr,int nreg )
/******************************************************************
Processing: Do an I2C bus transmit of the register struct *ptr.
A subset may be sent by setting subaddr to the desired byte
to start at and indicating the number of bytes to send
(excluding chip address and sub address bytes.
Inputs: ptr is address of register structure to transmit
subaddr is the register to start with. 0 = 1st reg
nreg is the number of data bytes to send after chip addr
& sub address.
Outputs: return success or failure if no acknowledge from target chip
Side-effects None
*******************************************************************/
{
int rtnvar;
byte * ptr;
byte chip_addr;
int i,j;
for (j = 0; j < MAXTRY; j++)
{
ptr = (byte*) hisptr; /* defeat strong typing */
chip_addr = *ptr++;
chip_addr &= 0xFE; /* clear chip address Read bit */
I2CStart();
rtnvar = I2CWriteData(chip_addr);/* send the chip address */
if (rtnvar == SUCCESS)
{
*ptr++= subaddr;
rtnvar = I2CWriteData((byte) subaddr); // Send SubAddress
if (rtnvar == SUCCESS)
{
ptr += subaddr; /* point to 1st reg to xmit */
for (i = 0; i < nreg; i++)
{
rtnvar = I2CWriteData(*ptr++); // Xmit data byte by byte
if (rtnvar != SUCCESS)
break;
}
}
}
I2CStop();
if (rtnvar == SUCCESS)
break;
}
return rtnvar;
}
DLLEXPORT int read_i2c_chip(void * hisptr, int subaddr,int nreg )
/******************************************************************
Processing: Do an I2C bus read int0 the register struct *ptr.
A subset may be sent by setting subaddr to the desired byte
to start at and indicating the number of bytes to read
(excluding chip address and sub address bytes.
Inputs: ptr is address of register structure to write into.
subaddr is the register to start with. 0 = 1st reg
nreg is the number of data bytes to read after chip
addr & sub address.
Outputs: return success or failure if no acknowledge from target chip.
Side-effects None.
*******************************************************************/
{
int rtnvar;
int i,j;
byte *ptr;
byte chip_addr;
for (j = 0; j < MAXTRY; j++)
{
ptr = (byte*) hisptr; /* defeat strong typing */
chip_addr = *ptr++;
chip_addr &= ~1; /* clr chip address Read bit */
I2CStart();
rtnvar = I2CWriteData(chip_addr); /* send the chip address */
if (rtnvar == SUCCESS)
{
*ptr++ = subaddr; /* put sub address into struct */
rtnvar = I2CWriteData((byte) subaddr); // Send SubAddress
if (rtnvar == SUCCESS)
{
I2CStart();
chip_addr |= 1; /* set chip address Read bit */
rtnvar = I2CWriteData(chip_addr);/* send the chip address*/
if (rtnvar == SUCCESS)
{
ptr += subaddr; /* point to 1st reg to xmit */
for (i = 0; i < nreg - 1; i++)
{
*ptr++ =I2CReadData(); // Fetch data byte by byte
I2CReadAck(); /* ack all but last byte*/
}
*ptr++ = I2CReadData(); // Fetch last byte
/* and DON't Ack it */
}
}
}
I2CStop();
if (rtnvar == SUCCESS)
break;
}
return rtnvar;
}
DLLEXPORT int readhard_i2c_chip(void * hisptr, int subaddr,int nreg )
/******************************************************************
Processing: Do an I2C bus read int0 the register struct *ptr.
A subset may be sent by setting subaddr to the desired byte
to start at and indicating the number of bytes to read
(excluding chip address and sub address bytes.
This routine is a debug version of read_i2c_chip() above.
It presses on rather than bailing out after a No Ack
from the IIC bus target device which helps scope out problems.
Inputs: ptr is address of register structure to write into.
subaddr is the register to start with. 0 = 1st reg
nreg is the number of data bytes to read after chip
addr & sub address.
Outputs: return success or failure. Ignore negative acks and press on.
Side-effects None.
*******************************************************************/
{
int rtnvar;
int i;
byte *ptr;
byte chip_addr;
ptr = (byte*) hisptr; /* defeat strong typing */
chip_addr = *ptr++;
chip_addr &= ~1; /* clr chip address Read bit */
I2CStart();
rtnvar = I2CWriteData(chip_addr);/* send the chip address */
*ptr++ = subaddr; /* put sub address into struct */
rtnvar |= I2CWriteData((byte) subaddr); // Send SubAddress
/* I2CStop(); */ /* 7175 won't work with this in */
I2CStart();
chip_addr |= 1; /* set chip address Read bit */
rtnvar |= I2CWriteData(chip_addr);/* send the chip address*/
ptr += subaddr; /* point to 1st reg to xmit */
for (i = 0; i < nreg - 1; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -