I’m trying to use the Microchip Code Configurator to make an I2C communication between two PIC16F1827. My application is very similar to the example they give with an emulated EEPROM. I've used Proteus to simulate the code but the resulat wasn't satisfying. So I have a question and a problem:
In the master code, the EEPROM address makes two bytes, but in the slave code, it seems to be just one byte. I don’t understand why. I’ve changed the master code and it seems to be ok now, but can someone explain me why the master code and the slave code are not compatible?
My real problem is about the I2C interrupts while reading. Actually, when I try to make a read of one byte (I assume that the EEPROM address is already set to the correct value), two interrupts occur. The first one after the Ack, then R_nW bit is set, D_nA and ACKSTAT bits are clear. Then, after the NAck (when the master received enough bytes, in this case just one), a second interrupt occurs. But the R_nW bit is cleared by hardware. So I can’t use the “I2C1_SLAVE_READ_COMPLETED” case. Worse, the “I2C1_SLAVE_WRITE_COMPLETED” case is executed. I don’t understand why this occurs. Of course, I can change the I2C1_ISR to prevent this problem, but I don’t think that is the best to solve the problem.
I would be really grateful if someone can help me. :)
EDIT : Following the suggestion of Olin Lathrop, I've written the code without using the MCC. I still have the same problem.
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
#pragma config WDTE = ON // Watchdog Timer Enable->WDT disabled
#pragma config PWRTE = OFF // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = OFF // MCLR Pin Function Select->MCLR/VPP pin function is digital input
#pragma config CP = OFF // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config CPD = OFF // Data Memory Code Protection->Data memory code protection is disabled
#pragma config BOREN = OFF // Brown-out Reset Enable->Brown-out Reset disabled
#pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
#pragma config IESO = OFF // Internal/External Switchover->Internal/External Switchover mode is disabled
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is disabled
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off
#pragma config PLLEN = OFF // PLL Enable->4x PLL disabled
#pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will not cause a Reset
#pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LVP = OFF // Low-Voltage Programming Enable->High-voltage on MCLR/VPP must be used for programming
#define RX_ELMNTS 32
unsigned uint8_t I2C_slave_address = 0x03; // slave address
volatile unsigned char I2C_Array[RX_ELMNTS] = // array for master to write to
{0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88,
0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xFA,
0xEA, 0xDA, 0xCA, 0xBA, 0xFB, 0xFC, 0xFD, 0xFE,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
unsigned int index_i2c = 0; // used as an index pointer in array
unsigned char junk = 0; // used to place unnecessary data
unsigned char first = 1; // used to determine whether data address
// location or actual data
unsigned char clear = 0x00; // used to clear array location once
// it has been read
void initialize(void); // Initialize routine
void main(void) {
initialize(); // call initialize routine
while (1) // main while() loop
{
asm("CLRWDT"); // while here just clear WDT and wait for
} // the ISR to be called
} // end main
void initialize(void) {
//uC SET UP
OSCCON = 0b01111010; // Internal OSC @ 16MHz
OPTION_REG = 0b11010111; // WPU disabled, INT on rising edge, FOSC/4
// Prescaler assigned to TMR0, rate @ 1:256
WDTCON = 0b00010111; // prescaler 1:65536
// period is 2 sec(RESET value)
PORTB = 0x00; // Clear PORTC
LATB = 0x00; // Clear PORTC latches
TRISB = 0b00010010; // Set RC3, RC4 as inputs for I2C
//I2C SLAVE MODULE SET UP
SSP1STAT = 0b10000000; // Slew rate control disabled for standard
// speed mode (100 kHz and 1 MHz)
SSP1CON1 = 0b00110110; // Enable serial port, I2C slave mode,
// 7-bit address
SSP1CON2bits.SEN = 1; // Clock stretching is enabled
//SSP1CON3bits.BOEN = 1; // SSPBUF is updated and NACK is generated
// for a received address/data byte,
// ignoring the state of the SSPOV bit
// only if the BF bit = 0
//SSP1CON3bits.SDAHT = 1; // Minimum of 300 ns hold time on SDA after
// the falling edge of SCL
//SSP1CON3bits.SBCDE = 1; // Enable slave bus collision detect interrupts
SSP1ADD = I2C_slave_address << 1; // Load the slave address
SSP1IF = 0; // Clear the serial port interrupt flag
BCL1IF = 0; // Clear the bus collision interrupt flag
BCL1IE = 1; // Enable bus collision interrupts
SSP1IE = 1; // Enable serial port interrupts
PEIE = 1; // Enable peripheral interrupts
GIE = 1; // Enable global interrupts
}//end initialize
void interrupt ISR() {
if (SSP1IF) {
if (SSP1STATbits.R_nW) {
if (!SSP1STATbits.D_nA) {
// read and adress
SSP1BUF = I2C_Array[index_i2c++];
SSP1CON1bits.CKP = 1;
}
if (SSP1STATbits.D_nA) {
//read and data
SSP1BUF = I2C_Array[index_i2c++];
SSP1CON1bits.CKP = 1;
}
}
if (!SSP1STATbits.R_nW) {
if (!SSP1STATbits.D_nA) {
//write and adress
first = 1;
junk = SSP1BUF;
SSP1CON1bits.CKP = 1;
}
if (SSP1STATbits.D_nA) {
//write and data
if (first) {
index_i2c = SSP1BUF;
first = 0;
} else {
if (index_i2c < RX_ELMNTS) {
I2C_Array[index_i2c++] = SSP1BUF;
} else {
junk = SSP1BUF;
}
}
if (SSP1CON1bits.WCOL) {
SSP1CON1bits.WCOL = 0;
junk = SSP1BUF;
}
SSP1CON1bits.CKP = 1;
}
}
}
if (BCL1IF) {
junk = SSP1BUF;
BCL1IF = 0;
SSP1CON1bits.CKP = 1;
}
SSP1IF = 0;
}