Interface MCP7940N Real time I2c device

Dear all

I am trying to interface Arduino Uno board with MCP7940-N RTC device . I have tested the code with DS1307 where i used to get proper SDA/SCL response using logical analyzer.

Here is my code tested

#include "I2C.h"

const int MCP7940_I2C  = 0x6F;  // I2C Address for the RTC

const int REG_RTCSEC   = 0x00;  // Register Address: Time Second
const int REG_RTCMIN   = 0x42;  // Register Address: Time Minute
const int REG_RTCHOUR  = 0X03;  // Register Address: Time Hour
const int REG_RTCWKDAY = 0x03;  // Register Address: Date Day of Week
const int REG_RTCDATE  = 0x04;  // Register Address: Date Day
const int REG_RTCMTH   = 0x05;  // Register Address: Date Month
const int REG_RTCYEAR  = 0x06;  // Register Address: Date Year

byte      timeStamp[7];         // Byte array holding a full time stamp.

// Array position is the same as the register address.

void setup()
{

  Serial.begin (9600);
  
  I2c.begin    ();       // Initialize the I2C library
  I2c.pullup   (0);      // Disable the internal pullup resistors
  I2c.setSpeed (0);      // Enable 100kHz I2C Bus Speed
  I2c.timeOut  (250);    // Set a 250ms timeout before the bus resets
  
  // These are the values that will be written to the MCP7940
  timeStamp[0]  = convertToBcd( 05);    // SECONDS
  timeStamp[1]  = convertToBcd(42);    // MINUTES
  timeStamp[2]  = convertToBcd(15);    // HOURS
  timeStamp[3]  = convertToBcd(   6);    // DAY OF WEEK (arbitrary value 1 - 7)
  timeStamp[4]  = convertToBcd( 26);    // DAY
  timeStamp[5]  = convertToBcd( 8);    // MONTH
  timeStamp[6]  = convertToBcd( 20);    // YEAR

  // Write our time stamp to the time/date registers
  I2c.write(MCP7940_I2C, REG_RTCSEC, timeStamp, 7);

  // Initialize our chip with any further configuration data
  init_MCP7940();
  
}

void loop()
{
  
  I2c.read(MCP7940_I2C, REG_RTCSEC,  7, timeStamp);
  
  Serial.print    ("Current Time: ");
  Serial.print    (convertFromBcd(timeStamp[2] & 0x3F));
  Serial.print    (":");
  if              (convertFromBcd(timeStamp[1] & 0x7F) / 10 == 0) Serial.print ("0");
  Serial.print    (convertFromBcd(timeStamp[1] & 0x7F));
  Serial.print    (":");
  if              (convertFromBcd(timeStamp[0] & 0x7F) / 10 == 0) Serial.print ("0");  
  Serial.println  (convertFromBcd(timeStamp[0] & 0x7F));

  delay(1000);
  
}

void init_MCP7940() {
  
  byte    registerValue = 0x00;    // Holds the received register value
  byte    twelveHour    = 0x00;    // 0 = 24 Hour Clock Mode / 1 = 12 Hour Clock Mode
  byte    startClock    = 0x01;    // 0 = Start Oscillator   / 1 = Stop Oscillator
  
  // Turn on/off: 12 hour vs. 24 hour clock
  I2c.read    (MCP7940_I2C, REG_RTCHOUR, 1);
  registerValue = I2c.receive();
  if (twelveHour == 0x00) I2c.write (MCP7940_I2C, REG_RTCHOUR, bitClear (registerValue, 6));
  if (twelveHour == 0x01) I2c.write (MCP7940_I2C, REG_RTCHOUR, bitSet   (registerValue, 6));

  // Turn on/off: Oscillator (starts the clock)
  I2c.read    (MCP7940_I2C, REG_RTCSEC, 1);
  registerValue = I2c.receive();
  if (startClock == 0x00) I2c.write (MCP7940_I2C, REG_RTCSEC, bitClear (registerValue, 7));
  if (startClock == 0x01) I2c.write (MCP7940_I2C, REG_RTCSEC, bitSet(registerValue, 7));
  
}


byte convertToBcd(byte byteDecimal) {

  return (byteDecimal / 10) << 4 | (byteDecimal % 10);

}

byte convertFromBcd(byte byteBCD) {

  byte byteMSB = 0;
  byte byteLSB = 0;

  byteMSB      = (byteBCD & B11110000) >> 4;
  byteLSB      = (byteBCD & B00001111);

  return       ((byteMSB * 10) + byteLSB);
}

If check Both code . i could see Serial Monitor printing Data . But when i connect SDA/SCL line it wont respond to slave device.

I have attached waveform for reference.

Code 2:

#include <Wire.h>
#include <MCP794xx.h>


MCP794xx rtc1;

void setup() {

  // Start Serial Communication
  Serial.begin(9600);

  // Run through setting the date and time.
  rtc1.setHours12(5, true); // Set the time to 11 AM
  //rtc1.setHours24(11);		// Set the time to 1100 (24h format)
  rtc1.setMinutes(13);		// Set the minutes to 39
  rtc1.setSeconds(45);		// Set the second to 45

  // You can also set the time in a single function call
  rtc1.setTime12(5, true, 13, 45);			// Set the time in 12h format
  //rtc1.setTime24(11, 39, 45);				// Set the time in 24h format



  rtc1.setYear(20);			// Set the year to 18
  rtc1.setMonth(_AUG);		// Set the Month
  rtc1.setDate(28);			// Set the date (0-31)
  rtc1.setWeekday(_WED);		// Set the day of the week

  // You can also set the date in a single function call
  rtc1.setCalendar(20, _AUG, 26);	// Set the calendar, weekday must be set seperately
  rtc1.setWeekday(_WED);		// Set the weekday.

  rtc1.start();				// Turn on the clock, begins tracking time

  delay(1000);

  // Read back the date and time.
  Serial.print("Time: ");
  Serial.print(rtc1.getHours());		// returns Hours in int format
  Serial.print("h ");
  Serial.print(rtc1.getMinutes());	// returns minutes in int format
  Serial.print("m ");
  Serial.print(rtc1.getSeconds());	// returns seconds in in format.
  Serial.print(" s");

  // The PM value of the MCP7940 class is updated every time the hours are read from the module.
  // PM is TRUE if the time is in 12 hour format and in the after noon (i.e. 3:45 PM)
  // Otherwise PM is false
  if (rtc1.PM == true)
  {
    Serial.print(" PM\n");
  } else {
    Serial.print(" AM\n");
  }

  Serial.print("Weekday: ");
  // Returns the Day of the Week value, these can be user defined but the library contains predefined values
  Serial.print(rtc1.getWeekday());
  Serial.print(" | Date: ");
  Serial.print(rtc1.getDate());		// Returns the date of the month.
  Serial.print(" | Month: ");
  Serial.print(rtc1.getMonth());		// Returns the month
  Serial.print(" | Year: ");
  Serial.print(rtc1.getYear());		// Returns the last two digits of the year
  Serial.print("\n");

  delay(1000);

  Serial.print("Weekday: ");
  Serial.print(rtc1.getWeekday());
  Serial.print(" | Date: ");
  Serial.print(rtc1.getDate());
  Serial.print(" | Month: ");
  Serial.print(rtc1.getMonth());
  Serial.print(" | Year: ");
  Serial.print(rtc1.getYear());
  Serial.print("\n");

  // Set the Multifunction pin to output a square wave.

  rtc1.setMFPinSquareWave(_32kHz);
  delay(1000);
  rtc1.setMFPinSquareWave(_8kHz);
  delay(1000);
  rtc1.setMFPinSquareWave(_4kHz);
  delay(1000);
  rtc1.setMFPinSquareWave(_1Hz);
  delay(1000);


}

// the loop function runs over and over again until power down or reset
void loop() {


  Serial.print("Time: ");
  Serial.print(rtc1.getHours());
  Serial.print("h ");
  Serial.print(rtc1.getMinutes());
  Serial.print("m ");
  Serial.print(rtc1.getSeconds());
  Serial.print(" s");
  rtc1.PM ? Serial.print(" PM") : Serial.print(" AM");
  Serial.print("\n");

  rtc1.setMFPinSquareWave(_32kHz);
  delay(1000);
  rtc1.setMFPinSquareWave(_8kHz);
  delay(1000);
  rtc1.setMFPinSquareWave(_4kHz);
  delay(1000);
  rtc1.setMFPinSquareWave(_1Hz);
  delay(1000);
}

I can't understand the problem, MCP7940N does not work? Is it found by I2C scanner? Elaborate please.

I have connected my hardware as shown in attached image . refer schematic. I am trying use some test code from website to make it work

I have tested RTC device like Ds1307/PC8563 device where i could able to read and write data into Serial monitor or Seven segment display. i used logic analyzer to capture i2c signal.Where for above 2 i2c device i could able to get slave response

In this also i am trying to do the same thing . but when i see communication side it working but in actual bus it not coming.

When i go through datasheet of microchip , they are recommend to use 2.2K resistor. Arduino CKt uses 10k Resistor in SDA/SCL/MFP line

  1. weather my hardware is proper?
  2. Is there code like DS1307 where i could write and read time & capture signal like DS1307 devices
    code example for MCP7940 are more complicated.
  3. it say it found address but when i connect logical analzer it fails to read response. check SDA/SCL line for reference.

As suggested previously, your first test when having problems with an I2C device is to use the Arduino I2C scanner sketch to see if the device is detected.

There's a discussion of a multi frequency one here that I've used in the past.

Yes my mcp7940 is detected.i could make it work.

But I would like to understand .How to read the data from i2c device format. With above code it not working

But I got some library where they and with 7f and devide by 10 to get answer.

Is not possible to get answers ds1307 where we directly read from rtc

void loop()
{
  
  I2c.read(MCP7940_I2C, REG_RTCSEC,  7, timeStamp);
  
  Serial.print    ("Current Time: ");
  Serial.print    (convertFromBcd(timeStamp[2] & 0x3F));
  Serial.print    (":");
  if              (convertFromBcd(timeStamp[1] & 0x7F) / 10 == 0) Serial.print ("0");
  Serial.print    (convertFromBcd(timeStamp[1] & 0x7F));
  Serial.print    (":");
  if              (convertFromBcd(timeStamp[0] & 0x7F) / 10 == 0) Serial.print ("0");  
  Serial.println  (convertFromBcd(timeStamp[0] & 0x7F));
  
  delay(1000);
  
}

AJITnayak:
Yes my mcp7940 is detected.i could make it work.

But I would like to understand .How to read the data from i2c device format.

Then read the library code. You can write your own, just seeing first how it can be done.

I have tested the code with Arduino UNo board and its working well now.
I am testing code with another hardware where i used PIC18F24k controller but there i face same issue.
i know its irrevant to ask question here since its arduino forum. can someone suggest me here where i am doing wrong.

#include "mcc_generated_files/mcc.h"



unsigned int i=0; 
unsigned int k=0;  
unsigned int count;

unsigned int x;

#define LED RC7

#define CONTROLREG 0xFF
#define SDA            RC4                // Data pin for i2c
#define SCK            RC3                // Clock pin for i2c
#define SDA_DIR        TRISC4            // Data pin direction
#define SCK_DIR        TRISC3            // Clock pin direction

#define I2C_SPEED    150                // kbps    
    
unsigned short int cnt, num,Dgt=0;;
unsigned short int temp1,temp2,temp3;

#define OSC_ON 0x80
#define MCP7940_ADDR 0x6F
#define ADDR_SEC 0x00 
#define ADDR_MIN 0x01
#define ADDR_HOUR 0x02


unsigned char sec, min, hr,day, dat, mon, yr ; // time variables, BCD format
unsigned char rtcc_buf       ;   // global data buffer for the RTCC
unsigned char err_cnt = 0x00 ;   // error counter ; slave's I2C_NACK
unsigned char err_flg = 0x00 ;   // error flag ; reacts at slave's NACK & MSSP1IF  



#define Seg1 0x01
#define Seg2 0x02
#define Seg3 0x04
#define Seg4 0x08
#define Seg5 0x10
#define Seg6 0x20


unsigned char Flag_Update=0;


void Delay(unsigned int k)
{
unsigned  int j;
for(j=0;j<k;j++);
}




void SetSeg(unsigned short data, unsigned  short segno)

{
    switch(data) {
        case 0:
            PORTB = 0x3F;
            break;
        case 1:
            PORTB = 0x06;
            break;
        case 2:
            PORTB = 0x5B;
            break;
        case 3:
            PORTB = 0x4F;
            break;
        case 4:
            PORTB = 0x66;
            break;
        case 5:
            PORTB = 0x6D;
            break;
        case 6:
            PORTB = 0x7D;
            break;
        case 7:
            PORTB = 0x07;
            break;
        case 8:
            PORTB = 0x7F;
            break;
        case 9:
            PORTB = 0x6F;
            break;
        default :
            PORTB = 0X00;
            break;
    }

    if(segno==1) {
        PORTA = Seg4;
    }
    if(segno==2) {
        PORTA = Seg3;
    }
    if(segno==3) {
        PORTA = Seg2;
    }
    if(segno==4) {
        PORTA = Seg1;
    }

    if(segno==5) {
        PORTC=0X00;
        PORTC = 0x40;//DP2 fourth Segment

        // PORTCbits.RC5=1;
    }

    if(segno==6) {
        PORTC=0X00;
        PORTC= 0x20;//DP2 third Segment

        //PORTCbits.RC6=1;
    }


    if(segno==7) {
        PORTA=0X00;
        PORTA = Seg5; //DP2 Second Segment
        //     PORTAbits.RA4=1;
    }

    if(segno==8) {
        PORTA=0X00;
        PORTA = Seg6; //DP2 First Segment
        // PORTAbits.RA5=1;
    }

}

    

    

      unsigned int bcdtodecimal(unsigned int bcd) 
{
    unsigned int decimal;
    decimal = (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
    return decimal;
}

      unsigned char OverFlow;



      
      

void ISR_Routine(void) {
    if(PIR0bits.TMR0IF==1) {
        PIR0bits.TMR0IF = 0;
        count= count+1;
        OverFlow=OverFlow+1;
        if(count>=10) 
        {
                 
            Flag_Update=1;
            count=0;
             LED=!LED;
    
        }
    }



}




void I2C_Initialize()
{
    //  SDA_DIR=1;
   // SCK_DIR=1;
    SSP1STAT = 0x80;
    SSP1CON1 = 0x28;
    SSP1CON2 = 0x00;
    SSP1ADD  = 0x19;// intially 19
    SSP1CON1bits.SSPEN = 0;
  
    
}



void I2C_Master_Idle (void)
{
  while ((SSP1STATbits.RW) || (SSP1CON2 & 0x1F)); // Transmit is in progress
}

void I2C_Master_Wait (void)
{
    while(!SSPIF);                              //wait till SSPIF flag is set
    SSPIF=0;
}

void I2C_Master_Start(void)
{
  I2C_Master_Idle();    
  SSP1CON2bits.SEN = 1;  // Initiate start condition
  I2C_Master_Wait();
}

void I2C_Master_Restart(void)
{
  SSP1CON2bits.RSEN = 1; // Initiate repeated start condition
  I2C_Master_Wait();
}

void I2C_Master_Stop (void)
{
  SSP1CON2bits.PEN = 1; //Initiate stop condition
  I2C_Master_Wait();
  SSP1CON1bits.SSPEN = 0;
}

void I2C_Master_NAK (void)
{
    SSP1CON2bits.ACKDT = 1; //Set as negative acknowledgement
    SSP1CON2bits.ACKEN=1;  //Initiate negative acknowledgement signal
    I2C_Master_Wait();
}

void I2C_Master_Write (uint8_t data)
{
    while (1)
    {
        SSP1BUF = data;    //Write data to SSPBUF
        I2C_Master_Wait(); // Wait
        if (SSP1CON2bits.ACKSTAT) // Check for ack
        {
            I2C_Master_Restart(); // Restart if nak
        } else break; 
    }
}

uint8_t I2C_Master_Read (void)
{
  SSP1CON2bits.RCEN = 1;  // Enable reception
  while (!SSP1STATbits.BF) {}
  SSP1CON2bits.RCEN = 0; // Disable reception
  return SSP1BUF;  // Read data
}

void MCP7940_Write (uint8_t dev_addr, uint8_t reg_addr, uint8_t reg_data)
{
 
    I2C_Master_Start();  // Send START condition
    I2C_Master_Write((dev_addr << 1) & 0xfe );// Send address with R/W cleared for write
    I2C_Master_Write(reg_addr);  // Write reg_addr
    I2C_Master_Write(reg_data);  // Write reg_data    
    I2C_Master_Stop(); //Stop condition
    __delay_ms(200);
}

uint8_t MCP7940_Read (uint8_t dev_addr, uint8_t reg_addr)
{
    I2C_Master_Start();           //Start condition
    I2C_Master_Write((dev_addr << 1) | 0x01); //7 bit address + Read
    I2C_Master_Write(reg_addr);  // Write reg_addr
    uint8_t temp = I2C_Master_Read(); // read data t
    I2C_Master_NAK();           // Send NAK
    I2C_Master_Stop();          //Stop condition
    __delay_ms(200);
    return temp;
}

void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();
    INTCONbits.GIE=1;
    INTCONbits.PEIE=1;   
   
   // I2C_Initialize();
       
    
    I2C1_Initialize();
    MCP7940_Write(MCP7940_ADDR, ADDR_SEC, 0x0 | OSC_ON); // sec to zero BUT osc on
    MCP7940_Write(MCP7940_ADDR, ADDR_MIN, 0x59); //  min to 59
    MCP7940_Write(MCP7940_ADDR, ADDR_HOUR, 0x12); //  hour to 12

    while (1)
        
        
    {
     
        sec = MCP7940_Read(MCP7940_ADDR, ADDR_SEC);        
        min = MCP7940_Read(MCP7940_ADDR, ADDR_MIN);
   
            
       if(Flag_Update==1) {
            SetSeg(min >> 4,4);
            __delay_ms(5);
            SetSeg(min & 0x0f,3);
            __delay_ms(5);
            SetSeg(sec >> 4,2);
            __delay_ms(5);
            SetSeg(sec & 0x0f,1);
            __delay_ms(5);
            Flag_Update = 0;    //ready for next update
        }    
              
    }
}