DS3232M RTC demo program. Tested on the K64F (this example) and the KL25Z, but should work on any platform by changing the SDA and SCL pins. USB serial baud rate is 230400, tested on TeraTerm. Demo includes setting the DS3232's time, turning on and off the 32KHz and 1Hz outputs and accessing the DS3232's temperature. Also included are DS3232 user RAM access tests and user RAM CRC data calculations. Since user RAM is battery backed up, CRC routines are included to insure that the data stored in user RAM is intact.

Dependencies:   ds3232m mbed mbed-rtos

main.cpp

Committer:
loopsva
Date:
2016-03-11
Revision:
4:df12939cba66
Parent:
3:f0eb506d4add

File content as of revision 4:df12939cba66:

#include "mbed.h"
#include "rtos.h"                           //mbed rtos - uncomment to make RTOS available
#include "ds3232m.h"                        //Maxim RTC

#ifdef RTOS_H
Mutex MutexI2cWait_1;                       //lock/unlock I2C requests
RawSerial pc(USBTX, USBRX);                 //console interface for RTOS
#else
Serial pc(USBTX, USBRX);                    //console interface
#endif  //RTOS_H

#define SDA0        D14                     //assuming arduino pins
#define SCL0        D15
ds3232m rtc(SDA0, SCL0, 400000);            //Maxim real time clock

//--------------------------------------------------------------------------------------------------------------------------------------//
// Time variables

time_t ctTime;                              //time structure
int DST = 1;                                //Daylight Saving Time (or as defined in .ini file)
int TZone = -8;                             //Time Zone from UTC (or as defined in .ini file)
char timebuf_hms[10];                       //local time format buffer - 21:16:43
char timebuf_dMyy[14];                      //local time format buffer - 01-Apr-2014
char timebuf_dow[1];                        //local time format buffer - 5
int StartTime = 0;                          //time we powered up
bool allowDisplayTime = false;              //used to stop displaying date/time when entering data from the console

//--------------------------------------------------------------------------------------------------------------------------------------//
//Variables for USB Serial Port RX

uint32_t pcRxQty = 0;                       //RX data counter/pointer
char pcRxBuffer[128];                       //RX data buffer
bool pcRxLine = false;                      //CR or LF detected (end of line)
bool pcRxEOB = false;                       //RX buffer is full!!! cannot accept any more characters
char inchar = 0;                            //RX input character

//--------------------------------------------------------------------------------------------------------------------------------------//
// various Mutex lock/unlock definitions

void lockI2C() {
#ifdef RTOS_H
    MutexI2cWait_1.lock();
#endif  //RTOS_H
}

void unlockI2C() {
#ifdef RTOS_H
    MutexI2cWait_1.unlock();
#endif  //RTOS_H
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// This function is called when a character goes into the RX buffer.

#define DOUPONELINE         "\033[1A"
#define BS                  0x08                    //ascii backspace
#define CR                  0x0d                    //ascii CR
#define LF                  0x0a                    //ascii LF
#define ticC                0x03                    //ascii control C
#define DEGC_DEGF_FLOAT     9.0 / 5.0 + 32.0

void PcRxChar(char inchar) {
    if(inchar == CR) pc.printf(" %c %c", BS, BS);   //NOTE: Bug in K64F has issue with CR and/or LF, these 2 lines are needed
    if(inchar == LF) pc.printf(" %c %c", BS, BS);
    if(inchar == BS) { 
        if(pcRxQty == 0) {
            pcRxBuffer[pcRxQty] = 0;
        } else {
            pc.printf("%c %c", BS, BS);
            pcRxQty--;
            pcRxBuffer[pcRxQty] = 0;
        }
    } else if((inchar == CR) || (inchar == LF)) { 
        pcRxLine = true;
        pc.printf("\r\n");
    } else if(inchar == ticC) {
        NVIC_SystemReset();
    } else {
        if(pcRxQty < (sizeof(pcRxBuffer) - 2)) {
            pcRxBuffer[pcRxQty] = inchar;
            pcRxQty++;
            pcRxBuffer[pcRxQty] = 0;
            pc.printf("%c", pcRxBuffer[pcRxQty - 1]);
        } else {
            pc.printf ("\r\n*** pcRxBuffer is full!!\r\n");
            pcRxEOB = true;
        }
    }
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Read received chars from USB UART interrupt

void PcRxIRQ(void){
/*
#if defined(TARGET_KL25Z)
    NVIC_DisableIRQ(UART0_IRQn);        // n=0, 1 or 2  Disable Rx interrupt on kl25z
#endif
#if defined(TARGET_K64F)
    NVIC_DisableIRQ(UART0_RX_TX_IRQn);  // n=0, 1 or 2  Disable Rx interrupt on k64f
#endif
#if defined(TARGET_LPC1768)
    LPC_UART0->IER = 0;                 //Disable Rx interrupt on mbed1768
#endif
*/
    while (pc.readable()) {
        inchar = pc.getc();             //read data from USB
        PcRxChar(inchar);               //go process char
    }
/*
#if defined(TARGET_KL25Z)
    NVIC_EnableIRQ(UART0_IRQn);         // n=0, 1 or 2  Re-enable Rx interrupt on kl25z
#endif
#if defined(TARGET_K64F)
    NVIC_EnableIRQ(UART0_RX_TX_IRQn);   // n=0, 1 or 2  Re-enable Rx interrupt on k64f
#endif
#if defined(TARGET_LPC1768)
    LPC_UART0->IER = 1;                 //RE-enable Rx interrupt on mbed1768
#endif
*/
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//clear RxData buffer with all 00's and clear flags

void pcClrLineBuf() {
    pcRxQty = 0;                                                            // data counter/pointer
    for(int i = 0; i < (sizeof(pcRxBuffer) - 1); i++) pcRxBuffer[i] = 0;    // clear out rx buffer
    pcRxLine = false;
    pcRxEOB = false;
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Update time display values

void UpdateTimeRegs() {
    strftime(timebuf_dMyy, 14, "%d-%b-%Y", localtime(&ctTime));
    strftime(timebuf_hms, 10, "%H:%M:%S", localtime(&ctTime));
    strftime(timebuf_dow, 1, "%u", localtime(&ctTime));
}

void UpdateTime() {
    ctTime = time(NULL) + ((TZone + DST) * 3600);   //timezone and dst offsets
    UpdateTimeRegs();
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// display current local date and time

void PrintDateTime() {
    pc.printf("%sDate: %s   ",  DOUPONELINE, timebuf_dMyy);
    pc.printf("Time: %s \r\n", timebuf_hms);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//Manually set the date and time

ds3232m::Time_rtc rtc_m = {};
struct tm t;

bool SetRTC() {
    pc.printf("Enter current date and time:\n");
    pc.printf("MM DD YY HH MM SS[enter]\n");  
    pcClrLineBuf(); 
     
    //wait for string above
    do{
#ifdef RTOS_H
        Thread::wait(10);
#else
        wait_ms(10);
#endif
    } while((pcRxLine == false) && (pcRxEOB == false));
    
    //load up the time structure
    t.tm_year = (2000 + ((pcRxBuffer[6] - '0') * 10) + pcRxBuffer[7] - '0');
    t.tm_mon =  (((pcRxBuffer[0] - '0') * 10) + pcRxBuffer[1] - '0');
    t.tm_mday = (((pcRxBuffer[3] - '0') * 10) + pcRxBuffer[4] - '0');
    t.tm_hour = (((pcRxBuffer[9] - '0') * 10) + pcRxBuffer[10] - '0');
    t.tm_min = (((pcRxBuffer[12] - '0') * 10) + pcRxBuffer[13] - '0');
    t.tm_sec = (((pcRxBuffer[15] - '0') * 10) + pcRxBuffer[16] - '0');
    
    //adjust for tm structure required values
    t.tm_year = t.tm_year - 1900;
    t.tm_mon = t.tm_mon - 1;  
    t.tm_wday = t.tm_wday & 7;
    
    //if error exists, exit without changing time
    if(t.tm_year < 113) return(32);
    if(t.tm_mon > 12) return(16); 
    if(t.tm_mday > 31) return(8);  
    if(t.tm_hour > 23) return(4); 
    if(t.tm_min > 59) return(2); 
    if(t.tm_sec > 59) return(1); 
    
    //set up the DS3232's RTC
    rtc_m.sec = t.tm_sec;
    rtc_m.min = t.tm_min;
    rtc_m.hour = t.tm_hour;
    rtc_m.wday = t.tm_wday;
    rtc_m.date = t.tm_mday;
    rtc_m.mon = t.tm_mon + 1;
    rtc_m.year = t.tm_year + 1900;
    rtc.setTime(rtc_m);    //(time structure)

    //set the mbed's time
    time_t ctTime = mktime(&t);
    //reset system up time since it will be out of whack once the time is updated
    StartTime = ctTime;                         //have to change sysuptime now
    ctTime = ctTime - (TZone + DST) * 3600;     //take out local time
    set_time(ctTime);
    UpdateTime();
    return(0);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Load the local mbed-RTC from that external DS3232 RTC

void loadRTC() {
    lockI2C();
    //get data from DS3232
    rtc.getTime(rtc_m);
    unlockI2C();
    t.tm_sec = rtc_m.sec;
    t.tm_min = rtc_m.min;
    t.tm_hour = rtc_m.hour;
    t.tm_mday = rtc_m.date;
    t.tm_mon = rtc_m.mon - 1;
    t.tm_year = rtc_m.year - 1900;
            
    //set the mbed's time
    time_t ctTime = mktime(&t);
    ctTime = ctTime - (TZone + DST) * 3600;     //take out local time
    set_time(ctTime);
    UpdateTime(); 
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Pull the temperature out of the DS3232 RTC

void Get3232Temp() {
    pc.printf("%c", BS);
    lockI2C();
    if(rtc.startTempCycle(rtc_m) == true) {
        unlockI2C();
        pc.printf(" - DS3232M start converstion ok \r\n");
    } else {
        unlockI2C();
        pc.printf(" - DS3232M start converstion BUSY!!! \r\n");
    }  
    //wait for DS3232 temperature conversion to finish
    int i = 80;
    for(i = 80; i > 0; i--) {
#ifdef RTOS_H
        Thread::wait(20);
#else
        wait_ms(20);
#endif
        lockI2C();
        if((rtc.checkTempBusy(rtc_m)) == true) break;
        unlockI2C();
    }
        
    //timed out or display temperature
    if(i > 0) {
        float ds3232tempC = rtc.getTemperature(rtc_m);
        unlockI2C();
#if (defined(TARGET_K64F) ||  defined(TARGET_DISCO_F746NG))
        pc.printf(" - DS3232M Temperature: %.2fC  %.1fF\r\n", (double)ds3232tempC, (double)ds3232tempC * DEGC_DEGF_FLOAT);
#else
        pc.printf(" - DS3232M Temperature: %.2fC  %.1fF\r\n", ds3232tempC, ds3232tempC * DEGC_DEGF_FLOAT);
#endif
    } else {
        unlockI2C();
        pc.printf("*** DS3232M Temperature timeout!!!!\r\n");
    }
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Checking for characters to execute commands from.  It's a thread if RTOS is used.

#ifdef RTOS_H
void cli_thread(void const *argument) {
    pc.printf(" - Starting CLI RTOS thread\r\n");
    while (true) {      //while loop only for RTOS
        Thread::wait(73);
#else
void cli_thread() {
#endif
        if(pcRxQty != 0) {
            pc.printf("\r\n");
            if(pcRxBuffer[0] == 'A') rtc.set32KhzOutput(rtc_m, true, false);   //turn on 32KHz output
            if(pcRxBuffer[0] == 'a') rtc.set32KhzOutput(rtc_m, false, false);  //turn off 32KHz output
            if(pcRxBuffer[0] == 'B') rtc.set1hzOutput(rtc_m, true, false);   //turn on 1Hz output
            if(pcRxBuffer[0] == 'b') rtc.set1hzOutput(rtc_m,false, false);  //turn off 1Hz output
            if(pcRxBuffer[0] == 'c') {
                allowDisplayTime = true;
                SetRTC();  //change DS3232 time
                allowDisplayTime = false;
                pcRxBuffer[0] = 'c';
            }
            uint8_t errorValue = 0;
            if(pcRxBuffer[0] == 'g') {  //get and display stored data string
                errorValue = rtc.getUserRAM(pcRxBuffer, rtc_m, 128, 124);
                if(errorValue) {
                    pc.printf("'Get' user RAM error: %d\r\n", errorValue);
                } else if(pcRxBuffer[0] == NULL) {
                    pc.printf("User RAM empty!!\r\n");
                } else {
                    //pcRxBuffer[31] = NULL;    //guarantee that the string max length is 32 bytes
                    pc.printf("%s\r\n", pcRxBuffer);
                }
                pcRxBuffer[0] = 'g';
                errorValue = 0;
            }
            if(pcRxBuffer[0] == 's') {  //save data string
                allowDisplayTime = true;
                pc.printf("Enter text string to save: ");
                pcClrLineBuf();
                do {
#ifdef RTOS_H
                    Thread::wait(20);
#else
                    wait_ms(20);
#endif
                } while((pcRxLine == false) && (pcRxEOB == false));
                lockI2C();
                errorValue = rtc.putUserRAM(pcRxBuffer, rtc_m, 128, pcRxQty + 2);
                unlockI2C();
                if(errorValue) pc.printf("'Put' user RAM error: %d\r\n", errorValue);
                allowDisplayTime = false;
                pcRxBuffer[0] = 's';
                errorValue = 0;
            }
            if(pcRxBuffer[0] == 't') Get3232Temp();  //display the DS3232's temperature
            if(pcRxBuffer[0] == 'z') {  
                lockI2C();
                rtc.LoadRTCRam(rtc_m);
                unlockI2C();
                pc.printf("CRC16 value: 0x%04X\r\n", rtc.calculateCRC16(pcRxBuffer, rtc_m, 0x14, 0xea));
            }
            if((pcRxBuffer[0] != 'a') && (pcRxBuffer[0] != 'A') && (pcRxBuffer[0] != 'b') 
                && (pcRxBuffer[0] != 'B') && (pcRxBuffer[0] != 'c') && (pcRxBuffer[0] != 'g') 
                && (pcRxBuffer[0] != 's') && (pcRxBuffer[0] != 't') && (pcRxBuffer[0] != 'z')) pc.printf("Entry Error!!\r\n");
            pc.printf("\r\n");
            pcClrLineBuf();
        }
#ifdef RTOS_H
    }   //RTOS while loop
#endif
}

//--------------------------------------------------------------------------------------------------------------------------------------//

int main() {
    pc.baud(230400);
    ctTime = time(NULL);
    StartTime = ctTime;                     //get time we started up
    pc.printf("\r\n\r\nDS3232M demo  Christmas-2014  K. Braun\r\n");
    
    //check for RTOS operation
#ifdef RTOS_H
    pc.printf("RTOS installed...\r\n");
#else
    pc.printf("not using RTOS...\r\n");
#endif

    //pc RX character callback interrupt
    pc.printf("Initializing Serial Port Rx Interrupt...   \r\n");
    pc.attach(&PcRxIRQ, pc.RxIrq);
    
    pc.printf("Checking the mbed's RTC...\r\n");
#ifdef RTOS_H
    Thread::wait(1500);
#else
    wait_ms(1500);
#endif

    ctTime = time(NULL);
    
    //first, see if K64F's RTC already running
    if((StartTime == ctTime) || (ctTime <= 1000000000)) {
        pc.printf("*** mbed's local RTC is not initialized\r\n");
        loadRTC();
        StartTime = ctTime;
        
        //now see if DS3232's clock needs to be set
        if(ctTime <= 1000000000) {
            pc.printf("*** Local RTC stopped, initializing the RTC.  !!CHECK BATTERY!!\r\n");
            pc.printf("*** Note: Time is incorrect, needs to be updated!!!\r\n");
            
            //set up the DS3232's clock
            if(SetRTC() != 0) pc.printf("Entry Error!!");
            pcClrLineBuf();
        }
    } 
    
    //sync up the mbed's time with the DS3232's time    
    loadRTC();
    StartTime = ctTime;
    pc.printf(" - RTC Start Time:   ");
    PrintDateTime();
    pc.printf(" - Day of Week: %s\r\n", timebuf_dow);  //day of the week
        
    //get the DS3232's temperature
    Get3232Temp();
    
#ifdef RTOS_H
    //turn on the rest of the os threads
    pc.printf("Initializing os threads...\r\n");
    Thread th3(cli_thread, NULL, osPriorityNormal);
    Thread::wait(300);
#endif
    
    int CheckTime = ctTime;
    pc.printf("Hit 'A' or 'a' - turn on/off the 32KHz output\r\n");
    pc.printf("Hit 'B' or 'b' - turn on/off the 1Hz output (1Hz pin needs pull-up)\r\n");
    pc.printf("Hit 'c' - change the date & time\r\n");
    pc.printf("Hit 'g' - get data string from DS3232 user RAM\r\n");
    pc.printf("Hit 's' - store data string in the DS3232 user RAM\r\n");
    pc.printf("Hit 't' - get DS3232's temperature\r\n");
    pc.printf("Hit 'z' - get user RAM CRC data\r\n");
    pc.printf("Hit '^C' - reboot\r\n");
    pc.printf("\r\n");
    
    //Ready!!
    while (true) {
#ifdef RTOS_H
        Thread::wait(50);
#else
        wait_ms(50);
#endif
        UpdateTime();
        if(CheckTime != ctTime) {
            CheckTime = ctTime;
            if(allowDisplayTime == false) PrintDateTime();
        }
#ifndef RTOS_H
        cli_thread();
#endif      
    }
}