1 /*!
2  * \file      rtc-board.c
3  *
4  * \brief     Target board RTC timer and low power modes management
5  *
6  * \copyright Revised BSD License, see section \ref LICENSE.
7  *
8  * \code
9  *                ______                              _
10  *               / _____)             _              | |
11  *              ( (____  _____ ____ _| |_ _____  ____| |__
12  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
13  *               _____) ) ____| | | || |_| ____( (___| | | |
14  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
15  *              (C)2013-2017 Semtech
16  *
17  * \endcode
18  *
19  * \author    Miguel Luis ( Semtech )
20  *
21  * \author    Gregory Cristian ( Semtech )
22  *
23  * \author    Marten Lootsma(TWTG) on behalf of Microchip/Atmel (c)2017
24  */
25 #include <hal_init.h>
26 #include <hw_timer.h>
27 #include "board-config.h"
28 #include "board.h"
29 #include "timer.h"
30 #include "systime.h"
31 #include "gpio.h"
32 
33 #include "rtc-board.h"
34 
35 #define RTC_DEBUG_ENABLE                            1
36 #define RTC_DEBUG_DISABLE                           0
37 
38 #define RTC_DEBUG_GPIO_STATE                        RTC_DEBUG_DISABLE
39 #define RTC_DEBUG_PRINTF_STATE                      RTC_DEBUG_DISABLE
40 
41 #define MIN_ALARM_DELAY                             3 // in ticks
42 
43 /*!
44  * \brief Indicates if the RTC is already Initialized or not
45  */
46 static bool RtcInitialized = false;
47 static volatile bool RtcTimeoutPendingInterrupt = false;
48 static volatile bool RtcTimeoutPendingPolling = false;
49 
50 typedef enum AlarmStates_e
51 {
52     ALARM_STOPPED = 0,
53     ALARM_RUNNING = !ALARM_STOPPED
54 } AlarmStates_t;
55 
56 /*!
57  * RTC timer context
58  */
59 typedef struct
60 {
61     uint32_t Time;  // Reference time
62     uint32_t Delay; // Reference Timeout duration
63     uint32_t AlarmState;
64 }RtcTimerContext_t;
65 
66 /*!
67  * Keep the value of the RTC timer when the RTC alarm is set
68  * Set with the \ref RtcSetTimerContext function
69  * Value is kept as a Reference to calculate alarm
70  */
71 static RtcTimerContext_t RtcTimerContext;
72 
73 #if( RTC_DEBUG_GPIO_STATE == RTC_DEBUG_ENABLE )
74 Gpio_t DbgRtcPin0;
75 Gpio_t DbgRtcPin1;
76 #endif
77 
78 /*!
79  * Used to store the Seconds and SubSeconds.
80  *
81  * WARNING: Temporary fix fix. Should use MCU NVM internal
82  *          registers
83  */
84 uint32_t RtcBkupRegisters[] = { 0, 0 };
85 
86 /*!
87  * \brief Callback for the hw_timer when alarm expired
88  */
89 static void RtcAlarmIrq( void );
90 
91 /*!
92  * \brief Callback for the hw_timer when counter overflows
93  */
94 static void RtcOverflowIrq( void );
95 
RtcInit(void)96 void RtcInit( void )
97 {
98     if( RtcInitialized == false )
99     {
100 #if( RTC_DEBUG_GPIO_STATE == RTC_DEBUG_ENABLE )
101         GpioInit( &DbgRtcPin0, RTC_DBG_PIN_0, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
102         GpioInit( &DbgRtcPin1, RTC_DBG_PIN_1, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
103 #endif
104         // RTC timer
105         HwTimerInit( );
106         HwTimerAlarmSetCallback( RtcAlarmIrq );
107         HwTimerOverflowSetCallback( RtcOverflowIrq );
108 
109         RtcTimerContext.AlarmState = ALARM_STOPPED;
110         RtcSetTimerContext( );
111         RtcInitialized = true;
112     }
113 }
114 
RtcSetTimerContext(void)115 uint32_t RtcSetTimerContext( void )
116 {
117     RtcTimerContext.Time = ( uint32_t )HwTimerGetTime( );
118     return ( uint32_t )RtcTimerContext.Time;
119 }
120 
RtcGetTimerContext(void)121 uint32_t RtcGetTimerContext( void )
122 {
123     return RtcTimerContext.Time;
124 }
125 
RtcGetMinimumTimeout(void)126 uint32_t RtcGetMinimumTimeout( void )
127 {
128     return( MIN_ALARM_DELAY );
129 }
130 
RtcMs2Tick(TimerTime_t milliseconds)131 uint32_t RtcMs2Tick( TimerTime_t milliseconds )
132 {
133     return ( uint32_t )( ( ( ( uint64_t )milliseconds ) << 10 ) / 1000 );
134 }
135 
RtcTick2Ms(uint32_t tick)136 TimerTime_t RtcTick2Ms( uint32_t tick )
137 {
138     uint32_t seconds = tick >> 10;
139 
140     tick = tick & 0x3FF;
141     return ( ( seconds * 1000 ) + ( ( tick * 1000 ) >> 10 ) );
142 }
143 
RtcDelayMs(TimerTime_t milliseconds)144 void RtcDelayMs( TimerTime_t milliseconds )
145 {
146     uint32_t delayTicks = 0;
147     uint32_t refTicks = RtcGetTimerValue( );
148 
149     delayTicks = RtcMs2Tick( milliseconds );
150 
151     // Wait delay ms
152     while( ( ( RtcGetTimerValue( ) - refTicks ) ) < delayTicks )
153     {
154         __NOP( );
155     }
156 }
157 
RtcSetAlarm(uint32_t timeout)158 void RtcSetAlarm( uint32_t timeout )
159 {
160     RtcStartAlarm( timeout );
161 }
162 
RtcStopAlarm(void)163 void RtcStopAlarm( void )
164 {
165     RtcTimerContext.AlarmState = ALARM_STOPPED;
166 }
167 
RtcStartAlarm(uint32_t timeout)168 void RtcStartAlarm( uint32_t timeout )
169 {
170     CRITICAL_SECTION_BEGIN( );
171 
172     RtcStopAlarm( );
173 
174     RtcTimerContext.Delay = timeout;
175 
176 #if( RTC_DEBUG_PRINTF_STATE == RTC_DEBUG_ENABLE )
177     printf( "TIMEOUT \t%010ld\t%010ld\n", RtcTimerContext.Time, RtcTimerContext.Delay );
178 #endif
179 #if( RTC_DEBUG_GPIO_STATE == RTC_DEBUG_ENABLE )
180     GpioWrite( &DbgRtcPin0, 0 );
181     GpioWrite( &DbgRtcPin1, 0 );
182 #endif
183 
184     RtcTimeoutPendingInterrupt = true;
185     RtcTimeoutPendingPolling = false;
186 
187     RtcTimerContext.AlarmState = ALARM_RUNNING;
188     if( HwTimerLoadAbsoluteTicks( RtcTimerContext.Time + RtcTimerContext.Delay ) == false )
189     {
190         // If timer already passed
191         if( RtcTimeoutPendingInterrupt == true )
192         {
193             // And interrupt not handled, mark as polling
194             RtcTimeoutPendingPolling = true;
195             RtcTimeoutPendingInterrupt = false;
196 #if( RTC_DEBUG_GPIO_STATE == RTC_DEBUG_ENABLE )
197             GpioWrite( &DbgRtcPin0, 1 );
198 #endif
199         }
200     }
201     CRITICAL_SECTION_END( );
202 }
203 
RtcGetTimerValue(void)204 uint32_t RtcGetTimerValue( void )
205 {
206     return ( uint32_t )HwTimerGetTime( );
207 }
208 
RtcGetTimerElapsedTime(void)209 uint32_t RtcGetTimerElapsedTime( void )
210 {
211     return ( uint32_t)( HwTimerGetTime( ) - RtcTimerContext.Time );
212 }
213 
RtcGetCalendarTime(uint16_t * milliseconds)214 uint32_t RtcGetCalendarTime( uint16_t *milliseconds )
215 {
216     uint32_t ticks = 0;
217 
218     uint32_t calendarValue = HwTimerGetTime( );
219 
220     uint32_t seconds = ( uint32_t )calendarValue >> 10;
221 
222     ticks =  ( uint32_t )calendarValue & 0x3FF;
223 
224     *milliseconds = RtcTick2Ms( ticks );
225 
226     return seconds;
227 }
228 
RtcBkupWrite(uint32_t data0,uint32_t data1)229 void RtcBkupWrite( uint32_t data0, uint32_t data1 )
230 {
231     CRITICAL_SECTION_BEGIN( );
232     RtcBkupRegisters[0] = data0;
233     RtcBkupRegisters[1] = data1;
234     CRITICAL_SECTION_END( );
235 }
236 
RtcBkupRead(uint32_t * data0,uint32_t * data1)237 void RtcBkupRead( uint32_t* data0, uint32_t* data1 )
238 {
239     CRITICAL_SECTION_BEGIN( );
240     *data0 = RtcBkupRegisters[0];
241     *data1 = RtcBkupRegisters[1];
242     CRITICAL_SECTION_END( );
243 }
244 
RtcProcess(void)245 void RtcProcess( void )
246 {
247     CRITICAL_SECTION_BEGIN( );
248 
249     if( (  RtcTimerContext.AlarmState == ALARM_RUNNING ) && ( RtcTimeoutPendingPolling == true ) )
250     {
251         if( RtcGetTimerElapsedTime( ) >= RtcTimerContext.Delay )
252         {
253             RtcTimerContext.AlarmState = ALARM_STOPPED;
254 
255             // Because of one shot the task will be removed after the callback
256             RtcTimeoutPendingPolling = false;
257 #if( RTC_DEBUG_GPIO_STATE == RTC_DEBUG_ENABLE )
258             GpioWrite( &DbgRtcPin0, 0 );
259             GpioWrite( &DbgRtcPin1, 1 );
260 #endif
261             // NOTE: The handler should take less then 1 ms otherwise the clock shifts
262             TimerIrqHandler( );
263 #if( RTC_DEBUG_GPIO_STATE == RTC_DEBUG_ENABLE )
264             GpioWrite( &DbgRtcPin1, 0 );
265 #endif
266         }
267     }
268     CRITICAL_SECTION_END( );
269 }
270 
RtcTempCompensation(TimerTime_t period,float temperature)271 TimerTime_t RtcTempCompensation( TimerTime_t period, float temperature )
272 {
273     return period;
274 }
275 
RtcAlarmIrq(void)276 static void RtcAlarmIrq( void )
277 {
278     RtcTimerContext.AlarmState = ALARM_STOPPED;
279     // Because of one shot the task will be removed after the callback
280     RtcTimeoutPendingInterrupt = false;
281 #if( RTC_DEBUG_GPIO_STATE == RTC_DEBUG_ENABLE )
282     GpioWrite( &DbgRtcPin1, 1 );
283 #endif
284     // NOTE: The handler should take less then 1 ms otherwise the clock shifts
285     TimerIrqHandler( );
286 #if( RTC_DEBUG_GPIO_STATE == RTC_DEBUG_ENABLE )
287     GpioWrite( &DbgRtcPin1, 0 );
288 #endif
289 }
290 
RtcOverflowIrq(void)291 static void RtcOverflowIrq( void )
292 {
293     //RtcTimerContext.Time += ( uint64_t )( 1 << 32 );
294 }
295