1 /*******************************************************************************
\r
2 * (c) Copyright 2008-2013 Microsemi SoC Products Group. All rights reserved.
\r
4 * SmartFusion2 MSS RTC bare metal driver implementation.
\r
6 * SVN $Revision: 5090 $
\r
7 * SVN $Date: 2013-02-18 12:13:31 +0000 (Mon, 18 Feb 2013) $
\r
10 #include "../../CMSIS/mss_assert.h"
\r
17 /*-------------------------------------------------------------------------*//**
\r
18 * CONTROL_REG register masks.
\r
20 #define CONTROL_RUNNING_MASK 0x00000001u
\r
22 #define CONTROL_RTC_START_MASK 0x00000001u
\r
23 #define CONTROL_RTC_STOP_MASK 0x00000002u
\r
24 #define CONTROL_ALARM_ON_MASK 0x00000004u
\r
25 #define CONTROL_ALARM_OFF_MASK 0x00000008u
\r
26 #define CONTROL_RESET_MASK 0x00000010u
\r
27 #define CONTROL_UPLOAD_MASK 0x00000020u
\r
28 #define CONTROL_WAKEUP_CLR_MASK 0x00000100u
\r
29 #define CONTROL_UPDATED_MASK 0x00000400u
\r
31 /*-------------------------------------------------------------------------*//**
\r
32 * MODE_REG register masks.
\r
34 #define MODE_CLK_MODE_MASK 0x00000001u
\r
35 #define MODE_WAKEUP_EN_MASK 0x00000002u
\r
36 #define MODE_WAKEUP_RESET_MASK 0x00000004u
\r
37 #define MODE_WAKEUP_CONTINUE_MASK 0x00000008u
\r
39 /*-------------------------------------------------------------------------*//**
\r
42 #define MAX_BINARY_HIGHER_COUNT 0x7FFu
\r
43 #define MASK_32_BIT 0xFFFFFFFFu
\r
44 #define MAX_PRESCALAR_COUNT 0x03FFFFFFu
\r
45 #define CALENDAR_SHIFT 8u
\r
47 #define COMPARE_ALL_BITS 0xFFFFFFFFu
\r
49 #define SYSREG_RTC_WAKEUP_M3_EN_MASK 0x00000001u
\r
51 /*-------------------------------------------------------------------------*//**
\r
52 * Index into look-up table.
\r
63 /*-------------------------------------------------------------------------*//**
\r
72 static void set_rtc_mode(uint8_t requested_mode);
\r
74 static void add_alarm_cfg_values
\r
76 uint8_t calendar_item,
\r
77 uint32_t * p_calendar_value,
\r
78 uint32_t * p_compare_mask
\r
82 /*-------------------------------------------------------------------------*//**
\r
83 * See "mss_rtc.h" for details of how to use this function.
\r
92 ASSERT(prescaler <= MAX_PRESCALAR_COUNT);
\r
94 if(prescaler <= MAX_PRESCALAR_COUNT)
\r
99 /* Disable alarm. */
\r
100 RTC->CONTROL_REG = CONTROL_ALARM_OFF_MASK;
\r
102 /* Disable Interrupt */
\r
103 MSS_RTC_disable_irq();
\r
104 NVIC_ClearPendingIRQ(RTC_Wakeup_IRQn);
\r
106 /* Clear RTC wake up interrupt signal */
\r
107 MSS_RTC_clear_irq();
\r
109 /* Enable the RTC to interrupt the Cortex-M3. */
\r
110 SYSREG->RTC_WAKEUP_CR |= SYSREG_RTC_WAKEUP_M3_EN_MASK;
\r
112 /* Select mode of operation, including the wake configuration. */
\r
113 if(MSS_RTC_CALENDAR_MODE == mode)
\r
115 RTC->MODE_REG = MODE_CLK_MODE_MASK;
\r
119 RTC->MODE_REG = 0u;
\r
122 /* Reset the alarm and compare registers to a known value. */
\r
123 RTC->ALARM_LOWER_REG = 0u;
\r
124 RTC->ALARM_UPPER_REG = 0u;
\r
125 RTC->COMPARE_LOWER_REG = 0u;
\r
126 RTC->COMPARE_UPPER_REG = 0u;
\r
128 /* Reset the calendar counters */
\r
129 MSS_RTC_reset_counter();
\r
131 /* Set new Prescaler value */
\r
132 RTC->PRESCALER_REG = prescaler;
\r
136 /*-------------------------------------------------------------------------*//**
\r
137 See "mss_rtc.h" for details of how to use this function.
\r
140 MSS_RTC_set_calendar_count
\r
142 const mss_rtc_calendar_t *new_rtc_value
\r
145 uint8_t error = 0u;
\r
146 uint8_t clock_mode;
\r
148 const uint8_t g_rtc_max_count_lut[] =
\r
150 /* Calendar mode */
\r
161 const uint8_t g_rtc_min_count_lut[] =
\r
163 /* Calendar mode */
\r
174 /* Assert if the values cross the limit */
\r
175 ASSERT(new_rtc_value->second >= g_rtc_min_count_lut[SECONDS]);
\r
176 ASSERT(new_rtc_value->second <= g_rtc_max_count_lut[SECONDS]);
\r
177 ASSERT(new_rtc_value->minute >= g_rtc_min_count_lut[MINUTES]);
\r
178 ASSERT(new_rtc_value->minute <= g_rtc_max_count_lut[MINUTES]);
\r
179 ASSERT(new_rtc_value->hour >= g_rtc_min_count_lut[HOURS]);
\r
180 ASSERT(new_rtc_value->hour <= g_rtc_max_count_lut[HOURS]);
\r
181 ASSERT(new_rtc_value->day >= g_rtc_min_count_lut[DAYS]);
\r
182 ASSERT(new_rtc_value->day <= g_rtc_max_count_lut[DAYS]);
\r
183 ASSERT(new_rtc_value->month >= g_rtc_min_count_lut[MONTHS]);
\r
184 ASSERT(new_rtc_value->month <= g_rtc_max_count_lut[MONTHS]);
\r
185 ASSERT(new_rtc_value->year >= g_rtc_min_count_lut[YEARS]);
\r
186 ASSERT(new_rtc_value->year <= g_rtc_max_count_lut[YEARS]);
\r
187 ASSERT(new_rtc_value->weekday >= g_rtc_min_count_lut[WEEKDAYS]);
\r
188 ASSERT(new_rtc_value->weekday <= g_rtc_max_count_lut[WEEKDAYS]);
\r
189 ASSERT(new_rtc_value->week >= g_rtc_min_count_lut[WEEKS]);
\r
190 ASSERT(new_rtc_value->week <= g_rtc_max_count_lut[WEEKS]);
\r
192 if(new_rtc_value->second < g_rtc_min_count_lut[SECONDS]) {error = 1u;}
\r
193 if(new_rtc_value->second > g_rtc_max_count_lut[SECONDS]) {error = 1u;}
\r
194 if(new_rtc_value->minute < g_rtc_min_count_lut[MINUTES]) {error = 1u;}
\r
195 if(new_rtc_value->minute > g_rtc_max_count_lut[MINUTES]) {error = 1u;}
\r
196 if(new_rtc_value->hour < g_rtc_min_count_lut[HOURS]) {error = 1u;}
\r
197 if(new_rtc_value->hour > g_rtc_max_count_lut[HOURS]) {error = 1u;}
\r
198 if(new_rtc_value->day < g_rtc_min_count_lut[DAYS]) {error = 1u;}
\r
199 if(new_rtc_value->day > g_rtc_max_count_lut[DAYS]) {error = 1u;}
\r
200 if(new_rtc_value->month < g_rtc_min_count_lut[MONTHS]) {error = 1u;}
\r
201 if(new_rtc_value->month > g_rtc_max_count_lut[MONTHS]) {error = 1u;}
\r
202 if(new_rtc_value->year < g_rtc_min_count_lut[YEARS]) {error = 1u;}
\r
203 if(new_rtc_value->year > g_rtc_max_count_lut[YEARS]) {error = 1u;}
\r
204 if(new_rtc_value->weekday < g_rtc_min_count_lut[WEEKDAYS]) {error = 1u;}
\r
205 if(new_rtc_value->weekday > g_rtc_max_count_lut[WEEKDAYS]) {error = 1u;}
\r
206 if(new_rtc_value->week < g_rtc_min_count_lut[WEEKS]) {error = 1u;}
\r
207 if(new_rtc_value->week > g_rtc_max_count_lut[WEEKS]) {error = 1u;}
\r
210 * This function can only be used when the RTC is configured to operate in
\r
211 * calendar counter mode.
\r
213 clock_mode = get_clock_mode();
\r
214 ASSERT(MSS_RTC_CALENDAR_MODE == clock_mode);
\r
216 if((0u == error) && (MSS_RTC_CALENDAR_MODE == clock_mode))
\r
218 uint32_t upload_in_progress;
\r
221 * Write the RTC new value.
\r
223 RTC->SECONDS_REG = new_rtc_value->second;
\r
224 RTC->MINUTES_REG = new_rtc_value->minute;
\r
225 RTC->HOURS_REG = new_rtc_value->hour;
\r
226 RTC->DAY_REG = new_rtc_value->day;
\r
227 RTC->MONTH_REG = new_rtc_value->month;
\r
228 RTC->YEAR_REG = new_rtc_value->year;
\r
229 RTC->WEEKDAY_REG = new_rtc_value->weekday;
\r
230 RTC->WEEK_REG = new_rtc_value->week;
\r
232 /* Data is copied, now issue upload command */
\r
233 RTC->CONTROL_REG = CONTROL_UPLOAD_MASK ;
\r
235 /* Wait for the upload to complete. */
\r
237 upload_in_progress = RTC->CONTROL_REG & CONTROL_UPLOAD_MASK;
\r
238 } while(upload_in_progress);
\r
242 /*-------------------------------------------------------------------------*//**
\r
243 * See "mss_rtc.h" for details of how to use this function.
\r
246 MSS_RTC_set_binary_count
\r
248 uint64_t new_rtc_value
\r
251 uint8_t clock_mode;
\r
254 * This function can only be used when the RTC is configured to operate in
\r
255 * binary counter mode.
\r
257 clock_mode = get_clock_mode();
\r
258 ASSERT(MSS_RTC_BINARY_MODE == clock_mode);
\r
260 if(MSS_RTC_BINARY_MODE == clock_mode)
\r
262 uint32_t rtc_upper_32_bit_value;
\r
264 rtc_upper_32_bit_value = (uint32_t)(new_rtc_value >> 32u) & MASK_32_BIT;
\r
266 /* Assert if the values cross the limit */
\r
267 ASSERT(rtc_upper_32_bit_value <= MAX_BINARY_HIGHER_COUNT);
\r
269 if(rtc_upper_32_bit_value <= MAX_BINARY_HIGHER_COUNT)
\r
271 uint32_t upload_in_progress;
\r
274 * Write the RTC new value.
\r
276 RTC->DATE_TIME_LOWER_REG = (uint32_t)new_rtc_value;
\r
277 RTC->DATE_TIME_UPPER_REG =
\r
278 (uint32_t)(( new_rtc_value >> 32u) & MAX_BINARY_HIGHER_COUNT);
\r
280 /* Data is copied, now issue upload command */
\r
281 RTC->CONTROL_REG = CONTROL_UPLOAD_MASK;
\r
283 /* Wait for the upload to complete. */
\r
285 upload_in_progress = RTC->CONTROL_REG & CONTROL_UPLOAD_MASK;
\r
286 } while(upload_in_progress);
\r
291 /*-------------------------------------------------------------------------*//**
\r
292 * See "mss_rtc.h" for details of how to use this function.
\r
295 MSS_RTC_get_calendar_count
\r
297 mss_rtc_calendar_t *p_rtc_calendar
\r
300 uint8_t clock_mode;
\r
302 * This function can only be used when the RTC is configured to operate in
\r
303 * calendar counter mode.
\r
305 clock_mode = get_clock_mode();
\r
306 ASSERT(MSS_RTC_CALENDAR_MODE == clock_mode);
\r
308 if(MSS_RTC_CALENDAR_MODE == clock_mode)
\r
310 p_rtc_calendar->second = (uint8_t)RTC->SECONDS_REG;
\r
311 p_rtc_calendar->minute = (uint8_t)RTC->MINUTES_REG;
\r
312 p_rtc_calendar->hour = (uint8_t)RTC->HOURS_REG;
\r
313 p_rtc_calendar->day = (uint8_t)RTC->DAY_REG;
\r
314 p_rtc_calendar->month = (uint8_t)RTC->MONTH_REG;
\r
315 p_rtc_calendar->year = (uint8_t)RTC->YEAR_REG;
\r
316 p_rtc_calendar->weekday = (uint8_t)RTC->WEEKDAY_REG;
\r
317 p_rtc_calendar->week = (uint8_t)RTC->WEEK_REG;
\r
322 * Set returned calendar count to zero if the RTC is not configured for
\r
323 * calendar counter mode. This should make incorrect release application
\r
324 * code behave consistently and help application debugging.
\r
326 memset(p_rtc_calendar, 0, sizeof(mss_rtc_calendar_t));
\r
330 /*-------------------------------------------------------------------------*//**
\r
331 * See "mss_rtc.h" for details of how to use this function.
\r
334 MSS_RTC_get_binary_count
\r
339 uint64_t rtc_count;
\r
340 uint8_t clock_mode;
\r
343 * This function can only be used when the RTC is configured to operate in
\r
344 * binary counter mode.
\r
346 clock_mode = get_clock_mode();
\r
347 ASSERT(MSS_RTC_BINARY_MODE == clock_mode);
\r
349 if(MSS_RTC_BINARY_MODE == clock_mode)
\r
351 rtc_count = RTC->DATE_TIME_LOWER_REG;
\r
352 rtc_count = rtc_count | ((uint64_t)RTC->DATE_TIME_UPPER_REG << 32u) ;
\r
357 * Set returned binary count to zero if the RTC is not configured for
\r
358 * binary counter mode. This should make incorrect release application
\r
359 * code behave consistently and help application debugging.
\r
367 /*-------------------------------------------------------------------------*//**
\r
370 static void add_alarm_cfg_values
\r
372 uint8_t calendar_item,
\r
373 uint32_t * p_calendar_value,
\r
374 uint32_t * p_compare_mask
\r
378 if(MSS_RTC_CALENDAR_DONT_CARE == calendar_item)
\r
380 *p_calendar_value = (uint32_t)(*p_calendar_value << CALENDAR_SHIFT);
\r
381 *p_compare_mask = (uint32_t)(*p_compare_mask << CALENDAR_SHIFT);
\r
385 *p_calendar_value = (uint32_t)((*p_calendar_value << CALENDAR_SHIFT) | (uint32_t)calendar_item);
\r
386 *p_compare_mask = (uint32_t)((*p_compare_mask << CALENDAR_SHIFT) | (uint32_t)0xFFu);
\r
390 /*-------------------------------------------------------------------------*//**
\r
391 * See "mss_rtc.h" for details of how to use this function.
\r
393 void MSS_RTC_set_calendar_count_alarm
\r
395 const mss_rtc_calendar_t * alarm_value
\r
398 uint32_t calendar_value;
\r
399 uint32_t compare_mask;
\r
402 mode = (uint8_t)(RTC->MODE_REG & MODE_CLK_MODE_MASK);
\r
404 * This function can only be used with the RTC set to operate in calendar
\r
407 ASSERT(MSS_RTC_CALENDAR_MODE == mode);
\r
408 if(MSS_RTC_CALENDAR_MODE == mode)
\r
410 uint8_t required_mode_reg;
\r
412 /* Disable the alarm before updating*/
\r
413 RTC->CONTROL_REG = CONTROL_ALARM_OFF_MASK;
\r
415 /* Set alarm and compare lower registers. */
\r
416 calendar_value = 0u;
\r
419 add_alarm_cfg_values(alarm_value->day, &calendar_value, &compare_mask);
\r
420 add_alarm_cfg_values(alarm_value->hour, &calendar_value, &compare_mask);
\r
421 add_alarm_cfg_values(alarm_value->minute, &calendar_value, &compare_mask);
\r
422 add_alarm_cfg_values(alarm_value->second, &calendar_value, &compare_mask);
\r
424 RTC->ALARM_LOWER_REG = calendar_value;
\r
425 RTC->COMPARE_LOWER_REG = compare_mask;
\r
427 /* Set alarm and compare upper registers. */
\r
428 calendar_value = 0u;
\r
431 add_alarm_cfg_values(alarm_value->week, &calendar_value, &compare_mask);
\r
432 add_alarm_cfg_values(alarm_value->weekday, &calendar_value, &compare_mask);
\r
433 add_alarm_cfg_values(alarm_value->year, &calendar_value, &compare_mask);
\r
434 add_alarm_cfg_values(alarm_value->month, &calendar_value, &compare_mask);
\r
436 RTC->ALARM_UPPER_REG = calendar_value;
\r
437 RTC->COMPARE_UPPER_REG = compare_mask;
\r
439 /* Configure the RTC to enable the alarm. */
\r
440 required_mode_reg = mode | MODE_WAKEUP_EN_MASK | MODE_WAKEUP_CONTINUE_MASK;
\r
441 set_rtc_mode(required_mode_reg);
\r
443 /* Enable the alarm */
\r
444 RTC->CONTROL_REG = CONTROL_ALARM_ON_MASK ;
\r
448 /*-------------------------------------------------------------------------*//**
\r
449 We only write the RTC mode register if really required because the RTC needs
\r
450 to be stopped for the mode register to be written. Stopping the RTC everytime
\r
451 the wakeup alarm configuration is set might induce drift on the RTC time.
\r
452 This function is intended to be used when setting alarms.
\r
454 static void set_rtc_mode(uint8_t requested_mode)
\r
456 if(RTC->MODE_REG != requested_mode)
\r
458 uint32_t rtc_running;
\r
459 rtc_running = RTC->CONTROL_REG & CONTROL_RUNNING_MASK;
\r
462 /* Stop the RTC in order to change the mode register content.*/
\r
464 RTC->MODE_REG = requested_mode;
\r
469 RTC->MODE_REG = requested_mode;
\r
474 /*-------------------------------------------------------------------------*//**
\r
475 * See "mss_rtc.h" for details of how to use this function.
\r
477 void MSS_RTC_set_binary_count_alarm
\r
479 uint64_t alarm_value,
\r
480 mss_rtc_alarm_type_t alarm_type
\r
485 mode = (uint8_t)(RTC->MODE_REG & MODE_CLK_MODE_MASK);
\r
487 * This function can only be used with the RTC set to operate in binary
\r
490 ASSERT(MSS_RTC_BINARY_MODE == mode);
\r
491 if(MSS_RTC_BINARY_MODE == mode)
\r
493 uint8_t required_mode_reg;
\r
495 /* Disable the alarm before updating*/
\r
496 RTC->CONTROL_REG = CONTROL_ALARM_OFF_MASK;
\r
498 /* Set the alarm value. */
\r
499 RTC->COMPARE_LOWER_REG = COMPARE_ALL_BITS;
\r
500 RTC->COMPARE_UPPER_REG = COMPARE_ALL_BITS;
\r
501 RTC->ALARM_LOWER_REG = (uint32_t)alarm_value;
\r
502 RTC->ALARM_UPPER_REG = (uint32_t)(alarm_value >> 32u);
\r
505 * Configure the RTC to enable the alarm.
\r
507 required_mode_reg = mode | MODE_WAKEUP_EN_MASK | MODE_WAKEUP_CONTINUE_MASK;
\r
508 if(MSS_RTC_PERIODIC_ALARM == alarm_type)
\r
511 * The RTC binary counter will be fully reset when the alarm occurs.
\r
512 * The counter will continue counting while the wake-up interrupt is
\r
515 required_mode_reg |= MODE_WAKEUP_RESET_MASK;
\r
517 set_rtc_mode(required_mode_reg);
\r
519 /* Enable the alarm */
\r
520 RTC->CONTROL_REG = CONTROL_ALARM_ON_MASK;
\r
524 /*-------------------------------------------------------------------------*//**
\r
525 * See "mss_rtc.h" for details of how to use this function.
\r
533 RTC->CONTROL_REG = CONTROL_RTC_START_MASK;
\r
536 /*-------------------------------------------------------------------------*//**
\r
537 * See "mss_rtc.h" for details of how to use this function.
\r
545 uint32_t rtc_running;
\r
548 * Send command to stop RTC.
\r
550 RTC->CONTROL_REG = CONTROL_RTC_STOP_MASK;
\r
553 * Wait for RTC internal synchronization to take place and RTC to actually
\r
557 rtc_running = RTC->CONTROL_REG & CONTROL_RUNNING_MASK;
\r
558 } while(rtc_running);
\r
561 /*-------------------------------------------------------------------------*//**
\r
562 See "mss_rtc.h" for details of how to use this function.
\r
565 MSS_RTC_reset_counter
\r
570 uint32_t upload_in_progress;
\r
572 RTC->CONTROL_REG = CONTROL_RESET_MASK;
\r
574 /* Wait for the upload to complete. */
\r
576 upload_in_progress = RTC->CONTROL_REG & CONTROL_UPLOAD_MASK;
\r
577 } while(upload_in_progress);
\r
580 /*-------------------------------------------------------------------------*//**
\r
581 See "mss_rtc.h" for details of how to use this function.
\r
583 uint32_t MSS_RTC_get_update_flag(void)
\r
586 updated = RTC->CONTROL_REG & CONTROL_UPDATED_MASK;
\r
590 /*-------------------------------------------------------------------------*//**
\r
591 See "mss_rtc.h" for details of how to use this function.
\r
593 void MSS_RTC_clear_update_flag(void)
\r
595 /* Clear the "updated" control bit. */
\r
596 RTC->CONTROL_REG = CONTROL_UPDATED_MASK;
\r
599 /*-------------------------------------------------------------------------*//**
\r
600 See "mss_rtc.h" for details of how to use this function.
\r
602 void MSS_RTC_enable_irq(void)
\r
605 * Only the NVIC level interrupt enable is performed within this function.
\r
606 * The RTC level interrupt enable is performed within the alarm setting
\r
608 * This avoid the MODE register being modified whenever Cortex-M3 RTC
\r
609 * interrupts are enabled/disabled.
\r
611 NVIC_EnableIRQ(RTC_Wakeup_IRQn);
\r
614 /*-------------------------------------------------------------------------*//**
\r
615 See "mss_rtc.h" for details of how to use this function.
\r
618 MSS_RTC_disable_irq
\r
624 * Only the NVIC level interrupt disable is performed within this function.
\r
625 * This avoid the MODE register being modified whenever Cortex-M3 RTC
\r
626 * interrupts are enabled/disabled.
\r
628 NVIC_DisableIRQ(RTC_Wakeup_IRQn);
\r
631 /*-------------------------------------------------------------------------*//**
\r
632 * See "mss_rtc.h" for details of how to use this function.
\r
640 /* Clear wake up interrupt signal */
\r
641 RTC->CONTROL_REG = CONTROL_WAKEUP_CLR_MASK;
\r
644 /*-------------------------------------------------------------------------*//**
\r
645 The get_clock_mode() function gets the clock mode of RTC hardware.
\r
646 Possible clock modes are:
\r
647 MSS_RTC_CALENDAR_MODE
\r
648 MSS_RTC_BINARY_MODE
\r
656 uint8_t clock_mode;
\r
658 clock_mode = (uint8_t)(RTC->MODE_REG & MODE_CLK_MODE_MASK);
\r
660 return(clock_mode);
\r