void i2cSlaveInitialize(I2cBusConnection* i2cBusConnection) { // Avoid more than one initialization if (i2cBusConnection->opened) { writeError(I2C_SLAVE_ALREADY_INITIALIZED); return; } i2cBusConnection->opened = true; appendString(getDebugOutputStreamLogger(), "I2C Slave Write Address="); appendHex2(getDebugOutputStreamLogger(), i2cBusConnection->i2cAddress); appendCRLF(getDebugOutputStreamLogger()); if (i2cBusConnection == NULL) { // Enable the I2C module with clock stretching enabled OpenI2C1(I2C_ON | I2C_7BIT_ADD | I2C_STR_EN, BRG_VAL); // 7-bit I2C slave address must be initialised here. // we shift because i2c address is shift to the right // to manage read and write address I2C1ADD = i2cBusConnection->i2cAddress >> 1; I2C1MSK = 0; // Interruption on I2C Slave // -> Priority of I2C Slave interruption mI2C1SetIntPriority(I2C_INT_PRI_3 | I2C_INT_SLAVE); // -> Enable Interruption Flag => See the same code in interruption mI2C1SClearIntFlag(); // Enable I2C (MACRO) EnableIntSI2C1; }
/** * Function Name: SI2C1Interrupt * Description : This is the ISR for I2C1 Slave interrupt. */ void __ISR(_I2C_1_VECTOR, ipl3) _SlaveI2CHandler(void) { // TODO : Find the right i2cBusConnection I2cBusConnection* i2cBusConnection = NULL; // last byte received is address and not data char isData = I2C1STATbits.D_A; char read = I2C1STATbits.R_W; char isStart = I2C1STATbits.S; char isSclRelease = I2C1CONbits.SCLREL; char readBufferFull = I2C1STATbits.RBF; // check for MASTER and Bus events and respond accordingly if (IFS0bits.I2C1MIF == 1) { mI2C1MClearIntFlag(); return; } if (IFS0bits.I2C1BIF == 1) { mI2C1BClearIntFlag(); return; } StreamLink* i2cStreamLink = getI2cStreamLink(); // handle the incoming message // Master want to write and send the address if (isStart && !read && !isData && readBufferFull) { // R/W bit = 0 --> indicates data transfer is input to slave // D/A bit = 0 --> indicates last byte was address // reset any state variables needed by a message sequence // perform a dummy read of the address portableSlaveReadI2C(i2cBusConnection); // release the clock to restart I2C portableSlaveClockRelease(i2cBusConnection); } // Master WRITE (InputStream) else if (isStart && !read && isData && readBufferFull) { // R/W bit = 0 --> indicates data transfer is input to slave // D/A bit = 1 --> indicates last byte was data int data = portableSlaveReadI2C(i2cBusConnection); Buffer* i2cSlaveInputBuffer = i2cStreamLink->inputBuffer; OutputStream* outputStream = getOutputStream(i2cSlaveInputBuffer); // Read data from the Master append(outputStream, data); // for debug support appendI2cDebugInputChar(data); // release the clock to restart I2C portableSlaveClockRelease(i2cBusConnection); } // Master send the address and want to read else if (isStart && read && !isData) { // R/W bit = 1 --> indicates data transfer is output from slave // D/A bit = 0 --> indicates last byte was address portableSlaveReadI2C(i2cBusConnection); Buffer* i2cSlaveOutputBuffer = i2cStreamLink->outputBuffer; // Get an inputStream to read the buffer to send to the master InputStream* i2cInputStream = getInputStream(i2cSlaveOutputBuffer); // There is available data if (i2cInputStream->availableData(i2cInputStream)) { char c = i2cInputStream->readChar(i2cInputStream); // for debug support appendI2cDebugOutputChar(c); portableSlaveWriteI2C(i2cBusConnection, c); } else { portableSlaveWriteI2C(i2cBusConnection, I2C_SLAVE_NO_DATA_IN_READ_BUFFER); } } // Master want to read else if (isStart && read && isData && !isSclRelease) { // R/W bit = 1 --> indicates data transfer is output from slave // D/A bit = 1 --> indicates last byte was data Buffer* i2cSlaveOutputBuffer = i2cStreamLink->outputBuffer; // Get an inputStream to read the buffer to send to the master InputStream* i2cInputStream = getInputStream(i2cSlaveOutputBuffer); // There is available data if (i2cInputStream->availableData(i2cInputStream)) { char c = i2cInputStream->readChar(i2cInputStream); // for debug support appendI2cDebugInputChar(c); // we send it to the master portableSlaveWriteI2C(i2cBusConnection, c); } else { // There is no data, we send it to the master portableSlaveWriteI2C(i2cBusConnection, I2C_SLAVE_NO_DATA_IN_READ_BUFFER); } } // finally clear the slave interrupt flag mI2C1SClearIntFlag(); }