15
« on: September 01, 2011, 08:39:48 PM »
I have found the problem in the Interrupt driver in the slave.
One of the status bits had the opposite polarity of what I thought.
If anyone would like a working chunk of I2c Slave interrupt driver here it is:
static __interrupt__ void _IIC_InterruptSlave(void) // I2C0 interrupt
{
char junk;
I2SR&=~IIC_IIF; // clear the interrupt flag
if(I2SR&IIC_IAL) {
I2SR&=~IIC_IAL; // If IAL (arbitration lost) set, clear it
if(I2SR&IIC_IAAS) {
buffOffset=0;
} else return;
}
if(I2SR&IIC_IAAS) { // IAAS is set, received our slave address
if(I2SR&IIC_SRW) { // if SRW set, tx mode
I2CR|=IIC_MTX; // Set hardware to tx mode
buffOffset=0; // Init buffer address
I2DR=buf[buffOffset++]; // Send the first character
} else { // rx mode
I2CR&=~IIC_MTX; // Set hardware to rx mode
buffOffset=0; // Init buffer address
junk=I2DR; // Do a dummy read
}
} else { // IAAS not set, in the middle of communication
if(I2CR&IIC_MTX){ // If in tx mode
if(I2SR&IIC_RXACK){ // Failed to receive an ACK?
I2CR&=~IIC_MTX; // Set hardware to rx mode
junk=I2DR; // Do a dummy read
}else { // Not done transmitting data
I2DR=buf[buffOffset++]; // Send the next character
}
}else { // If in rx mode
buf[buffOffset++]=I2DR; // Read the next character
}
}
}
Here is the setup routine for it:
//
// Configure the IIC hardware
//
void fnConfigIICSlave(IICTABLE *pars)
{
unsigned char ucSpeed;
POWER_UP(POWER_I2C); // enable clock to module {46}
PASPAR |= (AS_I2C_SCL_0_FUNCTION | AS_I2C_SDA_0_FUNCTION); // configure the SDA and SCL pins on AS
// The calculation of the correct divider ratio doesn't follow a formular but is best taken from a table.
// The required divider value is ((BUS_CLOCK/1000)/pars->usSpeed). Various typical speeds are supported here.
switch (pars->usSpeed) { // {31}
case 400: // high speed IIC
#if BUS_CLOCK > 60000000 // 80MHz
ucSpeed = 0x32; // set about 400k with 80MHz bus frequency
#elif BUS_CLOCK > 50000000 // 60MHz
ucSpeed = 0x0d; // set about 400k with 60MHz bus frequency
#elif BUS_CLOCK > 40000000 // 50MHz
ucSpeed = 0x0b; // set about 400k with 50MHz bus frequency
#else // assume 40MHz
ucSpeed = 0x0a; // set about 400k with 40MHz bus frequency
#endif
break;
case 100:
default: // default to 100kHz
#if BUS_CLOCK > 60000000 // 80MHz
ucSpeed = 0x3a; // set about 100k with 80MHz bus frequency
#elif BUS_CLOCK > 50000000 // 60MHz
ucSpeed = 0x15; // set about 100k with 60MHz bus frequency
#elif BUS_CLOCK > 40000000 // 50MHz
ucSpeed = 0x37; // set about 100k with 50MHz bus frequency
#else // assume 40MHz
ucSpeed = 0x36; // set about 100k with 40MHz bus frequency
#endif
break;
case 50:
#if BUS_CLOCK > 60000000 // 80MHz
ucSpeed = 0x3e; // set about 50k with 80MHz bus frequency
#elif BUS_CLOCK > 50000000 // 60MHz
ucSpeed = 0x19; // set about 50k with 60MHz bus frequency
#elif BUS_CLOCK > 40000000 // 50MHz
ucSpeed = 0x3b; // set about 50k with 50MHz bus frequency
#else // assume 40MHz
ucSpeed = 0x3a; // set about 50k with 40MHz bus frequency
#endif
break;
}
I2FDR = ucSpeed;
I2CR = (IIC_IEN); // enable IIC controller and set slave mode
IC_ICR_0_17 = IIC_INTERRUPT_PRIORITY; // define interrupts level and priority
fnSetIntHandler(IIC_VECTOR, (unsigned char *)_IIC_InterruptSlave); // enter the handler routine
IC_IMRL_0 &= ~(IIC_PIF_INT_L | MASK_ALL_INT);
I2CR|=IIC_IIEN; // Enable interrupts
}
Feel free to use it. You might want to put it in the i2c doc as an example.
The read routine in the application loop works to. Here it is:
if (fnMsgs(IICPortID) != 0) { // if IIC message waiting
while ((Length = fnRead(IICPortID, ucInputMessage, MESSAGESIZE)) != 0) {
memcpy(&input_i2c.count,ucInputMessage,Length);
}
}
Keith Flick