void I2C_SlaveInit(unsigned char addr){
// 7bit Slave Mode (MODE = 0)
I2C1CON0 = 0x00;
//I2C1CON0bits.CSTR = 1;
// Slave Address Match
#ifndef I2C_Allow0Adress
if (addr == 0x00){
addr = I2C_DefaultAddress;
}
#endif
#ifdef I2C_DoAddressShift
addr = addr << 1;
#endif
I2C1ADR0 = addr;
I2C1ADR1 = addr;
I2C1ADR2 = addr;
I2C1ADR3 = addr;
// ACK for every valid byte (ACKDT = 0)
// ACK at the end of a Read (ACKCNT = 0)
// Clock stretching DISabled (CSTRDIS = 0)
I2C1CON1 = 0b00000000;
// Auto-count disabled (ACNT = 0)
// General Call disabled (GCEN = 0)
// Fast mode enabled (FME = 1)
// ADB0 address buffer used (ADB = 0)
// SDA Hold time of 30 ns (SDAHT = 2)
// Bus free time of 8 I2C Clock pulses
// (BFRET = 1)
I2C1CON2 = 0x28;
// Clear all I2C flags
PIR3bits.I2C1IF = 0;
I2C1PIR = 0x00;
// Enable I2C interrupts
PIE3bits.I2C1IE = 1;
IPR3bits.I2C1IP = 1;
// NOTE: Enable global and peripheral interrupts somewhere!
//INTCON0bits.IPEN = 1;
//INTCON0bits.GIEH = 1;
// Enable local interrupt on ACK Sequence
I2C1PIE = 0;
I2C1PIEbits.ACKTIE = 1;
//I2C1PIEbits.PCIE = 1;
//I2C1PIEbits.RSCIE = 1;
//I2C1PIEbits.ADRIE = 1;
// Enable I2C module
I2C1CON0bits.EN = 1;
// Set the read and write position pointers to zero
}
/****************************************************************************
* Function:
* void I2C_SlaveInterruptRoutine(void)
*
* Description:
* This routine should be called when an interrupt was generated to
* check if it was I2C-related
*
*
* Preconditions:
* None
*
* Parameters:
* None
*
* Returns:
* None
*
* Remarks:
* None
*
****************************************************************************/
void I2C_SlaveInterruptRoutine(void) {
static char Widx = 0;
static char Ridx = 0;
char Temp = 0;
// I2C2
if (PIR3bits.I2C1IF) {
// Clear the I2C interrupt flag
PIR3bits.I2C1IF = 0;
if (I2C1PIRbits.ACKTIF) { // ACK Sequence Interrupt Detected
// Clear the interrupt flag
I2C1PIRbits.ACKTIF = 0;
// For Slave Read/Master Write
if (!I2C1STAT0bits.R) {
// Data Byte Received
if (I2C1STAT0bits.D) {
// Read from RXB
if( Widx >= sizeof(I2C_BaseData)){ //Simply Receive bytes until we have reached at least the size of a package frame (2 bytes)
I2C_BaseData* i2cbase = (I2C_BaseData*)&inputBuffer;
if(i2cbase->size == Widx){ //Ensure we dont write out of buffer
Temp = I2C1RXB; // Read out buffer to clear BF flag
}else{
inputBuffer[Widx++] = I2C1RXB;
}
if(i2cbase->size == Widx){ //Check if we have received all bytes
I2C_InputCallback(inputBuffer, Widx); //Fire event for whole packet received
}
}else{
inputBuffer[Widx++] = I2C1RXB;// Store data in buffer
}
}
} else { // For Slave Write/Master Read
// Write to TXB
if(Ridx == 0){
bufferInfo.size = sizeof(I2C_BaseData);
I2C_OutputCallback(&bufferInfo); // Call Method for populating output buffer
}
if(Ridx == bufferInfo.size){ // Prevent reading beyond buffer
I2C1TXB = 0; // Write dummy data to I2C
}else{
I2C1TXB = bufferInfo.buffer[Ridx++]; // Write next data to I2C
}
}
}
// STOP or RESTART Interrupt Detected
if ((I2C1PIRbits.PCIF) || (I2C1PIRbits.RSCIF)) {
// Clear whichever interrupt flag was set
if (I2C1PIRbits.PCIF)
I2C1PIRbits.PCIF = 0;
if (I2C1PIRbits.RSCIF)
I2C1PIRbits.RSCIF = 0;
Widx = 0;
Ridx = 0;
}
// Reset both interrupt and error flags
I2C1PIR = 0;
I2C1ERR = 0;
// Release SCL
I2C1CON0bits.CSTR = 0;
}
}