Example #1
0
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();
}