4
\$\begingroup\$

I am interfacing DS1307 RTC with PIC32MX795F512L. I am using I2C1 for DS1307 RTC and then using UART2 to send the RTC value to the terminal. I have written the code but don't know why I am not getting data.

In my code I am using

OpenI2C2 to open the i2c channel.
StartI2C2() to start the communication
StopI2C2() to stop the communication
MasterWriteI2C() to write the data
MasterReadI2C() to read the data

These are included in plib.h file.

Updated CODE:

OpenI2C2(I2C_EN, 163); // I2C channel Configuration

StartI2C2();            
IdleI2C2();             
n = MasterWriteI2C2(0xD0);  //device address
IdleI2C2();              
MasterWriteI2C2(0x07);      
IdleI2C2();
MasterWriteI2C2(0x00);
IdleI2C2();
StopI2C2();

StartI2C2();            
IdleI2C2();             
MasterWriteI2C2(0xD0);  
IdleI2C2(); 
MasterWriteI2C2(0x01);
IdleI2C2(); 
MasterWriteI2C2(0b00010011);
IdleI2C2(); 
StopI2C2();


StartI2C2();
IdleI2C2();
MasterWriteI2C2(0xD0);
IdleI2C2();
MasterWriteI2C2(0x01);
IdleI2C2();
StopI2C2();

StartI2C2();
IdleI2C2();
MasterWriteI2C2(0xD1);
IdleI2C2();
**res = MasterReadI2C2();**
IdleI2C2();
NotAckI2C2();
IdleI2C2();
StopI2C2();

I am using 163 ((33000000/2/100000)-2)as BRG value for I2C communication. I am debugging the code and can see all the values in I2C registers are correct but at res = MasterReadI2C2(), nothing shows up in I2C2RCV register which holds the received value and even nothing showing up in the res variable. I also used a variable n to check if the values are actually transmitting or not. So I received 0x00 as the value of n and according to document, 0 means transmission successful.

I don't know where I am missing the point.

\$\endgroup\$
9
  • \$\begingroup\$ You mean nothing as in really nothing, or nothing as in all three bytes are 0? \$\endgroup\$
    – Arsenal
    Commented Aug 21, 2015 at 11:57
  • \$\begingroup\$ sometime i get garbage values like ? or * or something else. Sometime terminal is completly blank or sometime i get NULL. I am using Docklight \$\endgroup\$
    – Aircraft
    Commented Aug 21, 2015 at 12:00
  • \$\begingroup\$ Maybe initialize the chars to a human readable, but nonsensical value like 'Z', currently it sounds more like you have a problem with your UART. (and you did realize, that you only get the time once and print it out forever?) And for this kind of test make sure to set your terminal to display hex or decimal values, as ASCII values might be very misleading. \$\endgroup\$
    – Arsenal
    Commented Aug 21, 2015 at 12:10
  • \$\begingroup\$ what do you mean by "initialize the chars to a human readable" which chars you are talking about?. my uart is working because if i send something like helloworld, i am getting this on terminal \$\endgroup\$
    – Aircraft
    Commented Aug 21, 2015 at 12:16
  • \$\begingroup\$ You have unitialized chars i j k and i1 (which is not used), which you put into the GetTime function, to check whether the values are changed and thus a time is read, you should initialize them with some value, which prints out nicely on the terminal. \$\endgroup\$
    – Arsenal
    Commented Aug 21, 2015 at 12:20

3 Answers 3

1
\$\begingroup\$
  1. Based on the datasheet:

Bit 7 of Register 0 is the clock halt (CH) bit. When this bit is set to 1, the oscillator is disabled. When cleared to 0, the oscillator is enabled

So when you set second, make sure bit 7 (CH) is 0. AND set bit 7 (CH) to zero every time the IC is powering up.

  1. Try to add small delay (10ms) before I2C start and after I2C stop.
  2. Try to set one register at one time.
  3. Adjust the pull-up resistor, try to change to 1.5k/1.8k Ohm

I worked this RTC with ATMega128 and CodeVisionAVR This code works:

rtc_init(0,1,0); // output pin for debugging

delay_ms(10);
i2c_start();
i2c_write(0xD0);
i2c_write(0x00);
i2c_write( (data_rtc[10]-48)*16 + (data_rtc[11]-48));      //second
i2c_stop();

delay_ms(10);
i2c_start();
i2c_write(0xD0);
i2c_write(0x01);
i2c_write( (data_rtc[8]-48)*16 + (data_rtc[9]-48));        // minutes
i2c_stop();

delay_ms(10);
i2c_start();
i2c_write(0xD0);
i2c_write(0x02);
i2c_write( (data_rtc[6]-48)*16 + (data_rtc[7]-48));        // hour
i2c_stop();

delay_ms(10);   
i2c_start();
i2c_write(0xD0);
i2c_write(0x04);
i2c_write( (data_rtc[4]-48)*16 + (data_rtc[5]-48));        // day
i2c_stop(); 

delay_ms(10);   
i2c_start();
i2c_write(0xD0);
i2c_write(0x05);
i2c_write( (data_rtc[2]-48)*16 + (data_rtc[3]-48));        // month
i2c_stop();

delay_ms(10);   
i2c_start();
i2c_write(0xD0);
i2c_write(0x06);
i2c_write( (data_rtc[0]-48)*16 + (data_rtc[1]-48));        // year
i2c_stop();

delay_ms(10); 
rtc_init(0,1,0);
\$\endgroup\$
6
  • \$\begingroup\$ okay so to get proper timing, we should always enable the oscillator that means bit 7 will always be 0 and in my code, RTC_SetTime(0x16,0x00,0x10) 0x10 means 0001 0000 that means I have already done that. so whats the problem. \$\endgroup\$
    – Aircraft
    Commented Aug 21, 2015 at 12:32
  • \$\begingroup\$ @CZabhinav, sorry for my mistake, I edited my answer \$\endgroup\$
    – Oka
    Commented Aug 21, 2015 at 12:48
  • \$\begingroup\$ what are you doing in this line i2c_write( (data_rtc[0]-48)*16 + (data_rtc[1]-48)); ?? \$\endgroup\$
    – Aircraft
    Commented Aug 21, 2015 at 13:02
  • 1
    \$\begingroup\$ Setting the time, but data_rtc[x] in ASCII format, so I subtract with 48. Then I multiply the left digit with 16. For example, we want to set second = 21, then i2c_write( ('2'-48)*16 + ('1'-48)) \$\endgroup\$
    – Oka
    Commented Aug 21, 2015 at 13:04
  • \$\begingroup\$ I havent done this type of conversion in my code. May be this is the error in my code. Am I right? \$\endgroup\$
    – Aircraft
    Commented Aug 21, 2015 at 13:06
1
\$\begingroup\$

Using the Microchip PLIB legacy libraries for I2C, you need to manually poll for the bus to be idle after each operation. An example is shown below:

StartI2C2(); // Send the Start Bit
IdleI2C2(); // Wait to complete
MasterWriteI2C2(0xE0); // Send slave address with write bit
IdleI2C2(); // Wait to complete
MasterWriteI2C2(addr);
IdleI2C2(); // Wait to complete
StopI2C2(); // Send Stop bit
IdleI2C2();
StartI2C2(); // Send the Start Bit
IdleI2C2(); // Wait to complete
MasterWriteI2C2(0xE1); // Send slave address with read bit
IdleI2C2(); // Wait to complete
val = MasterReadI2C2();
IdleI2C2();
NotAckI2C2(); // Master  Aknodledge End of transfer
StopI2C2(); // Send Stop bit
IdleI2C2(); 

The IdleI2C2() function is simply the following:

while(I2C2CONbits.SEN || I2C2CONbits.PEN || I2C2CONbits.RSEN || I2C2CONbits.RCEN || I2C2CONbits.ACKEN || I2C2STATbits.TRSTAT);

This line simply is checking any bits that signify that the peripheral is busy, (such as an active start or stop condition, currently clocking out data, etc.

\$\endgroup\$
1
  • \$\begingroup\$ I have used your code to interface it with DS1307. I have updated my code. Can you help me with it.! \$\endgroup\$
    – Aircraft
    Commented Nov 20, 2015 at 10:13
0
\$\begingroup\$

Looking at you code, I don't see anything glaringly wrong, but if we look at the DS1307 datasheet, page 13, it specifies that to do a data read from a specific location you write the address, the location in the DS1307 registers, then initiate a "Repeated Start" routine, send the address again, then read the data. You can read in a multibyte burst, sequentially, or a single byte and then send a STOP and start the process over again at a different register location.

I was recently finding an attempt to communicate between a master and slave PIC unsuccessful, and I had a DS1307 lying around, so I whipped up some code. Thankfully, for i2c.h, no more bit-banging. The code is written for the PIC18F8722, but you should find that something similar will work for you:

#include <pic18f8722.h>
            #include <i2c.h>
            #include <spi.h>
            #include <delays.h>
            #include "LCD.h"
            #include "SerComm.h"

            #pragma config OSC = HSPLL
            #pragma config WDT = OFF
            #pragma config FCMEN = OFF

            #define newline 0x0A
            #define carriageReturn 0x0D

            void initialize(void);
            unsigned char x;
            unsigned char seconds = 0x00;
            unsigned char minutes = 0x36;
            unsigned char hours = 0x48;
            unsigned char days = 0x03;
            unsigned char date = 0x17;
            unsigned char month = 0x08;
            unsigned char year = 0x15;
            unsigned char hyear, lyear, hmonth, lmonth, hdate, ldate, hdays, ldays, hhours, lhours, hminutes, lminutes, hseconds, lseconds;
            unsigned char time[7];

            void main(void)
            {
                lcdInit();
                initialize();
                CloseI2C2();

                OpenI2C2(MASTER, SLEW_OFF);

                IdleI2C2();
                StartI2C2();
                WriteI2C2(0xD0);
                WriteI2C2(0x00);
                WriteI2C2(seconds);
                WriteI2C2(minutes);
                WriteI2C2(hours);
                WriteI2C2(days);
                WriteI2C2(date);
                WriteI2C2(month);
                WriteI2C2(year);
                StopI2C2();

                while(1)
                {
                IdleI2C2();
                StartI2C2();
                WriteI2C2(0xD0);
                WriteI2C2(0x00);
                RestartI2C2();
                WriteI2C2(0xD1);
                for(x = 0; x < 6; x++)
                {
                   time[x] = ReadI2C2();
                   AckI2C2();
                }
                time[6] = ReadI2C2();
                NotAckI2C2();
                StopI2C2();

                hyear = ((time[6] & 0xF0) >> 4) + 0x30;
                lyear = (time[6] & 0x0F) + 0x30;
                hmonth = ((time[5] & 0xF0) >> 4) + 0x30;
                lmonth = (time[5] & 0x0F) + 0x30;
                hdate = ((time[4] & 0xF0) >> 4) + 0x30;
                ldate = (time[4] & 0x0F) + 0x30;
                hdays = ((time[3] & 0xF0) >> 4) + 0x30;
                ldays = (time[3] & 0x0F) + 0x30;
                hhours = ((time[2] & 0x10) >> 4) + 0x30;
                lhours = (time[2] & 0x0F) + 0x30;
                hminutes = ((time[1] & 0xF0) >> 4) + 0x30;
                lminutes = (time[1] & 0x0F) + 0x30;
                hseconds = ((time[0] & 0xF0) >> 4) + 0x30;
                lseconds = (time[0] & 0x0F) + 0x30;



                lcdGoTo(0x00);
                lcdWriteString("Time: ");
                lcdChar(hhours);
                lcdChar(lhours);
                lcdChar(':');
                lcdChar(hminutes);
                lcdChar(lminutes);
                lcdChar(':');
                lcdChar(hseconds);
                lcdChar(lseconds);
                SerTx(hhours);
                SerTx(lhours);
                SerTx(':');
                SerTx(hminutes);
                SerTx(lminutes);
                SerTx(':');
                SerTx(hseconds);
                SerTx(lseconds);
                SerTx(newline);
                SerTx(carriageReturn);
                }

            }

            void initialize(void)
            {
                TRISAbits.RA2=0; // Chip select pin for the SPI port expander;

                TRISDbits.RD5 = 1;  //Set the ports of the I2C bus;
                TRISDbits.RD6 = 0;

                SSP2STAT = 0x80;    //Disable the slew rate control;
                SSP2CON1 = 0x28;    //Enable the Serial Port, Set the mode to: Master Mode, clock = Fosc/(4*(SSP1ADD + 1);
                SSP2CON2 = 0x00;    //No bits to set here;

                SSP2ADD = 0x59;     //Set to 100 kHz at 40 MHz clock;

                TXSTA1 = 0x24;      //Set serial communication to High Speed, TX enabled, 8 bit mode;
                RCSTA1 = 0x90;      //Enable the serial port, Enable the Receiver;
                BAUDCON1 = 0x00;    //;

                SPBRG1 = 42;        //57600 kBaud;
            }

Please, don't be too harsh on the code. I hope this helps.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ In your while(1), you have written WriteI2C2(0x00);, what is this for.?? and with this line WriteI2C2(0xD1); you are trying to read back data but you haven't mentioned which register to read. Any way thanks for sharing your code, i'll definitely try this.! \$\endgroup\$
    – Aircraft
    Commented Aug 26, 2015 at 4:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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