0
\$\begingroup\$

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

\$\endgroup\$
  • \$\begingroup\$ Have you any way to write text to the host PC? If you have, write the RTC values to the host PC, inside the while (1) {...} loop. How does the correct time get set on the RTC? Also try blinking a led or part of the display each time round the while (1) {...} loop to ensure it is not blocked on something. Have you a simpler program which proves that the RTC code, and RTC, is working, something without the extra complexity of the LCD? \$\endgroup\$ – gbulmer Dec 27 '15 at 16:33
  • \$\begingroup\$ Yes. I can write to PC using UART. I will first check if my slave is even responding with an acknowledgement. We set the time and date on the RTC before entering the while loop. \$\endgroup\$ – PsychedGuy Dec 28 '15 at 1:18
1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ You mean, I need to call the I2C_restart function only during the I2C_Read operation?. I also need to 1st check if my slave is even responding with an acknowledgement after sending a byte to it. \$\endgroup\$ – PsychedGuy Dec 28 '15 at 14:22
  • \$\begingroup\$ The 2nd I2C_restart in your RTC_read is correct. The 1st one should be an I2C_start, not an I2C_restart. An I2C transaction always starts with a _start, never a _restart. \$\endgroup\$ – brhans Dec 28 '15 at 14:25
  • \$\begingroup\$ Thank you for your time and detailed answer. I will do as suggested and get back soon! \$\endgroup\$ – PsychedGuy Dec 28 '15 at 15:20
1
\$\begingroup\$

You are swapping i2c addr and data while passing them to RTC_Write(). Just check RTC_Write() function and code after I2C_Init() you will understand.

// for(i=0;i<7;i++)
RTC_Write(0,0x45); // when i=0

In RTC_Write function()
RTC_Write(unsigned data,unsigned char addr)
{
//...
SSPBUF = addr; //Write the location
//...
SSPBUF = data; //Write the data
//...
}

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.