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

📄 i2c_lib.c

📁 Discription: This multi-master driver provides the software interface to the I2C Bus hardware of th
💻 C
📖 第 1 页 / 共 2 页
字号:
_inline
void sendByte( byte dat )
{
// here arbitration functionality bit must be set
	U2RB_ABT = 0;
	U2SMR2 = 0xAF; // clock low, clock sync on, scl wait 9th, sda output stop on arb. loss 
	U2TB = (word) dat | 0x0100;
// TIMING: two cycles to allow clock to prepare sending
	waitCycles(2);
// release clock
	U2SMR2_SWC2 = 0;
}


_inline	
void decoupleFromBus( void )
{
// no reception interrupts
	OS_IncDI();
	BCNIC = IICIPL;
	S2RIC = 0x00;    // Interrupt Level priority 0 (denied)
	// Ports to input mode. This is garanted to be high
	PRCR2 = 1;
	PD7_0 &= 0xfc;
	U2MR = 0; 	//  port control
	U2SMR2 = 0x81;
	i2cContext.state=I2C_DECOUPLED;
	OS_DecRI();
}	

/*
 * ---------------------------------------------
 * Test Ack as Slave
 * returns with SCL low forced by SWC2 
 * ---------------------------------------------
 */
_inline
byte testAckAsSlave( void )
{
	word count = 0;
	byte ret = ack_OK;

	OS_IncDI();
	U2RB_ABT = 0;
// release clock
	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; // disable clock
	OS_DecRI();

	return ret;
}

/*
 * Re-allow clock to run for one byte
 */
_inline
void waitForNextByte( void )
{
// here arbitration functionality bit must be set
	U2RB_ABT = 0;  // clear arbitration loss
	U2SMR2 = 0xB5; // no sda-output, scl-wait 
// prepare to receive next byte. Bit 8 is low for acknowledgement.
	U2TB = 0x00FF;	 // sda=high except acknowledge
	waitCycles(2);
	U2SMR2_SWC2 = 0;  // enable clock
}			

_inline
void provideByteAsSlave( void )
{
// here arbitration functionality bit must be set
	U2RB_ABT = 0;
	U2SMR2 = 0xB5;
	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
// release clock
	U2SMR2_SWC2 = 0;
}
				

void new_uart2Receive(void); 

I2C_Context i2cContext;

_interrupt(10)
void stspInt( void )
{
	I2C_Context *ctxt;
	OS_EnterInterrupt();
	ctxt=&i2cContext;
	
// start or stop condition received.  reenable receive interrupt and prepare UART for next reception
	if( U2SMR_BBS )
	{
		// may only happen on repeated start as slave because this interrupt is off  during IDLE 
	} else {
		slaveWait();
	}
	OS_LeaveInterruptNoSwitch();
}		

_inline
void triggerNextReceptionNew( bool nack )
{
// Normally this function is entered with U2SMR2 = 0xA1.
	U2RB_ABT = 0;
	U2SMR2 = 0xA7;
	// no ack on last
	if(nack)
		U2TB = 0x01FF;
	else
		U2TB = 0x00FF;	
	// TIMING: two cycles to allow clock to prepare sending
	waitCycles(2); // This is  neccessary I maybe clock is not stopped because tx is not empty 
	U2SMR2_SWC2 = 0;
}	

_inline byte
read_rxbyte(void) {
	byte b = (U2RB<<1);
	if(U2RB&0x100)
		b++;
	return b;
}

/*
 * ----------------------------------------------------------------
 * Interpreter for MASTER scripts
 * executes commands until a command needs to wait for UART or 
 * CMD_I2C_SCRIPT_END is in the script
 * ----------------------------------------------------------------
 */
static void
i2c_interpreter(void) {
	byte ack;
	int cmd;
	word *countP;
	I2C_Context *ctxt=&i2cContext;
	while(1) {
		cmd = ctxt->script[ctxt->instrP++];
		switch(cmd) {
			case CMD_I2C_TRIGGER_RX:
				triggerNextReceptionNew(0);
				return;

			case CMD_I2C_TRIGGER_RX_NOACK:
				triggerNextReceptionNew(1);
				return;

			case CMD_I2C_WRITEB:
				sendByte(ctxt->script[ctxt->instrP++]);
				return;

			case CMD_I2C_WRITEDATA:
				sendByte(ctxt->data[ctxt->dataP++]);
				return;

			case CMD_I2C_LOOP:
				ctxt->scriptstack[ctxt->stackP++]=ctxt->script[ctxt->instrP++];
				ctxt->scriptstack[ctxt->stackP++]=ctxt->script[ctxt->instrP++];
				ctxt->scriptstack[ctxt->stackP++]=ctxt->instrP;
				break;	

			case CMD_I2C_ENDLOOP:
				countP=(word*)(ctxt->scriptstack+ctxt->stackP-3);			
				if(--(*countP)) {
					ctxt->instrP=ctxt->scriptstack[ctxt->stackP-1];
				} else {
					ctxt->stackP-=3;
				}
				break;
				
			case CMD_I2C_WAKEUP:
			 	if( flgOSStarted )
					OS_SignalCSema( &ctxt->i2cWaitSema );
				break;

			case CMD_I2C_READDATA:
				ctxt->data[ctxt->dataP++]=read_rxbyte();
				break;

			case CMD_I2C_SEND_NACKBIT:
				ack=testAckFromDvc();
				if(ack!=ack_NoAck) {
					ctxt->result = stat_arb_lost_in_nack; // maybe this is a success 
					decoupleFromBus();
					if(flgOSStarted)
						OS_SignalCSema(&ctxt->i2cWaitSema);
					return;
				}
				break;

			case CMD_I2C_SEND_ACKBIT:
				testAckFromDvc();
				break;

			case CMD_I2C_CHECK_ACK:
				U2SMR2_SDHI = 1; // allow slave to give ack/nack
				ack = testAckFromDvc();
				switch( ack )
				{
					case ack_Timeout:
						ctxt->result = stat_timeout_in_write;
						if( flgOSStarted )
							OS_SignalCSema( &ctxt->i2cWaitSema );
						return;
					case ack_NoAck:
						ctxt->result = stat_data_error_write;
						makeStop();
						if( flgOSStarted )
							OS_SignalCSema( &ctxt->i2cWaitSema );
						return;
				}
				break;

			case CMD_I2C_CHECK_ADDR_ARB:
				if(U2RB_ABT) {
					ctxt->result = stat_arb_lost_in_address;
					U2MR = 0x0A; // external clock
						     // SDA is automatically released 
					if( flgOSStarted )
						OS_SignalCSema( &ctxt->i2cWaitSema );
					return;
				}
				break;

			case CMD_I2C_CHECK_ARB:
				if( U2RB_ABT ) {
					ctxt->result = stat_arb_lost_in_write;
					decoupleFromBus();
					if( flgOSStarted )
						OS_SignalCSema( &ctxt->i2cWaitSema );
					return;
				}
				break;

			case CMD_I2C_REPSTART:
				makeRepStart(ctxt->script[ctxt->instrP++] );
				return;

			case CMD_I2C_STOP:
				makeStop();
				break;

			default:
				ctxt->result=stat_script_syntax_error;
			case CMD_I2C_SCRIPT_END:
				if(ctxt->result==stat_in_progress)
					ctxt->result=stat_success;
				ctxt->stackP=0;
				ctxt->instrP--; // do not advance past end
				return;
		}
	}
}

/*
 * ------------------------------------------
 * Interrupthandler runs the state machine 
 * while in master mode we are under control
 * of the interpreter
 * ------------------------------------------
 */
 
_interrupt(16)
void uart2Rcv( void )
{
	I2C_Context *ctxt;
	OS_EnterNestableInterrupt();
	ctxt=&i2cContext;
	switch(ctxt->state) {
		case I2C_MASTER:
			i2c_interpreter();
			if(ctxt->result !=  stat_arb_lost_in_address) {
				break;
			}
		case I2C_IDLE:
			if((U2RB&0x7f)!=ctxt->my_i2cAddr) {
				decoupleFromBus();
			} else {
				OS_IncDI();
				BCNIC = IICIPL; // enable Start/Stop Interrupt 
				U2SMR2 = 0x85;  // no sda output, no init on start, scl clock out enabled
				U2RB_ABT = 0;   // Clear Arbitration loss flag
				OS_DecRI();
				testAckAsSlave();
				if(!U2SMR_BBS) {
					slaveWait();
					break;
				}
				if(U2RB & 0x100) { // true means read
					slvCnt=0;
					ctxt->state=I2C_SLAVE_READ;	
					provideByteAsSlave();
				} else {
					ctxt->state=I2C_SLAVE_WAITADDR;	
					waitForNextByte();
				}  
			}
			break;

		case I2C_SLAVE_WAITADDR:
			slvCnt=read_rxbyte() & SLV_CNT_MASK;
			testAckAsSlave(); // never should fail because I was acknowledger
			if(ctxt->state==I2C_SLAVE_WAITADDR) {
				ctxt->state=I2C_SLAVE_WRITE;
				waitForNextByte();
			}
			break;

		case I2C_SLAVE_WRITE:
			i2cSlaveData[slvCnt]=read_rxbyte();
			slvCnt=(slvCnt+1) & SLV_CNT_MASK;
			testAckAsSlave(); // never should fail because I was acknowledger
			if(ctxt->state==I2C_SLAVE_WRITE) {
				waitForNextByte();
			}
			break;

		case I2C_SLAVE_READ:
			if(testAckAsSlave()==ack_OK)  {
				if(ctxt->state==I2C_SLAVE_READ) {
					provideByteAsSlave();
				}
			} else {
				if(ctxt->state==I2C_SLAVE_READ) {
					decoupleFromBus();
				}
			}
			break;

		case I2C_DECOUPLED:
		default:			
			break;
	} 
	OS_LeaveNestableInterrupt();
}
#pragma endoptimize		
#pragma endoptimize		

⌨️ 快捷键说明

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