⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.c

📁 Discription: This multi-master driver provides the software interface to the I2C Bus hardware of th
💻 C
📖 第 1 页 / 共 2 页
字号:
/*-------------------------------------------------------------------------------**
** Driver: I2C Bus Device Driver Package for M16C/62 serires MCUs.
**
** (c) 1999 Mitsubishi Electronics America, Inc.
**
** Three Diamond Lane
**
** Durham, North Carolina 27704 USA
**
** Ph 919-479-3333
**
** File: i2c.c
**
** Discription: This multi-master driver provides the software interface to the
**
** I2C Bus hardware of the M3062x series of Mitsubishi抯 MCU.
**
**-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------**
** Mitsubishi Electronics America, INC.
**
** Design Engineering Center-East
**
**
**
** (c) 1999 Mitsubishi Electronics America, Inc
**
** By: Bruce Embry
**
** July, 1999
**
** Version 1.00
**
**
**
**
**
**-------------------------------------------------------------------------------*/

#include "Rtos.h"

#include "Types/BaseTypes.h"
#include "i2c.h"
#include <stdio.h>
#include <string.h>

#define I2C_MAX_NACKS  3   // enough, except for EEPROM
#define I2C_MAX_ARBLOSS 37
#define EEPROM_MAX_NACKS 37 // enough for the promised 10 ms flash cycle (12 was enough in experiment, 11 not)
#define SCAN_MAX_NACKS 3
#define MAX_REVIV_CNT 3

#define I2C_INIT_DELAY 50

// the following globals are initialized once at bootup and are constant afterwards
extern bool flgOSStarted;
byte i2cBaudrate;

// the following globals are shared and must be "threadsafe"
unsigned char i2cSlaveData[ SLV_MEM_SIZE ];

void initForMaster( byte adr,byte dir_in);
void writeI2C( byte *pData, byte nBytes );
void readI2C( byte *pData, byte nBytes );

void init_i2c_mas_func(void)
{
	byte i;
	I2C_Context *ctxt=&i2cContext;
	memset(ctxt,0,sizeof(I2C_Context));
	for(i=0;i<MAX_NR_MULTIPLEXERS;i++) {
		ctxt->muxAddrs[i]=-1;
	}
	ctxt->currBus=-1; // state of mux unknown
	i2cBaudrate = I2C_BUS_BAUDRATE;
	for(i = 0; i< SLV_MEM_SIZE; i++)
		i2cSlaveData[i] = i*2+1;
	OS_CREATERSEMA( &ctxt->i2cLockSema );
	OS_CREATECSEMA( &ctxt->i2cWaitSema );
}

bool i2cBusy( void )
{
	if( i2cContext.state == I2C_IDLE ) return false;
	return true;
}

bool reviveBus( void )
{
	byte i;
	volatile word ttime1;
	volatile word ttime2;

	iic_stop();

// clock for max. twenty times until both lines are free
	for(i=0; i<20; i++)
	{
		ttime1 = (volatile word) OS_GetTime();
		while(!P7_1) {
//	SCL line presumably dead
			ttime2 = (volatile word) OS_GetTime();
			ttime2 = ( ttime2 > ttime1 ? (ttime2 - ttime1) : ~(ttime1 - ttime2) + 1);
			if( ttime2 > I2C_TIMEOUT ) {
				i=20;
				break;
			}
		}
		waitHalfCycle();
		if( P7_0 ) break;
		waitHalfCycle();
		OS_IncDI();
		PRCR2 = 1; // enable writing to P7/9 direction register
		PD7_1 = 1; // SCL=output
		P7_1 = 0;  // SCL=Low
		OS_DecRI(); 
		waitCycles(1);
		OS_IncDI();
		PRCR2 = 1;
		PD7_1 = 0;   // SCL=input
		OS_DecRI();
	}		
// SCL or SDA line presumably dead
	if ( i >= 20 )
	{
		iic_ini_lowlevel();
		return false;
	}

// OK, we have both lines high, make start/stop combination
	OS_IncDI();
	PRCR2 = 1;
	PD7_0 = 1;	// SDA=out
	P7_0 = 0;	// SDA=low
	waitHalfCycle();
	PRCR2 = 1;	//
	PD7_0 = 0;	// SDA=in (high)
	OS_DecRI();
	iic_ini_lowlevel();
	return true;
}	

void iic_ini(byte gotIdAdr)
{
	I2C_Context *ctxt=&i2cContext;
	byte failcnt = 0;
	byte i=0;
	ctxt->my_i2cAddr=gotIdAdr&0x7f;

	OS_Use( &ctxt->i2cLockSema );
	iic_ini_lowlevel();
	do {
		failcnt += 1;
		if( failcnt == 4 ) break;						    

		OS_Delay(I2C_INIT_DELAY);
		for(i = 0; i<I2C_INIT_DELAY; i++)
		{
			if( !U2SMR_BBS ) break; // BusBusy ?
			OS_Delay(1);
		}
		// if not free, try to make it free 
		if( i >= I2C_INIT_DELAY )
		{
			reviveBus();	
			continue;
		}
		// und nochmal testen ob frei
		for(i = 0; i<I2C_INIT_DELAY; i++)
		{
			if( P7_0 && P7_1 ) break;
			OS_Delay(1);
		}
		if (i >= I2C_INIT_DELAY ) {
			reviveBus();
			continue;
		}				
		break;
	} while( true );

	U2C1 = 0x05; // transmit enable, receive enable
	OS_Unuse( &ctxt->i2cLockSema );
}

/*
 * ---------------------------------------------------------
 * Register an I2C-Bus needs a Multiplexer address
 * and a choosen multiplexer number (0..15) as argument. 
 * A multiplexer may have up to 16 buses 
 * ---------------------------------------------------------
 */
void registerI2CMux( byte mdvcadr ,byte mux_nr)
{
	if(mux_nr<MAX_NR_MULTIPLEXERS) {
		i2cContext.muxAddrs[mux_nr]=mdvcadr;
		switchMux(mdvcadr,0);
	}
}

void sendI2cContent( byte len, byte* data )
{
	memcpy(i2cSlaveData, data, len);
}

void doScanI2C( byte* data,byte bus_nr)
{
	byte i, cnt = 0;

	memset( data, 0xff, MAX_I2C_DEVICES );

	for( i=0; i< 128; i++)
	{
		if( scanAddressI2C( i | (bus_nr<<8)) == stat_success )
		{
			data[cnt++] = i;
		}
		if( cnt == MAX_I2C_DEVICES) break;
	}
}

/*
 * --------------------------------------------------------------------------
 * Check if the EEProm needs 16 Bit address or 8 Bit access by trying 
 * to write a 16 Bit address with Write Control disabled. If it is a 
 * device with 8 Bit  address writing the second byte will fail.
 * --------------------------------------------------------------------------
 */
byte eepromRecognition( word devAdr, byte* enablePort, byte enablePortMask )
{
	byte pData[2] = { 0 };
	byte ans;
	byte memPort;

// for this test, the write control line must be high. Otherwise, data is corrupted.
	memPort = *enablePort;
	*enablePort |= enablePortMask;

	if( masterWriteI2C( 2, pData, devAdr ) == stat_data_error_write )
		ans = eeprom_Small;
	else
		ans = eeprom_Large;

	*enablePort = memPort;
	return ans;
}


/*
 * --------------------------------------------------------------------------------
 * Wait until the interrupthandlers are ready with executing the I2C-master script
 * or until a timeout occurs
 * --------------------------------------------------------------------------------
 */
byte 
i2c_wait_for_script(void) {
	volatile word ttime1;
	volatile word ttime2;
	I2C_Context *ctxt=&i2cContext;
	if( flgOSStarted )
	{
		OS_WaitCSemaTimed( &ctxt->i2cWaitSema, I2C_TIMEOUT );
	} else {
		ttime1 = (volatile word) OS_GetTime();
		while( ctxt->result == stat_in_progress) {
			ttime2 = (volatile word) OS_GetTime();
			ttime2 = ( ttime2 > ttime1 ? (ttime2 - ttime1) : ~(ttime1 - ttime2) + 1);

      			if( ttime2 > I2C_TIMEOUT )
     			{
				break;
      			}
      		}
	}
	if(ctxt->result==stat_in_progress) {
		return stat_timeout_at_address;
	}
	return ctxt->result;
}

/*
 * ----------------------------------------------------------------------------------------------------- 
 * Start a transaction as master and write the I2C-address to the Bus, 
 * Then wait until the interrupt handlers
 * have executed the I2C-script.
 * Automatically retry on arbitration loss or on error
 * ----------------------------------------------------------------------------------------------------- 
 */
static byte
i2c_execute_master_transaction(byte devAdr,word do_read,word max_errcount,word max_nackcount) {
	byte revivCnt=0;
	byte nackCnt=0;
	byte readCnt=0;
	byte narbCnt=0;
	byte flgFinished=false;
	byte retstat=stat_bus_broken;
	byte status;
	do {
		i2c_reset_script(&i2cContext);
		initForMaster(devAdr,do_read); 

⌨️ 快捷键说明

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