Arch GPRS V2 Real Time Clock

I had trouble getting the time to work on my Arch GPRS V2 in the last post, which is a shame because it would be incredibly useful. Fortunately, I stumbled across a lead which I was able to follow.

In the aptly titled “Where is the documentation” forum post, the attach_rtc function is mentioned. What a frustrating enigma! Search for it on the mbed site and you only get two hits, neither of which are official documentation.

So what is attach_rtc?  Dig far enough into the code repository and you will find it interfaces the internal time functions with an on board RTC, when an on chip RTC is unavailable (the LPC11U27 does not have an RTC). It does this by taking pointers to functions that you have to write, which read and write time to and from the time_t structure using your chosen RTC. As well as this, it has arguments for initialising, and checking if the RTC is enabled.

void attach_rtc(time_t (*read_rtc)(void), void (*write_rtc)(time_t), void (*init_rtc)(void), int (*isenabled_rtc)(void));

I was lucky to discover I had an RTC on the Arch GPRS V2, as it was not something I had properly researched when I purchased it.

RTC on schematic
DS1337 real time clock on the Arch GPRS V2 schematic

On the SeeedStudio repository on mbed, there is an example of reading from and writing to the DS1337 using a provided library. All I had to do was interface the read and write functions in this example with the time_t structure required for attach_rtc.

The time_t structure is an alias for an arithmetic type. It is the UNIX/POSIX time: the number of seconds since 00:00:00 January 1, 1970. The simplest way to get this into a format understood by the DS1337 was to use the localtime and mktime functions to convert back and forth between time_t and tm data types.

The other thing which had to be taken into account is the range of values used between tm and the DS1337. Namely, tm stores year as the number of years since 1900, and months is stored as 0-11 rather than 1-12. I have catered for this in the functions, shown below.

void my_rtc_write(time_t _time)
    // extract time_t to time info struct
    tm * timeinfo = localtime(&_time);

    RTC_DS1337->setSeconds   (timeinfo->tm_sec);
    RTC_DS1337->setMinutes   (timeinfo->tm_min);
    RTC_DS1337->setHours     (timeinfo->tm_hour);
    RTC_DS1337->setDays      (timeinfo->tm_mday);        // day of month
    RTC_DS1337->setDayOfWeek (timeinfo->tm_wday);
    RTC_DS1337->setMonths    (timeinfo->tm_mon + 1);     // tm stores months 0 - 11, DS1337 stores 1-12
    RTC_DS1337->setYears     (timeinfo->tm_year + 1900); // tm subtracts 1900 from year

time_t my_rtc_read()
    time_t  retval = 0;     // time since start of epoch
    tm      _time_tm;


    // extract values from RTC to tm struct
    _time_tm.tm_year = RTC_DS1337->getYears() - 1900; // tm stores (year - 1900)
    _time_tm.tm_mon  = RTC_DS1337->getMonths() - 1;   // tm stores months 0 - 11, DS1337 stores 1-12
    _time_tm.tm_mday = RTC_DS1337->getDays();
    _time_tm.tm_hour = RTC_DS1337->getHours();
    _time_tm.tm_min  = RTC_DS1337->getMinutes();
    _time_tm.tm_sec  = RTC_DS1337->getSeconds();

    // convert to time_t    
    retval = mktime(&_time_tm);
    if (retval == (time_t) -1)
        return 0;               // error
        return retval;

I also wrote basic functions for initialising and checking if it is enabled:

void my_rtc_init()
    _rtcEnabled = 1;

int my_rtc_enabled()
    return _rtcEnabled;

To test, I attached the RTC as required, and set it:

    tm timeinfo;
    timeinfo.tm_hour = 0;   timeinfo.tm_min = 0; timeinfo.tm_sec = 0;
    timeinfo.tm_year = (2001 - 1900); timeinfo.tm_mon = 0; timeinfo.tm_mday = 1;
    attach_rtc(&my_rtc_read, &my_rtc_write, &my_rtc_init, &my_rtc_enabled);

With the time initialised to midnight on 1st of January 2001, the timestamp was printed with each sensor reading in YYYYmmDD HHMMSS format.

RTC output
Timestamp showing the correct setting of the RTC, and the timer incrementing.

On a side note, I also ran into some serious issues with the controller simply not starting its main function. When I made seemingly innocuous changes to the code, it would not run properly, and then making more changes would sometimes fix it.

I noticed I had fallen into a bit of a trap with initialising all of my class instances as globals in main.cpp, due to a lot of basic tutorials doing this. I figured something had occurred during these initialisations which was causing an error (potentially, an order of initialisation issue). Changing this so that classes were initialised in the main appeared to fix these unpredictable problems.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s