MOD-RTC - Unable to set time

Started by rhiakath, April 01, 2013, 01:29:17 PM

Previous topic - Next topic

rhiakath

Hi there. I've written a small piece of C code to get and set the time on the RTC UEXT.
The read works very well, and i can see it increment the seconds. Unfortunately, I seem to be unable to set the time. There is no error writing to the register itself, but if i read it afterward, it has nothing to do with what i wrote.
Also, the values change everytime i write, they don't get completely discarded, so i must be hitting something.
I've tried on an A13, and a iMX233. The results are the same.
this is my code, currently for the I2C bus on the iMX233. On the A13, it should be bus 2.

#include "RTC.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <unistd.h>
#include <math.h>
#include <time.h>

#define I2C_Filename "/dev/i2c-0"
#define I2C_RTCAddress 0x51
char *Weekdays[7]= {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};

int ReadSystemTime ( uint8_t *Out_Day, uint8_t *Out_Month, uint8_t *Out_Year, uint8_t *Out_Weekday, uint8_t *Out_Hour, uint8_t *Out_Minute, uint8_t *Out_Second )
    {
    struct timeval Now;
    struct tm *tm;

    printf ( "Reading system time\n" );
    gettimeofday ( &Now, NULL );
    tm = localtime ( &Now.tv_sec );
    *Out_Second = tm->tm_sec;
    *Out_Minute = tm->tm_min;
    *Out_Hour = tm->tm_hour;
    *Out_Day = tm->tm_mday;
    *Out_Month = tm->tm_mon + 1;
    *Out_Year = tm->tm_year % 100;
    *Out_Weekday = tm->tm_wday;
    printf ( "System time is %d:%d:%d %d/%d/%d ( %s )\n", *Out_Hour, *Out_Minute, *Out_Second, *Out_Day, *Out_Month, *Out_Year, Weekdays[*Out_Weekday] );
    return 0;
    }

int WriteSystemTime ( uint8_t In_Day, uint8_t In_Month, uint8_t In_Year, uint8_t In_Weekday, uint8_t In_Hour, uint8_t In_Minute, uint8_t In_Second )
    {
    printf ( "Setting system time to %d:%d:%d %d/%d/%d ( %s )\n", In_Hour, In_Minute, In_Second, In_Day, In_Month, In_Year, Weekdays[In_Weekday] );
    struct tm time1;
    memset ( &time1, 0, sizeof ( time1 ) );
    time1.tm_sec = In_Second;
    time1.tm_min = In_Minute;
    time1.tm_hour = In_Hour;
    time1.tm_mday = In_Day;
    time1.tm_mon = In_Month - 1;
    time1.tm_year = In_Year + 100;

    time_t time2 = mktime ( &time1 );
    stime ( &time2 );
    return 0;
    }

int ReadRTC ( uint8_t *Out_Day, uint8_t *Out_Month, uint8_t *Out_Year, uint8_t *Out_Weekday, uint8_t *Out_Hour, uint8_t *Out_Minute, uint8_t *Out_Second )
    {
    int FileDescriptor;
    int Result;
    printf ( "Reading time from RTC\n" );
    if ( ( FileDescriptor = open ( I2C_Filename, O_RDWR ) ) < 0 )
        {
        printf ( "%s - Unable to open filename %s. \"%s\"\n", __FUNCTION__, I2C_Filename, strerror ( errno ) );
        return -1;
        }

    if ( ioctl ( FileDescriptor, I2C_SLAVE, I2C_RTCAddress ) < 0 )
        {
        printf ( "%s - Unable to do ioctl. \"%s\"\n", __FUNCTION__, strerror ( errno ) );
        close ( FileDescriptor );
        return -1;
        }

    uint8_t buffer[1];
    buffer[0] = 0x02; // Data address dos segundos
    Result = write ( FileDescriptor, buffer, sizeof ( buffer ) );
    if ( Result != sizeof ( buffer ) )
        {
        printf ( "%s - Unable to write to i2c buffer. \"%s\"\n", __FUNCTION__, strerror ( errno ) );
        close ( FileDescriptor );
        return -1;
        }


    uint8_t Answer[7];
    Result = read ( FileDescriptor, Answer, sizeof ( Answer ) );
    if ( Result != sizeof ( Answer ) )
        {
        printf ( "%s - Unable to read from i2c buffer. \"%s\"\n", __FUNCTION__, strerror ( errno ) );
        close ( FileDescriptor );
        return -1;
        }

    for ( Result = 0; Result < sizeof ( Answer ); ++Result )
        printf ( "%02X ", Answer[Result] );
    printf ( "\n" );

    *Out_Second = BCDToDecimal ( Answer[0] & 0x7F );
    *Out_Minute = BCDToDecimal ( Answer[0] & 0x7F );
    *Out_Hour = BCDToDecimal ( Answer[0] & 0x3F );
    *Out_Day = BCDToDecimal ( Answer[0] & 0x03F );
    *Out_Weekday = BCDToDecimal ( Answer[0] & 0x07 );
    *Out_Month = BCDToDecimal ( Answer[0] & 0x1F );
    *Out_Year = BCDToDecimal ( Answer[0] & 0xFF );

    printf ( "RTC time is %d:%d:%d %d/%d/%d ( %s )\n", *Out_Hour, *Out_Minute, *Out_Second, *Out_Day, *Out_Month, *Out_Year, Weekdays[*Out_Weekday] );
    close ( FileDescriptor );
    return 0;
    }

int WriteRTC ( uint8_t In_Day, uint8_t In_Month, uint8_t In_Year, uint8_t In_Weekday, uint8_t In_Hour, uint8_t In_Minute, uint8_t In_Second )
    {
    int FileDescriptor;
    int Result;

    printf ( "Setting RTC time to %d:%d:%d %d/%d/%d ( %s )\n", In_Hour, In_Minute, In_Second, In_Day, In_Month, In_Year, Weekdays[In_Weekday] );

    if ( ( FileDescriptor = open ( I2C_Filename, O_RDWR ) ) < 0 )
        {
        printf ( "%s - Unable to open filename %s. \"%s\"\n", __FUNCTION__, I2C_Filename, strerror ( errno ) );
        return -1;
        }

    if ( ioctl ( FileDescriptor, I2C_SLAVE, I2C_RTCAddress ) < 0 )
        {
        printf ( "%s - Unable to do ioctl. \"%s\"\n", __FUNCTION__, strerror ( errno ) );
        close ( FileDescriptor );
        return -1;
        }

    uint8_t buffer[1];
    buffer[0] = 0x02; // Data address dos segundos

    uint8_t NewTime[7];
    NewTime[0] = DecimalToBCD ( In_Second );
    NewTime[1] = DecimalToBCD ( In_Minute );
    NewTime[2] = DecimalToBCD ( In_Hour );
    NewTime[3] = DecimalToBCD ( In_Day );
    NewTime[4] = DecimalToBCD ( In_Weekday );
    NewTime[5] = DecimalToBCD ( In_Month );
    NewTime[6] = DecimalToBCD ( In_Year );

    uint8_t FullBuffer[8];
    FullBuffer[0] = 0x02;
    memcpy ( FullBuffer + 1, &NewTime, sizeof ( NewTime ) );
usleep ( 1000 );
    Result = write ( FileDescriptor, buffer, sizeof ( buffer ) );
    if ( Result != sizeof ( buffer ) )
    /*Result = write ( FileDescriptor, FullBuffer, sizeof ( FullBuffer ) );
    if ( Result != sizeof ( FullBuffer ) )*/
        {
        printf ( "%s - Unable to write to i2c buffer. \"%s\"\n", __FUNCTION__, strerror ( errno ) );
        close ( FileDescriptor );
        return -1;
        }

    for ( Result = 0; Result < sizeof ( NewTime ); ++Result )
        printf ( "%02X ", NewTime[Result] );
    printf ( "\n" );

    Result = write ( FileDescriptor, NewTime, sizeof ( NewTime ) );
    if ( Result != sizeof ( NewTime ) )
        {
        printf ( "%s - Unable to write to i2c buffer. \"%s\"\n", __FUNCTION__, strerror ( errno ) );
        close ( FileDescriptor );
        return -1;
        }

    close ( FileDescriptor );
    return 0;
    }


unsigned BCDToDecimal ( unsigned In_BCD )
    {
    unsigned cont = 0;
    unsigned Result = 0;
    for ( cont = 0; cont < sizeof ( In_BCD ); ++cont )
        {
        Result += ( In_BCD & 0x0F ) * pow ( 10, cont );
        In_BCD >>= 4;
        }
    return Result;
    }

unsigned DecimalToBCD ( unsigned In_Decimal )
    {
    unsigned cont = 0;
    unsigned Result = 0;
    for ( cont = 0; cont < sizeof ( In_Decimal ); ++cont )
        {
        Result += In_Decimal % 10 * pow ( 0x10, cont );
        In_Decimal /= 10;
        }
    return Result;
    }

int main ( int argc, char *argv[] )
    {
    uint8_t Hours, Minutes, Seconds, Day, Month, Year, Weekday;
    ReadRTC ( &Day, &Month, &Year, &Weekday, &Hours, &Minutes, &Seconds );
    ReadSystemTime ( &Day, &Month, &Year, &Weekday, &Hours, &Minutes, &Seconds );

    if ( argc != 2 )
        return -1;
    switch ( argv[1][0] )
        {
        case 'l':
            {
            printf ( "Setting system time from RTC\n" );
            ReadRTC ( &Day, &Month, &Year, &Weekday, &Hours, &Minutes, &Seconds );
            WriteSystemTime ( Day, Month, Year, Weekday, Hours, Minutes, Seconds );
            break;
            }
        case 's':
            {
            printf ( "Saving system time to RTC\n" );
            ReadSystemTime ( &Day, &Month, &Year, &Weekday, &Hours, &Minutes, &Seconds );
            WriteRTC ( Day, Month, Year, Weekday, Hours, Minutes, Seconds );
            break;
            }
        case 'b':
            {
            printf ( "Testing BCD conversion\n" );
            unsigned cont;
            printf ( "BCDToDecimal\n" );
            for ( cont = 0; cont < 0xFF; ++cont )
                {
                if ( ( cont & 0x0F ) >= 0x0A ) continue;
                if ( ( ( cont >> 4 ) & 0x0F ) >= 0x0A ) continue;
                printf ( "BCD - %02X DEC - %d\n", cont, BCDToDecimal ( cont ) );
                }
            printf ( "DecimalToBCD\n" );
            for ( cont = 0; cont < 0xFF; ++cont )
                {
                printf ( "BCD - %02X DEC - %d\n", DecimalToBCD ( cont ), cont );
                }
            break;
            }
        case 't':
            {
            while ( 1 )
                {
                printf ( "Saving system time to RTC\n" );
                ReadSystemTime ( &Day, &Month, &Year, &Weekday, &Hours, &Minutes, &Seconds );
                WriteRTC ( Day, Month, Year, Weekday, Hours, Minutes, Seconds );
                sleep ( 1 );
                ReadRTC ( &Day, &Month, &Year, &Weekday, &Hours, &Minutes, &Seconds );

                printf ( "\n\n\n" );
                }
            break;
            }
        }
    sleep ( 1 );
    ReadRTC ( &Day, &Month, &Year, &Weekday, &Hours, &Minutes, &Seconds );
    ReadSystemTime ( &Day, &Month, &Year, &Weekday, &Hours, &Minutes, &Seconds );
    return 0;
    }


A sample run outputs this:
Reading time from RTC
27 27 27 27 27 32 27
RTC time is 27:27:27 27/12/27 ( (null) )
Reading system time
System time is 12:38:34 27/3/13 ( Wednesday )
Saving system time to RTC
Reading system time
System time is 12:38:34 27/3/13 ( Wednesday )
Setting RTC time to 12:38:34 27/3/13 ( Wednesday )
34 38 12 27 03 03 13
Reading time from RTC
27 27 38 12 27 23 03
RTC time is 38:27:27 12/3/3 ( (null) )



Saving system time to RTC
Reading system time
System time is 12:38:35 27/3/13 ( Wednesday )
Setting RTC time to 12:38:35 27/3/13 ( Wednesday )
35 38 12 27 03 03 13
Reading time from RTC
27 27 38 38 22 27 03
RTC time is 38:27:27 38/7/3 ( Tuesday )



Saving system time to RTC
Reading system time
System time is 12:38:36 27/3/13 ( Wednesday )
Setting RTC time to 12:38:36 27/3/13 ( Wednesday )
36 38 12 27 03 03 13
Reading time from RTC
27 27 38 38 20 32 27
RTC time is 38:27:27 38/12/27 ( Sunday )


What am I doing wrong?
Thank you

EDIT: I've previously included this in the UEXT forum, but maybe that was not the best place, as this may be an A13 configuration issue.
We've tested the RTC with another hardware platform and it works perfectly.
We're currently trying to set the i2c speed to some lower value on the A13, to see if it works better.