I2C communication with RTC

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hello All,

   

I have just picked up working with PSoC and went through the PSoC 101 Lessons to get the basics. Turning LEDs on and off got old quite fast so now I am trying to communicate with an RTC through I2C.

   

With the “automatic mode” I am getting results that I do not understand. With the “manual mode” I seem to be able to feed the RTC with some data but just can’t extract it back.

   

Setup:
I am using PSoC Creator 3.1 SP3 with the CY8CKIT-049-42xx kit with the corresponding CyInstaller.
The RTC is a no-name DS1307 bought on eBay (I2C address = 0b1101000).
10k pullups are installed on the I2C lines, with the 32khz xtal for the RTC.

   

The code:
Nothing special in the header:

   
    

#include <project.h>

    

uint8 rtcBuffer[] = {0b00101010, 0b00101001, 0b00000111, 0b10, 0b10001, 0b100, 0b10111, 0b0};; // Values to be written in the RTC
uint8 rtcRegisterArray[8];  // array where data read from RTC will be placed.
uint8 i=0;
uint8 status;

   
   

I’ll start with the “manual mode” since this yields the most understandable results. Most if not all of the code I use for the communication comes straight from the I2C SCB datasheet from Cypress.

   
    

I2Crtc_Start();

    

CyDelay(1000); // Read somewhere to make sure to let the RTC initialize. 1s should be a safe value.

    

    // CyGlobalIntEnable;  // Uncomment this line to enable global interrupts.

    

    while(1){
       
        I2Crtc_I2CMasterClearStatus(); // Clear any previous status
        status = I2Crtc_I2CMasterSendStart(0x68, I2Crtc_I2C_WRITE_XFER_MODE);
        if(I2Crtc_I2C_MSTR_NO_ERROR == status) /* Check if transfer completed without errors */
        {
            // Send array of 8 bytes
            for(i=0; i<8u; i++){
                status = I2Crtc_I2CMasterWriteByte(rtcBuffer);
                if(I2Crtc_I2C_MSTR_NO_ERROR != status){
                    break;
                }
            }
        }
        I2Crtc_I2CMasterSendStop(); // Stop the Xmission

   
   

Results:
(refering to screeshot write_manual.png) The RTC ACKs when called and fed with 8 bytes of data. Looking good so far…

   

Afterwards, I read the first 8 registers in the RTC using the “manual mode”

   
     status = I2Crtc_I2CMasterSendStart(0x68, I2Crtc_I2C_READ_XFER_MODE);
        if(I2Crtc_I2C_MSTR_NO_ERROR == status){ /* Check if transfer completed without errors */
            // Read array of 8 bytes
            for(i=0; i<8u; i++){
                if(i < 7u){
                    rtcRegisterArray = I2Crtc_I2CMasterReadByte(I2Crtc_I2C_ACK_DATA);
                }
                else{ // sends a NACK after the last byte to be read to stop the RTC from sending data
                    rtcRegisterArray = I2Crtc_I2CMasterReadByte(I2Crtc_I2C_NAK_DATA);
                }
            }
        }
        I2Crtc_I2CMasterSendStop(); // Send Stop
   
   

Here the RTC returns random values for subsequent read operations: (refering to screenshot read_manual.png)
Some returned values event have ones in places where there should be a 0 according to the datasheet.

   

I am missing something here?

   
   

Now, if try to do the same with the “automatic mode”, even writing data does not seem to work. (The pinLedx here in the code are some LEDs that light up on the breadboard to help debug the code so I know where it’s stuck or not reaching.)

   
     I2Crtc_I2CMasterClearStatus(); // Clear any previous status
        I2Crtc_I2CMasterWriteBuf(0b01101000, rtcBuffer, 8, I2Crtc_I2C_MODE_COMPLETE_XFER); // "automatic" write command as used in the datasheet
        pinLed1_Write(1);
        CyDelay(500);
        pinLed1_Write(0);
        
        
        while(1){
            
            pinLed2_Write(1);
            
            if(0u != (I2Crtc_I2CMasterStatus() & I2Crtc_I2C_MSTAT_WR_CMPLT)){
            
                pinLed2_Write(0);    
                 //Transfer complete. Check Master status to make sure that transfer completed without errors.
                break;
            }
        }
   
   

Here too, the RTC ACKs the address call, but the PSoC stays mute afterwards. It even appears as if it keeps the clock low and never puts it back up (even 5 seconds to the right of this screenshot, the clock stays low). (refering to screeshot write_auto.png)

   

The LED#2 is kept lit which tells the program is stuck in the following loop.

   

If I comment out this verification and only add a delay to let the transfer to complete, I get exactly the same thing: The PSoC master calls the RTC address, gets the ACK and then keeps the clock low permanently.

   

Now, if I comment out the “write” portion of this program and only “read” the registers upon start in the RTC

   
     I2Crtc_I2CMasterClearStatus(); /* Clear any previous status */
        I2Crtc_I2CMasterReadBuf(0b1101000, rtcRegisterArray, 8, I2Crtc_I2C_MODE_COMPLETE_XFER); // "automatic" read command as used in the datasheet
        
        pinLed3_Write(1);
        while(1){
                
            if(0u != (I2Crtc_I2CMasterStatus() & I2Crtc_I2C_MSTAT_RD_CMPLT)){
                pinLed3_Write(0);    
                 //Transfer complete. Check Master status to make sure that transfer completed without errors.
                break;
            }
        }
   
   

here is what I get:(refering to screeshot read_auto.png)

   

Still, the clock looks like it stuck on “low” after the last byte.

   

Here too, I have to comment out the loop that checks the master status for a complete flag otherwise it never comes out of it (the LED3 stays on). I am guessing that the status never reaches COMPLETE since the stop command is never issued, because the clock is stuck low.

   

Thank you guys,

   

Marc

0 Likes
1 Solution
rola_264706
Level 8
Level 8
50 likes received 25 likes received 10 likes received

You must set the time on the DS1307 module or it will return only Zero.  So you must write the current time and date to the DS1307 then it will start to return the time and date and start counting. 

View solution in original post

5 Replies
rola_264706
Level 8
Level 8
50 likes received 25 likes received 10 likes received

You must set the time on the DS1307 module or it will return only Zero.  So you must write the current time and date to the DS1307 then it will start to return the time and date and start counting. 

Anonymous
Not applicable

Thanks Bob for the heads up.

   

Based on your suggestion, pushing the complete init values for the clock and the calendar helped. It made me realize I was trying to push a 7 in the 10minutes field which caused the RTC to "crash" I guess and return only zeros. However, the answer I get from the RTC looks quite random to me. I make a reading every seconds and each register returns completely random values, even some that are impossible (ones in bits that can only hold zero according to the datasheet). I have updated the code and the screenshots in the first post accordingly.

   

And the "auto" mode still holds the clock down after the first communication.

0 Likes
lock attach
Attachments are accessible only for community members.
rola_264706
Level 8
Level 8
50 likes received 25 likes received 10 likes received

Try this program. You will have to add the routine to write the start time.

0 Likes
Anonymous
Not applicable

Sorry for the late reply, I was out on vacation for a while...

I did not try the code you sent as I did not install Creator 4.1, but I went and read the code to compare. Reading the debug comments, I see that the program seems to get stuck after calling the "Get_Time" function. Has it ended up working?

0 Likes
rola_264706
Level 8
Level 8
50 likes received 25 likes received 10 likes received

I am using the latest PSoc Creator release and you will need to upgrade to PSOC Creator 4.1,

0 Likes