R4571 Real Time Clock (ETM21E-02)

The R4571 is a Real Time Clock (RTC) with internal oscillator and alarm/interrupt functions. This chip can be found in some Epson printers with clock features.

(photo by Blunoise, Public Domain)

Datasheet:

http://www.epsondevice.com/docs/qd/en/DownloadServlet?id=ID000392

Connect it to the Arduino:

The R4571 is connected to the Arduino using pins (CE, DIO, CLK) and Vdd can be connect to +5V (or +3.3V). FOUT chip pin can be used as a source clock (see notes) IRQ pin can be used as counter time interrupt.

The Vdd range is 1.6V - 5.5V and the battery it could be a lithium battery (see datasheet). Be careful to connect value minor than 3V because the DIO Pin High and Low voltage levels are based on Vdd (comunication problems)

Comunication protocol:

The R4571 use a 3-wire serial interface (Most Significant Bit First). How described in code section, to realize the protocol the arduino shiftIn and shiftOut functions have been used. To perform a write register operation call writeReg(register,value). To perform a read register operation call readReg(register).

The chip read/write one-shot access is based on fews steps:

  1. Set the Clock Pin to low:
   How it's described at CLK pin description in datasheet
   the read mode clockis on fall edge and the write mode 
   clock is on raise edge.
   So, based on the shiftOut documentation 
   (http://arduino.cc/en/Reference/ShiftOut) the clock pin
   must be setted LOW at beginning of any transmission
   because the comunication always start with a byte sended 
   by arduino that contain operation mode and address.(see nexts points)

  1. Set CE Pin High

  2. Send the first byte:
   The first byte must contain read/write mode on first part and the register address on rest part.
   For a read operation byte first part must be 1001 (09h).
   For a write operation byte first part must be 0001 (01h).
   Example:to make a read operation on register 0x03 the first byte to transmit is 1001 0011 (0x93)

  1. Send/Receive the data (1 byte):
    • On read operation the data is retrieved by calling the shiftIn function.
    • On write operation data is sended to the device by calling shiftOut function.

  2. Set CE Pin Low : end of transmission

Time/Date read and set:

To read or set time and date just call the appropriate function:

  • setTime(uint8_t hours , uint8_t minutes , uint8_t seconds);
  • setDate (uint8_t weekDay,uint8_t day,uint8_t month,uint8_t year);
  • getDate();

The week days starts from Sunday (value 0x01) to Saturday (value 0x07).

  • Examples:
    • set date “Fri 12 July 2013”: setDate(0x06,0x12,0x07,0x13)
    • set time “12:00:00”: setTime(0x12,0x00,0x00)
    • get date string: char * dateString = getDate()
        this function return date in form “Fri 2013-07-12”

  • Read a single address:
    e.g.: get minutes value 

  1. uint8_t minutes = readReg(0x01) ;
  2. //or
  3. uint8_t minutes  = readReg(R4571_MIN);

Code:

  • RTC_R4571.h

  1. //SET PIN HERE
  2. #define CE_PIN 10
  3. #define CLOCK_PIN 13
  4. #define DATA_PIN 12
  5.  
  6. //RTC RX-4571 REGISTER
  7. #define R4571_SEC             0x00
  8. #define R4571_MIN             0x01
  9. #define R4571_HOURS           0x02
  10. #define R4571_WDAY            0x03
  11. #define R4571_DAY             0x04
  12. #define R4571_MONTH           0x05
  13. #define R4571_YEAR            0x06
  14. #define R4571_RAM             0x07
  15.  
  16. #define R4571_MIN_ALARM       0x08
  17. #define R4571_HOURS_ALARM     0x09
  18. #define R4571_WDAY_ALARM      0x0A
  19. #define R4571_DAY_ALARM       0x0B
  20.  
  21. #define R4571_TIMER_SETUP     0x0C
  22. #define R4571_TIMER_COUNTER   0x0D
  23. #define R4571_EXT_REGISTER    0x0E
  24. #define R4571_FLAG_REGISTER   0x0F
  25.  
  26.  
  27. #include <inttypes.h>
  28. #include <Arduino.h>
  29.  
  30. class rtc_R4571
  31. {
  32. public:
  33.   uint8_t readReg(unsigned char reg);
  34.   void writeReg(uint8_t reg, uint8_t value);
  35.   void setTime(uint8_t hours,uint8_t minutes,uint8_t seconds);
  36.   void setDate(uint8_t weekDay,uint8_t day,uint8_t month,uint8_t year);
  37.   char * getDate();
  38.   rtc_R4571();  //class constructor: set pin directions
  39. };
  40.  

  • RTC_R4571.cpp

  1. #include "RTC_R4571.h"
  2.  
  3. uint8_t rtc_R4571::readReg(unsigned char reg)
  4. {
  5.  
  6.   if (reg > 0x0F)
  7.     return 0;
  8.  
  9.   pinMode(DATA_PIN, OUTPUT);
  10.   digitalWrite(CLOCK_PIN, LOW); // set to rising edge (see http://arduino.cc/en/Reference/ShiftOut)
  11.   digitalWrite(CE_PIN, 1);
  12.   uint8_t completeAddr=0;
  13.   completeAddr+=0x90; //read mode
  14.   completeAddr+=reg;
  15.   shiftOut(DATA_PIN,CLOCK_PIN,MSBFIRST,completeAddr); //set read mode on addr (send first 8 bit [mode|addr])
  16.   pinMode(DATA_PIN, INPUT);                           //see datasheet
  17.   uint8_t readVal=0;
  18.   readVal = shiftIn(DATA_PIN, CLOCK_PIN, MSBFIRST); //read the data
  19.   digitalWrite(CE_PIN, 0);
  20.  
  21.   return readVal;
  22. }
  23.  
  24. void rtc_R4571::writeReg(uint8_t reg, uint8_t value)
  25. {
  26.   pinMode(DATA_PIN, OUTPUT);
  27.   digitalWrite(CLOCK_PIN, LOW);
  28.   digitalWrite(CE_PIN, 1);
  29.   uint8_t completeAddr=0;
  30.   completeAddr+=0x10; //write mode
  31.   completeAddr+=reg;
  32.   shiftOut(DATA_PIN,CLOCK_PIN,MSBFIRST,completeAddr); //set write mode on addr
  33.   shiftOut(DATA_PIN,CLOCK_PIN,MSBFIRST,value); //write data
  34.   digitalWrite(CE_PIN, 0);
  35. }
  36.  
  37. void rtc_R4571::setTime(uint8_t hours, uint8_t minutes, uint8_t seconds)
  38. {
  39.   //example 12:05:00 -> setTime(0x12,0x05,0x00);
  40.   writeReg(R4571_HOURS,hours);
  41.   writeReg(R4571_MIN,minutes);
  42.   writeReg(R4571_SEC,seconds);  
  43. }
  44.  
  45. void rtc_R4571::setDate(uint8_t weekDay, uint8_t day, uint8_t month, uint8_t year)
  46. {
  47.   //Sun=0x01 ....... Sat=0x07
  48.   //example Fri 12 July 2013 -> setDate(0x05,0x12,0x07,0x13);
  49.  
  50.   //if you want to set wday directly using writeReg
  51.   //this value must be inserted (see datasheet):
  52.   //0x01=Sun , 0x02=Mon , 0x04=Tue , 0x08=Wed , 0x010=Thu , 0x20=Fri  0x40=Sat
  53.  
  54.   switch(weekDay)
  55.   {
  56.     case 0x01:
  57.     {
  58.       writeReg(R4571_WDAY,0x01);
  59.       break;}
  60.     case 0x02:
  61.     {
  62.       writeReg(R4571_WDAY,0x02);
  63.       break;}
  64.     case 0x03:
  65.     {
  66.       writeReg(R4571_WDAY,0x04);
  67.       break;}
  68.     case 0x04:
  69.     {
  70.       writeReg(R4571_WDAY,0x08);
  71.       break;}
  72.     case 0x05:
  73.     {
  74.       writeReg(R4571_WDAY,0x10);
  75.       break;}
  76.     case 0x06:
  77.     {
  78.       writeReg(R4571_WDAY,0x20);
  79.       break;}
  80.     case 0x07:
  81.     {
  82.       writeReg(R4571_WDAY,0x40);
  83.       break;}
  84.   }
  85.  
  86.   if(day < 0x32)
  87.   writeReg(R4571_DAY,day);
  88.  
  89.   if(month< 0x13)
  90.   writeReg(R4571_MONTH,month);
  91.  
  92.   if(year < 100)
  93.   writeReg(R4571_YEAR,year);    
  94. }
  95.  
  96. char* rtc_R4571::getDate()
  97. {
  98.   static char dateString[15];
  99.   //put data in a string  use : char *date = getDate();
  100.   uint8_t wday=readReg(3);
  101.   uint8_t day=readReg(4);
  102.   uint8_t month=readReg(5);
  103.   uint8_t year=readReg(6);
  104.  
  105.   switch (wday)
  106.   {
  107.     case 0x01:
  108.     {
  109.       sprintf(dateString,"Sun 20%02x-%02x-%02x",year,month,day);
  110.       break;      
  111.     }
  112.     case 0x02:
  113.     {
  114.       sprintf(dateString,"Mon 20%02x-%02x-%02x",year,month,day);
  115.       break;      
  116.     }
  117.     case 0x04:
  118.     {
  119.       sprintf(dateString,"Tue 20%02x-%02x-%02x",year,month,day);
  120.       break;      
  121.     }
  122.     case 0x08:
  123.     {
  124.       sprintf(dateString,"Wed 20%02x-%02x-%02x",year,month,day);
  125.       break;      
  126.     }
  127.     case 0x10:
  128.     {
  129.       sprintf(dateString,"Thu 20%02x-%02x-%02x",year,month,day);
  130.       break;      
  131.     }
  132.     case 0x20:
  133.     {
  134.       sprintf(dateString,"Fri 20%02x-%02x-%02x",year,month,day);
  135.       break;      
  136.     }
  137.     case 0x40:
  138.     {
  139.       sprintf(dateString,"Sat 20%02x-%02x-%02x",year,month,day);
  140.       break;      
  141.     }
  142.   }
  143.  
  144.   return dateString;
  145. }
  146.  
  147.  
  148. rtc_R4571::rtc_R4571()  //constructor
  149. {
  150.   pinMode(CLOCK_PIN, OUTPUT);  
  151.   pinMode(CE_PIN, OUTPUT);      
  152.   digitalWrite(CE_PIN, 0);
  153.   delay(100);  //wait the oscillator stabilization (see datasheet)    
  154. }

Example:

  1.  
  2. #include "RTC_R4571.h"
  3.  
  4. static rtc_R4571 rtc;
  5.  
  6. void setup() {  
  7.  
  8.  
  9.   Serial.begin(9600);
  10.   rtc.setTime(0x12,0x00,0x00); // 12:00:00
  11.   rtc.setDate(0x06,0x12,0x07,0x13);  //Fri 12 July 2013                                  
  12. }
  13.  
  14. void loop()
  15. {
  16. //   //example get register per register
  17.    uint8_t h=rtc.readReg(R4571_HOURS);
  18.    uint8_t min=rtc.readReg(R4571_MIN);
  19.    uint8_t sec=rtc.readReg(R4571_SEC);    
  20.  
  21.    char timeString[8];
  22.    sprintf(timeString,"%02x:%02x:%02x \n",h,min,sec);
  23.  
  24.    //example get data string in format "WDAY YYYY-MM-DD"  ("Fri 2013-07-12")
  25.    char *dataString;
  26.    dataString = rtc.getDate();
  27.    Serial.println(timeString);
  28.    Serial.println(dataString);
  29.    delay(500);
  30. }
  31.  

Notes:

This chips has an out clock specific pin (FOUT) and the frequency can be set by FOE pin and FSEL0 FSEL1 bits in extension register. Another interesting function of the device is the fixed-cycle counter: When a "1" is written to the TE bit, the fixed-cycle timer countdown starts from the preset value. A fixed-cycle timer interrupt event starts a countdown based on the countdown period (source clock). When the count value changes from 001h to 000h, an interrupt event occurs( transition of IRQ Pin from HIGH to LOW).

Data can be cathed in continuous operation and objected address is auto incremented. Auto incrementing of the address is cyclic, so address "F" is followed by address "0". This method was not implemented in code at this time.

Share