DS3231 Extremely Accurate I2C-Integrated RTC/TCXO/Crystal.

DS3231.cpp

Committer:
mcm
Date:
2017-12-20
Revision:
3:0226d018fdcb
Parent:
2:3710775b1864

File content as of revision 3:0226d018fdcb:

/**
 * @brief       DS3231.cpp
 * @details     Extremely Accurate I2C-Integrated RTC/TCXO/Crystal.
 *              Function file.
 *
 *
 * @return      NA
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017    The ORIGIN
 * @pre         NaN.
 * @warning     NaN
 * @pre         This code belongs to AqueronteBlog ( http://unbarquero.blogspot.com ).
 */

#include "DS3231.h"


DS3231::DS3231 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq )
    : _i2c          ( sda, scl )
    , _DS3231_Addr  ( addr )
{
    _i2c.frequency( freq );
}


DS3231::~DS3231()
{
}



/**
 * @brief       DS3231_ReadTemperature ( DS3231_vector_data_t* )
 *
 * @details     It gets the temperature.
 *
 * @param[in]    NaN
 *
 * @param[out]   myTemperature:     Temperature data.
 *
 *
 * @return       Status of DS3231_ReadTemperature.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         The temperature registers are updated after each user-initiated conversion and on every 64-second conversion.
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_ReadTemperature   ( DS3231_vector_data_t*  myTemperature )
{
    char         cmd[]       =   { DS3231_MSB_TEMPERATURE, 0 };
    uint32_t     aux         =   0;


    // It gets the temperature
    aux = _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux = _i2c.read  ( _DS3231_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );


    // Parse the data
    // 1. Check if the Temperature is positive or negative
    if ( ( cmd[0] & 0b10000000 ) == 0b00000000 )
        myTemperature->Temperature   =   cmd[0];                           // Positive value
    else
        myTemperature->Temperature   =   -1.0 * ( ( ~cmd[0] ) + 1 );       // Negative value


    // 2. Decimal part. 0.25°C resolution
    switch( cmd[1] )
    {
        // x.00°C
    default:
    case 0b00000000:
        break;

        // x.25°C
    case 0b01000000:
        myTemperature->Temperature  +=    0.25;
        break;

        // x.50°C
    case 0b10000000:
        myTemperature->Temperature  +=    0.50;
        break;

        // x.75°C
    case 0b11000000:
        myTemperature->Temperature  +=    0.75;
        break;
    }




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}



/**
 * @brief       DS3231_ReadRawTemperature ( DS3231_vector_data_t* )
 *
 * @details     It gets the raw temperature.
 *
 * @param[in]    NaN
 *
 * @param[out]   myRawTemperature:  Raw Temperature data.
 *
 *
 * @return       Status of DS3231_ReadTemperature.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         The temperature registers are updated after each user-initiated conversion and on every 64-second conversion.
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_ReadRawTemperature   ( DS3231_vector_data_t*  myRawTemperature )
{
    char         cmd[]       =   { DS3231_MSB_TEMPERATURE, 0 };
    uint32_t     aux         =   0;


    // It gets the temperature
    aux = _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux = _i2c.read  ( _DS3231_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );


    // Parse the data
    myRawTemperature->MSBTemperature    =   cmd[0];
    myRawTemperature->LSBTemperature    =   cmd[1];




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}



/**
 * @brief       DS3231_StartNewConvertTemperature  ( void )
 *
 * @details     It triggers a new temperature conversion.
 *
 * @param[in]    NaN.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_StartNewConvertTemperature.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_StartNewConvertTemperature  ( void )
{
    char         cmd[]  =   { DS3231_CONTROL_STATUS, 0 };
    uint32_t     aux    =   0;
    uint32_t     ii     =   0;


    // BSY MUST be checked before triggering a new temperature conversion
    do
    {
        aux  =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
        aux  =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

        ii++;
    }
    while ( ( ( cmd[1] & STATUS_BUSY_MASK ) != STATUS_BUSY_NOBUSY ) && ( ii < DS3231_TIMEOUT ) );


    // if something went wrong, there will not be a new temperature conversion
    cmd[0]  =   DS3231_CONTROL;
    if ( ii < DS3231_TIMEOUT )
    {
        // It triggers a new temperature conversion
        // It reads CONTROL register
        aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
        aux     =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

        // Start a new temperature conversion
        cmd[1] |=   CONTROL_STATUS_CONVERT_TEMPERATURE_ENABLED;
        aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

        // Wait until the temperature conversion is completed
        ii   =   0;
        do
        {
            aux  =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
            aux  =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

            ii++;
        }
        while ( ( ( cmd[1] & CONTROL_STATUS_CONVERT_TEMPERATURE_MASK ) != CONTROL_STATUS_CONVERT_TEMPERATURE_DISABLED ) && ( ii < DS3231_TIMEOUT ) );
    }

    // If TIMEOUT happens, something went wrong!
    if ( ii >= DS3231_TIMEOUT )
        aux   =   I2C_FAILURE;




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}



/**
 * @brief       DS3231_ReadRawAging ( DS3231_vector_data_t* )
 *
 * @details     It gets the raw aging.
 *
 * @param[in]    NaN
 *
 * @param[out]   myRawAging:        Raw Aging data.
 *
 *
 * @return       Status of DS3231_ReadRawAging.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_ReadRawAging ( DS3231_vector_data_t* myRawAging )
{
    char         cmd       =   DS3231_AGING_OFFSET;
    uint32_t     aux       =   0;


    // It gets the raw aging value
    aux = _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux = _i2c.read  ( _DS3231_Addr, &cmd, 1 );
    
    myRawAging->RawAging     =   cmd;



    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}



/**
 * @brief       DS3231_Status32kHzPin ( DS3231_status_enable_32khz_output_t )
 *
 * @details     It enables/disables the 32kHz output pin.
 *
 * @param[in]    my32kHzPin:        32kHz pin enabled/disabled.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_Status32kHzPin.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_Status32kHzPin  ( DS3231_status_enable_32khz_output_t  my32kHzPin )
{
    char         cmd[]     =   { DS3231_CONTROL_STATUS, 0 };
    uint32_t     aux       =   0;


    // It reads the status register to parse the data
    aux  =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    cmd[1] &=  ~STATUS_ENABLE_32KHZ_OUTPUT_MASK;
    cmd[1] |=   my32kHzPin;

    // Update the register
    aux  =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}



/**
 * @brief       DS3231_ClearAlarmFlag ( DS3231_status_alarm1_flag_t , DS3231_status_alarm2_flag_t )
 *
 * @details     It clears alarm flags.
 *
 * @param[in]    myA1F:             Reset/Mask alarm 1 flag.
 * @param[in]    myA2F:             Reset/Mask alarm 2 flag.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_ClearAlarmFlag.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_ClearAlarmFlag  ( DS3231_status_alarm1_flag_t myA1F, DS3231_status_alarm2_flag_t myA2F )
{
    char         cmd[]     =   { DS3231_CONTROL_STATUS, 0 };
    uint32_t     aux       =   0;


    // It reads the status register to parse the data
    aux  =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    cmd[1] &=  ~( STATUS_ALARM1_FLAG_MASK | STATUS_ALARM2_FLAG_MASK );
    cmd[1] |=   ( myA1F | myA2F );

    // Update the register
    aux  =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}



/**
 * @brief       DS3231_SetAlarm1 ( DS3231_alarm1_register_t )
 *
 * @details     It sets the alarm 1.
 *
 * @param[in]    myAlarm1:          Alarm 1 options.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_SetAlarm1.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_SetAlarm1   ( DS3231_alarm1_register_t myAlarm1 )
{
    char         cmd[]              =   { 0, 0 };
    uint32_t     aux                =   0;
    uint32_t     Alarm1SecondAux    =   0;              // A1M1
    uint32_t     Alarm1MinuteAux    =   0;              // A1M2
    uint32_t     Alarm1HourAux      =   0;              // A1M3
    uint32_t     Alarm1DayDateAux   =   0;              // A1M4 & DYDT


    // Read all the registers involved in the alarm1
    // A1M1
    cmd[0]   =   DS3231_ALARM_1_SECONDS;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    Alarm1SecondAux  =  ( cmd[1] & ~ALARM1_A1M1_MASK );

    // A1M2
    cmd[0]   =   DS3231_ALARM_1_MINUTES;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    Alarm1MinuteAux  =  ( cmd[1] & ~ALARM1_A1M2_MASK );

    // A1M3
    cmd[0]   =   DS3231_ALARM_1_HOURS;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    Alarm1HourAux  =  ( cmd[1] & ~ALARM1_A1M3_MASK );

    // A1M4 & DY/#DT
    cmd[0]   =   DS3231_ALARM_1_DAY_DATE;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    Alarm1DayDateAux  =  ( cmd[1] & ~( ALARM1_A1M4_MASK | ALARM1_DYDT_MASK ) );


    // Set all ( A1M1, A1M2, A1M3 A1M4 and DY/#DT ) to 0
    cmd[0]   =   DS3231_ALARM_1_SECONDS;
    cmd[1]   =   Alarm1SecondAux;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    cmd[0]   =   DS3231_ALARM_1_MINUTES;
    cmd[1]   =   Alarm1MinuteAux;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    cmd[0]   =   DS3231_ALARM_1_HOURS;
    cmd[1]   =   Alarm1HourAux;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    cmd[0]   =   DS3231_ALARM_1_DAY_DATE;
    cmd[1]   =   Alarm1DayDateAux;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );


    // Update the Alarm 1 rate
    switch ( myAlarm1 )
    {
    case ALARM1_ALARM_ONCE_PER_SECOND:
        cmd[0]   =   DS3231_ALARM_1_SECONDS;
        cmd[1]   =   ( Alarm1SecondAux | ALARM1_A1M1_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    case ALARM1_WHEN_SECONDS_MATCH:
        cmd[0]   =   DS3231_ALARM_1_MINUTES;
        cmd[1]   =   ( Alarm1MinuteAux | ALARM1_A1M2_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    case ALARM1_WHEN_MINUTES_AND_SECONDS_MATCH:
        cmd[0]   =   DS3231_ALARM_1_HOURS;
        cmd[1]   =   ( Alarm1HourAux | ALARM1_A1M3_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    case ALARM1_WHEN_HOURS_MINUTES_AND_SECONDS_MATCH:
        cmd[0]   =   DS3231_ALARM_1_DAY_DATE;
        cmd[1]   =   ( Alarm1DayDateAux | ALARM1_A1M4_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );
        break;

    default:
    case ALARM1_WHEN_DATE_HOURS_MINUTES_AND_SECONDS_MATCH:
        break;

    case ALARM1_WHEN_DAY_HOURS_MINUTES_AND_SECONDS_MATCH:
        cmd[0]   =   DS3231_ALARM_1_DAY_DATE;
        cmd[1]   =   ( Alarm1DayDateAux | ALARM1_DYDT_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );
        break;
    }




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}


/**
 * @brief       DS3231_SetAlarm2 ( DS3231_alarm2_register_t )
 *
 * @details     It sets the alarm 2.
 *
 * @param[in]    myAlarm1:          Alarm 2 options.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_SetAlarm2.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_SetAlarm2   ( DS3231_alarm2_register_t myAlarm2 )
{
    char         cmd[]              =   { 0, 0 };
    uint32_t     aux                =   0;
    uint32_t     Alarm2MinuteAux    =   0;              // A2M2
    uint32_t     Alarm2HourAux      =   0;              // A2M3
    uint32_t     Alarm2DayDateAux   =   0;              // A2M3 & DYDT


    // Read all the registers involved in the alarm2
    // A2M2
    cmd[0]   =   DS3231_ALARM_2_MINUTES;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    Alarm2MinuteAux  =  ( cmd[1] & ~ALARM2_A2M2_MASK );

    // A2M3
    cmd[0]   =   DS3231_ALARM_2_HOURS;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    Alarm2HourAux  =  ( cmd[1] & ~ALARM2_A2M3_MASK );

    // A2M4 & DY/#DT
    cmd[0]   =   DS3231_ALARM_2_DAY_DATE;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    Alarm2DayDateAux  =  ( cmd[1] & ~( ALARM2_A2M4_MASK | ALARM2_DYDT_MASK ) );


    // Set all ( A2M2, A2M3 A2M4 and DY/#DT ) to 0
    cmd[0]   =   DS3231_ALARM_2_MINUTES;
    cmd[1]   =   Alarm2MinuteAux;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    cmd[0]   =   DS3231_ALARM_2_HOURS;
    cmd[1]   =   Alarm2HourAux;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    cmd[0]   =   DS3231_ALARM_2_DAY_DATE;
    cmd[1]   =   Alarm2DayDateAux;
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );


    // Update the Alarm 2 rate
    switch ( myAlarm2 )
    {
    case ALARM2_ALARM_ONCE_PER_MINUTE:
        cmd[0]   =   DS3231_ALARM_2_MINUTES;
        cmd[1]   =   ( Alarm2MinuteAux | ALARM2_A2M2_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    case ALARM2_WHEN_MINUTES_MATCH:
        cmd[0]   =   DS3231_ALARM_2_HOURS;
        cmd[1]   =   ( Alarm2HourAux | ALARM2_A2M3_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    case ALARM2_WHEN_HOURS_MINUTES_MATCH:
        cmd[0]   =   DS3231_ALARM_2_DAY_DATE;
        cmd[1]   =   ( Alarm2DayDateAux | ALARM2_A2M4_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );
        break;

    default:
    case ALARM2_WHEN_DATE_HOURS_AND_MINUTES_MATCH:
        break;

    case ALARM2_WHEN_DAY_HOURS_AND_MINUTES_MATCH:
        cmd[0]   =   DS3231_ALARM_2_DAY_DATE;
        cmd[1]   =   ( Alarm2DayDateAux | ALARM2_DYDT_MASK );

        aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );
        break;
    }





    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}


/**
 * @brief       DS3231_SetAlarmsInterrupt ( DS3231_control_status_alarm1_t , DS3231_control_status_alarm2_t )
 *
 * @details     It enables/disable alarm interrupts.
 *
 * @param[in]    myAlarm1:          Enable/Disable Alarm1 interrupt.
 * @param[in]    myAlarm2:          Enable/Disable Alarm2 interrupt.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_SetAlarmsInterrupt.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_SetAlarmsInterrupt   ( DS3231_control_status_alarm1_t myAlarm1, DS3231_control_status_alarm2_t myAlarm2 )
{
    char         cmd[]              =   { DS3231_CONTROL, 0 };
    uint32_t     aux                =   0;


    // Read the Control Register
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    // Parse the data
    cmd[1]  &=  ~( CONTROL_STATUS_ALARM1_MASK | CONTROL_STATUS_ALARM2_MASK );
    cmd[1]  |=   ( myAlarm1 | myAlarm2 );


    // If both alarms are off then, disables the alarm interrupts, enables them otherwise.
    if ( ( myAlarm1 == CONTROL_STATUS_ALARM1_DISABLED ) && ( myAlarm2 == CONTROL_STATUS_ALARM2_DISABLED ) )
        cmd[1]  &=  ~CONTROL_STATUS_INTERRUPT_CONTROL_MASK;
    else
        cmd[1]  |=   CONTROL_STATUS_INTERRUPT_CONTROL_INT;


    // Update the register
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );



    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}


/**
 * @brief       DS3231_SetSquareWaveOutput ( DS3231_control_status_rate_select_t )
 *
 * @details     It enables/disable the square-wave output.
 *
 * @param[in]    myRate:            Square-wave output frequency.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_SetSquareWaveOutput.
 *
 *
 * @author      Manuel Caballero
 * @date        19/December/2017
 * @version     19/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_SetSquareWaveOutput ( DS3231_control_status_rate_select_t myRate )
{
    char         cmd[]              =   { DS3231_CONTROL, 0 };
    uint32_t     aux                =   0;


    // Read the Control Register
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _DS3231_Addr, &cmd[1], 1 );

    // Parse the data
    cmd[1]  &=  ~CONTROL_STATUS_RATE_SELECT_MASK;
    cmd[1]  |=   myRate;


    // Enable the square-wave output.
    cmd[1]  &=  ~CONTROL_STATUS_INTERRUPT_CONTROL_MASK;


    // Update the register
    aux      =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );



    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}


/**
 * @brief       DS3231_GetDate ( DS3231_vector_date_time_t* )
 *
 * @details     It gets the date.
 *
 * @param[in]    myDate:            Current Date.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_GetDate.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_GetDate ( DS3231_vector_date_time_t* myDate )
{
    char         cmd     =   0;
    uint32_t     aux     =   0;


    // Read Date Register
    cmd  =   DS3231_DATE;
    aux  =   _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd, 1 );

    myDate->Date         =   _MYBCD_TO_DECIMAL( cmd );

    // Read Month Register
    cmd  =   DS3231_MONTH_CENTURY;
    aux  =   _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd, 1 );

    myDate->Month        =   _MYBCD_TO_DECIMAL( cmd & MONTH_MONTH_MASK );
    myDate->Century      =   _MYBCD_TO_DECIMAL( cmd & MONTH_CENTURY_MASK );

    // Read Year Register
    cmd  =   DS3231_YEAR;
    aux  =   _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd, 1 );

    myDate->Year         =   _MYBCD_TO_DECIMAL( cmd );

    // Read Day of the Week Register
    cmd  =   DS3231_DAY;
    aux  =   _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd, 1 );

    myDate->DayOfWeek    =   _MYBCD_TO_DECIMAL( cmd );




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}


/**
 * @brief       DS3231_SetDate ( DS3231_vector_date_time_t )
 *
 * @details     It sets the date.
 *
 * @param[in]    myTime:            Date to store.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_SetDate.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_SetDate ( DS3231_vector_date_time_t myDate )
{
    char         cmd[]   =   { 0, 0 };
    uint32_t     aux     =   0;


    // Update Date Register
    cmd[0]  =   DS3231_DATE;
    cmd[1]  =   _MYDECIMAL_TO_BCD( myDate.Date );
    aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    // Update Month Register
    cmd[0]  =   DS3231_MONTH_CENTURY;
    cmd[1]  =   _MYDECIMAL_TO_BCD( myDate.Month | myDate.Century );
    aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    // Update Year Register
    cmd[0]  =   DS3231_YEAR;
    cmd[1]  =   _MYDECIMAL_TO_BCD( myDate.Year );
    aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    // Update Day Register
    cmd[0]  =   DS3231_DAY;
    cmd[1]  =   _MYDECIMAL_TO_BCD( myDate.DayOfWeek );
    aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );



    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}


/**
 * @brief       DS3231_GetTime ( DS3231_vector_date_time_t* )
 *
 * @details     It gets the time in decimal.
 *
 * @param[in]    myTime:            Current Time.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_GetTime.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_GetTime ( DS3231_vector_date_time_t* myTime )
{
    char         cmd     =   0;
    uint32_t     aux     =   0;


    // Read Hours Register
    cmd  =   DS3231_HOURS;
    aux  =   _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd, 1 );

    myTime->Hours        =   _MYBCD_TO_DECIMAL( ( cmd & ~( HOURS_nAM_PM_MASK | HOURS_12_n24_MASK ) ) );
    myTime->Mode_nAM_PM  =   ( cmd & HOURS_nAM_PM_MASK );
    myTime->Mode_12_n24  =   ( cmd & HOURS_12_n24_MASK );

    // Read Minutes Register
    cmd  =   DS3231_MINUTES;
    aux  =   _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd, 1 );

    myTime->Minutes  =   _MYBCD_TO_DECIMAL( cmd );

    // Read Seconds Register
    cmd  =   DS3231_SECONDS;
    aux  =   _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd, 1 );

    myTime->Seconds  =   _MYBCD_TO_DECIMAL( cmd );




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}

/**
 * @brief       DS3231_SetTime ( DS3231_vector_date_time_t )
 *
 * @details     It sets the time in BCD.
 *
 * @param[in]    myTime:            Time to store.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_SetTime.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_SetTime ( DS3231_vector_date_time_t myTime )
{
    char         cmd[]   =   { 0, 0 };
    uint32_t     aux     =   0;


    // Update Hours Register
    cmd[0]  =   DS3231_HOURS;
    cmd[1]  =   ( _MYDECIMAL_TO_BCD( myTime.Hours ) | myTime.Mode_12_n24 | myTime.Mode_nAM_PM );
    aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    // Update Minutes Register
    cmd[0]  =   DS3231_MINUTES;
    cmd[1]  =   _MYDECIMAL_TO_BCD( myTime.Minutes );
    aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );

    // Update Seconds Register
    cmd[0]  =   DS3231_SECONDS;
    cmd[1]  =   _MYDECIMAL_TO_BCD( myTime.Seconds );
    aux     =   _i2c.write ( _DS3231_Addr, &cmd[0], 2, false );




    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}



/**
 * @brief       DS3231_GetControlStatusRegister ( DS3231_vector_data_t* )
 *
 * @details     It gets the Control/Status register.
 *
 * @param[in]    myControlStatusReg:    Current value of the Register.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of DS3231_GetControlStatusRegister.
 *
 *
 * @author      Manuel Caballero
 * @date        20/December/2017
 * @version     20/December/2017     The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
DS3231::DS3231_status_t  DS3231::DS3231_GetControlStatusRegister ( DS3231_vector_data_t* myControlStatusReg )
{
    char         cmd     =   DS3231_CONTROL_STATUS;
    uint32_t     aux     =   0;


    // Read Control/Status Register
    aux  =   _i2c.write ( _DS3231_Addr, &cmd, 1, true );
    aux  =   _i2c.read  ( _DS3231_Addr, &cmd, 1 );

    myControlStatusReg->Control_Status_Register =    cmd;


    if ( aux == I2C_SUCCESS )
        return   DS3231_SUCCESS;
    else
        return   DS3231_FAILURE;
}