# Pic18F67K40 unable to read 7940 RTCC over I2C

I'm trying to integrate the MCP7940N RTCC into my design. The MCU is the PIC18F67K40 and I'm using I2C to communicate. I created a new starter project to make sure that it works there before I add to my larger design. My IDE is MPLab X v5.4 with MCC 4.02, core v5.0.2. I can't get even this basic project to communicate correctly, I believe the problem is with the timing of the pulses. For this prototype I'm using the Explorer 8 and Mikroe's RTC6 Click board. I started with the RTC Example and I2CSimple Foundation Service. The RTCC Datasheet says it can handle I2C clock up to 400 kHz.

Initialization
...
#pragma config FEXTOSC = OFF    // External Oscillator mode Selection bits->Oscillator not enabled
#pragma config RSTOSC = HFINTOSC_64MHZ
...
SSP1CLKPPS = 0x13;   //RC3->MSSP1:SCL1;
RC3PPS = 0x19;   //RC3->MSSP1:SCL1;
RC5PPS = 0x1A;   //RC5->MSSP1:SDA1;
SSP1DATPPS = 0x15;   //RC5->MSSP1:SDA1;
...
SSP1STAT = 0x80;
SSP1CON1 = 0x18;
SSP1CON2 = 0x00;
SSP1CON1bits.SSPEN = 0;
...
// NOSC HFINTOSC; NDIV 1;
OSCCON1 = 0x60;
// CSWHOLD may proceed; SOSCPWR Low power;
OSCCON3 = 0x00;
// MFOEN disabled; LFOEN disabled; ADOEN disabled; SOSCEN disabled; EXTOEN disabled; HFOEN disabled;
OSCEN = 0x00;
// HFFRQ 64_MHz;
OSCFRQ = 0x08;
// TUN 0;
OSCTUNE = 0x00;


I can open the I2C channel just find, but when I try to read a register on the RTCC it hangs waiting for PIR3bits.SSP1IF to be set but it never is. I'm using MCC to generate the RTC and I2C code for me. Thank you.

Edit 1: Here is the schematic for the RTC click board.

• Do you have an oscilloscope, a logic analyzer, or even a logic probe? I2C always gives me fits, it's always because I've done something stupid, and I always resolve it by looking at the lines on a scope in astonishment, looking at my code or my schematic, and then smacking my forehead and thinking "dumbass!" Feb 28 at 22:06
• Speaking of which -- a schematic would help. You do have pullups, right? Feb 28 at 22:06
• I haven’t actually built the circuit myself. I’m using the RTC 6 click and the explorer 8 with the PIM for my MCU.
– Sean
Feb 28 at 22:30
• Explorer 8. microchip.com/promo/explorer-8-development-board & RTC 6 mikroe.com/rtc6-click
– Sean
Feb 28 at 22:31
• The RTC chips are different if I'm not mistaken. You are targeting MCP7940N, whereas the RTC 6 click has MCP79410 (whether they are too dissimilar I don't know, but they may have different I²C addresses) Mar 1 at 0:22

I think I finally got it working. Had to buy a logic analyzer and make a few changes, but it seems to be working now. First I changed my clock settings to this:

Second I changed the SDA line from RC5 to RC4 to match what the RTC6 click was expecting. I probably didn't need to, but I wrote my own I2C logic for a basic write & read because the MCC generated code was way too complicated for me to follow.

Here is the I2C.h

#ifndef I2C
#define I2C

#include <xc.h>
#include <stdint.h>

void I2C_Initialize(void);
void I2C_Start();
void I2C_Write(uint8_t address, uint8_t reg, uint8_t data);
void I2C_Stop();

#endif


and the I2C.c file. I'm including the mcc.h file just so I can use the __delay_ms function in my write code.

#include "I2C.h"
#include "./mcc_generated_files/mcc.h"

void I2C_Initialize(){
SSP1STAT = 0x80;
SSP1CON1 = 0x08;
SSP1CON2 = 0x00;
SSP1CON1bits.SSPEN = 0;
}

void I2C_Start(){
SSP1CON1bits.SSPEN = 1;
SSP1CON2bits.SEN = 1;
while(SSP1CON2bits.SEN);
PIR3bits.SSP1IF = 0;
}

void I2C_Write(uint8_t address, uint8_t reg, uint8_t data){
I2C_Start();
SSP1BUF = (address << 1);//left shift 1 bit to clear 7th bit (7th bit == 0 for write)
while(!PIR3bits.SSP1IF);
PIR3bits.SSP1IF = 0;
if(SSP1CON2bits.ACKSTAT){
SSP1CON2bits.PEN = 1;
while(SSP1CON2bits.PEN);
return;
}

SSP1BUF = reg;
while(!PIR3bits.SSP1IF);
PIR3bits.SSP1IF = 0;
if(SSP1CON2bits.ACKSTAT){
SSP1CON2bits.PEN = 1;
while(SSP1CON2bits.PEN);
return;
}

SSP1BUF = data;
while(!PIR3bits.SSP1IF);
PIR3bits.SSP1IF = 0;
__delay_ms(5);
I2C_Stop();
}

I2C_Start();
uint8_t data;

SSP1BUF = (address << 1);//left shift 1 bit to clear 7th bit (7th bit == 0 for write)
while(!PIR3bits.SSP1IF);
PIR3bits.SSP1IF = 0;
if(SSP1CON2bits.ACKSTAT){
SSP1CON2bits.PEN = 1;
while(SSP1CON2bits.PEN);
return (0xFF);
}

SSP1BUF = reg;
while(!PIR3bits.SSP1IF);
PIR3bits.SSP1IF = 0;
if(SSP1CON2bits.ACKSTAT){
SSP1CON2bits.PEN = 1;
while(SSP1CON2bits.PEN);
return (0xFF);
}

SSP1CON2bits.RSEN = 1;
while(SSP1CON2bits.RSEN);
PIR3bits.SSP1IF = 0;

address = (address << 1); //shift left 1 bit to clear 7th bit
address |= 0x01; //bitwise OR to set 7th bit a 1 (read is 1))
while(!PIR3bits.SSP1IF);
PIR3bits.SSP1IF = 0;
if(SSP1CON2bits.ACKSTAT){
SSP1CON2bits.PEN = 1;
while(SSP1CON2bits.PEN);
return (0xFF);
}
SSP1CON2bits.RCEN = 1;
while(!SSP1STATbits.BF);
data = SSP1BUF;

SSP1CON2bits.ACKDT = 1;
SSP1CON2bits.ACKEN = 1;
while(SSP1CON2bits.ACKEN);

I2C_Stop();

return data;
}

void I2C_Stop(){
SSP1CON2bits.PEN = 0;
while(SSP1CON2bits.PEN);
SSP1CON1bits.SSPEN = 0;
SSP1CON2bits.RCEN = 0;
}


All combined I now see this in my logic analyzer.

Hope this helps someone else. Here is the link to my github for this project