CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

i2C and ds1307

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kmp84



Joined: 02 Feb 2010
Posts: 353

View user's profile Send private message

i2C and ds1307
PostPosted: Tue Jul 19, 2016 8:37 am     Reply with quote

Hello All,
I have problem with realtime driver DS1307. In my current project I have:
-CCS ver.5.049
-pic18F46k22 at 32MHZ
-CCS TCP/IP STACK (MODBUS TCPIP TASK)
-Uart1 #INT_RDA interrupt (Reading data at 9600 from scale device and storing to modbus registers)
-DS1307 RTC task ( reading time and data with interval of one second and storing data to modbus registers)

Sometime get garbage data from ds1307 and time and data are destroyed.

Some parts of code:
Code:


   #include <18F46K22.h>
   #include "tcpip\p18cxxx.h"
   #fuses HSM,PLLEN,NOWDT
   #use delay(crystal=8M, clock=32M) // kmp Edit

#include <modbus.c>
#define MAX_INPUT_REGS 10 // InputRegisters (R)
#define MAX_HOLD_REGS 100 // HoldingRegisters (R/W)

unsigned int16 hold_regs[MAX_HOLD_REGS];
unsigned int16 input_regs[MAX_INPUT_REGS];

void main()
{
   
   Init();                          //Initialize the PIC

   StackInit();                     //Initialize the TCP/IP Stack
   
   modbus_init();                   //Initialize the ModBus TCP/IP protocol
   
   ds1307_init();                   //Initialize the Real Time Clock - ds1307
   
   enable_interrupts(INT_RDA);      //Enable serial receiv Interrupt
   
   enable_interrupts(GLOBAL);       //Enable Global Interrupt
   
   for(;;){
      StackTask();   //Call StackTask() once per main loop iteration
      ModbusTask();  //Call ModbusTask() one per main loop iteration after StackTask()
     
      ModbusAppTask();  // ModbusApplication Task();
     
      EsitPwiTask();    // ESIT Pwi Scale Task();
     
      input_regs[0] = PwiConnStatus;   // Put ConnError Byte
      input_regs[1] = make16(SW1,SW2); // Put ESIT PWI Status Byte as 16 bit Input Register!   
      input_regs[2] = pwi_weght;       // Put Weight to MODBUS Map
      input_regs[3] = pwi_tare;        // Put Tare to MODBUS Map
     
      RtcTask();              // RTC Task();
     
      input_regs[4] = yr;     // Put Year in ModbusReg
      input_regs[5] = month;  // Put Month in ModbusReg 
      input_regs[6] = day;    // Put Day in ModbusReg
      input_regs[7] = hrs;    // Put Hour in ModbusReg
      input_regs[8] = min;    // Put Min. in ModbusReg
      input_regs[9] = sec;    // Put Sec. in ModbusReg
   }
}


DS1307 RTC Driver:

Code:

///////////////////////////////////////////////////////////////////////////////
///                               DS1307.C                                   ///
///                     Driver for Real Time Clock                           ///
///                                                                          ///
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
///                 used when PIC loses power and DS1307 run from 3V BAT     ///
///               - Disable squarewave output                                ///
///                                                                          ///
/// ds1307_set_date_time(day,mth,year,dow,hour,min,sec)  Set the date/time   ///
///                                                                          ///
/// ds1307_get_date(day,mth,year,dow)               Get the date             ///
///                                                                          ///
/// ds1307_get_time(hr,min,sec)                     Get the time             ///
///                                                                          ///
////////////////////////////////////////////////////////////////////////////////

/***************Example RTC SetUp******************/
  // Set date for -> 15 June 2005 Tuesday
  // Set time for -> 15:20:55
  // ds1307_set_date_time(15,6,5,2,15,20,55);

#define RTC_SDA  PIN_C4
#define RTC_SCL  PIN_C3

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)

BYTE sec;
BYTE min;
BYTE hrs;
BYTE day;
BYTE month;
BYTE yr;
BYTE dow;

BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)
{
   BYTE seconds = 0;

   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x00);      // REG 0
   i2c_start();
   i2c_write(0xD1);      // RD from RTC
   seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
   i2c_stop();
   seconds &= 0x7F;

   delay_us(3);

   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x00);      // REG 0
   i2c_write(bin2bcd(seconds));     // Start oscillator with current "seconds value
   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x07);      // Control Register
   i2c_write(0x80);     // Disable squarewave output pin
   i2c_stop();

}

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

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

void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x03);            // Start at REG 3 - Day of week
  i2c_start();
  i2c_write(0xD1);
  dow  = bcd2bin(i2c_read() & 0x7f);   // REG 3
  day  = bcd2bin(i2c_read() & 0x3f);   // REG 4
  mth  = bcd2bin(i2c_read() & 0x1f);   // REG 5
  year = bcd2bin(i2c_read(0));            // REG 6
  i2c_stop();
}

void ds1307_get_time(BYTE &hr, BYTE &min, BYTE &sec)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x00);            // Start at REG 0 - Seconds
  i2c_start();
  i2c_write(0xD1);
  sec = bcd2bin(i2c_read() & 0x7f);
  min = bcd2bin(i2c_read() & 0x7f);
  hr  = bcd2bin(i2c_read(0) & 0x3f);
  i2c_stop();

}

BYTE bin2bcd(BYTE binary_value)
{
  BYTE temp;
  BYTE 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.
BYTE bcd2bin(BYTE bcd_value)
{
  BYTE 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));
}

/************RTC Task() ds1307***************/
void RtcTask(void){
   static unsigned int16 CurrTick,PrevTick;
   
   CurrTick = get_ticks();                          //Get Tick.
   if(tick_difference(CurrTick, PrevTick) > 1000) { //If TimeOut 1 sec?
      PrevTick = CurrTick;                          //Equal Vars.     
      ds1307_get_date(day,month,yr,dow);            //Get Data
      ds1307_get_time(hrs,min,sec);                 //Get Time
      //output_toggle(PIN_C0);
   }   
   //printf("%02d/\%02d/\%02d",day,month,yr);
   //printf("\%02d:\%02d:\%02d\r\n", hrs,min,sec);
}


Any suggestion?
Thanks!
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Tue Jul 19, 2016 9:12 am     Reply with quote

Have you actually looked at the I2C bus with a scope?. What do the rise times look like (what resistors are you using)?. What speed is it clocking at?.

I'd start by actually specifying a baud rate for the I2C. The DS1307, supports 100KHz _max_. I don't know what speed the use statement defaults to, but it may simply be trying to clock the chip too fast. Alternatively, if the resistors are a little borderline, the minimum high time specification may not be being met.

Given your chip has hardware I2C, use it. Change your I2C setup to:

#use i2c(master, I2C1, slow)

This forces the hardware I2C to be used, and the baud rate to be set to 100K or below. It'll also make the input thresholds I2C levels (0.7 Vdd, versus the default 0.8Vdd).
kmp84



Joined: 02 Feb 2010
Posts: 353

View user's profile Send private message

PostPosted: Tue Jul 19, 2016 11:09 am     Reply with quote

Hi Mr.Ttelmah,
I think that the problem is solved! But I'll put device in some test stage some hours and will write again tomorrow!

PS. I lost my way this piece of code makes problem:
Code:

#int_rda
void esit_rx_isr(void){          // Serial Async. State Machine
   int8 temp_byte;               // Define byte temp var.
   
   temp_byte=fgetc(UART_ESIT);   // Get Byte from HW buffer
   
   if(!fl_start && temp_byte==PWI_STX){      // if !fl_start && temp_byte == PWI_STX(0x02)?
      buff_rx_pwi[0]=temp_byte;  // put in rx buffer
      index_rx_pwi=1;            // Set rx_pwi index to next byte location
      fl_start=TRUE;             // set start flag
   }
   else if(fl_start && temp_byte==PWI_CR){   // If Last-1 byte = 0x0D
      buff_rx_pwi[index_rx_pwi++]=temp_byte; // put byte in buff and inc. index
      fl_crc_byte=TRUE;                      // -> signal with "fl_crc_byte"
   }   
   else if(fl_crc_byte){                     // If last CRC byte ?
      buff_rx_pwi[index_rx_pwi]=temp_byte;   // Get last CRC byte without inc index
      fl_stop=TRUE;                          // Set flag_stop (Finished packed - READY for proceed!)
   }
   
   else if(fl_start && (!fl_stop)){          // if flag_start and NOT flag_stop ?
      buff_rx_pwi[index_rx_pwi++]=temp_byte; // put byte(s) in buffer and inc. index
   }
}


Could it make a problem?

PS. Mr. Ttelmah some comment about Hardware I2C vs Software I2C?

Thanks very much !
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Tue Jul 19, 2016 11:44 am     Reply with quote

The RDA code, just puts the bytes into a linear buffer, resetting when STX is seen, and signalling to the main code when the CRC has been received. Only problem it could cause, is if the data was invalid, and you had a packet longer than the buffer.

The only time to use software I2C, is if you haven't got hardware....

It can be useful though to receive from a 3.3v device, using pins that have TTL input buffers.
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Jul 19, 2016 12:07 pm     Reply with quote

just a comment, since I use both the 46k22 and the 1307..

I use the 1307 to generate an interrupt every second and have never had any bad data from the RTC. I'm either using 2K2 or 3K3 pullups on the I2C bus lines and INT line.

Jay
kmp84



Joined: 02 Feb 2010
Posts: 353

View user's profile Send private message

PostPosted: Wed Jul 20, 2016 1:47 am     Reply with quote

Hi Mr."Ttelmah" and "Temtronic",
The Problem is SOLVED! Every things work very good!

May be it's another thread but I will write here because it is related to the same project. I want to make some "industrial" controller for automation and I have a version that contains the following components:
- CPU-pic18F46K22 at Q=8Mhzx4=32MHz Clock;
- ENC28J60 Ethrrnet Controller;
- DS1307 RTC and EEProm 24xxx on I2C1 Bus;
- 2x rs232/485 on hardware UART1 and UART2;
- Some optoisolated digital In/Out;

My current dilemma now is how and what power down circuit to made on the next revission of my board to store about 20-30 int32 vars. to nonvolatile memory?

May be I have to use high cap. 1000/2000uF domain circuit ?
May be I have to Use F-RAM vs. EEPROM?
May be I have to reduce cpu clock speed to have enought time to store data to memory ?

Thank you for Attention!
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Wed Jul 20, 2016 2:21 am     Reply with quote

Realistically use the FRAM.

Speed, as fast as you can drive it....

As an alternative to 'triggered' writes, you can even use the memory as if it is direct variables (so access values in memory just like variables in your RAM), using 'addressmod'. With this approach, the only thing you need to ensure, is that power remains 'good' _while_ a complete write is taking place. A few uSec.

Use the hardware SSP2 port. So on your chip RB1, 2 & 3.

Assuming you will probably have 24v as the main power, monitor this. Then if you want triggered writes, you can write if this goes below perhaps 12v, and still have an age to write the variables.
kmp84



Joined: 02 Feb 2010
Posts: 353

View user's profile Send private message

PostPosted: Wed Jul 20, 2016 6:05 am     Reply with quote

Hi Mr."Ttelmah",

I have never using "ccs addressmod". Any sample example program how to use it? Is it better to use F-RAM chip and DS1307 on the same I2C bus(because ds1307 max speed is 100k )?
Can I use CCS example 24cxx.c for R/W F-RAM over I2C?
Quote:

Use the hardware SSP2 port. So on your chip RB1, 2 & 3.

SSP2 is not of such pins of processor 18F46K22.?

Thanks!
newguy



Joined: 24 Jun 2004
Posts: 1908

View user's profile Send private message

PostPosted: Wed Jul 20, 2016 6:18 am     Reply with quote

One more suggestion: MRAM vs FRAM. Speaking from experience, I did find a certain batch of FRAM EEPROM that "wore out" from heavy use even though an FRAM is never supposed to fail. Pretty sure it was a bad batch because the replacement has been perfect, but.....
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Wed Jul 20, 2016 7:41 am     Reply with quote

Was thinking of the 26K22. On the 46K22, SSP2 is on RD0, D1 & D4.

On chip life, I've had thousands of FRAM's, do _billions_ of cycles. I really do suspect you just had a faulty batch of chips. We have all had those (many PIC's included).

Honestly much better to drive the FRAM using SSP. You could write 20 variables in the time it'd take to write one using I2C......

Key point is that you can just do sequential writes. As fast as you can copy bytes to the SSP registers. You can transfer a byte in 1uSec using SSP on your chip, and the FRAM can take this.

Addressmod, when it works (a lot of compiler versions had problems, but it seems to be working now again), allows you to treat an external memory, as if it is part of your normal PIC memory space. You just read and write the variables as if they are in RAM.
The manual entry has an example based on an EEPROM for it.
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jul 20, 2016 7:47 am     Reply with quote

Another possible option, often overlooked is the CMOS RAM that's in the RTC ! Yes, only 56 bytes BUT depending on what you NEED to store and HOW it's stored, you can save a LOT of information, 448 bits actually.
Heck you already have the RTC..might as well use it's RAM !

There may be RTC with more RAM, have a look.

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Wed Jul 20, 2016 10:03 am     Reply with quote

Look at the DS3234.

More accurate (has a built in TXCO).
256 bytes of RAM built in.
Uses 4MHz SPI, so you can read and write it much faster.

As Temtronic rightly points out, it is worth simplifying this if you can.

Other thing you need to get right is how you monitor the power. The thing that causes problems is not shutting things down and completing writes _before_ the power completely goes....
kmp84



Joined: 02 Feb 2010
Posts: 353

View user's profile Send private message

PostPosted: Thu Jul 21, 2016 1:42 am     Reply with quote

Hi Mr."Ttelmah" and Mr."Temtronic" and Mr."Newguy"
Sorry for the delay in my response! I will do some tests and will write again. Your tips are very useful for me!

Thank you very much!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group