/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include "ch.h"
#include "hal.h"
/*===========================================================================*/
/* Notes. */
/*===========================================================================*/
/*
This structure is used to hold the values representing a calendar time.
It contains the following members, with the meanings as shown.
int tm_sec seconds after minute [0-61] (61 allows for 2 leap-seconds)
int tm_min minutes after hour [0-59]
int tm_hour hours after midnight [0-23]
int tm_mday day of the month [1-31]
int tm_mon month of year [0-11]
int tm_year current year-1900
int tm_wday days since Sunday [0-6]
int tm_yday days since January 1st [0-365]
int tm_isdst daylight savings indicator (1 = yes, 0 = no, -1 = unknown)
*/
RTCTime timespec;
RTCAlarm alarmspec;
RTCWakeup wakeupspec;
RTCCallbackConfig cb_cfg;
time_t unix_time;
/**
* Alarms callback
*/
static inline void exti_rtcalarm_cb(EXTDriver *extp, expchannel_t channel){
(void)extp;
(void)channel;
if (RTCD1.id_rtc->ISR | RTC_ISR_ALRBF){
RTCD1.id_rtc->ISR &= ~RTC_ISR_ALRBF;
}
if (RTCD1.id_rtc->ISR | RTC_ISR_ALRAF){
RTCD1.id_rtc->ISR &= ~RTC_ISR_ALRAF;
}
palTogglePad(GPIOB, GPIOB_LED_R);
}
/**
* Periodic wakeup callback
*/
static inline void exti_rtcwakeup_cb(EXTDriver *extp, expchannel_t channel){
(void)extp;
(void)channel;
/* manually clear flags because exti driver does not do that */
if (RTCD1.id_rtc->ISR | RTC_ISR_WUTF){
RTCD1.id_rtc->ISR &= ~RTC_ISR_WUTF;
}
palTogglePad(GPIOB, GPIOB_LED_B);
palTogglePad(GPIOB, GPIOB_LED_R);
}
static const EXTConfig extcfg = {
{
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART, exti_rtcalarm_cb},/* RTC alarms */
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},/* timestamp */
{EXT_CH_MODE_RISING_EDGE| EXT_CH_MODE_AUTOSTART, exti_rtcwakeup_cb},/* wakeup */
},
EXT_MODE_EXTI(
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0)/* 15 */
};
/**
* Convert from STM32 BCD to classical format.
*/
void bcd2tm(struct tm *timp, uint32_t tv_time, uint32_t tv_date){
timp->tm_isdst = -1;
timp->tm_wday = ((tv_date >> 13) & 0x7);
if(timp->tm_wday == 7)
timp->tm_wday = 0;
timp->tm_mday = (tv_date & 0xF) + ((tv_date >> 4) & 0x3) * 10;
timp->tm_mon = (((tv_date >> 8) & 0xF) + ((tv_date >> 12) & 0x1) * 10) - 1;
timp->tm_year = (((tv_date >> 16)& 0xF) + ((tv_date >> 20) & 0xF) * 10) + 2000 - 1900;
timp->tm_sec = (tv_time & 0xF) + ((tv_time >> 4) & 0x7) * 10;
timp->tm_min = ((tv_time >> 8)& 0xF) + ((tv_time >> 12) & 0x7) * 10;
timp->tm_hour = ((tv_time >> 16)& 0xF) + ((tv_time >> 20) & 0x3) * 10;
}
/**
* Convert from classical format to STM32 BCD
*/
void tm2bcd(struct tm *timp, RTCTime *timespec){
uint32_t v = 0;
timespec->tv_date = 0;
timespec->tv_time = 0;
v = timp->tm_year - 100;
timespec->tv_date |= (((v / 10) & 0xF) << 20) | ((v % 10) << 16);
if (timp->tm_wday == 0)
v = 7;
else
v = timp->tm_wday;
timespec->tv_date |= (v & 7) << 13;
v = timp->tm_mon + 1;
timespec->tv_date |= (((v / 10) & 1) << 12) | ((v % 10) << 8);
v = timp->tm_mday;
timespec->tv_date |= (((v / 10) & 3) << 4) | (v % 10);
v = timp->tm_hour;
timespec->tv_time |= (((v / 10) & 3) << 20) | ((v % 10) << 16);
v = timp->tm_min;
timespec->tv_time |= (((v / 10) & 7) << 12) | ((v % 10) << 8);
v = timp->tm_sec;
timespec->tv_time |= (((v / 10) & 7) << 4) | (v % 10);
}
/**
* Main function.
*/
int main(void){
struct tm timp;
halInit();
chSysInit();
extStart(&EXTD1, &extcfg);
/* tune wakeup callback */
wakeupspec.wakeup = ((uint32_t)4) << 16; /* select 1 Hz clock source */
wakeupspec.wakeup |= 3; /* set counter value to 3. Period will be 3+1 seconds. */
rtcSetWakeup(&RTCD1, &wakeupspec);
/* enable wakeup callback */
cb_cfg.cb_cfg = WAKEUP_CB_FLAG;
rtcSetCallback(&RTCD1, &cb_cfg);
/* get current time in unix format */
rtcGetTime(&RTCD1, ×pec);
bcd2tm(&timp, timespec.tv_time, timespec.tv_date);
unix_time = mktime(&timp);
if (unix_time == -1){/* incorrect time in RTC cell */
unix_time = 1000000000;
}
/* set correct time */
tm2bcd((localtime(&unix_time)), ×pec);
rtcSetTime(&RTCD1, ×pec);
while (TRUE){
rtcGetTime(&RTCD1, ×pec);
bcd2tm(&timp, timespec.tv_time, timespec.tv_date);
unix_time = mktime(&timp);
chThdSleepMilliseconds(1500);
}
return 0;
}