1 /*******************************************************************************
2 * @file  rsi_timers.h
3  *******************************************************************************
4  * # License
5  * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
6  *******************************************************************************
7  *
8  * SPDX-License-Identifier: Zlib
9  *
10  * The licensor of this software is Silicon Laboratories Inc.
11  *
12  * This software is provided 'as-is', without any express or implied
13  * warranty. In no event will the authors be held liable for any damages
14  * arising from the use of this software.
15  *
16  * Permission is granted to anyone to use this software for any purpose,
17  * including commercial applications, and to alter it and redistribute it
18  * freely, subject to the following restrictions:
19  *
20  * 1. The origin of this software must not be misrepresented; you must not
21  *    claim that you wrote the original software. If you use this software
22  *    in a product, an acknowledgment in the product documentation would be
23  *    appreciated but is not required.
24  * 2. Altered source versions must be plainly marked as such, and must not be
25  *    misrepresented as being the original software.
26  * 3. This notice may not be removed or altered from any source distribution.
27  *
28  ******************************************************************************/
29 
30 //Include Files
31 
32 #include "rsi_ccp_common.h"
33 #include "rsi_error.h"
34 
35 #ifndef RSI_TIMERS_H
36 #define RSI_TIMERS_H
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 // LOCAL OR GLOBAL DEFINES
43 
44 #define RSI_TIMERS_API_VERSION RSI_DRIVER_VERSION_MAJOR_MINOR(2, 00)  // API version 0.1
45 #define RSI_TIMERS_DRV_VERSION RSI_DRIVER_VERSION_MAJOR_MINOR(00, 01) // driver version 0.1
46 
47 #define MICRO_SEC_MODE      1
48 #define _256_MICRO_SEC_MODE 2
49 #define COUNTER_DOWN_MODE   0
50 
51 // TIMERS Events
52 #define RSI_TIMERS_EVENT_TIMER0_TIMEOUT (1UL << 0) // Timer0 timeout interrupt
53 #define RSI_TIMERS_EVENT_TIMER1_TIMEOUT (1UL << 1) // Timer1 timeout interrupt
54 #define RSI_TIMERS_EVENT_TIMER2_TIMEOUT (1UL << 2) // Timer2 timeout interrupt
55 #define RSI_TIMERS_EVENT_TIMER3_TIMEOUT (1UL << 3) // Timer3 timeout interrupt
56 
57 #define TIMER_MODE 0x18
58 
59 // Example defines
60 #define TIMER_0 0
61 #define TIMER_1 1
62 #define TIMER_2 2
63 #define TIMER_3 3
64 
65 #define ULP_TIMER_RF_REF_CLK         0
66 #define ULP_TIMER_ULP_32KHZ_RO_CLK   1
67 #define ULP_TIMER_ULP_32KHZ_RC_CLK   2
68 #define ULP_TIMER_ULP_32KHZ_XTAL_CLK 3
69 #define ULP_TIMER_ULP_MHZ_RC_CLK     4
70 #define ULP_TIMER_ULP_20MHZ_RO_CLK   5
71 #define ULP_TIMER_SOC_CLK            6
72 
73 #define ULP_TIMER_CLK_DIV_FACT 0
74 
75 #define PERIODIC_TIMER 1
76 #define ONESHOT_TIMER  0
77 
78 typedef TIMERS_Type RSI_TIMERS_T;
79 
80 // brief  TIMERS Driver Capabilities.
81 typedef struct {
82   unsigned int timerCount : 4;   // Number of Timers
83   unsigned int microSecMode : 1; // supports Micro second mode
84 } RSI_TIMERS_CAPABILITIES_T;
85 
86 /// @brief Enumeration to represent ulp-timer direction
87 typedef enum {
88   DOWN_COUNTER,   ///< For ULP Timer up-counting direction
89   UP_COUNTER,     ///< For ULP Timer down-counting direction
90   LAST_DIRECTION, ///< Last member of enum for validation
91 } ulp_timer_dir_t;
92 
93 /*===================================================*/
94 /**
95  * @fn          rsi_error_t RSI_TIMERS_SetDirection(RSI_TIMERS_T *pTIMER, uint8_t timerNum, boolean_t countDir)
96  * @brief   This API is used to set direction of the timer
97  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
98  * @param[in]   timerNum   : Timer number(0 to 3)
99  * @param[in]   countDir   :  counter direction
100  *                          - \ref UP_COUNTER
101  *                          - \ref DOWN_COUNTER
102  * @return    return the timer error code
103  */
RSI_TIMERS_SetDirection(RSI_TIMERS_T * pTIMER,uint8_t timerNum,ulp_timer_dir_t countDir)104 STATIC INLINE rsi_error_t RSI_TIMERS_SetDirection(RSI_TIMERS_T *pTIMER, uint8_t timerNum, ulp_timer_dir_t countDir)
105 {
106   if (timerNum <= TIMER_3) {
107     if (countDir == UP_COUNTER) {
108       pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.COUNTER_UP = ENABLE;
109     } else if (countDir == DOWN_COUNTER) {
110       pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.COUNTER_UP = DISABLE;
111     } else {
112       return ERROR_INVAL_COUNTER_DIR;
113     }
114   } else {
115     return ERROR_INVAL_TIMER_NUM;
116   }
117   return RSI_OK;
118 }
119 
120 /*===================================================*/
121 /**
122  * @fn          uint32_t RSI_TIMERS_getDirection(const RSI_TIMERS_T *pTIMER, uint8_t timerNum)
123  * @brief   This API is used to get direction of the timer
124  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
125  * @param[in]   timerNum   : Timer number(0 to 3)
126  *
127  * @return   countDir   :  counter direction
128  *                        -  1 for UP_COUNTER
129  *                        -  0 for DOWN_COUNTER
130  */
RSI_TIMERS_getDirection(const RSI_TIMERS_T * pTIMER,uint8_t timerNum)131 STATIC INLINE uint32_t RSI_TIMERS_getDirection(const RSI_TIMERS_T *pTIMER, uint8_t timerNum)
132 {
133   uint8_t counterDir;
134   if (timerNum <= TIMER_3) {
135     counterDir = pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.COUNTER_UP;
136     return counterDir;
137   } else {
138     return ERROR_INVAL_TIMER_NUM;
139   }
140 }
141 
142 /*===================================================*/
143 /**
144  * @fn          uint32_t RSI_TIMERS_GetTimerMode(const RSI_TIMERS_T *pTIMER, uint8_t timerNum)
145  * @brief   This API is used to get the mode of timer
146  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
147  * @param[in]   timerNum   : Timer number(0 to 3)
148  * @return    return the type of timer if valid timer else error code
149  */
RSI_TIMERS_GetTimerMode(const RSI_TIMERS_T * pTIMER,uint8_t timerNum)150 STATIC INLINE uint32_t RSI_TIMERS_GetTimerMode(const RSI_TIMERS_T *pTIMER, uint8_t timerNum)
151 {
152   if (timerNum <= TIMER_3) {
153     return (pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_MODE);
154   } else {
155     return ERROR_INVAL_TIMER_NUM;
156   }
157 }
158 /*===================================================*/
159 /**
160  * @fn          rsi_error_t RSI_TIMERS_TimerStart(RSI_TIMERS_T *pTIMER, uint8_t timerNum)
161  * @brief		This API is used to start the timer
162  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
163  * @param[in]   timerNum   : Timer number(0 to 3)
164  * @return 		return the timer error code
165  */
RSI_TIMERS_TimerStart(RSI_TIMERS_T * pTIMER,uint8_t timerNum)166 STATIC INLINE rsi_error_t RSI_TIMERS_TimerStart(RSI_TIMERS_T *pTIMER, uint8_t timerNum)
167 {
168   if (timerNum <= TIMER_3) {
169     pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_START = ENABLE;
170   } else {
171     return ERROR_INVAL_TIMER_NUM;
172   }
173   return RSI_OK;
174 }
175 
176 /*===================================================*/
177 /**
178  * @fn          rsi_error_t RSI_TIMERS_TimerStop(RSI_TIMERS_T *pTIMER, uint8_t timerNum)
179  * @brief		This API is used to stop the timer
180  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
181  * @param[in]   timerNum   : Timer number(0 to 3)
182  * @return 		return the timer error code
183  */
RSI_TIMERS_TimerStop(RSI_TIMERS_T * pTIMER,uint8_t timerNum)184 STATIC INLINE rsi_error_t RSI_TIMERS_TimerStop(RSI_TIMERS_T *pTIMER, uint8_t timerNum)
185 {
186   if (timerNum <= TIMER_3) {
187     pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_STOP = ENABLE;
188   } else {
189     return ERROR_INVAL_TIMER_NUM;
190   }
191   return RSI_OK;
192 }
193 
194 /*===================================================*/
195 /**
196  * @fn          rsi_error_t RSI_TIMERS_InterruptEnable(RSI_TIMERS_T *pTIMER , uint8_t timerNum)
197  * @brief		This API is used to enable the timer interrupt
198  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
199  * @param[in]   timerNum   : Timer number(0 to 3)
200  * @return 		return the timer error code
201  */
RSI_TIMERS_InterruptEnable(RSI_TIMERS_T * pTIMER,uint8_t timerNum)202 STATIC INLINE rsi_error_t RSI_TIMERS_InterruptEnable(RSI_TIMERS_T *pTIMER, uint8_t timerNum)
203 {
204   if (timerNum <= TIMER_3) {
205     pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_INTR_ENABLE = ENABLE;
206   } else {
207     return ERROR_INVAL_TIMER_NUM;
208   }
209   return RSI_OK;
210 }
211 
212 /*===================================================*/
213 /**
214  * @fn          rsi_error_t RSI_TIMERS_InterruptDisable(RSI_TIMERS_T *pTIMER , uint8_t timerNum)
215  * @brief		This API is used to disable the timer interrupt
216  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
217  * @param[in]   timerNum   : Timer number(0 to 3)
218  * @return 		return the timer error code
219  */
RSI_TIMERS_InterruptDisable(RSI_TIMERS_T * pTIMER,uint8_t timerNum)220 STATIC INLINE rsi_error_t RSI_TIMERS_InterruptDisable(RSI_TIMERS_T *pTIMER, uint8_t timerNum)
221 {
222   if (timerNum <= TIMER_3) {
223     pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_INTR_ENABLE = DISABLE;
224   } else {
225     return ERROR_INVAL_TIMER_NUM;
226   }
227   return RSI_OK;
228 }
229 
230 /*===================================================*/
231 /**
232  * @fn          rsi_error_t RSI_TIMERS_InterruptClear(RSI_TIMERS_T *pTIMER , uint8_t timerNum)
233  * @brief		This API is used to clear the timer interrupt
234  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
235  * @param[in]   timerNum   : Timer number(0 to 3)
236  * @return 		return the timer error code
237  */
RSI_TIMERS_InterruptClear(RSI_TIMERS_T * pTIMER,uint8_t timerNum)238 STATIC INLINE rsi_error_t RSI_TIMERS_InterruptClear(RSI_TIMERS_T *pTIMER, uint8_t timerNum)
239 {
240   if (timerNum <= TIMER_3) {
241     pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_INTR_CLR = ENABLE;
242   } else {
243     return ERROR_INVAL_TIMER_NUM;
244   }
245   return RSI_OK;
246 }
247 
248 /*===================================================*/
249 /**
250  * @fn          rsi_error_t RSI_TIMERS_SetMatch( RSI_TIMERS_T *pTIMER, uint8_t timerNum, uint32_t match)
251  * @brief		This API is used to disable the timer interrupt
252  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
253  * @param[in]   timerNum   : Timer number(0 to 3)
254  * @param[in]   match      : delay time
255  * @return 		return the timer error code
256  */
RSI_TIMERS_SetMatch(RSI_TIMERS_T * pTIMER,uint8_t timerNum,uint32_t match)257 STATIC INLINE rsi_error_t RSI_TIMERS_SetMatch(RSI_TIMERS_T *pTIMER, uint8_t timerNum, uint32_t match)
258 {
259   if (timerNum <= TIMER_3) {
260     pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_MATCH = match;
261   } else {
262     return ERROR_INVAL_TIMER_NUM;
263   }
264   return RSI_OK;
265 }
266 
267 /*===================================================*/
268 /**
269  * @fn          rsi_error_t RSI_TIMERS_InterruptStatus(const RSI_TIMERS_T *pTIMER , uint8_t timerNum)
270  * @brief		This API is used to get the timer interrupt status
271  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
272  * @param[in]   timerNum   : Timer number(0 to 3)
273  * @return 		return the timer interrupt status if valid timer else 0.
274  */
RSI_TIMERS_InterruptStatus(const RSI_TIMERS_T * pTIMER,uint8_t timerNum)275 STATIC INLINE uint8_t RSI_TIMERS_InterruptStatus(const RSI_TIMERS_T *pTIMER, uint8_t timerNum)
276 {
277   if (timerNum <= TIMER_3) {
278     return (uint8_t)(pTIMER->MCUULP_TMR_INTR_STAT & (1 << timerNum));
279   } else {
280     return 0;
281   }
282 }
283 
284 /*===================================================*/
285 /**
286  * @fn          rsi_error_t RSI_TIMERS_SetTimerType( RSI_TIMERS_T *pTIMER, uint8_t timerType,  uint8_t timerNum)
287  * @brief		This API is used to set the timer type
288  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
289  * @param[in]   timerType  : timer type
290  *	                          - \ref MICRO_SEC_MODE
291  *                            - \ref _256_MICRO_SEC_MODE
292  *                            - \ref COUNTER_DOWN_MODE
293  * @param[in]   timerNum   : Timer number(0 to 3)
294  * @return 		return the timer error code
295  */
RSI_TIMERS_SetTimerType(RSI_TIMERS_T * pTIMER,uint8_t timerType,uint8_t timerNum)296 STATIC INLINE rsi_error_t RSI_TIMERS_SetTimerType(RSI_TIMERS_T *pTIMER, uint8_t timerType, uint8_t timerNum)
297 {
298   if (timerNum <= TIMER_3) {
299     if ((timerType == MICRO_SEC_MODE) || (timerType == _256_MICRO_SEC_MODE) || (timerType == COUNTER_DOWN_MODE)) {
300       pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_TYPE = (unsigned int)(timerType & 0x03);
301     } else {
302       return ERROR_INVAL_TIMERTYPE;
303     }
304   } else {
305     return ERROR_INVAL_TIMER_NUM;
306   }
307   return RSI_OK;
308 }
309 
310 /*===================================================*/
311 /**
312  * @fn          rsi_error_t RSI_TIMERS_SetTimerMode(RSI_TIMERS_T *pTIMER, boolean_t mode,uint8_t timerNum)
313  * @brief		This API is used to set the timer mode
314  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
315  * @param[in]   mode       : in which mode timer run
316  *                           - \ref PERIODIC_TIMER
317  *                           - \ref ONESHOT_TIMER
318  * @param[in]   timerNum   : Timer number(0 to 3)
319  * @return 		return the timer error code
320  */
RSI_TIMERS_SetTimerMode(RSI_TIMERS_T * pTIMER,boolean_t mode,uint8_t timerNum)321 STATIC INLINE rsi_error_t RSI_TIMERS_SetTimerMode(RSI_TIMERS_T *pTIMER, boolean_t mode, uint8_t timerNum)
322 {
323   if (timerNum <= TIMER_3) {
324     if ((mode == PERIODIC_TIMER) || (mode == ONESHOT_TIMER)) {
325       pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_MODE = (unsigned int)(mode & 0x01);
326     } else {
327       return ERROR_INVAL_TIMER_MODE;
328     }
329   } else {
330     return ERROR_INVAL_TIMER_NUM;
331   }
332   return RSI_OK;
333 }
334 
335 /*===================================================*/
336 /**
337  * @fn          uint32_t RSI_TIMERS_GetTimerType(const RSI_TIMERS_T *pTIMER, uint8_t timerNum)
338  * @brief		This API is used to get the type of timer
339  * @param[in]   pTIMER     : Pointer to the TIMERS instance register area
340  * @param[in]   timerNum   : Timer number(0 to 3)
341  * @return 		return the type of timer if valid timer else error code
342  */
RSI_TIMERS_GetTimerType(const RSI_TIMERS_T * pTIMER,uint8_t timerNum)343 STATIC INLINE uint32_t RSI_TIMERS_GetTimerType(const RSI_TIMERS_T *pTIMER, uint8_t timerNum)
344 {
345   if (timerNum <= TIMER_3) {
346     return (pTIMER->MATCH_CTRL[timerNum].MCUULP_TMR_CNTRL_b.TMR_TYPE);
347   } else {
348     return ERROR_INVAL_TIMER_NUM;
349   }
350 }
351 
352 // TIMERS FUNCTION PROTOTYPES
353 RSI_DRIVER_VERSION_M4 RSI_TIMERS_GetVersion(void);
354 
355 RSI_TIMERS_CAPABILITIES_T RSI_TIMERS_GetCapabilities(void);
356 
357 rsi_error_t timers_microsec_timer_config(RSI_TIMERS_T *pTIMER,
358                                          uint8_t timerNum,
359                                          uint16_t integer,
360                                          uint8_t fractional,
361                                          uint8_t mode);
362 uint32_t timers_read_timer(RSI_TIMERS_T *pTIMER, uint8_t timerNum, boolean_t countDir);
363 void IRQ002_Handler();
364 
365 #ifdef __cplusplus
366 }
367 #endif
368 
369 #endif // RSI_TIMERS_H
370