Bootload from SD card to sector 0, and jump to sector 24 where new firmware resides

Dependencies:   FatFS mbed

Fork of Panel-Controller-Bootloader by Emma

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers rtc.c Source File

rtc.c

00001 /*--------------------------------------------------------------------------  */
00002 /*  RTC controls for STM32                                                    */
00003 /*  Copyright (c) 2009, Martin Thomas 4/2009, 3BSD-license                    */
00004 /*  partly based on code from STMircoelectronics, Peter Dannegger, "LaLaDumm" */
00005 /*--------------------------------------------------------------------------  */
00006 
00007 #include <stdint.h>
00008 #include <stdbool.h>
00009 #include "stm32f10x.h"
00010 #include "rtc.h"
00011 
00012 #define FIRSTYEAR   2000        // start year
00013 #define FIRSTDAY    6           // 0 = Sunday
00014 
00015 static const uint8_t DaysInMonth[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00016 
00017 /*******************************************************************************
00018 * Function Name  : isDST
00019 * Description    : checks if given time is in Daylight Saving time-span.
00020 * Input          : time-struct, must be fully populated including weekday
00021 * Output         : none
00022 * Return         : false: no DST ("winter"), true: in DST ("summer")
00023 *  DST according to German standard
00024 *  Based on code from Peter Dannegger found in the microcontroller.net forum.
00025 *******************************************************************************/
00026 static bool isDST( const RTC_t *t )
00027 {
00028     uint8_t wday, month;        // locals for faster access
00029 
00030     month = t->month;
00031 
00032     if( month < 3 || month > 10 ) {     // month 1, 2, 11, 12
00033         return false;                   // -> Winter
00034     }
00035 
00036     wday  = t->wday;
00037 
00038     if( t->mday - wday >= 25 && (wday || t->hour >= 2) ) { // after last Sunday 2:00
00039         if( month == 10 ) {             // October -> Winter
00040             return false;
00041         }
00042     } else {                            // before last Sunday 2:00
00043         if( month == 3 ) {              // March -> Winter
00044             return false;
00045         }
00046     }
00047 
00048     return true;
00049 }
00050 
00051 /*******************************************************************************
00052 * Function Name  : adjustDST
00053 * Description    : adjusts time to DST if needed
00054 * Input          : non DST time-struct, must be fully populated including weekday
00055 * Output         : time-stuct gets modified
00056 * Return         : false: no DST ("winter"), true: in DST ("summer")
00057 *  DST according to German standard
00058 *  Based on code from Peter Dannegger found in the microcontroller.net forum.
00059 *******************************************************************************/
00060 static bool adjustDST( RTC_t *t )
00061 {
00062     uint8_t hour, day, wday, month;         // locals for faster access
00063 
00064     hour  = t->hour;
00065     day   = t->mday;
00066     wday  = t->wday;
00067     month = t->month;
00068 
00069     if ( isDST(t) ) {
00070         t->dst = 1;
00071         hour++;                             // add one hour
00072         if( hour == 24 ){                   // next day
00073             hour = 0;
00074             wday++;                         // next weekday
00075             if( wday == 7 ) {
00076                 wday = 0;
00077             }
00078             if( day == DaysInMonth[month-1] ) {     // next month
00079                 day = 0;
00080                 month++;
00081             }
00082             day++;
00083         }
00084         t->month = month;
00085         t->hour  = hour;
00086         t->mday  = day;
00087         t->wday  = wday;
00088         return true;
00089     } else {
00090         t->dst = 0;
00091         return false;
00092     }
00093 }
00094 
00095 /*******************************************************************************
00096 * Function Name  : counter_to_struct
00097 * Description    : populates time-struct based on counter-value
00098 * Input          : - counter-value (unit seconds, 0 -> 1.1.2000 00:00:00),
00099 *                  - Pointer to time-struct
00100 * Output         : time-struct gets populated, DST not taken into account here
00101 * Return         : none
00102 *  Based on code from Peter Dannegger found in the microcontroller.net forum.
00103 *******************************************************************************/
00104 static void counter_to_struct( uint32_t sec, RTC_t *t )
00105 {
00106     uint16_t day;
00107     uint8_t year;
00108     uint16_t dayofyear;
00109     uint8_t leap400;
00110     uint8_t month;
00111 
00112     t->sec = sec % 60;
00113     sec /= 60;
00114     t->min = sec % 60;
00115     sec /= 60;
00116     t->hour = sec % 24;
00117     day = (uint16_t)(sec / 24);
00118 
00119     t->wday = (day + FIRSTDAY) % 7;     // weekday
00120 
00121     year = FIRSTYEAR % 100;             // 0..99
00122     leap400 = 4 - ((FIRSTYEAR - 1) / 100 & 3);  // 4, 3, 2, 1
00123 
00124     for(;;) {
00125         dayofyear = 365;
00126         if( (year & 3) == 0 ) {
00127             dayofyear = 366;                    // leap year
00128             if( year == 0 || year == 100 || year == 200 ) { // 100 year exception
00129                 if( --leap400 ) {                   // 400 year exception
00130                     dayofyear = 365;
00131                 }
00132             }
00133         }
00134         if( day < dayofyear ) {
00135             break;
00136         }
00137         day -= dayofyear;
00138         year++;                 // 00..136 / 99..235
00139     }
00140     t->year = year + FIRSTYEAR / 100 * 100; // + century
00141 
00142     if( dayofyear & 1 && day > 58 ) {   // no leap year and after 28.2.
00143         day++;                  // skip 29.2.
00144     }
00145 
00146     for( month = 1; day >= DaysInMonth[month-1]; month++ ) {
00147         day -= DaysInMonth[month-1];
00148     }
00149 
00150     t->month = month;               // 1..12
00151     t->mday = day + 1;              // 1..31
00152 }
00153 
00154 /*******************************************************************************
00155 * Function Name  : struct_to_counter
00156 * Description    : calculates second-counter from populated time-struct
00157 * Input          : Pointer to time-struct
00158 * Output         : none
00159 * Return         : counter-value (unit seconds, 0 -> 1.1.2000 00:00:00),
00160 *  Based on code from "LalaDumm" found in the microcontroller.net forum.
00161 *******************************************************************************/
00162 static uint32_t struct_to_counter( const RTC_t *t )
00163 {
00164     uint8_t i;
00165     uint32_t result = 0;
00166     uint16_t idx, year;
00167 
00168     year = t->year;
00169 
00170     /* Calculate days of years before */
00171     result = (uint32_t)year * 365;
00172     if (t->year >= 1) {
00173         result += (year + 3) / 4;
00174         result -= (year - 1) / 100;
00175         result += (year - 1) / 400;
00176     }
00177 
00178     /* Start with 2000 a.d. */
00179     result -= 730485UL;
00180 
00181     /* Make month an array index */
00182     idx = t->month - 1;
00183 
00184     /* Loop thru each month, adding the days */
00185     for (i = 0; i < idx; i++) {
00186         result += DaysInMonth[i];
00187     }
00188 
00189     /* Leap year? adjust February */
00190     if (year%400 == 0 || (year%4 == 0 && year%100 !=0)) {
00191         ;
00192     } else {
00193         if (t->month > 1) {
00194             result--;
00195         }
00196     }
00197 
00198     /* Add remaining days */
00199     result += t->mday;
00200 
00201     /* Convert to seconds, add all the other stuff */
00202     result = (result-1) * 86400L + (uint32_t)t->hour * 3600 +
00203         (uint32_t)t->min * 60 + t->sec;
00204 
00205     return result;
00206 }
00207 
00208 /*******************************************************************************
00209 * Function Name  : rtc_gettime
00210 * Description    : populates structure from HW-RTC, takes DST into account
00211 * Input          : None
00212 * Output         : time-struct gets modified
00213 * Return         : always true/not used
00214 *******************************************************************************/
00215 bool rtc_gettime (RTC_t *rtc)
00216 {
00217     uint32_t t;
00218 
00219     while ( ( t = RTC_GetCounter() ) != RTC_GetCounter() ) { ; }
00220     counter_to_struct( t, rtc ); // get non DST time
00221     adjustDST( rtc );
00222 
00223     return true;
00224 }
00225 
00226 /*******************************************************************************
00227 * Function Name  : my_RTC_SetCounter
00228 * Description    : sets the hardware-counter
00229 * Input          : new counter-value
00230 * Output         : None
00231 * Return         : None
00232 *******************************************************************************/
00233 static void my_RTC_SetCounter(uint32_t cnt)
00234 {
00235     /* Wait until last write operation on RTC registers has finished */
00236     RTC_WaitForLastTask();
00237     /* Change the current time */
00238     RTC_SetCounter(cnt);
00239     /* Wait until last write operation on RTC registers has finished */
00240     RTC_WaitForLastTask();
00241 }
00242 
00243 /*******************************************************************************
00244 * Function Name  : rtc_settime
00245 * Description    : sets HW-RTC with values from time-struct, takes DST into
00246 *                  account, HW-RTC always running in non-DST time
00247 * Input          : None
00248 * Output         : None
00249 * Return         : not used
00250 *******************************************************************************/
00251 bool rtc_settime (const RTC_t *rtc)
00252 {
00253     uint32_t cnt;
00254     RTC_t ts;
00255 
00256     cnt = struct_to_counter( rtc ); // non-DST counter-value
00257     counter_to_struct( cnt, &ts );  // normalize struct (for weekday)
00258     if ( isDST( &ts ) ) {
00259         cnt -= 60*60; // Subtract one hour
00260     }
00261     PWR_BackupAccessCmd(ENABLE);
00262     my_RTC_SetCounter( cnt );
00263     PWR_BackupAccessCmd(DISABLE);
00264 
00265     return true;
00266 }
00267 
00268 /*******************************************************************************
00269 * Function Name  : rtc_init
00270 * Description    : initializes HW RTC,
00271 *                  sets default time-stamp if RTC has not been initialized before
00272 * Input          : None
00273 * Output         : None
00274 * Return         : not used
00275 *  Based on code from a STM RTC example in the StdPeriph-Library package
00276 *******************************************************************************/
00277 int rtc_init(void)
00278 {
00279     volatile uint16_t i;
00280 
00281     /* Enable PWR and BKP clocks */
00282     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
00283 
00284     /* LSI clock stabilization time */
00285     for(i=0;i<5000;i++) { ; }
00286 
00287     if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) {
00288         /* Backup data register value is not correct or not yet programmed (when
00289            the first time the program is executed) */
00290 
00291         /* Allow access to BKP Domain */
00292         PWR_BackupAccessCmd(ENABLE);
00293 
00294         /* Reset Backup Domain */
00295         BKP_DeInit();
00296 
00297         /* Enable LSE */
00298         RCC_LSEConfig(RCC_LSE_ON);
00299 
00300         /* Wait till LSE is ready */
00301         while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) { ; }
00302 
00303         /* Select LSE as RTC Clock Source */
00304         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
00305 
00306         /* Enable RTC Clock */
00307         RCC_RTCCLKCmd(ENABLE);
00308 
00309         /* Wait for RTC registers synchronization */
00310         RTC_WaitForSynchro();
00311 
00312         /* Wait until last write operation on RTC registers has finished */
00313         RTC_WaitForLastTask();
00314 
00315         /* Set RTC prescaler: set RTC period to 1sec */
00316         RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
00317 
00318         /* Wait until last write operation on RTC registers has finished */
00319         RTC_WaitForLastTask();
00320 
00321         /* Set initial value */
00322         RTC_SetCounter( (uint32_t)((11*60+55)*60) ); // here: 1st January 2000 11:55:00
00323 
00324         /* Wait until last write operation on RTC registers has finished */
00325         RTC_WaitForLastTask();
00326 
00327         BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
00328 
00329         /* Lock access to BKP Domain */
00330         PWR_BackupAccessCmd(DISABLE);
00331 
00332     } else {
00333 
00334         /* Wait for RTC registers synchronization */
00335         RTC_WaitForSynchro();
00336 
00337     }
00338 
00339     return 0;
00340 }
00341 
00342 
00343