Page 1 of 1

I2C not working on 18F25K20

PostPosted: Wed Jul 23, 2014 2:05 pm
by Ray
Hi,

I'm new to this forum, and any help would be appreciated.

I have I2C code for a DS3232 clock that was compiled with the XC8 compiler and runs fine on a 18F2520. However I can get it to work on a 18F25K20. I think I am missing something re the I/O setup. Is there anything special necessary to enable the C3 and C4 pins to use the MSSP in I2C mode?


ds3232.c
Code: Select all
////////////////////////////////////////////////////////////////////////////////
///                               DS3232.C                                   ///
///                     Driver for Real Time Clock                           ///
///                                                                          ///
/// ds3232_init() - Enable oscillator without clearing the seconds register -///
///                 used when PIC loses power and DS1307 run from 3V BAT     ///
///               - Disable squarewave output                                ///
///                                                                          ///
/// ds3232_set_date_time(day,mth,year,dow,hour,min,sec)  Set the date/time   ///
///                                                                          ///
/// ds3232_get_date(day,mth,year,dow)               Get the date             ///
///                                                                          ///
/// ds3232_get_time(hr,min,sec)                     Get the time             ///
///                                                                          ///
////////////////////////////////////////////////////////////////////////////////

#include "device.h"
#include <plib\i2c.h>

#define RTC_SDA  PIN_C4
#define RTC_SCL  PIN_C3

int bin2bcd(int binary_value);
int bcd2bin(int bcd_value);

void ds3232_init(void)
{
   BYTE seconds = 0;

   OpenI2C(MASTER, SLEW_OFF);
 
   StartI2C();
   WriteI2C(0xD0);      // WR to RTC
   WriteI2C(0x00);      // REG 0
   RestartI2C();
   WriteI2C(0xD1);      // RD from RTC
   seconds = bcd2bin(ReadI2C()); // Read current "seconds" in DS1307
   // NotAckI2C();
    StopI2C();
   seconds &= 0x7F;

   delay_us(3);

   StartI2C();
   WriteI2C(0xD0);      // WR to RTC
   WriteI2C(0x00);      // REG 0
   WriteI2C(bin2bcd(seconds));     // Start oscillator with current "seconds value
   RestartI2C();
   WriteI2C(0xD0);      // WR to RTC
   WriteI2C(0x0E);      // Control Register
   WriteI2C(0x00);     // Set to 0x00
   NotAckI2C();
   StopI2C();

}

void ds3232_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec)
{
  sec &= 0x7F;
  hr &= 0x3F;

  StartI2C();
  WriteI2C(0xD0);              // I2C write address
  WriteI2C(0x00);              // Start at REG 0 - Seconds
  WriteI2C(sec);               // REG 0 ** Modified
  WriteI2C(min);               // REG 1 ** Modified
  WriteI2C(hr);                // REG 2 ** Modified
  WriteI2C(bin2bcd(dow));      // REG 3
  WriteI2C(day);               // REG 4 ** Modified
  WriteI2C(mth);               // REG 5 ** Modified
  WriteI2C(year);              // REG 6 ** Modified
//  i2c_write(0x80);            // REG 7 - Disable squarewave output pin
  StopI2C();
}

void ds3232_get_date(int *day, int *mth, int *year, int *dow)
{
  StartI2C();
  WriteI2C(0xD0);
  WriteI2C(0x02);            // Start at REG  - Day of week
  RestartI2C();
  WriteI2C(0xD1);
  *dow  = bcd2bin(ReadI2C() & 0x7f);   // REG 3
  AckI2C();
  *day  = bcd2bin(ReadI2C() & 0x3f);   // REG 4
  AckI2C();
  *mth  = bcd2bin(ReadI2C() & 0x1f);   // REG 5
  AckI2C();
  *year = bcd2bin(ReadI2C());            // REG 6
  NotAckI2C();
  StopI2C();
}

void ds3232_get_time(int *hr, int *min, int *sec)
{
  StartI2C();
  WriteI2C(0xD0);
  WriteI2C(0x00);            // Start at REG 0 - Seconds
  RestartI2C();
  WriteI2C(0xD1);
  *sec = bcd2bin(ReadI2C() & 0x7f);
  AckI2C();
  *min = bcd2bin(ReadI2C() & 0x7f);
  AckI2C();
  *hr  = bcd2bin(ReadI2C() & 0x3f);
  NotAckI2C();
  StopI2C();

}

int bin2bcd(int binary_value)
{
  int temp;
  int retval;

  temp = binary_value;
  retval = 0;

  while(1)
  {
    // Get the tens digit by doing multiple subtraction
    // of 10 from the binary value.
    if(temp >= 10)
    {
      temp -= 10;
      retval += 0x10;
    }
    else // Get the ones digit by adding the remainder.
    {
      retval += temp;
      break;
    }
  }

  return(retval);
}


// Input range - 00 to 99.
int bcd2bin(int bcd_value)
{
  int temp;

  temp = bcd_value;
  // Shifting upper digit right by 1 is same as multiplying by 8.
  temp >>= 1;
  // Isolate the bits for the upper digit.
  temp &= 0x78;

  // Now return: (Tens * 8) + (Tens * 2) + Ones

  return(temp + (temp >> 2) + (bcd_value & 0x0f));
}

Re: I2C not working on 18F25K20

PostPosted: Wed Jul 23, 2014 2:43 pm
by ric
How exactly is it failing?
Are the SCL/SDA pins toggling at all when you try to output a START?
The "K" version does have an extra register (SSPMSK), but the default value in there should work fine for you.

Re: I2C not working on 18F25K20

PostPosted: Wed Jul 23, 2014 3:32 pm
by Ray
ric,

I don't have a hardware monitor, however when I run the code on a 18F2520, I can see the correct values in the variables. When I run the code on a 18F25k20, the values are all 0 as if the ds3232 did not respond, or the pgm did not read the response from the ds3232.

Do you know of any other working I2C code for the 25K20 that I might have a look at? Do you know of anything special to enable the I2C pins? I had a look at the SSPMSK register, how ever I don't see any problems there.

Re: I2C not working on 18F25K20

PostPosted: Wed Jul 23, 2014 10:01 pm
by ric
Do you have a PICkit3 or ICD3?
Single step the code, and use a meter to check if the SDA and SCL pins are high before StartI2C();
and low after.
If they are low all the time, you may have forgotten the pullup resistors.

Re: I2C not working on 18F25K20

PostPosted: Thu Jul 24, 2014 2:12 am
by DavidBLit
Ray wrote:ric,

I don't have a hardware monitor, however when I run the code on a 18F2520, I can see the correct values in the variables. When I run the code on a 18F25k20, the values are all 0 as if the ds3232 did not respond, or the pgm did not read the response from the ds3232.

Do you know of any other working I2C code for the 25K20 that I might have a look at? Do you know of anything special to enable the I2C pins? I had a look at the SSPMSK register, how ever I don't see any problems there.


Are you sure the 'K device is even running correctly? There's more of a difference between the two devices than just the "K" wedged in there might suggest: http://ww1.microchip.com/downloads/en/DeviceDoc/41310A.pdf.

You just might want to back up, blink an LED, and make sure you understand the differences between the two devices... ;)

(FYI: the SSPMSK register has no effect on I2C Master operation.)

Re: I2C not working on 18F25K20

PostPosted: Sun Dec 28, 2014 11:09 am
by shaddai
I know I'm way late to the party, but is SSPCON's SSPEN bit set?

todd