1 | #include <avr/io.h>
|
2 | #include <util/atomic.h>
|
3 | #include <util/delay.h>
|
4 | #include <avr/interrupt.h>
|
5 | #include "avr_compiler.h"
|
6 |
|
7 |
|
8 | /*! \brief CCP write helper function written in assembly.
|
9 | *
|
10 | * This function is written in assembly because of the timecritial
|
11 | * operation of writing to the registers.
|
12 | *
|
13 | * \param address A pointer to the address to write to.
|
14 | * \param value The value to put in to the register.
|
15 | */
|
16 | void CCPWrite( volatile uint8_t * address, uint8_t value )
|
17 | {
|
18 | volatile uint8_t * tmpAddr = address;
|
19 |
|
20 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
21 | {
|
22 | #ifdef RAMPZ
|
23 | RAMPZ = 0;
|
24 | #endif
|
25 | asm volatile(
|
26 | "movw r30, %0" "\n\t"
|
27 | "ldi r16, %2" "\n\t"
|
28 | "out %3, r16" "\n\t"
|
29 | "st Z, %1" "\n\t"
|
30 | :
|
31 | : "r" (tmpAddr), "r" (value), "M" (CCP_IOREG_gc), "i" (&CCP)
|
32 | : "r16", "r30", "r31"
|
33 | );
|
34 | }
|
35 | }
|
36 |
|
37 | /**
|
38 | * \internal
|
39 | * \brief Check if RTC32 is busy synchronizing
|
40 | *
|
41 | * \retval true Is busy
|
42 | * \retval false Is ready
|
43 | */
|
44 | uint8_t rtc32_is_busy(void)
|
45 | {
|
46 | return RTC32.SYNCCTRL & RTC32_SYNCBUSY_bm;
|
47 | }
|
48 |
|
49 | ISR(RTC32_OVF_vect)
|
50 | {
|
51 | /* Toggle status led */
|
52 | PORTR.DIRTGL = PIN0_bm;
|
53 | }
|
54 |
|
55 |
|
56 | int main(void)
|
57 | {
|
58 | /* Apply a resetr of the VBAT */
|
59 | VBAT.CTRL |= VBAT_ACCEN_bm;
|
60 |
|
61 | /* Set access enable bit */
|
62 | CCPWrite((void *)&VBAT.CTRL, VBAT_RESET_bm);
|
63 |
|
64 | /* Enable 32.768kHz crystal oscillator */
|
65 | VBAT.CTRL |= VBAT_XOSCEN_bm | VBAT_XOSCSEL_bm;
|
66 |
|
67 | /* Wait until oscillator is stable */
|
68 | while(!(VBAT.STATUS & VBAT_XOSCRDY_bm));
|
69 |
|
70 | /* Enable low power mode for external oscillator */
|
71 | OSC.XOSCCTRL = OSC_X32KLPM_bm;
|
72 |
|
73 | /* Reset RTC32 module */
|
74 | RTC32.CTRL = 0;
|
75 |
|
76 | /* Wait until sync done */
|
77 | while(rtc32_is_busy());
|
78 |
|
79 | /* Set PER to 1024. CLK source of the RTC32 is 1024 ticks / second = 1 Hz */
|
80 | RTC32.PER = 1024;
|
81 |
|
82 | /* Reset CNT register */
|
83 | RTC32.CNT = 0;
|
84 |
|
85 | /* Wait until sync done */
|
86 | while(rtc32_is_busy());
|
87 |
|
88 | /* Enable overflow interrupts */
|
89 | RTC32.INTCTRL = RTC32_OVFINTLVL_MED_gc;
|
90 |
|
91 | /* Enable real time module */
|
92 | RTC32.CTRL = RTC32_ENABLE_bm;
|
93 |
|
94 | /* Wait until sync done */
|
95 | while(rtc32_is_busy());
|
96 |
|
97 | /* Set port C pin 7 as output */
|
98 | PORTC.DIRSET = PIN7_bm;
|
99 |
|
100 | /* Enable medium priority interrupts */
|
101 | PMIC.CTRL = PMIC_MEDLVLEN_bm;
|
102 |
|
103 | /* Set sleep mode and enable sleep */
|
104 | SLEEP.CTRL = SLEEP_SMODE_PSAVE_gc | SLEEP_SEN_bm;
|
105 |
|
106 | /* Enable global interrupts */
|
107 | sei();
|
108 |
|
109 | while(1)
|
110 | {
|
111 | /* Go sleeping */
|
112 | asm("sleep");
|
113 | }
|
114 | }
|