RTC_DS1307 + PIC18F458 displaying time and date as zeroes

ci2cpicrtc

I am trying to get the RTCDS1307 + PIC hardware to work in order to display the appropriate data and time. But the problem is that, its displaying the time and date as 00:00:00 and 00/00/2000 as shown in the snap below.
enter image description here

I presume that the RTC registers aren't be set properly or there is no data tx and rx happening at all when it comes to the hardware.I cross checked the code/bit rate calculations and everything seems to be fine. I don't understand how come it isn't working. Is there anything wrong with the I2C initialization or my approach?. Any help regarding this would be appreciated.Here is the code:

#include<P18F458.h>
#include<xc.h>
#include<htc.h>
#include"LCD.h"

#define RTC_ADDRW 0xD0
#define RTC_ADDRR 0xD1
#define _XTAL_FREQ 20000000

unsigned char sec,min,hour,date,month,year;
unsigned char data[7] = {0x45,0x59,0x71,0x04,0x05,0x10,0x06};
int i;

void I2C_idle()
{
    while((SSPCON2 & 0x1F)|(SSPSTATbits.R_W));
}
void I2C_start()
{
    I2C_idle();
    SSPCON2bits.SEN = 1; //Set start enable bit
    while(SSPCON2bits.SEN); //Wait until cleared by hardware
}


void I2C_stop()
{
    SSPCON2bits.PEN = 1; //Set stop enable bit
    while(SSPCON2bits.PEN); //Wait until cleared by hardware
    I2C_idle();
}

void I2C_restart()
{
    SSPCON2bits.RSEN = 1; //Initiates Repeated Start Condition on SDA   and SCL pins 
    while(SSPCON2bits.RSEN==1); //Wait until cleared by hardware
    I2C_idle();
}

void RTC_Write(unsigned data,unsigned char addr)
{
    I2C_start();
    I2C_idle();
    SSPBUF = RTC_ADDRW; //Slave address +Write Command
    I2C_idle();
    SSPBUF = addr; //Write the location
    I2C_idle();
    SSPBUF = data; //Write the data
    I2C_idle();
    I2C_stop(); //Enable stop bit
    I2C_idle();
}
void I2C_Init()
{
    TRISCbits.TRISC3 = 1; // SCL direction input
    TRISCbits.TRISC4 = 1; //SDA direction input
    SSPCON1bits.SSPM3 = 1; //SSPM0:SSPM3 = 0001 (Master Mode
    SSPCON1bits.SSPM2 = 0;
    SSPCON1bits.SSPM1 = 0;
    SSPCON1bits.SSPM0 = 0;
    SSPSTATbits.SMP = 1;
    SSPADD = 0x31; /*For Fosc 20MHz, Required Bit Rate = 100 KHz
                                                       SSPADD = ((20MHz/4)/100 KHz - 1)= 0x31*/
    PIR1bits.SSPIF = 0;
    SSPCON2 = 0;
    SSPCON1bits.SSPEN = 1;
    RTC_Write(0,0x00);
 }

unsigned char RTC_Read(unsigned char addr)
{
    unsigned char x;
    I2C_start(); //Enable repeated start condition
    SSPBUF = RTC_ADDRW;
    I2C_idle();
    SSPBUF = addr;
    I2C_idle();
    I2C_restart();
    SSPBUF = RTC_ADDRR;
    I2C_restart();
    SSPCON2bits.RCEN = 1; //Enable to recieve data
    I2C_idle();
    SSPCON2bits.ACKDT = 1; //Acknowledge the operation (Send NACK)
    SSPCON2bits.ACKEN = 1; //Acknowledge sequence on SCL and SDA pins
    I2C_stop();
    x = SSPBUF; //store the recieved value in a var
    return(x);

}
unsigned char BCD2Upperch(unsigned char bcd)
{
    unsigned char temp;
    temp = bcd >> 4;
    temp = temp | 0x30;
    return (temp);

}

unsigned char BCD2Lowerch(unsigned char bcd)
{
    unsigned char temp;
    temp = bcd & 0x0F;
    temp = temp | 0x30;
    return (temp);
}


void main()
{
    TRISCbits.TRISC0 = 0;
    TRISCbits.TRISC1 = 0;
    TRISCbits.TRISC2 = 0;
    TRISD = 0;
    char16x2LCDInit();
    __delay_ms(20);
    I2C_Init();
    for(i=0 ; i<7 ; i++)
        RTC_Write(data[i],i);
    __delay_ms(20);


    while(1)
    {
        sec = RTC_Read(0x00);
        min = RTC_Read(0x01);
        hour = RTC_Read(0x02);
        date = RTC_Read(0x04);
        month = RTC_Read(0x05);
        year = RTC_Read(0x06);

        arraydisp("Time: ",0x80);
        Write_Data(BCD2Upperch(hour));
        Write_Data(BCD2Lowerch(hour));
        Write_Data(':');
        Write_Data(BCD2Upperch(min));
        Write_Data(BCD2Lowerch(min));
        Write_Data(':');
        Write_Data(BCD2Upperch(sec));
        Write_Data(BCD2Lowerch(sec));
        arraydisp("Date: ",0xC0);
        Write_Data(BCD2Upperch(date));
        Write_Data(BCD2Lowerch(date));
        Write_Data('/');
        Write_Data(BCD2Upperch(month));
        Write_Data(BCD2Lowerch(month));
        Write_Data('/');
        LCDWriteInt(20,2);
        Write_Data(BCD2Upperch(year));
        Write_Data(BCD2Lowerch(year));


    }

Thank you all in advance.

Best Regards
~VD

Best Answer

Your RTC_Read function should start with an I2C_start, not an I2C_restart.

The I2C_restart only belongs at the point where you change from write mode (sending the register address) to read mode (reading data).

To address your other questions:

  • you should check the ACK bit after you send the RTC read/write address (and wait for I2C_Idle) right at the beginning of your RTC_read/RTC_write functions. You can't wait until after the I2C transaction is complete before checking ACK.
  • If the RTC fails to ACK, you should end the I2C transaction (by sending an I2C_stop) and then possibly trying again and/or displaying an error message. Once you have this working, an ACK fail most likely indicates a hardware fault of some kind ...

Also, as anishkumar has noted in his answer, you have mixed up your address & data parameters in your RTC_write function call.