Go Down

Topic: Converting R8025 RTC Library to Arduino 1.0 (Read 3053 times) previous topic - next topic



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.

Code: [Select]
#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)
   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)
       days -= 365 + leap;
   for (m = 1; ; ++m) {
       uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
       if (leap && m == 2)
       if (days < daysPerMonth)
       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.write(RX8025_CTRL1_REG);     //CTRL1 Address
 // set the clock to 24hr format  
 ctReg1 |= RX8025_CTRL1_1224_BIT;
 //Set VDSL and XST bits. Also clear PON (power on reset) flag.
 Wire.write(RX8025_CTRL2_VDSL_BIT | RX8025_CTRL2_XST_BIT );  

 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.write(RX8025_SEC_REG);  //beginning from SEC Register address

 Wire.write(bin2bcd(dt.year() - 2000));  



//Read the current time-date and return it in DateTime format
DateTime R8025::now() {
 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

 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 ;  

 //set XST and VDSL flags.Clear all other flags
 uint8_t ctReg2 = RX8025_CTRL2_XST_BIT | RX8025_CTRL2_VDSL_BIT;

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.write(RX8025_CTRL1_REG); //CTRL1 Address
 //Set DALE bit to 0 and take care of other bits of CTRL1

  Wire.write(RX8025_ALDMIN_REG); //ALD Minute register 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.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);


//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()

//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.write((digitalOffset & 0x7F));


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

Code: [Select]
[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 HM_INTERRUPT 0x01

// Simple general-purpose date/time class (no TZ / DST / leap second handling!)
class DateTime {
    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;   

    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 {
    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);
    uint8_t intType, intPeriodicity, intHH24, intMM;



The art of getting good answers lies in asking good questions.


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.


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*)


R8025.cpp:142: error: call of overloaded 'write(int)' is ambiguous

Code: [Select]
is the usual solution (and has been pointed out many times...).
The art of getting good answers lies in asking good questions.


Wonderful, thanks PaulS - that cleared all the errors.


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.


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:

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

Go Up

Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

via Egeo 16
Torino, 10131