|
|
View previous topic :: View next topic |
Author |
Message |
kmp84
Joined: 02 Feb 2010 Posts: 354
|
i2C and ds1307 |
Posted: Tue Jul 19, 2016 8:37 am |
|
|
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: 19520
|
|
Posted: Tue Jul 19, 2016 9:12 am |
|
|
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: 354
|
|
Posted: Tue Jul 19, 2016 11:09 am |
|
|
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: 19520
|
|
Posted: Tue Jul 19, 2016 11:44 am |
|
|
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: 9229 Location: Greensville,Ontario
|
|
Posted: Tue Jul 19, 2016 12:07 pm |
|
|
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: 354
|
|
Posted: Wed Jul 20, 2016 1:47 am |
|
|
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: 19520
|
|
Posted: Wed Jul 20, 2016 2:21 am |
|
|
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: 354
|
|
Posted: Wed Jul 20, 2016 6:05 am |
|
|
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
|
|
Posted: Wed Jul 20, 2016 6:18 am |
|
|
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: 19520
|
|
Posted: Wed Jul 20, 2016 7:41 am |
|
|
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: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Jul 20, 2016 7:47 am |
|
|
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: 19520
|
|
Posted: Wed Jul 20, 2016 10:03 am |
|
|
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: 354
|
|
Posted: Thu Jul 21, 2016 1:42 am |
|
|
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! |
|
|
|
|
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
|