📄 i2c.c
字号:
/***********************************************************************/
/* File: */
/* Copyright (c) 2000 ZORAN Corporation, All Rights Reserved */
/* THIS IS PROPRIETARY SOURCE CODE OF ZORAN CORPORATION */
/* */
/* =========== */
/* Descripton: */
/* =========== */
/* */
/* Log: */
/* === */
/* $Name: V_1_16 V_1_15 V_1_14 V_1_13 V_1_12 NV_1_00 $
/* $Header: v:/dsg/rcs/dsg/vp2k/Customer/device/i2c/i2c.c 1.13 2001/07/23 02:48:33 cliff Exp $
/* $Log: i2c.c $
/* Revision 1.13 2001/07/23 02:48:33 cliff
/* Revision 1.12 2001/05/17 07:17:23 leslie
/* Revision 1.11 2001/04/06 01:23:56 stephaneh
/* Fixed Read / Write Problem for Milleno project
/* Revision 1.9 2001/02/16 00:39:27 stephaneh
/* Added semaphore lock while using EEPROM for Valino Drive
/* Revision 1.8 2001/01/25 20:18:02 stephaneh
/* Updated sdebug comment
/* Revision 1.7 2001/01/25 20:12:46 stephaneh
/* Modified i2c_write( ) to return FALSE when an error occured
/* Revision 1.6 2000/12/11 07:14:58 cliff
/* Revision 1.5 2000/12/06 10:43:58 cliff
/* Revision 1.4 2000/11/09 04:07:28 cliff
/***********************************************************************/
#define RELEASE_TRACE_MODULE
#ifdef RELEASE_TRACE_MODULE
#define _DEBUG
#endif
#ifdef _DEBUG
#ifdef RELEASE_TRACE_MODULE
#define IFTRACE if (1)
#else
#define IFTRACE if (gTraceCore)
extern int gTraceCore;
#endif
#endif
#include <sysdefs.h>
#define sda_set_input sda_hi
#define scl_set_input scl_hi
#include "i2c_io.h"
#include "..\..\..\playcore\timing\timing.h"
#ifdef MILLENO
#include "..\..\..\kernel\ker_api.h" // ZRN SH0215:Needed for Semaphore definition
#include "..\..\..\drive\samsung\meml_ex.h"
BOOL EEPROM_ByteWrite(BYTE addr,BYTE data);
BYTE EEPROM_ByteRead(BYTE addr);
#endif
#define I2C_MAX_WAIT 5000L /* in microseconds */
#ifndef I2C_WAIT_MORE_TIME
#define HOLDING_TIME 10
#else
#define HOLDING_TIME 50
#endif
#ifndef STANDARD_I2C_PROTOCOL//ZORAN LX0517
/*
* These local functions wait for the other end the set the bit to a
* certain level.
*/
static BOOL wait_sda_lo(void)
{
int i = I2C_MAX_WAIT/5;
sda_set_input();
while(i && !is_sda_lo()) {
i--;
delay_us(5);
}
return i?TRUE:FALSE;
}
static BOOL wait_sda_hi(void)
{
int i = I2C_MAX_WAIT/5;
sda_set_input();
while(i && !is_sda_hi()) {
i--;
delay_us(5);
}
return i?TRUE:FALSE;
}
static BOOL wait_scl_hi(void)
{
int i = I2C_MAX_WAIT/5;
scl_set_input();
while(i && !is_scl_hi()) {
i--;
delay_us(5);
}
return i?TRUE:FALSE;
}
/*
* This function is called before an I2C transfer is started. A start
* condition is signified with a high-to-low transition of SDA while SCL
* is high.
*/
static BOOL i2c_start(void)
{
// scl_lo(); // SEC LEE0216 :
scl_hi(); // SEC LEE0216
delay_us(HOLDING_TIME);
sda_hi();
// scl_hi(); // SEC LEE0216
if (!wait_scl_hi())
return FALSE;
sda_lo(); /* this triggers the start */
delay_us(HOLDING_TIME);
scl_lo();
return TRUE;
}
/*
* The function is used to tell the device the the transmission is over.
* The stop condition is signified by a low-to-high transition of SDA
* while SCL is high.
*/
static BOOL i2c_stop(void)
{
scl_lo();
delay_us(HOLDING_TIME);
sda_lo();
scl_hi();
delay_us(HOLDING_TIME);
if (!wait_scl_hi())
return FALSE;
sda_hi(); /* this triggers the stop */
if (!wait_sda_hi())
return FALSE;
return TRUE;
}
/*
* This function sends one byte on the I2C bus. The bits in the byte are
* sent in the order of the high bit first and the lowest bit last.
*/
static unsigned i2c_putc(unsigned char d)
{
unsigned char mask;
unsigned ack;
for (mask = 0x80; mask; mask >>= 1)
{
if (d & mask)
sda_hi();
else
sda_lo();
delay_us(HOLDING_TIME); // SEC LEE0216
scl_hi();
delay_us(HOLDING_TIME);
scl_lo();
delay_us(HOLDING_TIME);
}
sda_hi(); /* ack handshake after every byte */
delay_us(HOLDING_TIME);
scl_hi();
delay_us(HOLDING_TIME);
if (is_sda_lo()) /* sda low means an ack */
ack = TRUE;
else
ack = FALSE;
scl_lo();
delay_us(HOLDING_TIME); // SEC LEE0216
return ack;
}
/*
* This function is used to get data from another I2C device. The |rdack|
* parameter is used to tell the device if we want to read more bytes. If
* |rdack| is true then we want to receive the byte at the next address,
* otherwise we don't want anymore bytes.
*/
static unsigned char i2c_getc(unsigned rdack)
{
unsigned char d;
unsigned char i;
sda_hi(); /* don't drive the data line */
for (i = 0, d = 0; i < 8; i++) {
d <<= 1;
scl_hi(); /* drive clock high to get data */
delay_us(HOLDING_TIME);
if (!wait_scl_hi())
return 0xFF; /* i2c error */
if (is_sda_hi())
d |= 1; /* bit is a one */
scl_lo(); /* drive clock back down */
delay_us(HOLDING_TIME);
}
if (rdack)
sda_lo(); /* send an ack */
scl_hi();
if (!wait_scl_hi())
return 0xFF; /* i2c error */
scl_lo();
if (rdack)
sda_hi(); /* release if set */
return d;
}
static BOOL i2c_select_device( unsigned char addr, unsigned char subaddr )
{
if (!i2c_start())
{
#ifdef NO_C_STDLIB
rtouts("\nError sending I2C start");
#else
dbprintf("Error sending I2C start\n");
#endif
return FALSE;
}
if (!i2c_putc(addr)){
#ifdef NO_C_STDLIB
rtouts("\nError writing I2C address");
#else
dbprintf("Error writing I2C address\n");
#endif
return FALSE;
}
if (!i2c_putc(subaddr)){
#ifdef NO_C_STDLIB
rtouts("\nError writing I2C subaddress");
#else
dbprintf("Error writing I2C subaddress\n");
#endif
return FALSE;
}
return TRUE;
}
/*
* This function writes address, subaddr, and data on the I2C bus.
* The bits in the byte are
* sent in the order of the high bit first and the lowest bit last.
*/
BOOL i2c_write(unsigned char addr,
unsigned char subaddr,
unsigned char dat)
{
BOOL res;
#ifdef MILLENO
res = EEPROM_ByteWrite(subaddr,dat);
#else
#ifdef VALINO_DRIVE
semaphore_set(SEM_EEPROM); // ZRN SH0215:Avoid conflict between Core and Drive
#endif
if (res = i2c_select_device( addr, subaddr )){
if (!(res = i2c_putc(dat)))
{
#ifdef NO_C_STDLIB
rtouts("\nError writing data");
#else
dbprintf("Error writing data\n");
#endif
}
}
/* <<< ZRN SH0125: Modified to return FALSE if an error occured */
if(res == FALSE)
i2c_stop();
else
res = i2c_stop(); /* done */
/* >>> */
if (!res) { /* sda low means an ack */
#ifdef NO_C_STDLIB
rtouts("\nI2C WRITE ERROR\n");
#else
dbprintf("I2C WRITE ERROR\n\0");
#endif
}
#ifdef VALINO_DRIVE
semaphore_clear(SEM_EEPROM);
#endif
#endif // MILLENO
return res;
}
BOOL i2c_write_string( unsigned char addr, unsigned char subaddr, int count, unsigned char *data )
{
// int retry = 10; // SEC LEE0216
unsigned char retry = 10; // SEC LEE0216
while (count&&retry){
if (i2c_write(addr, subaddr, *data)){
subaddr++;
data++;
count--;
retry = 10;
}
else
retry--;
delay_us(1000L); /* wait 1 ms */
}
return retry?TRUE:FALSE;
}
BOOL i2c_read_string( unsigned char addr, unsigned char subaddr, int count, unsigned char *data )
{
BOOL res;
#ifdef MILLENO
while (--count)
*data++ = EEPROM_ByteRead(subaddr++);
*data = EEPROM_ByteRead(subaddr);
res = TRUE;
#else
#ifdef VALINO_DRIVE
semaphore_set(SEM_EEPROM);
#endif
if (res = i2c_select_device( addr, subaddr )){
if (!i2c_start()) /* another start for read */
return FALSE;
i2c_putc((unsigned char)(addr|1)); /* set up for a read */
while (--count)
*data++ = i2c_getc(1);
*data = i2c_getc(0);
}
i2c_stop();
#ifdef VALINO_DRIVE
semaphore_clear(SEM_EEPROM);
#endif
#endif // MILLENO
return res;
}
#ifdef MILLENO
BOOL is24_wr(BYTE data);
void ack_wr(void);
BOOL EEPROM_ByteWrite(BYTE addr,BYTE data){
BYTE i;
BOOL bRes = TRUE;
semaphore_set(SEM_EEPROM); // ZRN SH0215:Avoid conflict between Core and Drive
ack_wr(); //device address set
if(!is24_wr(addr))
{
bRes = FALSE;
rtouts("\nEW Addr ERROR"); // sub address set
}
if(!is24_wr(data)) //data set
{
bRes = FALSE;
rtouts("\nEW Data ERROR");
}
scl_lo(); //ECK clear
for(i=0;i<4;i++);
sda_lo(); //EDT clear
for(i=0;i<4;i++);
scl_hi(); //ECK set
for(i=0;i<4;i++);
sda_hi(); //EDT set
for(i=0;i<4;i++);
semaphore_clear(SEM_EEPROM); // ZRN SH0215:Avoid conflict between Core and Drive
return bRes;
}
// Return TRUE if OK, FALSE otherwise
BOOL is24_wr(BYTE data){
BYTE count,i;
BOOL bRes = TRUE;
__DI();
// *PTR(&P7CR_shadow) |= 0x08;
// P7CR = *PTR(&P7CR_shadow); //edt output port
for(count=0;count<8;count++){
scl_lo();//ECK clear
for(i=0;i<4;i++);
if(data&0x80)
sda_hi();//EDT set
else
sda_lo();//EDT clear
for(i=0;i<4;i++);
scl_hi();//ECK set
for(i=0;i<4;i++);
data = data<<1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -