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