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

📄 i2c_lib.c

📁 Discription: This multi-master driver provides the software interface to the I2C Bus hardware of th
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "Types/BaseTypes.h"

#include "Rtos.H"
#include "i2c.h"

#pragma optimize 1
#pragma optimize Tw
#define IICIPL  6
#define S2RIPL  3

extern byte i2cBaudrate;
extern bool flgOSStarted;

// the following globals are shared and must be made "threadsafe"

extern byte i2cSlaveData[];
static byte slvCnt = 0;
bool flgRepeatedStart;
byte debugdat = stat_success;


// ;;; ***************************************************************************
// ;;; ***************************************************************************
// ;;; void iic_ini(R0L,A0)
// ;;;						I2C Bus Initialization 
// ;;; --------------------------------------------------------------------------

/*
 * -----------------------------------------------------------------
 * slaveWait:
 * 	switch into a mode waiting for data from an other master
 * -----------------------------------------------------------------
 */
_inline
void slaveWait( void ) // must be called with interrupts off
{
// UART2 receive interrupt enable.
	S2RIC = S2RIPL;
// Disable STSP interrupts.
	BCNIC = 0x00;

	PRCR2 = 1; 
	PD7 &= 0xfc; 
// Init function, SDA high, SCL wait after reception
	U2SMR2 = 0xD5;   
// set to I2C mode, external clock
	U2MR = 0x0A; // external clock, i2c-mode
// clear arbitration bit
	U2RB_ABT = 0;
// initialize transmit register with ack bit low, in case that I'm adressed
//	if(U2C0_TXEPT) 
//		U2TB = 0x00FF;
	U2TB = 0x00FF;
// clear slave flags
	i2cContext.state=I2C_IDLE;
}

/* 
 *  Interface function
 */
void iic_ini_lowlevel( void )
{
	 OS_IncDI();	
// UART2 transmit interrupt disable
	S2TIC = 0x00;

// set PD7 to input mode SDA and SCL
	PRCR2 = 1;
	PD7 &= 0xfc;
// set U2SMR to I2C mode, clock synch disable, SCL wait output disable,
// SDA output stop bit disable, UART2 init. bit enabled, SCL wait output
// bit 2 to UART2 clock, SDA output  disable to high impedance, and
// Start/stop condition control bit to 1.
	U2SMR = 0x01;
// Set MSB format for I2C mode and set outputs to open drain
	U2C0 = 0xB0;
// Set baudrate.  _i2c_baudrate is define in i2c.c and setup in i2c.h.
	U2BRG = i2cBaudrate;
// init slave wait mode, master data and slave data counters
// allow sending and receiving
	slaveWait();
	OS_DecRI();
}

// ;;; ***************************************************************************
// ;;; ***************************************************************************
// ;;; unsigned char iic_stop(void)
// ;;			Disable I2C Bus.   Return values are;
// ;;								0:	Stop I2C function completed.
// ;;								1:	Cannot stop I2C operation, bus is busy.
// ;;									M16C is currently performing Master Transmission
// ;;; --------------------------------------------------------------------------

byte iic_stop(void)
{

	OS_IncDI();
	S2TIC = 0x00;
	S2RIC = 0x00;
	BCNIC = 0x00;
	P7 |= 0x03;	 // SDA/SCL High
// now deactivate I2C bus
	PRCR2 = 1;
	PD7 &= 0xFC;
	U2C1 = 0x00;
	U2MR = 0x00; // internal clock, Port mode
	U2SMR = 0x00;
	U2SMR2 = 0x80;
	OS_DecRI();
	return 0;
}

_inline
bool makeStart( byte addr )
{
	word count = 0;
	OS_IncDI();
// set SDA to high impedance before releasing clock for clean start condition
	U2SMR2 = 0xC1;
// switch to port control
	U2MR = 0x00; // port control
// turn transmission and reception off. If this is omitted, reception sometimes fails, I don't know why.
	U2C1 = 0x00;
// delay for clean start condition
	waitHalfCycle();
// generate start condition by pulling SDA down
	P7_0 = 0;
	PRCR2 = 1;
	PD7_0 = 1;
// delay for clean start condition
	waitCycles(1); // half cycle should be enough (tFall+t_HD_STA)=300+4us jk
	//waitHalfCycle(); //jk
	//check if SCL is already down, if yes we may have lost arbitration
// clear arbitration flag and pull clock down. Enable UART control.
	U2RB_ABT = 0;  // reset abort indication
	U2SMR2 = 0xAF; // Pull down clk
	U2MR = 0x02;   // internal clk, i2c mode
	i2cContext.state=I2C_MASTER;
// now clock is down, we are safe from interrupts
	OS_DecRI();
// TIMING: at least two cycles for master synchronization
	waitCycles(2);
//	waitHalfCycle();

// switch interrupts on and close port which was opened to generate start condition
	OS_IncDI();
	S2RIC = S2RIPL;
	PRCR2 = 1;
	PD7_0 = 0;
	P7_0 = 1;
	OS_DecRI();

// turn transmission and reception on again. If this is omitted, reception sometimes fails,
// I don't know why.
	U2C1 = 0x05;
// load address into send buffer. clear 9th bit for acknowledgement in case that I lose during
// device address arbitration.
	U2TB = (word) addr | 0x0000;
// keep clock low for two cycles, which is the time needed for the transmission shift register
// to be loaded and before the clock starts 
	waitCycles(2);
// release clock
	U2SMR2_SWC2 = 0;  // release clock
	return true;
}

_inline bool
makeRepStart(byte addr) {
	I2C_Context *ctxt=&i2cContext;
	word count = 0;
	OS_IncDI();
// set SDA to high impedance before releasing clock for clean start condition
	U2SMR2 = 0xC1;
// switch to port control
	U2MR = 0x00; // port control
// turn transmission and reception off. If this is omitted, reception sometimes fails, I don't know why.
	U2C1 = 0x00;
// in case of repeated start condition, wait until clock is high to synchronize masters
	while( !P7_1 )
	{
		if( ++count == I2C_IRQ_TIMEOUT )
		{
			ctxt->result=stat_timeout_in_start;
			ctxt->state=I2C_IDLE;
			OS_DecRI();
			return false;
		}
	}		
// delay for clean start condition
	waitHalfCycle();
// generate start condition by pulling SDA down
	P7_0 = 0;
	PRCR2 = 1;
	PD7_0 = 1;
// delay for clean start condition
	waitCycles(1);
// clear arbitration flag and pull clock down. Enable UART control.
	U2RB_ABT = 0;  // reset abort indication
	U2SMR2 = 0xAF; // Pull down clk
	U2MR = 0x02;   // internal clk, i2c mode
	ctxt->state=I2C_MASTER;
// now clock is down, we are safe from interrupts
	OS_DecRI();
// TIMING: at least two cycles for master synchronization
	waitCycles(2);
//	waitHalfCycle();

// switch interrupts on and close port which was opened to generate start condition
	OS_IncDI();
	S2RIC = S2RIPL;
	PRCR2 = 1; 
	PD7_0 = 0;  
	P7_0 = 1;
	OS_DecRI();

// turn transmission and reception on again. If this is omitted, reception sometimes fails,
// I don't know why.
	U2C1 = 0x05;
// load address into send buffer. clear 9th bit for acknowledgement in case that I lose during
// device address arbitration.
	U2TB = (word) addr | 0x0000;
// keep clock low for two cycles, which is the time needed for the transmission shift register
// to be loaded and before the clock starts 
	waitCycles(2);
// release clock
	U2SMR2_SWC2 = 0;  // release clock
	return true;
}

void 
initForMaster( byte i2c_addr ,byte dir_in)
{
	volatile word ttime1;
	volatile word ttime2;
	byte startadr;
	I2C_Context *ctxt=&i2cContext;
// wait until bus free
	startadr = i2c_addr << 1;
	if( dir_in )
		startadr|=1;
		 
	ttime1 = ( volatile word ) OS_GetTime();
	while(true)
	{
		OS_DI();
		if( !(U2SMR_BBS) ) 
			break;
		OS_EI();
		ttime2 = (volatile word) OS_GetTime();
		ttime2 = ( ttime2 > ttime1 ? (ttime2 - ttime1) : ~(ttime1 - ttime2) + 1);
		if( ttime2 > I2C_TIMEOUT_MASTER ) {
			ctxt->result=stat_timeout_in_init;
			// script does not need to be aborted because we are still in idle state 
			OS_SignalCSema( &ctxt->i2cWaitSema );
			return;
		}
	}
	if( BCNIC & 0x08) 
		slaveWait();
// set flag for master action
// interrupts are reenabled in makeStart
	if( !makeStart( startadr )) {
		if( flgOSStarted )
			OS_SignalCSema( &ctxt->i2cWaitSema );
	}
}

static bool 
makeStop( void )
{
	word count = 0;
	I2C_Context *ctxt=&i2cContext;
// first draw clock down
	P7_1 = 0;
	OS_IncDI();
	PRCR2 = 1;
	PD7_1 = 1;
	OS_DecRI();
// switch to port control
	U2MR = 0; //  Port control
// now draw SDA down
	P7_0 = 0;
	OS_IncDI();
	PRCR2 = 1;
	PD7_0 = 1;
	OS_DecRI();
// TIMING: half a cycle for well-defined stop condition
	waitHalfCycle();
// now release clock
	OS_IncDI();
	PRCR2 = 1;
	PD7_1 = 0; 
	P7_1 = 1;
	OS_DecRI();
// wait until clock goes high for master synchronization
	while(!P7_1) {
		if( ++count == I2C_IRQ_TIMEOUT ) {
			ctxt->result=stat_timeout_in_stop;
			return false;
		}
	}
	
// TIMING: half a cycle for well-defined stop condition
	waitHalfCycle();
// now release SDA. Disable interrupts to make sure that the I2C
// interface is set to slave mode by slaveWait right after the stop condition
// has been produced.
	OS_IncDI();
	PRCR2 = 1;
	PD7_0 = 0;
	P7_0 = 1;
	count = 0;
	while(!P7_0) {
		if( ++count == I2C_IRQ_TIMEOUT ) {
			OS_DecRI();
			ctxt->result=stat_timeout_in_stop;
			return false;
		}
	}
	slaveWait();
	OS_DecRI();
	return true;
}

_inline
byte testAckFromDvc( void )
{
// this function is normally entered with U2SMR2 = 0x8F

	word count = 0l;
	byte ans = ack_OK;

	//waitCycles(1); // not necessary because the clock already did this
// interrupts must not hit here
	OS_IncDI();
// release clock
	U2SMR2_SWC = 0;
	
// wait until clock goes high for synchronization with other master
	while(!P7_1) {
		if( ++count == I2C_IRQ_TIMEOUT )
		{
			OS_DecRI();
			return ack_Timeout;
		}
	}

//	TIMING: set the sampling point to the middle of a one-cycle interval
	waitHalfCycle(); 

	if( P7_0 )
		ans = ack_NoAck;

//	TIMING: half a cycle is necessary for master synchronization
//	waitHalfCycle();
// draw clock down. Now we are safe again from interrupts
	U2SMR2_SWC2 = 1; 
	OS_DecRI();
	return ans;
}

⌨️ 快捷键说明

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