SAMV71 Xplained Ultra Software Package 1.5

main.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
00028 /* ---------------------------------------------------------------------------- */
00029 
00030 /**
00031  * \page rtc RTC Example
00032  *
00033  * \section Purpose
00034  *
00035  * This basic example shows how to use the Real-Time Clock (RTC) peripheral
00036  * available on the Atmel SAMV7/E7 microcontrollers. The RTC enables easy
00037  * time and date management and allows the user to monitor events like a
00038  * configurable alarm, second change, calendar change, and so on.
00039  *
00040  * \section Requirements
00041  *
00042  * This package can be used with SAMV71 Xplained Ultra board or SAME70 Xplained board.
00043  *
00044  * \section Description
00045  *
00046  * Upon startup, the program displays the currently set time and date
00047  * and a menu to perform the following:
00048  *     \code
00049  *     Menu:
00050  *        t - Set time
00051  *        d - Set date
00052  *        i - Set time alarm
00053  *        m - Set date alarm
00054  *        c - Clear the alarm notification (only if it has been triggered)
00055  *     \endcode
00056  *
00057  * Setting the time, date and time alarm is done by using Menu option "t", "d",
00058  * the display is updated accordingly.
00059  *
00060  * The time alarm is triggered only when the second, minute and hour match the
00061  * pre-set values; the date alarm is triggered only when the month and date
00062  * match the pre-set values. If both time alarm and date alarm are set, only
00063  * when the second, minute, hour, month and date match the pre-set values,
00064  * the alarm will be triggered.
00065  *
00066  * \section Usage
00067  *
00068  *  -# Build the program and download it inside the board.
00069  *     Please refer to the Getting Started with SAM V71/E70 Microcontrollers.pdf
00070  * -# On the computer, open and configure a terminal application
00071  *    (e.g. HyperTerminal on Microsoft Windows) with these settings:
00072  *   - 115200 baud rate
00073  *   - 8 bits of data
00074  *   - No parity
00075  *   - 1 stop bit
00076  *   - No flow control
00077  * -# Start the application.
00078  * -# In the terminal window, the following text should appear:
00079  *    \code
00080  *     -- RTC Example xxx --
00081  *     -- xxxxxx-xx
00082  *     -- Compiled: xxx xx xxxx xx:xx:xx --
00083  *
00084  *     Menu:
00085  *     t - Set time
00086  *     d - Set date
00087  *     i - Set time alarm
00088  *     m - Set date alarm
00089  *     q - Quit
00090  *    \endcode
00091  * -# Press one of the keys listed in the menu to perform the corresponding action.
00092  *
00093  * \section References
00094  * - rtc/main.c
00095  * - rtc.c
00096  * - rtc.h
00097 */
00098 
00099 /**
00100  * \file
00101  *
00102  * This file contains all the specific code for the rtc example.
00103  */
00104 
00105 /*----------------------------------------------------------------------------
00106  *        Headers
00107  *----------------------------------------------------------------------------*/
00108 
00109 #include "board.h"
00110 
00111 #include <stdint.h>
00112 #include <stdio.h>
00113 #include <stdarg.h>
00114 
00115 /*----------------------------------------------------------------------------
00116  *        Local definitions
00117  *----------------------------------------------------------------------------*/
00118 
00119 /** Main menu is being displayed. */
00120 #define STATE_MENU              0
00121 /** Time is being edited. */
00122 #define STATE_SET_TIME          1
00123 /** Date is being edited. */
00124 #define STATE_SET_DATE          2
00125 /** Time alarm is being edited. */
00126 #define STATE_SET_TIME_ALARM    3
00127 /** Date alarm is being edited. */
00128 #define STATE_SET_DATE_ALARM    4
00129 
00130 /** Maximum size of edited string */
00131 #define MAX_EDIT_SIZE       10
00132 
00133 /** Macro for check digit character */
00134 #define IsDigitChar(c) ((c) >= '0' && (c) <='9')
00135 /** Macro for converting char to digit */
00136 #define CharToDigit(c) ((c) - '0')
00137 
00138 /*----------------------------------------------------------------------------
00139  *        Local variables
00140  *----------------------------------------------------------------------------*/
00141 volatile uint16_t Temperature = 0;
00142 volatile uint32_t CountDownTimer = 0;
00143 /** Current state of application. */
00144 static unsigned int bState = STATE_MENU;
00145 
00146 /** Edited hour. */
00147 static unsigned char newHour;
00148 /** Edited minute. */
00149 static unsigned char newMinute;
00150 /** Edited second. */
00151 static unsigned char newSecond;
00152 
00153 /** Edited year. */
00154 static unsigned short newYear;
00155 /** Edited month. */
00156 static unsigned char newMonth;
00157 /** Edited day. */
00158 static unsigned char newDay;
00159 /** Edited day-of-the-week. */
00160 static unsigned char newWeek;
00161 
00162 /** Indicates if alarm has been triggered and not yet cleared. */
00163 static unsigned char alarmTriggered = 0;
00164 
00165 /** store time string */
00166 static char rtc_time[8+1] = {'0', '0', ':', '0', '0', ':', '0', '0','\0'};
00167 /** store date string */
00168 static char date[10+1] = {'0', '0', '/', '0', '0', '/', '0', '0', '0', '0', '\0'};
00169 /** week string */
00170 static char pDayNames[7][4] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
00171 /** console erase sequence */
00172 static char pEraseSeq[] = "\b \b";
00173 /** output format string buffer */
00174 static char calendar[80];
00175 /** identify refreshing menu */
00176 static unsigned int bMenuShown = 0;
00177 
00178 /*----------------------------------------------------------------------------
00179  *        Local functions
00180  *----------------------------------------------------------------------------*/
00181 /**
00182  * \brief Print a formatted string into a buffer.
00183  */
00184 static signed int _PrnToBuf(char *pBuf, const char *pFormat, ...)
00185 {
00186     va_list ap;
00187     signed int rc;
00188 
00189     va_start(ap, pFormat);
00190     rc = vsprintf( pBuf, pFormat, ap);
00191     va_end(ap);
00192 
00193     return rc;
00194 }
00195 
00196 /**
00197  * \brief Get new time, successful value is put in newHour, newMinute, newSecond.
00198  */
00199 static int _GetNewTime(void)
00200 {
00201     char ucKey;
00202     int i = 0;
00203 
00204     /* clear setting variable */
00205     newHour = newMinute = newSecond = 0xFF;
00206 
00207     /* use time[] as a format template */
00208     while (1) {
00209         ucKey = DBG_GetChar();
00210 
00211         /* end input */
00212         if (ucKey == 0x0d || ucKey == 0x0a) {
00213             puts("\n\r");
00214             break;
00215         }
00216 
00217         /* DEL or BACKSPACE */
00218         if (ucKey == 0x7f || ucKey == 0x08) {
00219             if (i > 0) {
00220                 /* end of time[], index then one more back */
00221                 if (!rtc_time[i]) {
00222                     --i;
00223                 }
00224 
00225                 puts(pEraseSeq);
00226                 --i;
00227 
00228                 /* delimiter ':' for time is uneditable */
00229                 if (!IsDigitChar(rtc_time[i]) && i > 0) {
00230                     puts(pEraseSeq);
00231                     --i;
00232                 }
00233             }
00234         }
00235 
00236         /* end of time[], no more input except above DEL/BS or enter to end */
00237         if (!rtc_time[i]) {
00238             continue;
00239         }
00240 
00241         if (!IsDigitChar(ucKey)) {
00242             continue;
00243         }
00244 
00245         DBG_PutChar(ucKey);
00246         rtc_time[i++] = ucKey;
00247 
00248         /* ignore non digit position if not end */
00249         if (!IsDigitChar(rtc_time[i]) && i < 8) {
00250             DBG_PutChar(rtc_time[i]);
00251             ++i;
00252         }
00253     }
00254 
00255     if (i == 0)
00256         return 0;
00257 
00258     if (i != 0 && rtc_time[i] != '\0')
00259         return 1; /* failure input */
00260 
00261     newHour = CharToDigit(rtc_time[0]) * 10 + CharToDigit(rtc_time[1]);
00262     newMinute = CharToDigit(rtc_time[3]) * 10 + CharToDigit(rtc_time[4]);
00263     newSecond = CharToDigit(rtc_time[6]) * 10 + CharToDigit(rtc_time[7]);
00264 
00265     /* verification of data is left to RTC internal Error Checking */
00266     return 0;
00267 }
00268 
00269 /**
00270  * \brief Calculate week from year, month,day.
00271  */
00272 static char _CalcWeek(int year, int month, int day)
00273 {
00274     char week;
00275 
00276     if (month == 1 || month == 2) {
00277         month += 12;
00278         --year;
00279     }
00280 
00281     week = (day + 2 * month + 3 * (month + 1 ) / 5 + year + year / 4 -
00282             year / 100 + year / 400) % 7;
00283     ++week;
00284 
00285     return week;
00286 }
00287 
00288 /**
00289  * \brief Get new time, successful value is put in newYear, newMonth, newDay,
00290  * newWeek.
00291  */
00292 static int _GetNewDate(void)
00293 {
00294     char ucKey;
00295     int i=0;
00296 
00297     /* clear setting variable */
00298     newYear = 0xFFFF;
00299     newMonth = newDay = newWeek = 0xFF;
00300 
00301     /* use time[] as a format template */
00302     while (1) {
00303         ucKey = DBG_GetChar();
00304 
00305         /* end input */
00306         if (ucKey == 0x0d || ucKey == 0x0a) {
00307             puts( "\n\r" );
00308             break;
00309         }
00310         /* DEL or BACKSPACE */
00311         if (ucKey == 0x7f || ucKey == 0x08) {
00312             if (i > 0) {
00313                 /* end of date[], index then one more back */
00314                 if (!date[i]) {
00315                     --i;
00316                 }
00317 
00318                 puts(pEraseSeq);
00319                 --i;
00320 
00321                 /* delimiter '/' for date is uneditable */
00322                 if (!IsDigitChar( date[i] ) && i > 0) {
00323                     puts(pEraseSeq);
00324                     --i;
00325                 }
00326             }
00327         }
00328 
00329         /* end of time[], no more input except above DEL/BS or enter to end */
00330         if (!date[i])
00331             continue;
00332 
00333         if (!IsDigitChar(ucKey))
00334             continue;
00335 
00336         DBG_PutChar(ucKey);
00337         date[i++] = ucKey;
00338 
00339         /* ignore non digit position */
00340         if (!IsDigitChar(date[i]) && i < 10) {
00341             DBG_PutChar(date[i]);
00342             ++i;
00343         }
00344     }
00345 
00346     if (i == 0)
00347         return 0;
00348 
00349     if (i != 0 && date[i] != '\0' && i != 6)
00350         return 1; /* failure input */
00351 
00352     /* MM-DD-YY */
00353     newMonth = CharToDigit(date[0]) * 10 + CharToDigit(date[1]);
00354     newDay = CharToDigit(date[3] ) * 10 + CharToDigit(date[4]);
00355     if (i != 6) {
00356         /* not scenario of getting mm/dd/ only for alarm */
00357         newYear = CharToDigit(date[6]) * 1000 + CharToDigit(date[7]) * 100 +
00358             CharToDigit(date[8]) * 10 + CharToDigit(date[9]);
00359         newWeek = _CalcWeek(newYear, newMonth, newDay);
00360     }
00361 
00362     /* verification of data is left to RTC internal Error Checking */
00363     return 0;
00364 }
00365 
00366 /**
00367  *  Interrupt handler for TC0 interrupt.
00368  */
00369 void TC0_Handler(void)
00370 {
00371     volatile uint32_t dummy;
00372     /* Clear status bit to acknowledge interrupt */
00373     dummy = TC0->TC_CHANNEL[ 0 ].TC_SR;
00374     // Recalibrate at every 1 minute
00375     if (CountDownTimer >= 240) {
00376         RTC_ClockCalibration(RTC, Temperature);
00377         TRACE_INFO("RTC has been re-calibrated \n\r");
00378         CountDownTimer = 0;
00379     }
00380     CountDownTimer++;
00381 }
00382 
00383 /**
00384  * \brief Displays the user interface on the terminal.
00385  */
00386 static void _RefreshDisplay(void)
00387 {
00388     unsigned char hour, minute, second;
00389     unsigned short year;
00390     unsigned char month, day, week;
00391 
00392     if (bState != STATE_MENU) {
00393         /* not in menu display mode, in set mode */
00394     } else {
00395         /* Retrieve date and time */
00396         RTC_GetTime(RTC, &hour, &minute, &second);
00397         RTC_GetDate(RTC, &year, &month, &day, &week);
00398 
00399         /* display */
00400         if (!bMenuShown) {
00401             printf("\n\rMenu:\n\r" );
00402             printf("  t - Set time\n\r" );
00403             printf("  d - Set date\n\r" );
00404             printf("  i - Set time alarm\n\r" );
00405             printf("  m - Set date alarm\n\r" );
00406             printf("  p - PPM calibration of RTC\n\r" );
00407 
00408             if (alarmTriggered)
00409                 printf("  c - Clear alarm notification\n\r");
00410 
00411             printf("  q - Quit!\n\r" );
00412             printf("\n\r" );
00413             bMenuShown = 1;
00414         }
00415 
00416         /* update current date and time */
00417         _PrnToBuf(rtc_time, "%02d:%02d:%02d", hour, minute, second);
00418         _PrnToBuf(date, "%02d/%02d/%04d", month, day, year);
00419         _PrnToBuf(calendar, " [Time/Date: %s, %s %s ][Alarm status:%s]",
00420                 rtc_time, date, pDayNames[week-1], alarmTriggered?"Triggered!":"" );
00421         printf("\r%s", calendar);
00422     }
00423 }
00424 
00425 /**
00426  * \brief Interrupt handler for the RTC. Refreshes the display.
00427  */
00428 void RTC_Handler(void)
00429 {
00430     uint32_t dwStatus = RTC->RTC_SR;
00431 
00432     /* Second increment interrupt */
00433     if ((dwStatus & RTC_SR_SEC) == RTC_SR_SEC) {
00434         /* Disable RTC interrupt */
00435         RTC_DisableIt(RTC, RTC_IDR_SECDIS);
00436 
00437         _RefreshDisplay();
00438 
00439         RTC->RTC_SCCR = RTC_SCCR_SECCLR;
00440 
00441         RTC_EnableIt(RTC, RTC_IER_SECEN);
00442     }
00443     /* Time or date alarm */
00444     else {
00445         if ((dwStatus & RTC_SR_ALARM) == RTC_SR_ALARM) {
00446             /* Disable RTC interrupt */
00447             RTC_DisableIt(RTC, RTC_IDR_ALRDIS);
00448 
00449             alarmTriggered = 1;
00450             _RefreshDisplay();
00451             bMenuShown = 0; /* shown additional menu item for clear notification */
00452             RTC->RTC_SCCR = RTC_SCCR_ALRCLR;
00453 
00454             RTC_EnableIt(RTC, RTC_IER_ALREN);
00455         }
00456     }
00457 }
00458 
00459 /**
00460  *  Configure Timer Counter 0 to generate an interrupt every 250ms.
00461  */
00462 static void _ConfigureTc(void)
00463 {
00464     uint32_t div;
00465     uint32_t tcclks;
00466 
00467     /** Enable peripheral clock. */
00468     PMC_EnablePeripheral(ID_TC0);
00469 
00470     /** Configure TC for a 4Hz frequency and trigger on RC compare. */
00471     TC_FindMckDivisor(4, BOARD_MCK/2, &div, &tcclks, BOARD_MCK);
00472     TC_Configure(TC0, 0, tcclks | TC_CMR_CPCTRG);
00473     TC0->TC_CHANNEL[0].TC_RC = (BOARD_MCK / div) / 4;
00474 
00475     /* Configure and enable interrupt on RC compare */
00476     NVIC_ClearPendingIRQ(TC0_IRQn);
00477     NVIC_EnableIRQ(TC0_IRQn);
00478 
00479     NVIC_SetPriority(TC0_IRQn ,2);
00480     TC0->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;
00481 
00482     TC_Start(TC0, 0);
00483 
00484 }
00485 
00486 /*----------------------------------------------------------------------------
00487  *         Global functions
00488  *----------------------------------------------------------------------------*/
00489 
00490 /**
00491  * \brief Application entry point for RTC example.
00492  *
00493  * \return Unused (ANSI-C compatibility).
00494  */
00495 
00496 extern int main(void)
00497 {
00498     uint8_t ucKey;
00499 
00500     /* Disable watchdog */
00501     WDT_Disable(WDT);
00502 
00503     /* Enable I and D cache */
00504     SCB_EnableICache();
00505     SCB_EnableDCache();
00506 
00507     /* Output example information */
00508     printf("\n\r\n\r\n\r");
00509     printf("-- RTC Example %s --\n\r", SOFTPACK_VERSION);
00510     printf("-- %s\n\r", BOARD_NAME);
00511     printf("-- Compiled: %s %s With %s--\n\r", __DATE__, __TIME__, COMPILER_NAME);
00512 
00513      printf("Configure TC.\n\r");
00514     _ConfigureTc();
00515     //put 25  as a default temp, if there is no temperature sensor
00516     Temperature = 25;
00517 
00518     /* Default RTC configuration */
00519     RTC_SetHourMode(RTC, 0); /* 24-hour mode */
00520     if (RTC_SetTimeAlarm(RTC, 0, 0, 0)) {
00521         printf("\n\r Disable time alarm fail!");
00522     }
00523 
00524     if (RTC_SetDateAlarm(RTC, 0, 0)) {
00525         printf("\n\r Disable date alarm fail!");
00526     }
00527 
00528     /* Configure RTC interrupts */
00529     NVIC_DisableIRQ(RTC_IRQn);
00530     NVIC_ClearPendingIRQ(RTC_IRQn);
00531     NVIC_SetPriority(RTC_IRQn, 0);
00532     NVIC_EnableIRQ(RTC_IRQn);
00533     RTC_EnableIt(RTC, RTC_IER_SECEN | RTC_IER_ALREN);
00534 
00535     /* Refresh display once */
00536     _RefreshDisplay();
00537     newHour = 0;
00538     newMinute = 0;
00539     newSecond = 30;
00540     RTC_SetTimeAlarm(RTC, &newHour, &newMinute, &newSecond);
00541     bMenuShown = 0;
00542     alarmTriggered = 0;
00543     RTC_ClockCalibration(RTC, Temperature);
00544 
00545     /* Handle key presses */
00546     while ( 1 ) {
00547         ucKey = DBG_GetChar();
00548 
00549         /* set time */
00550         if (ucKey == 't') {
00551             bState = STATE_SET_TIME;
00552 
00553             do {
00554                 printf("\n\r\n\r Set time(hh:mm:ss): ");
00555             } while (_GetNewTime());
00556 
00557             /* if valid input, none of variable for time is 0xff */
00558             if (newHour != 0xFF) {
00559                 if (RTC_SetTime(RTC, newHour, newMinute, newSecond)) {
00560                     printf("\n\r Time not set, invalid input!\n\r");
00561                 }
00562             }
00563 
00564             bState = STATE_MENU;
00565             bMenuShown = 0;
00566             _RefreshDisplay();
00567             CountDownTimer = 0;
00568         }
00569 
00570         if (ucKey == 'p') {
00571             RTC_ClockCalibration(RTC, 30);
00572             bState = STATE_MENU;
00573             bMenuShown = 0;
00574             _RefreshDisplay();
00575         }
00576 
00577         /* set date */
00578         if (ucKey == 'd') {
00579             bState = STATE_SET_DATE;
00580 
00581             do {
00582                 printf("\n\r\n\r Set date(mm/dd/yyyy): ");
00583             } while (_GetNewDate());
00584 
00585             /* if valid input, none of variable for date is 0xff(ff) */
00586             if (newYear !=0xFFFF) {
00587                 if (RTC_SetDate(RTC, newYear, newMonth, newDay, newWeek)) {
00588                     printf("\n\r Date not set, invalid input!\n\r");
00589                 }
00590             }
00591 
00592             /* only 'mm/dd' input */
00593             if (newMonth != 0xFF && newYear == 0xFFFF) {
00594                 printf("\n\r Not Set for no year field!\n\r");
00595             }
00596 
00597             bState = STATE_MENU;
00598             bMenuShown = 0;
00599             CountDownTimer = 0;
00600             _RefreshDisplay();
00601         }
00602 
00603 
00604         /* set time alarm */
00605         if (ucKey == 'i') {
00606             bState = STATE_SET_TIME_ALARM;
00607 
00608             do {
00609                 printf("\n\r\n\r Set time alarm(hh:mm:ss): ");
00610             } while (_GetNewTime());
00611 
00612             if (newHour != 0xFF) {
00613                 if (RTC_SetTimeAlarm(RTC, &newHour, &newMinute, &newSecond)) {
00614                     printf("\n\r Time alarm not set, invalid input!\n\r");
00615                 } else {
00616                     printf("\n\r Time alarm is set at %02d:%02d:%02d!",
00617                             newHour, newMinute, newSecond);
00618                 }
00619             }
00620             bState = STATE_MENU;
00621             bMenuShown = 0;
00622             alarmTriggered = 0;
00623             CountDownTimer = 0;
00624             _RefreshDisplay();
00625         }
00626 
00627         /* set date alarm */
00628         if (ucKey == 'm') {
00629             bState = STATE_SET_DATE_ALARM;
00630 
00631             do {
00632                 printf("\n\r\n\r Set date alarm(mm/dd/): ");
00633             } while (_GetNewDate());
00634 
00635             if ( newYear == 0xFFFF && newMonth != 0xFF) {
00636                 if (RTC_SetDateAlarm(RTC, &newMonth, &newDay)) {
00637                     printf("\n\r Date alarm not set, invalid input!\n\r");
00638                 } else {
00639                     printf("\n\r Date alarm is set on %02d/%02d!",
00640                             newMonth, newDay);
00641                 }
00642 
00643             }
00644             bState = STATE_MENU;
00645             bMenuShown = 0;
00646             alarmTriggered = 0;
00647             CountDownTimer = 0;
00648             _RefreshDisplay();
00649         }
00650 
00651         /* clear trigger flag */
00652         if (ucKey == 'c') {
00653             alarmTriggered = 0;
00654             bMenuShown = 0;
00655             _RefreshDisplay();
00656         }
00657 
00658         /* quit */
00659         if (ucKey == 'q') {
00660             break;
00661         }
00662     }
00663 
00664     return 0;
00665 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines