Pages: [1]   Go Down
Author Topic: Converting R8025 RTC Library to Arduino 1.0  (Read 1196 times)
0 Members and 1 Guest are viewing this topic.
UK
Offline Offline
Sr. Member
****
Karma: 0
Posts: 273
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I have been doing my best to convert the R8025 RTC library to Arduino 1.0 but I'm still getting compile errors.... wondering if any eagle eyed programmers out there can spot my oversights... :-)  This is my first go at updating a library to Arduino 1.0 so any help is much appreciated.

.cpp code below & the .h code in the next post - I had to remove some comments to fit it in the post - sorry.  I will post the full completed code as attachements when done.

R8025.cpp
Code:
#include <Wire.h>
#include <avr/pgmspace.h>
#include "R8025.h"
#include <Arduino.h>

#define SECONDS_PER_DAY 86400L

static uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };

// number of days since 2000/01/01, valid for 2001..2099
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
    if (y >= 2000)
        y -= 2000;
    uint16_t days = d;
    for (uint8_t i = 1; i < m; ++i)
        days += pgm_read_byte(daysInMonth + i - 1);
    if (m > 2 && y % 4 == 0)
        ++days;
    return days + 365 * y + (y + 3) / 4 - 1;
}

static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
    return ((days * 24L + h) * 60 + m) * 60 + s;
}

static uint8_t conv2d(const char* p) {
    uint8_t v = 0;
    if ('0' <= *p && *p <= '9')
        v = *p - '0';
    return 10 * v + *++p - '0';
}

DateTime::DateTime (long t) {
    ss = t % 60;
    t /= 60;
    mm = t % 60;
    t /= 60;
    hh = t % 24;
    uint16_t days = t / 24;
    uint8_t leap;
    for (yOff = 0; ; ++yOff) {
        leap = yOff % 4 == 0;
        if (days < 365 + leap)
            break;
        days -= 365 + leap;
    }
    for (m = 1; ; ++m) {
        uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
        if (leap && m == 2)
            ++daysPerMonth;
        if (days < daysPerMonth)
            break;
        days -= daysPerMonth;
    }
    d = days + 1;
}

DateTime::DateTime (uint16_t year, uint8_t month, uint8_t date, uint8_t hour, uint8_t min, uint8_t sec, uint8_t wd) {
    if (year >= 2000)
        year -= 2000;
    yOff = year;
    m = month;
    d = date;
    hh = hour;
    mm = min;
    ss = sec;
    wday = wd;
}

DateTime::DateTime (const char* date, const char* time) {
    // sample input: date = "Dec 26 2009", time = "12:34:56"
    yOff = conv2d(date + 9);
    // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    switch (date[0]) {
        case 'J': m = date[1] == 'a' ? 1 : m = date[2] == 'n' ? 6 : 7; break;
        case 'F': m = 2; break;
        case 'A': m = date[2] == 'r' ? 4 : 8; break;
        case 'M': m = date[2] == 'r' ? 3 : 5; break;
        case 'S': m = 9; break;
        case 'O': m = 10; break;
        case 'N': m = 11; break;
        case 'D': m = 12; break;
    }
    d = conv2d(date + 4);
    hh = conv2d(time);
    mm = conv2d(time + 3);
    ss = conv2d(time + 6);
}

long DateTime::get() const {
    uint16_t days = date2days(yOff, m, d);
    return time2long(days, hh, mm, ss);
}

static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }

uint8_t R8025::begin(void) {
  unsigned char ctReg1=0, ctReg2=0;
  Wire.beginTransmission(RX8025_ADDRESS);
  Wire.write(RX8025_CTRL1_REG);     //CTRL1 Address
  // set the clock to 24hr format  
  ctReg1 |= RX8025_CTRL1_1224_BIT;
  Wire.write(ctReg1);
  //Set VDSL and XST bits. Also clear PON (power on reset) flag.
  Wire.write(RX8025_CTRL2_VDSL_BIT | RX8025_CTRL2_XST_BIT );  
  Wire.endTransmission();
  delay(10);

  return 1;
  // This implementation can be changed to return 0 when power on reset is
  // deteted to instruct user to adjust current date-time.
}

//Adjust the time-date specified in DateTime format
//writing any non-existent time-data may interfere with normal operation of the RTC
void R8025::adjust(const DateTime& dt) {

  Wire.beginTransmission(RX8025_ADDRESS);
  Wire.write(RX8025_SEC_REG);  //beginning from SEC Register address

  Wire.write(bin2bcd(dt.second()));
  Wire.write(bin2bcd(dt.minute()));
  Wire.write(bin2bcd(dt.hour()));
  Wire.write(dt.dayOfWeek());
  Wire.write(bin2bcd(dt.date()));
  Wire.write(bin2bcd(dt.month()));
  Wire.write(bin2bcd(dt.year() - 2000));  

  Wire.endTransmission();

}

//Read the current time-date and return it in DateTime format
DateTime R8025::now() {
  Wire.beginTransmission(RX8025_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  
  Wire.requestFrom(RX8025_ADDRESS, 8);
  Wire.read(); //ignore this data read from 0xF. Refer app note. Only Mode 3 Read operation
                  // is supported by wire library. i.e 0xF->0x0->0x2
  uint8_t ss = bcd2bin(Wire.read());
  uint8_t mm = bcd2bin(Wire.read());
  uint8_t hh = bcd2bin(Wire.read());
  uint8_t wd =  Wire.read();
  uint8_t d = bcd2bin(Wire.read());
  uint8_t m = bcd2bin(Wire.read());
  uint16_t y = bcd2bin(Wire.read()) + 2000;
  
  return DateTime (y, m, d, hh, mm, ss, wd);
}

void R8025::enableINTA_Interrupts(uint8_t periodicity)
{
  intType=PERIODIC_INTERRUPT; //Record interrupt type and periodicity for use of refreshINTA() method
  intPeriodicity=periodicity;

  uint8_t ctReg1= periodicity + 4;
  /*
  The above statement maps the periodicity defines from 0-3 into actual register value to be set for that mode.
  This arithmetic operation is simpler and faster than switch-case or if-else... Hence,
 
  EverySecond maps to RX8025_CTRL1_CT_PER_SEC    
  EveryMinute maps to RX8025_CTRL1_CT_PER_MIN    
  EveryHour  maps to RX8025_CTRL1_CT_PER_HOUR    
  EveryMonth maps to RX8025_CTRL1_CT_PER_MONTH  

*/
 //Maintain the clock in 24 Hour format
  ctReg1 |= RX8025_CTRL1_1224_BIT ;  
  Wire.beginTransmission(RX8025_ADDRESS);
  Wire.write(RX8025_CTRL1_REG);
  Wire.write(ctReg1);
  Wire.endTransmission();
  delay(10);

  //set XST and VDSL flags.Clear all other flags
  Wire.beginTransmission(RX8025_ADDRESS);
  uint8_t ctReg2 = RX8025_CTRL2_XST_BIT | RX8025_CTRL2_VDSL_BIT;
  Wire.write(RX8025_CTRL2_REG);
  Wire.write(ctReg2);
  Wire.endTransmission();
  delay(10);
}

void R8025::enableINTA_Interrupts(uint8_t hh24, uint8_t mm)
{
   // hh24 is hours in 24 format (0-23). mm is in minutes(0 - 59)
   intType=HM_INTERRUPT; //Record interrupt type, hh24 and mm for use of refreshINTA() method
   intHH24 = hh24;
   intMM = mm;

   Wire.beginTransmission(RX8025_ADDRESS);
   Wire.write(RX8025_CTRL1_REG); //CTRL1 Address
  //Set DALE bit to 0 and take care of other bits of CTRL1
   Wire.write(RX8025_CTRL1_1224_BIT);
   Wire.endTransmission();
 
   Wire.beginTransmission(RX8025_ADDRESS);
   Wire.write(RX8025_ALDMIN_REG); //ALD Minute register Address
   Wire.write(bin2bcd(mm));
   Wire.write(bin2bcd(hh24));
   Wire.endTransmission();
  
   Wire.beginTransmission(RX8025_ADDRESS);
   Wire.write(RX8025_CTRL2_REG); //CTRL2 Address
   //Set DAFG bit to 0 and take care of other bits of CTRL2
   Wire.write(RX8025_CTRL2_VDSL_BIT | RX8025_CTRL2_XST_BIT );  
   Wire.endTransmission();

   Wire.beginTransmission(RX8025_ADDRESS);
   Wire.write(RX8025_CTRL1_REG); //CTRL1 Address
  //Set DALE bit to 1 and take care of other bits of CTRL1
   Wire.write(RX8025_CTRL1_1224_BIT | RX8025_CTRL1_DALE_BIT);
   Wire.endTransmission();

}

//Disable Interrupts. This is equivalent to begin() method.
void R8025::disableINTA_Interrupts()
{
   begin(); //Restore the to initial value.
}

//This method must be called after an interrupt is detected. This refreshes the interrupt.
void R8025::refreshINTA()
{

 if(intType==PERIODIC_INTERRUPT)
 {
 //It is essential to clear CTFG flag to make /INTA high. Otherwise next interrupt will not be
 //detected by MCU. This is mentioned in page-19 timing-diagram of RX8025 App manual
 enableINTA_Interrupts(intPeriodicity); //Writing to CTRL2 is sufficient. But calling this method
                                        //is equilvalent for cleatring flag and setting Level interrupt.
 }
 else if(intType==HM_INTERRUPT)
 {
  enableINTA_Interrupts(intHH24, intMM);
  }
}

void R8025::changeOffset(uint8_t digitalOffset)
{
   // 'digitalOffset' can be any 7bit number
   Wire.beginTransmission(RX8025_DIGOFF_REG);
   Wire.write((digitalOffset & 0x7F));
   Wire.endTransmission();
}

Logged

UK
Offline Offline
Sr. Member
****
Karma: 0
Posts: 273
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is the R8025.h file for the above question:

Code:
R8025.h
[code]// R8025 Class is by Seeed Technology Inc(http://www.seeedstudio.com) and used
// in Seeeduino Stalker v2 for battery management(MCU power saving mode)
// & to generate timestamp for data logging. DateTime Class is a modified
// version supporting day-of-week.

// Original DateTime Class and its utility code is by Jean-Claude Wippler at JeeLabs
// http://jeelabs.net/projects/cafe/wiki/RTClib
// Released under MIT License http://opensource.org/licenses/mit-license.php

#ifndef R8025_H
#define R8025_H


#define RX8025_ADDRESS       0x32 //I2C Slave address

/* RX8025 Registers. Refer Sec 8.2 of application manual */
#define RX8025_SEC_REG        0x00 
#define RX8025_MIN_REG        0x10 
#define RX8025_HOUR_REG       0x20
#define RX8025_WDAY_REG       0x30
#define RX8025_MDAY_REG       0x40
#define RX8025_MONTH_REG      0x50
#define RX8025_YEAR_REG       0x60
#define RX8025_DIGOFF_REG     0x70
#define RX8025_ALWMIN_REG     0x80
#define RX8025_ALWHOUR_REG    0x90
#define RX8025_ALWWDAY_REG    0xA0
#define RX8025_ALDMIN_REG     0xB0
#define RX8025_ALDHOUR_REG    0xC0
#define RX8025_RESERVED_REG   0xD0
#define RX8025_CTRL1_REG      0xE0
#define RX8025_CTRL2_REG      0xF0

#define RX8025_CTRL1_CT_BIT      (7 << 0)

/* periodic level interrupts used for powersaving mode of MCU*/
#define RX8025_CTRL1_CT_PER_OFF     0
#define RX8025_CTRL1_CT_PER_SEC     4
#define RX8025_CTRL1_CT_PER_MIN     5
#define RX8025_CTRL1_CT_PER_HOUR    6
#define RX8025_CTRL1_CT_PER_MONTH   7

/*Periodicity */
#define EverySecond   0
#define EveryMinute   1
#define EveryHour     2
#define EveryMonth    3

//CTRL1 and CTLR2 register bits

#define RX8025_CTRL1_TEST_BIT    (1 << 3)
#define RX8025_CTRL1_1224_BIT    (1 << 5)
#define RX8025_CTRL1_DALE_BIT    (1 << 6)
#define RX8025_CTRL1_WALE_BIT    (1 << 7)

#define RX8025_CTRL2_DAFG_BIT    (1 << 0)
#define RX8025_CTRL2_WAFG_BIT    (1 << 1)
#define RX8025_CTRL2_CTFG_BIT    (1 << 2)
#define RX8025_CTRL2_CLEN1_BIT   (1 << 3)
#define RX8025_CTRL2_PON_BIT     (1 << 4)
#define RX8025_CTRL2_XST_BIT     (1 << 5)
#define RX8025_CTRL2_VDET_BIT    (1 << 6)
#define RX8025_CTRL2_VDSL_BIT    (1 << 7)


#define PERIODIC_INTERRUPT 0x00
#define HM_INTERRUPT 0x01


// Simple general-purpose date/time class (no TZ / DST / leap second handling!)
class DateTime {
public:
    DateTime (long t =0);
    DateTime (uint16_t year, uint8_t month, uint8_t date,
              uint8_t hour, uint8_t min, uint8_t sec, uint8_t wday);
    DateTime (const char* date, const char* time);

    uint8_t second() const      { return ss; }
    uint8_t minute() const      { return mm; }
    uint8_t hour() const        { return hh; }
 
    uint8_t date() const        { return d; }
    uint8_t month() const       { return m; }
    uint16_t year() const       { return 2000 + yOff; }

    uint8_t dayOfWeek() const   { return wday;}  /*Su=0 Mo=1 Tu=3 We=4 Th=5 Fr=6 Sa=7 */

    // 32-bit time as seconds since 1/1/2000
    long get() const;   

protected:
    uint8_t yOff, m, d, hh, mm, ss, wday;
};

// RTC RX8025 chip connected via I2C and uses the Wire library.
// Only 24 Hour time format is supported in this implementation
class R8025 {
public:
    uint8_t begin(void);
    void adjust(const DateTime& dt);  //Changes the date-time
    static DateTime now();            //Gets the current date-time

    //Decides the /INTA pin's output setting
    //periodicity cn be any of following defines: EverySecond, EveryMinute, EveryHour or EveryMonth
    void enableINTA_Interrupts(uint8_t periodicity);
    void enableINTA_Interrupts(uint8_t hh24, uint8_t mm);
    void disableINTA_Interrupts();
    void refreshINTA();
    void changeOffset(uint8_t digitalOffset);
protected:
    uint8_t intType, intPeriodicity, intHH24, intMM;
};

#endif
[/code]
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 548
Posts: 46042
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What errors are you getting?
Logged

Offline Offline
God Member
*****
Karma: 3
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I'm still getting compile errors

Don't keep us all waiting :-) You need to post the errors you're getting, and ideally the lines of the code that the errors refer to.
Logged

UK
Offline Offline
Sr. Member
****
Karma: 0
Posts: 273
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Folks, sorry - I should have posted the compile errors at the start....

I have solved some of the errors by changing the (0x00) address format to ((byte)0x00).

The remaining errors are:

R8025.cpp: In member function 'void R8025::adjust(const DateTime&)':
R8025.cpp:142: error: call of overloaded 'write(int)' is ambiguous
Wire.h:55: note: candidates are: virtual size_t TwoWire::write(uint8_t)
Print.h:49: note:                 size_t Print::write(const char*)
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 548
Posts: 46042
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
R8025.cpp:142: error: call of overloaded 'write(int)' is ambiguous
Code:
Wire.write((byte)whateverTheValueWas);
is the usual solution (and has been pointed out many times...).
Logged

UK
Offline Offline
Sr. Member
****
Karma: 0
Posts: 273
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wonderful, thanks PaulS - that cleared all the errors.
Logged

UK
Offline Offline
Sr. Member
****
Karma: 0
Posts: 273
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the help.
In summary... to pass this on to others in a similar position:

The following changes were made to a pre-1.0 library to get it to compile in Arduino 1.0:
(In this case only changes to the .cpp file were needed).

Changed #include <WProgram.h> to #include <Arduino.h>
Changed Wire.send to Wire.write
Chnaged Wire.receive to Wire.read
Changed hex addresses from: (0x00) to ((byte)0x00)
Changed (int) to ((byte)int)

I have attached the updated R8025 Library files.

* R8025.cpp (9.05 KB - downloaded 28 times.)
* R8025.h (3.68 KB - downloaded 24 times.)
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Actually this fix was not working for me (Seeeduino Stalker V2.0 with Arduino 1.0.1
After searching for hours for a working fix, I found one provided in the seeedstudio forum under the following adress:
http://www.seeedstudio.com/forum/viewtopic.php?f=16&t=2762&p=10199&hilit=stalker+r8025#p10199

...for all the guys who stumble over this after me in desperate search.
Logged

Pages: [1]   Go Up
Jump to: