Exemple #1
0
void ResetToInitState(void)
{
	State              = STATE_RESET;
	InterruptPulse     = 0;
	DrivingNeighborBus = 0;
	ticks              = 0;

	DisableDownstreamInterrupt;				// Disable all GPIO interrupts on port 1
	Setup_As_Input(PIN_UPSTREAM);			
	Setup_As_Output(PIN_DOWNSTREAM);		// Reset all downstream modules

	PRT1DR = 0;										// Neighbor bus drives low

	Disable_I2C_Pullups;
	
	DL_Reg.ID     = 0;
	DL_Reg.Config = DL_REGS_CONFIG_DISABLE;

	EzI2Cs_SetAddr(0);
}
Exemple #2
0
// Returns 1 if DaisyLink initialization is complete and Module
// function should be active.  Returns 0 if Module function should
// ignore I2C activity.  For some reason this compiler does not
// allow a function to return a bool.
char DaisyLink(BYTE *I2CRAM)
{
	struct DL_Regs *vDL_Regs = (struct DL_Regs *)I2CRAM;		// The copy of DL_Reg "seen" by the EzI2C
	char active = 0;

	switch( State )
	{
	
	// In this state, a reset condition exists.  The I2C should be unresponsive
	// and the DaisyLink state should wait until the upstream line goes high
	// before proceeding to the SETUP state.
	case STATE_RESET:
		if( IsNotActive(PIN_UPSTREAM) )				// If the mainboard has released the RESET condition
		{
			State = STATE_SETUP;					// Move to the Setup state
			DL_Reg.ID = DEFAULT_I2C_ID;
			Refresh(I2CRAM);						// Update I2C registers to show default I2C ID
			Enable_I2C_Pullups;
			EzI2Cs_SetAddr(DEFAULT_I2C_ID);			// Make this module respond to the I2C default ID
		}
		break;
		
	// In this state, the Module will respond to DaisyLink registers at the I2C default address.
	// This state is maintained until either the upstream line goes low again, or the I2C
	// address is changed.
	case STATE_SETUP:
		if( IsActive(PIN_UPSTREAM) )				// If the module is RESET again
		{
			ResetToInitState();
			Refresh(I2CRAM);
		}
		else if( DEFAULT_I2C_ID != vDL_Regs->ID )	// If the I2C ID has been set, move to the next state
		{
			DL_Reg.ID = vDL_Regs->ID;				// Fetch the newly set I2C ID
			State = STATE_STANDBY;					// Move to the Standby state
			EzI2Cs_SetAddr(DL_Reg.ID);				// Make this module respond to the newly set I2C ID
			Setup_As_Input(PIN_DOWNSTREAM);			// Allow the downstream module to leave the RESET state
		}
		break;
		
	// In this state, the module will respond to DaisyLink registers at the assigned I2C address.
	// This state is maintained until either the upstream line goes low again, or the DL_REGS_CONFIG_DISABLE
	// bit is set low by the mainboard (and with it, the state of the DL_REGS_CONFIG_PULLUPS bit).
	case STATE_STANDBY:
		if( IsActive(PIN_UPSTREAM) )				// If the module is RESET again
		{
			ResetToInitState();
			Refresh(I2CRAM);
		}
		else if( 0 == (vDL_Regs->Config & DL_REGS_CONFIG_DISABLE))			// If the mainboard has finished setting up this module
		{
			DL_Reg.Config = (vDL_Regs->Config & DL_REGS_CONFIG_PULLUPS);	// Keep the new resistor setting
			if( 0 == (DL_Reg.Config & DL_REGS_CONFIG_PULLUPS) )				// If pullups are disabled (this is not the last module in the chain)
			{
				Disable_I2C_Pullups;
			}
			Refresh(I2CRAM);
			active = 1;								// Enable the functionality of this module
			State = STATE_ACTIVE;					// Move to the Active state
		}
		break;
		
	// In this state, the module will respond to DaisyLink Registers and all module function registers
	// at the assigned I2C address.  It will remain in this state until interrupted by the module's
	// main function, a module upstream, or the mainboard (a reset).
	case STATE_ACTIVE:
		// If we are in an interrupt state
		if( DL_Reg.Config & DL_REGS_CONFIG_INTERRUPT )
		{
			// If the config register has been cleared
			if( !(vDL_Regs->Config & DL_REGS_CONFIG_INTERRUPT) )
			{
				DL_Reg.Config &= ~DL_REGS_CONFIG_INTERRUPT;		// Clear this module's interrupt state
				vDL_Regs->Config = DL_Reg.Config;
				InterruptPulse = 0;								// Indicate that we can stop pulling on the upstream neighbor bus
			}
			vDL_Regs->ID = DL_Reg.ID;							// Refresh the ID register (read from I2C bus)
			// Refresh all DaisyLink registers except for the ID and Config registers
			memcpy(&(vDL_Regs->DLVersion), &(DL_Reg.DLVersion), sizeof(struct DL_Regs)-2);
		}
		else
		{
			Refresh(I2CRAM);				// Refresh the DaisyLink I2C registers
		}
		// If this module's interrupt pulse has reached its maximum length
		if( InterruptPulse && (((WORD)ticks - intStart) > 10) )
		{
			InterruptPulse = 0;				// Indicate that we can stop pulling on the upstream neighbor bus
		}
		// NOTE: Only sample the downstream neighbor bus once while interrupts are off and act on what you find
		//       before restoring interrupts. The interrupt routine will then handle any changes that might have
		//       occurred while interrupts were off once interrupts are enabled again.
		DisableDownstreamInterrupt;			// Disable interrupts from the downstream neighbor bus
		if( IsActive(PIN_DOWNSTREAM) )
		{
			// If we should be driving the upstream bus, but aren't
			if( !DrivingNeighborBus )
			{
				Setup_As_Output(PIN_UPSTREAM);
				DrivingNeighborBus = 1;				// Drive the upstream neighbor bus line
			}
		}
		else
		{
			// If we shouldn't be driving the upstream bus, but are
			if( DrivingNeighborBus && !InterruptPulse )
			{
				Setup_As_Input(PIN_UPSTREAM);
				DrivingNeighborBus = 0;				// Release the upstream neighbor bus line
			}
		}
		// If upstream neighbor bus is being driven and it isn't by us
		if( !DrivingNeighborBus && IsActive(PIN_UPSTREAM) )
		{
			// Reset the DaisyLink
			State = STATE_RESET;
			ResetToInitState();
			Refresh(I2CRAM);
			break;
		}
		EnableDownstreamInterrupt;				// Enable the downstream neighbor bus interrupt
		active = 1;
		break;
	default:
		ResetToInitState();
		Refresh(I2CRAM);
		break;
	}

	return active;
}
Exemple #3
0
void I2C_Init(void)
{
	EzI2Cs_SetRamBuffer(sizeof(I2C_Regs), 0, (char*)(&I2C_Regs));
	EzI2Cs_SetAddr(I2C_SLAVE_ADDRESS);
	EzI2Cs_Start();  // Turn on I2C
}