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

📄 i2c_lib_ok_before_opt.c

📁 Discription: This multi-master driver provides the software interface to the I2C Bus hardware of th
💻 C
字号:
#include "Types/Sfr.h"

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

#define IICIPL 4
#define S2RIPL ( IICIPL - 1 )
//#define S2RIPL 7

// extern OS_TIMER i2cTimeoutTimer;
// extern OS_CSEMA i2cWaitSema;


extern byte i2cSlaveData[];

extern byte id_adr;
extern byte i2cBaudrate;
extern word miic;

static byte* datPtr;
static byte numBytes;
static byte datCnt;
static byte slvCnt = 0;

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

_inline
void slaveWait( void )
{
// Disable STSP interrupts.
	U2MR = 0x00;
	BCNIC = 0x00;
	S2RIC = 0x00;
	_nop();
	_nop();
	PRCR2=1;
	PD7 &= 0xfc;
// external clock mode
	U2SMR = 0x01;
	U2SMR2 = 0xD5;
	P7_0 = 1;
	U2MR = 0x0A;
// initialize transmit register with ack bit low, in case that I'm adressed
	if(U2C0_TXEPT) U2TB = 0x00FF;
// clear arbitration bit
	U2RB_ABT = 0;
// UART2 receive interrupt enable.
	S2RIC = S2RIPL;
	miic = 0;
// master action is over
}


void iic_ini(byte gotIdAdr)
{
	 OS_IncDI();	
// set ID "Device" address for slave mode and save ID as well as data buffer address
	id_adr = gotIdAdr & 0x7f;
// UART2 transmit interrupt disable
	S2TIC = 0x00;
	S2RIC = 0x00;
	BCNIC = 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 SDA output to high impedance
	P7 |= 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();
	OS_Delay(100);
	while(U2SMR_BBS);
	U2C1 = 0x05;
}

// ;;; ***************************************************************************
// ;;; ***************************************************************************
// ;;; unsigned char iic_kill(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();
	P7 |= 0x03;	 // SDA/SCL High
// now deactivate I2C bus
	PRCR2 = 1;
	PD7 &= 0xFC;
	U2C1 = 0x00;
	U2MR = 0x00;
	U2SMR = 0x00;
	U2SMR2 = 0x80;
	BCNIC = 0x00;
	S2TIC = 0x00;
	S2RIC = 0x00;
	_nop();
	_nop();
	OS_DecRI();
	return 0;
}

void makeStart( byte addr )
{
	word count = 0;
	OS_IncDI();
// clear arbitration flag
	U2SMR2 = 0x8f;
// TIMING: SEEMS TO BE NOT NECESSARY
	while(!P7_1) {
		if( ++count == I2C_IRQ_TIMEOUT ) break;
	}
	if( !P7_1 )
	{
		miic = 0;
		status = stat_timeout;
		OS_DecRI();
		return;
	}
	P7_0 = 0;
	PRCR2 = 1;
	PD7_0 = 1;
	U2MR = 0;

// TIMING: at least two cycles for master synchronization
	waitCycles(2);

	U2C1 = 0x00;
	U2SMR2_SWC2 = 1;
	U2MR = 0x02;
	U2C1 = 0x05;
// load address into send buffer.
	U2TB = (word) addr | 0x0100;

	U2SMR2_CSC = 1;
// TIMING: at least two cycles for allowing clock to prepare for sending
	waitCycles(2);
	S2RIC = S2RIPL;
	U2SMR2_SWC2 = 0;

	PRCR2 = 1;
	PD7_0 = 0;
	U2RB_ABT = 0;

	miic |= miic_start_cond_done | miic_address_sent;
	OS_DecRI();
}

//;;; --------------------------------------------------------------------------
//;;	Master start write/read function;  Make Start.
//;;; --------------------------------------------------------------------------
void initForMaster( byte addr )
{
	int ttime;
// wait until bus free
	ttime = OS_GetTime();
	while(true)
	{
		OS_DI();
		if( !(U2SMR & 0x04) ) break;
		OS_EI();
		if( OS_GetTime() - ttime > I2C_TIMEOUT ) {
			miic = 0;
			status = stat_timeout;
			return;
		}
	}
	if( BCNIC & 0x08) slaveWait();
// set flag for master action
	miic |= miic_i_am_master;
	datCnt = 0;
// interrupts are reenabled in makeStart
	makeStart( addr );
}


bool makeStop( void )
{
	word count = 0;
// first draw clock down
	OS_IncDI();
	P7_1 = 0;
	PRCR2 = 1;
	PD7 |= 0x02;
	U2MR = 0;
// TIMING: Seems to be not necessary
//	waitCycles(3);
// now draw SDA down
	P7_0 = 0;
	PRCR2 = 1;
	PD7 |= 0x01;
// TIMING: half a cycle for well-defined stop condition
	waitHalfCycle();
// now release clock
	PRCR2 = 1;
	PD7 &= ~0x02;
	P7_1 = 1;
	while(!P7_1) {
		if( ++count == I2C_IRQ_TIMEOUT ) {
			OS_DecRI();
			return false;
		}
	}
	
// TIMING: half a cycle for well-defined stop condition
	waitHalfCycle();
// now release SDA
	PRCR2 = 1;
	PD7 &= ~0x01;
	P7_0 = 1;
	count = 0;
	while(!P7_0) {
		if( ++count == I2C_IRQ_TIMEOUT ) {
			OS_DecRI();
			return false;
		}
	}
	slaveWait();
	OS_DecRI();
	return true;
}
// enable I2C in external clock mode (slave)

_inline
byte testAckFromDvc( void )
{
	word count = 0l;
	byte ans = ack_OK;;

	waitCycles(1);
	OS_IncDI();
	U2SMR2 = 0x83;

// timeout after ~200 ms

	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();
	U2SMR2 = 0xA3;
	OS_DecRI();
	return ans;

}

_inline
void sendByte( byte dat )
{
// clear arbitration flag, because otherwise SDA is blocked by the "SDA output stop" function
	U2RB_ABT = 0;
// put next data byte to transmission register
	OS_IncDI();
	U2TB = (word) dat | 0x0100;
// TIMING: two cycles to allow clock to prepare sending
	waitCycles(2);
// release clock
	U2SMR2 = 0x8F;
	OS_DecRI();
}

_inline
void triggerNextReception( void )
{
	U2RB_ABT = 0;
// if the last byte is going to be received, then set bit 9 of transmission buffer for "no ack".
	OS_IncDI();
	if( datCnt == numBytes - 1)
		U2TB = 0x01FF;
	else
		U2TB = 0x00FF;	
// TIMING: two cycles to allow clock to prepare sending
	waitCycles(2);
	U2SMR2 = 0x87;
	OS_DecRI();
}	

void writeI2C( byte *pData, byte nBytes )
{
	miic |= miic_opmode_write;
	datPtr = pData;
	numBytes = nBytes;
	datCnt = 0;

	sendByte( datPtr[datCnt++] );
}	

void readI2C( byte* pData, byte nBytes )
{
	miic |= miic_opmode_read;
	datPtr = pData;
	numBytes = nBytes;
	datCnt = 0;
	triggerNextReception();
}

_interrupt(10)
void stspInt( void )
{
	OS_EnterInterrupt();
// start or stop condition received.  reenable receive interrupt and prepare UART for next reception

	if(U2SMR_BBS && ( miic & miic_slave_work_in_progress ))
	{
		miic = 0;
	}
	if(!U2SMR_BBS)
	{
		slaveWait();
	}
	OS_LeaveInterruptNoSwitch();
}		

_inline
byte testAckAsSlave( void )
{
	word count = 0;
	byte ret = ack_OK;
// set acknowledge bit by releasing clock. Since bit 8 of the transmission register is 0,
// SDA is drawn to low by the next clock cycle from the master.

	OS_IncDI();
	U2SMR2_SWC = 0;
// wait until clock goes high, timeout after ~200 ms
	while(!P7_1) {
		if( ++count == I2C_IRQ_TIMEOUT )
		{
			OS_DecRI();
			return ack_Timeout;
		}
	}
	if( P7_0 ) ret = ack_NoAck;
	count = 0;
	while(P7_1) {
		if( ++count == I2C_IRQ_TIMEOUT )
		{
			OS_DecRI();
			return ack_Timeout;
		}
	}
// stop clock
	U2SMR2_SWC2 = 1;
	OS_DecRI();

	return ret;
}

_inline	
void decoupleFromBus( void )
{

// no reception interrupts
	S2RIC = 0x00;
	BCNIC = IICIPL;
// put outputs to high impedance and switch to port control
	P7 |= 0x03;
	PRCR2 = 1;
	PD7 &= ~0x03;
	U2MR = 0;
	U2SMR2_SWC2 = 0;
	_nop();
	_nop();
}	

_inline
void waitForNextByte( void )
{
// prepare to receive next byte. Bit 8 is low for acknowledgement.
	OS_IncDI();
	U2TB = 0x00FF;
	waitCycles(2);
	U2RB_ABT = 0;
	U2SMR2_SWC = 1;
	U2SMR2_SWC2 = 0;
	OS_DecRI();
}			

_inline
void provideByteAsSlave( void )
{
// put next data byte to transmission register
	OS_IncDI();
	U2TB = (word) i2cSlaveData[slvCnt] | 0x0100;
	slvCnt = (slvCnt + 1) & SLV_CNT_MASK;
// wait until transmission module is ready
	waitCycles(2);
// clear arbitration flag, because otherwise SDA is blocked by the "SDA output stop" function
	U2RB_ABT = 0;
// release clock
	U2SMR2_SWC = 1;
	U2SMR2_SWC2 = 0;
	OS_DecRI();
}
				
//;;	UART2 RECV INTERRUPT.
//;;; ******************************************************************************

_interrupt(16)
void uart2Rcv( void )
{
	byte ack;

	OS_EnterNestableInterrupt();
	if(miic & miic_i_am_master )
	{
		if(miic & miic_address_sent)
		{
			if( !U2RB_ABT )
			{
				miic &= ~miic_address_sent;
				ack = testAckFromDvc();
				switch( ack )
				{
					case ack_Timeout:
						status = stat_timeout;
						miic = 0;
						break;
					case ack_OK:
						status = stat_success;
						break;
					default:
						status = stat_no_ack_from_device;
						miic = 0;
						if( !makeStop() ) status = stat_timeout;
						break;
				}
				OS_LeaveNestableInterrupt();
				return;
			} else {
// arbitration lost. I could be addressed, so set to slave mode and go to address recognition
				status = stat_arb_lost;
				miic = 0;
			}
		}
		if(miic & miic_opmode_write)
		{
			if( !U2RB_ABT )
			{
// OK, starting to transmit data. We always expect an acknowledgement when writing.
				ack = testAckFromDvc();
				switch( ack )
				{
					case ack_Timeout:
						status = stat_timeout;
						miic = 0;
						OS_LeaveNestableInterrupt();
						return;
					case ack_NoAck:
						status = stat_data_error;
						miic = 0;
						if( !makeStop() ) status = stat_timeout;
						OS_LeaveNestableInterrupt();
						return;
					default:
						break;
				}
// all data sent? then make stop condition.
				if( datCnt == numBytes )
				{
					status = stat_success;
					miic &= ~miic_opmode_write;
					OS_LeaveNestableInterrupt();
					return;
				}
				sendByte( datPtr[datCnt++] );
				OS_LeaveNestableInterrupt();
				return;
			} else {
// disable SDA output
				testAckAsSlave();
				decoupleFromBus();
				miic = 0;
				status = stat_arb_lost;
				OS_LeaveNestableInterrupt();
				return;
			}
		}
		if( miic & miic_opmode_read )
		{
// save byte received
			datPtr[datCnt] = (byte) (U2RB << 1);
			if(U2RB & 0x0100) datPtr[datCnt] += 1;
			if(datPtr[datCnt] == 0x80)
			{
				_nop();
			} else {
				_nop();
			}
			++datCnt;
// test acknowledgment: if no ack, reception is complete.
			ack = testAckFromDvc();
			switch( ack )
			{
				case ack_Timeout:
					status = stat_timeout;
					miic = 0;
					OS_LeaveNestableInterrupt();
					return;
				case ack_NoAck:
					if( datCnt != numBytes )
					{
						status = stat_data_error;
						miic = 0;
					} else {
						status = stat_success;
						miic &=	~miic_opmode_read;
					}
					OS_LeaveNestableInterrupt();
					return;
				default:
					break;
			}
			triggerNextReception();
			OS_LeaveNestableInterrupt();
			return;
		}				
						
	}
// OK, I'm slave and receiving data. If I2C address doesn't fit, go to taiki.
// otherwise initialize slave routines.		
// switch on start/stop interrupt
	BCNIC = IICIPL;
	if( miic & miic_slave_work_in_progress )
	{
		if( miic & miic_opmode_slave_write )
		{
			i2cSlaveData[ slvCnt ] = (byte) (U2RB << 1);
			if( U2RB & 0x0100 ) i2cSlaveData[ slvCnt ] += 1;
			slvCnt = (slvCnt + 1) & SLV_CNT_MASK;
			testAckAsSlave();
			waitForNextByte();
		}
		if( miic & miic_opmode_slave_read )
		{
			if( testAckAsSlave() == ack_OK )
				provideByteAsSlave();
			else
			{
//				slaveWait();

// clear arbitration flag, because otherwise SDA is blocked by the "SDA output stop" function
				U2RB_ABT = 0;
// release clock
				U2SMR2_SWC = 1;
				U2SMR2_STAC = 1;
				U2SMR2_ASL = 1;
				U2SMR2_SDHI = 0;
				U2TB = 0x00FF;
				U2SMR2_SWC2 = 0;

//				P2_3 = 1;
//				P2_3 = 0;
//				P2_3 = 1;
//				P2_3 = 0;
			}
		}
		if( miic & miic_opmode_wait_for_data_adr )
		{
			slvCnt = (byte) ((U2RB & SLV_CNT_MASK) << 1);
			if( U2RB & 0x0100 ) slvCnt += 1;
			miic &= ~miic_opmode_wait_for_data_adr;
			miic |= miic_opmode_slave_write;
			testAckAsSlave();
			waitForNextByte();
		}
	} else {
		if( ((byte) (U2RB & 0x007f)) != id_adr )
		{
// switch to external clock mode, wait for ack and decouple
			testAckAsSlave();
			decoupleFromBus();
		} else {
// I'm addressed. 
			miic |= miic_slave_work_in_progress;
// enable SDA output
			U2SMR2_CSC = 0;
			U2SMR2_SDHI = 0;
			PRCR2 = 1;
			PD7_0 = 1;
			P7_0 = 0;
			U2MR = 0;
			testAckAsSlave();
			PRCR2 = 1;
			PD7_0 = 0;
			P7_0 = 1;
			U2MR = 0x0A;
			U2SMR2_ASL = 0;
			U2SMR2_STAC = 1;
			if( U2RB & 0x0100 )
			{
				miic |= miic_opmode_slave_read;
				provideByteAsSlave();						
			} else {
				miic |= miic_opmode_wait_for_data_adr;
				waitForNextByte();
			}
		}
	}
	OS_LeaveNestableInterrupt();
}
		


⌨️ 快捷键说明

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