I have written a simple I2C slave interface for the F28027F and it seems to be working as expected, but there is one remaining problem. When I add the I2C stuff into motorware lab1 it runs for a while then hangs (seems to be holding scl low). This locks up the bus until there is a reset. When I reduce the overhead of mainISR the problem goes away.
This is is what I have found causes the problem:
I get the I2C_IntSrc_Slave_Addr (7) interrupt, if it is a read command I also immediately get the I2C_IntSrc_Tx_Rdy (5). Normally this isn't a problem. If mainISR is executing at this time it seems that one of the interrupts is missed and the I2C module locks up. I have verified this behavior by timing the ISRs with a logic analyzer.
I am not using FIFOs, which I imagine could mitigate the problem. I use the I2C_IntSrc_Slave_Addr interrupt to setup to clear some array indices and set I2CDXR to the first value (if I do this on the I2C_IntSrc_Tx_Rdy interrupt the first byte sent uses the previous value of I2CDXR), I could probably do this on a stop interrupt just as well. I could also implement some sort of timeout check as well. I mainly just want to understand what the problem is in this case.
Init Code:
void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; //I2C_Obj *I2CARegs=(I2C_Obj *)obj->I2CaHandle; // Initialize I2C /* I2CARegs->I2CSAR = 0x0050; // Slave address - EEPROM control code I2CARegs->I2COAR =1; // I2CCLK = SYSCLK/(I2CPSC+1) I2CARegs->I2CPSC = 6; // Prescaler - need 7-12 Mhz on module clk I2CARegs->I2CCLKL = 20; // NOTE: must be non zero I2CARegs->I2CCLKH = 20; // NOTE: must be non zero I2CARegs->I2CIER = (1<<6)|(1<<4)|(1<<3); // Enable SCD & ARDY interrupts I2CARegs->I2CMDR = 0x0020; // Take I2C out of reset*/ // Stop I2C when suspended //PIE_enableInt(PIE_Handle pieHandle, const PIE_GroupNumber_e group, const PIE_InterruptSource_e intSource)*/ I2C_setSlaveAddress(obj->I2CaHandle, 0x0001); I2C_setupClock(obj->I2CaHandle, 6, 20,20); I2C_enableInt(obj->I2CaHandle,I2C_IntEn_Rx_Rdy|I2C_IntEn_Tx_Rdy|I2C_IntEn_Slave_Addr); I2C_setSlave(obj->I2CaHandle); I2C_enable(obj->I2CaHandle); } void HAL_enableI2CInt(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; PIE_enableInt(obj->pieHandle,PIE_GroupNumber_8,PIE_InterruptSource_I2CA1 ); CPU_enableInt(obj->cpuHandle,CPU_IntNumber_8); }
Isr code:
interrupt void i2c_int1a_isr(void) // I2C-A { // Read interrupt source halHandle->gpioHandle->AIOTOGGLE=(1<<2); int IntSource; IntSource = (int)I2C_getIntSource(halHandle->I2CaHandle); //GPIO_toggle(myGpio, GPIO_Number_1); // Interrupt source = stop condition detected /*if(IntSource == I2C_SCD_ISRC) { } // end of stop condition detected */ if(IntSource==I2C_IntSrc_Slave_Addr) { RxPointer=0; TxPointer=0; //GPIO_toggle(myGpio, GPIO_Number_2); //I2caRegs.I2CDXR=StatusPacket[0]; } if(IntSource==I2C_IntSrc_Rx_Rdy) { if(RxPointer<sizeof(RxPacket)) RxPacket[RxPointer]=I2C_getData(halHandle->I2CaHandle); if(RxPointer==1) RxLength=RxPacket[RxPointer]; if(RxPointer==(RxLength+3)) { memcpy((void*)DecodeBuffer,(void*)RxPacket,sizeof(DecodeBuffer)); DecodePacket=1; } RxPointer++; } if(IntSource==I2C_IntSrc_Tx_Rdy) { if(TxPointer<(sizeof(StatusPacket)-1)) TxPointer++; /*if(TxPointer==0) GPIO_setLow(myGpio, GPIO_Number_3); else GPIO_setHigh(myGpio,GPIO_Number_3);*/ I2C_putData(halHandle->I2CaHandle,StatusPacket[TxPointer]); } // Enable future I2C (PIE Group 8) interrupts //PieCtrlRegs.PIEACK.all = PIEACK_GROUP8; PIE_clearInt(halHandle->pieHandle,PIE_GroupNumber_8); //halHandle->gpioHandle->AIOCLEAR=(1<<2); }