1 /*
2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /***********************************************************************************************************************
8 * Includes
9 **********************************************************************************************************************/
10 #include "r_ulpt.h"
11
12 /***********************************************************************************************************************
13 * Macro definitions
14 **********************************************************************************************************************/
15
16 /** "ULPT" in ASCII, used to determine if channel is open. */
17 #define ULPT_OPEN (0x554C5054ULL)
18
19 #define ULPT_PRV_ULPTCR_STATUS_FLAGS (0xE0U)
20 #define ULPT_PRV_ULPTCMSR_VALID_BITS (0x77U)
21
22 #define ULPT_PRV_ULPTCR_START_TIMER (0xE1U)
23 #define ULPT_PRV_ULPTCR_STOP_TIMER (0xE0U)
24 #define ULPT_PRV_ULPTCR_FORCE_STOP_TIMER (0xE4U)
25
26 /**********************************************************************************************************************
27 * Typedef definitions
28 **********************************************************************************************************************/
29 #if defined(__ARMCC_VERSION) || defined(__ICCARM__)
30 typedef void (BSP_CMSE_NONSECURE_CALL * ulpt_prv_ns_callback)(timer_callback_args_t * p_args);
31 #elif defined(__GNUC__)
32 typedef BSP_CMSE_NONSECURE_CALL void (*volatile ulpt_prv_ns_callback)(timer_callback_args_t * p_args);
33 #endif
34
35 /***********************************************************************************************************************
36 * Private function prototypes
37 **********************************************************************************************************************/
38 static fsp_err_t r_ulpt_common_preamble(ulpt_instance_ctrl_t * p_instance_ctrl);
39
40 static void r_ulpt_hardware_cfg(ulpt_instance_ctrl_t * p_instance_ctrl, timer_cfg_t const * const p_cfg);
41
42 static void r_ulpt_period_register_set(ulpt_instance_ctrl_t * p_instance_ctrl, uint32_t period_counts);
43 static uint32_t r_ulpt_clock_frequency_get(R_ULPT0_Type * p_ulpt_regs);
44
45 #if ULPT_CFG_PARAM_CHECKING_ENABLE
46 static fsp_err_t r_ulpt_open_param_checking(ulpt_instance_ctrl_t * p_instance_ctrl, timer_cfg_t const * const p_cfg);
47
48 #endif
49
50 /* ISRs. */
51 void ulpt_int_isr(void);
52
53 /***********************************************************************************************************************
54 * Private global variables
55 **********************************************************************************************************************/
56
57 /***********************************************************************************************************************
58 * Global Variables
59 **********************************************************************************************************************/
60
61 /** ULPT implementation of General Timer Driver. */
62 const timer_api_t g_timer_on_ulpt =
63 {
64 .open = R_ULPT_Open,
65 .stop = R_ULPT_Stop,
66 .start = R_ULPT_Start,
67 .reset = R_ULPT_Reset,
68 .enable = R_ULPT_Enable,
69 .disable = R_ULPT_Disable,
70 .periodSet = R_ULPT_PeriodSet,
71 .dutyCycleSet = R_ULPT_DutyCycleSet,
72 .compareMatchSet = R_ULPT_CompareMatchSet,
73 .infoGet = R_ULPT_InfoGet,
74 .statusGet = R_ULPT_StatusGet,
75 .callbackSet = R_ULPT_CallbackSet,
76 .close = R_ULPT_Close,
77 };
78
79 /*******************************************************************************************************************//**
80 * @addtogroup ULPT
81 * @{
82 **********************************************************************************************************************/
83
84 /***********************************************************************************************************************
85 * Functions
86 **********************************************************************************************************************/
87
88 /*******************************************************************************************************************//**
89 * Initializes the ULPT module instance. Implements @ref timer_api_t::open.
90 *
91 * The ULPT implementation of the general timer can accept an optional ulpt_extended_cfg_t extension parameter. For
92 * ULPT, the extension specifies the clock to be used as timer source and the output pin configurations. If the
93 * extension parameter is not specified (NULL), the default clock LOCO is used and the output pins are disabled.
94 *
95 * Example:
96 * @snippet r_ulpt_example.c R_ULPT_Open
97 *
98 * @retval FSP_SUCCESS Initialization was successful and timer has started.
99 * @retval FSP_ERR_ASSERTION A required input pointer is NULL or the period is not in the valid range of
100 * 1 to 0xFFFF.
101 * @retval FSP_ERR_ALREADY_OPEN R_ULPT_Open has already been called for this p_ctrl.
102 * @retval FSP_ERR_IRQ_BSP_DISABLED A required interrupt has not been enabled in the vector table.
103 * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT Requested channel number is not available on ULPT.
104 **********************************************************************************************************************/
R_ULPT_Open(timer_ctrl_t * const p_ctrl,timer_cfg_t const * const p_cfg)105 fsp_err_t R_ULPT_Open (timer_ctrl_t * const p_ctrl, timer_cfg_t const * const p_cfg)
106 {
107 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
108
109 #if ULPT_CFG_PARAM_CHECKING_ENABLE
110 fsp_err_t err = r_ulpt_open_param_checking(p_instance_ctrl, p_cfg);
111 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
112 #endif
113
114 uint32_t base_address = (uint32_t) R_ULPT0_BASE +
115 (p_cfg->channel * ((uint32_t) R_ULPT1_BASE - (uint32_t) R_ULPT0_BASE));
116 p_instance_ctrl->p_reg = (R_ULPT0_Type *) base_address;
117
118 p_instance_ctrl->p_cfg = p_cfg;
119
120 /* Power on the ULPT channel. */
121 R_BSP_MODULE_START(FSP_IP_ULPT, p_cfg->channel);
122
123 /* Clear ULPTCR. This stops the timer if it is running and clears the flags. */
124 p_instance_ctrl->p_reg->ULPTCR = 0U;
125
126 /* The timer is stopped in sync with the count source. */
127 FSP_HARDWARE_REGISTER_WAIT(0U, p_instance_ctrl->p_reg->ULPTCR_b.TCSTF);
128
129 /* Clear ULPTMR2 before ULPTMR1 to prevent clock destablization if the mode is changed. */
130 p_instance_ctrl->p_reg->ULPTMR2 = 0U;
131
132 /* Set count source and divider and configure pins. */
133 r_ulpt_hardware_cfg(p_instance_ctrl, p_cfg);
134
135 /* Set period register and update duty cycle if output mode is used. */
136 r_ulpt_period_register_set(p_instance_ctrl, p_cfg->period_counts);
137
138 if (p_cfg->cycle_end_irq >= 0)
139 {
140 R_BSP_IrqCfgEnable(p_cfg->cycle_end_irq, p_cfg->cycle_end_ipl, p_instance_ctrl);
141 }
142
143 /* Set callback and context pointers */
144 p_instance_ctrl->p_callback = p_cfg->p_callback;
145 p_instance_ctrl->p_context = p_cfg->p_context;
146 p_instance_ctrl->p_callback_memory = NULL;
147
148 p_instance_ctrl->open = ULPT_OPEN;
149
150 /* All done. */
151 return FSP_SUCCESS;
152 }
153
154 /*******************************************************************************************************************//**
155 * Starts timer. Implements @ref timer_api_t::start.
156 *
157 * Example:
158 * @snippet r_ulpt_example.c R_ULPT_Start
159 *
160 * @retval FSP_SUCCESS Timer started.
161 * @retval FSP_ERR_ASSERTION p_ctrl is null.
162 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
163 **********************************************************************************************************************/
R_ULPT_Start(timer_ctrl_t * const p_ctrl)164 fsp_err_t R_ULPT_Start (timer_ctrl_t * const p_ctrl)
165 {
166 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
167
168 fsp_err_t err = r_ulpt_common_preamble(p_instance_ctrl);
169 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
170
171 /* Start timer */
172 p_instance_ctrl->p_reg->ULPTCR = ULPT_PRV_ULPTCR_START_TIMER;
173
174 return FSP_SUCCESS;
175 }
176
177 /*******************************************************************************************************************//**
178 * Stops the timer. Implements @ref timer_api_t::stop.
179 *
180 * Example:
181 * @snippet r_ulpt_example.c R_ULPT_Stop
182 *
183 * @retval FSP_SUCCESS Timer stopped.
184 * @retval FSP_ERR_ASSERTION p_ctrl was NULL.
185 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
186 **********************************************************************************************************************/
R_ULPT_Stop(timer_ctrl_t * const p_ctrl)187 fsp_err_t R_ULPT_Stop (timer_ctrl_t * const p_ctrl)
188 {
189 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
190
191 fsp_err_t err = r_ulpt_common_preamble(p_instance_ctrl);
192 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
193
194 /* Stop timer */
195 p_instance_ctrl->p_reg->ULPTCR = ULPT_PRV_ULPTCR_STOP_TIMER;
196
197 return FSP_SUCCESS;
198 }
199
200 /*******************************************************************************************************************//**
201 * Resets the counter value to the period minus one. Implements @ref timer_api_t::reset.
202 *
203 * @retval FSP_SUCCESS Counter reset.
204 * @retval FSP_ERR_ASSERTION p_ctrl is NULL
205 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
206 **********************************************************************************************************************/
R_ULPT_Reset(timer_ctrl_t * const p_ctrl)207 fsp_err_t R_ULPT_Reset (timer_ctrl_t * const p_ctrl)
208 {
209 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
210
211 fsp_err_t err = r_ulpt_common_preamble(p_instance_ctrl);
212 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
213
214 /* Reset counter to period minus one. */
215 p_instance_ctrl->p_reg->ULPTCNT = p_instance_ctrl->period - 1U;
216
217 return FSP_SUCCESS;
218 }
219
220 /*******************************************************************************************************************//**
221 * Enables external event triggers that start, stop, clear, or capture the counter. Implements @ref timer_api_t::enable.
222 *
223 * Example:
224 * @snippet r_ulpt_example.c R_ULPT_Enable
225 *
226 * @retval FSP_SUCCESS External events successfully enabled.
227 * @retval FSP_ERR_ASSERTION p_ctrl was NULL.
228 * @retval FSP_ERR_NOT_OPEN The instance is not opened.
229 **********************************************************************************************************************/
R_ULPT_Enable(timer_ctrl_t * const p_ctrl)230 fsp_err_t R_ULPT_Enable (timer_ctrl_t * const p_ctrl)
231 {
232 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
233 #if ULPT_CFG_PARAM_CHECKING_ENABLE
234 FSP_ASSERT(NULL != p_instance_ctrl);
235 FSP_ERROR_RETURN(ULPT_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN);
236 #endif
237
238 /* Reset counter to period minus one. */
239 p_instance_ctrl->p_reg->ULPTCNT = p_instance_ctrl->period - 1U;
240
241 /* Enable captures. */
242 p_instance_ctrl->p_reg->ULPTCR = ULPT_PRV_ULPTCR_START_TIMER;
243
244 return FSP_SUCCESS;
245 }
246
247 /*******************************************************************************************************************//**
248 * Disables external event triggers that start, stop, clear, or capture the counter. Implements @ref timer_api_t::disable.
249 *
250 * Example:
251 * @snippet r_ulpt_example.c R_ULPT_Disable
252 *
253 * @retval FSP_SUCCESS External events successfully disabled.
254 * @retval FSP_ERR_ASSERTION p_ctrl was NULL.
255 * @retval FSP_ERR_NOT_OPEN The instance is not opened.
256 **********************************************************************************************************************/
R_ULPT_Disable(timer_ctrl_t * const p_ctrl)257 fsp_err_t R_ULPT_Disable (timer_ctrl_t * const p_ctrl)
258 {
259 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
260 #if ULPT_CFG_PARAM_CHECKING_ENABLE
261 FSP_ASSERT(NULL != p_instance_ctrl);
262 FSP_ERROR_RETURN(ULPT_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN);
263 #endif
264
265 /* Disable captures. */
266 p_instance_ctrl->p_reg->ULPTCR = ULPT_PRV_ULPTCR_STOP_TIMER;
267
268 return FSP_SUCCESS;
269 }
270
271 /*******************************************************************************************************************//**
272 * Updates period. The new period is updated immediately and the counter is reset to the maximum value. Implements
273 * @ref timer_api_t::periodSet.
274 *
275 * @warning If periodic output is used, the duty cycle buffer registers are updated after the period buffer register.
276 * If this function is called while the timer is running and an AGT underflow occurs during processing, the duty cycle
277 * will not be the desired 50% duty cycle until the counter underflow after processing completes.
278 *
279 * @warning Stop the timer before calling this function if one-shot output is used.
280 *
281 * Example:
282 * @snippet r_ulpt_example.c R_ULPT_PeriodSet
283 *
284 * @retval FSP_SUCCESS Period value updated.
285 * @retval FSP_ERR_ASSERTION A required pointer was NULL, or the period was not in the valid range of
286 * 1 to 0xFFFF.
287 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
288 **********************************************************************************************************************/
R_ULPT_PeriodSet(timer_ctrl_t * const p_ctrl,uint32_t const period_counts)289 fsp_err_t R_ULPT_PeriodSet (timer_ctrl_t * const p_ctrl, uint32_t const period_counts)
290 {
291 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
292 #if ULPT_CFG_PARAM_CHECKING_ENABLE
293
294 /* Validate period parameter. */
295 FSP_ASSERT(0U != period_counts);
296 #endif
297
298 fsp_err_t err = r_ulpt_common_preamble(p_instance_ctrl);
299 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
300
301 /* Set period. */
302 r_ulpt_period_register_set(p_instance_ctrl, period_counts);
303
304 return FSP_SUCCESS;
305 }
306
307 /*******************************************************************************************************************//**
308 * Updates duty cycle. If the timer is counting, the new duty cycle is reflected after the next counter underflow.
309 * Implements @ref timer_api_t::dutyCycleSet.
310 *
311 * Example:
312 * @snippet r_ulpt_example.c R_ULPT_DutyCycleSet
313 *
314 * @retval FSP_SUCCESS Duty cycle updated.
315 * @retval FSP_ERR_ASSERTION A required pointer was NULL, or the pin was not ULPT_ULPTO_ULPTOA or ULPT_ULPTO_ULPTOB.
316 * @retval FSP_ERR_INVALID_ARGUMENT Duty cycle was not in the valid range of 0 to period (counts) - 1
317 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
318 * @retval FSP_ERR_UNSUPPORTED ULPT_CFG_OUTPUT_SUPPORT_ENABLE is 0.
319 **********************************************************************************************************************/
R_ULPT_DutyCycleSet(timer_ctrl_t * const p_ctrl,uint32_t const duty_cycle_counts,uint32_t const pin)320 fsp_err_t R_ULPT_DutyCycleSet (timer_ctrl_t * const p_ctrl, uint32_t const duty_cycle_counts, uint32_t const pin)
321 {
322 #if ULPT_CFG_OUTPUT_SUPPORT_ENABLE
323 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
324 #if ULPT_CFG_PARAM_CHECKING_ENABLE
325 FSP_ASSERT((pin == ULPT_OUTPUT_PIN_ULPTOA) || (pin == ULPT_OUTPUT_PIN_ULPTOB));
326 #endif
327
328 fsp_err_t err = r_ulpt_common_preamble(p_instance_ctrl);
329 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
330
331 #if ULPT_CFG_PARAM_CHECKING_ENABLE
332 if (0U != p_instance_ctrl->period)
333 {
334 FSP_ERROR_RETURN(duty_cycle_counts < (p_instance_ctrl->period), FSP_ERR_INVALID_ARGUMENT);
335 }
336 #endif
337
338 uint32_t temp_duty_cycle_counts = duty_cycle_counts;
339 uint32_t ulptcmsr_ulptoab_start_level_bit = 1U << 2 << (4 * pin); /* polarity set*/
340 ulpt_extended_cfg_t const * p_extend = (ulpt_extended_cfg_t const *) p_instance_ctrl->p_cfg->p_extend;
341 if (p_extend->ulptoab_settings & ulptcmsr_ulptoab_start_level_bit)
342 {
343 /* Invert duty cycle if this pin starts high since the high portion is at the beginning of the cycle. */
344 temp_duty_cycle_counts = p_instance_ctrl->period - temp_duty_cycle_counts - 1;
345 }
346
347 /* Set duty cycle. */
348 volatile uint32_t * const p_ulptcm = &p_instance_ctrl->p_reg->ULPTCMA;
349 p_ulptcm[pin] = temp_duty_cycle_counts;
350
351 return FSP_SUCCESS;
352 #else
353 FSP_PARAMETER_NOT_USED(p_ctrl);
354 FSP_PARAMETER_NOT_USED(duty_cycle_counts);
355 FSP_PARAMETER_NOT_USED(pin);
356
357 FSP_RETURN(FSP_ERR_UNSUPPORTED);
358 #endif
359 }
360
361 /*******************************************************************************************************************//**
362 * Placeholder for unsupported compareMatch function. Implements @ref timer_api_t::compareMatchSet.
363 *
364 * @retval FSP_ERR_UNSUPPORTED ULPT compare match is not supported.
365 **********************************************************************************************************************/
R_ULPT_CompareMatchSet(timer_ctrl_t * const p_ctrl,uint32_t const compare_match_value,timer_compare_match_t const match_channel)366 fsp_err_t R_ULPT_CompareMatchSet (timer_ctrl_t * const p_ctrl,
367 uint32_t const compare_match_value,
368 timer_compare_match_t const match_channel)
369 {
370 /* This function isn't supported. It is defined only to implement a required function of timer_api_t.
371 * Mark the input parameter as unused since this function isn't supported. */
372 FSP_PARAMETER_NOT_USED(p_ctrl);
373 FSP_PARAMETER_NOT_USED(compare_match_value);
374 FSP_PARAMETER_NOT_USED(match_channel);
375
376 return FSP_ERR_UNSUPPORTED;
377 }
378
379 /*******************************************************************************************************************//**
380 * Gets timer information and store it in provided pointer p_info. Implements @ref timer_api_t::infoGet.
381 *
382 * Example:
383 * @snippet r_ulpt_example.c R_ULPT_InfoGet
384 *
385 * @retval FSP_SUCCESS Period, count direction, and frequency stored in p_info.
386 * @retval FSP_ERR_ASSERTION A required pointer is NULL.
387 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
388 **********************************************************************************************************************/
R_ULPT_InfoGet(timer_ctrl_t * const p_ctrl,timer_info_t * const p_info)389 fsp_err_t R_ULPT_InfoGet (timer_ctrl_t * const p_ctrl, timer_info_t * const p_info)
390 {
391 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
392 #if ULPT_CFG_PARAM_CHECKING_ENABLE
393 FSP_ASSERT(NULL != p_info);
394 #endif
395
396 fsp_err_t err = r_ulpt_common_preamble(p_instance_ctrl);
397 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
398
399 /* Get and store period */
400 p_info->period_counts = p_instance_ctrl->period;
401
402 /* Get and store clock frequency */
403 /* ulpt_extended_cfg_t const * p_extend = (ulpt_extended_cfg_t const *) p_instance_ctrl->p_cfg->p_extend;*/
404 p_info->clock_frequency = r_ulpt_clock_frequency_get(p_instance_ctrl->p_reg);
405
406 /* ULPT supports only counting down direction */
407 p_info->count_direction = TIMER_DIRECTION_DOWN;
408
409 return FSP_SUCCESS;
410 }
411
412 /*******************************************************************************************************************//**
413 * Retrieves the current state and counter value stores them in p_status. Implements @ref timer_api_t::statusGet.
414 *
415 * Example:
416 * @snippet r_ulpt_example.c R_ULPT_StatusGet
417 *
418 * @retval FSP_SUCCESS Current status and counter value provided in p_status.
419 * @retval FSP_ERR_ASSERTION A required pointer is NULL.
420 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
421 **********************************************************************************************************************/
R_ULPT_StatusGet(timer_ctrl_t * const p_ctrl,timer_status_t * const p_status)422 fsp_err_t R_ULPT_StatusGet (timer_ctrl_t * const p_ctrl, timer_status_t * const p_status)
423 {
424 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
425
426 #if ULPT_CFG_PARAM_CHECKING_ENABLE
427 FSP_ASSERT(NULL != p_status);
428 #endif
429
430 fsp_err_t err = r_ulpt_common_preamble(p_instance_ctrl);
431 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
432
433 /* Read the state. */
434 p_status->state = (timer_state_t) p_instance_ctrl->p_reg->ULPTCR_b.TCSTF;
435
436 /* Read counter value */
437 p_status->counter = p_instance_ctrl->p_reg->ULPTCNT;
438
439 return FSP_SUCCESS;
440 }
441
442 /*******************************************************************************************************************//**
443 * Updates the user callback with the option to provide memory for the callback argument structure.
444 * Implements @ref timer_api_t::callbackSet.
445 *
446 * @retval FSP_SUCCESS Callback updated successfully.
447 * @retval FSP_ERR_ASSERTION A required pointer is NULL.
448 * @retval FSP_ERR_NOT_OPEN The control block has not been opened.
449 * @retval FSP_ERR_NO_CALLBACK_MEMORY p_callback is non-secure and p_callback_memory is either secure or NULL.
450 **********************************************************************************************************************/
R_ULPT_CallbackSet(timer_ctrl_t * const p_api_ctrl,void (* p_callback)(timer_callback_args_t *),void const * const p_context,timer_callback_args_t * const p_callback_memory)451 fsp_err_t R_ULPT_CallbackSet (timer_ctrl_t * const p_api_ctrl,
452 void ( * p_callback)(timer_callback_args_t *),
453 void const * const p_context,
454 timer_callback_args_t * const p_callback_memory)
455 {
456 ulpt_instance_ctrl_t * p_ctrl = (ulpt_instance_ctrl_t *) p_api_ctrl;
457
458 #if ULPT_CFG_PARAM_CHECKING_ENABLE
459 FSP_ASSERT(p_ctrl);
460 FSP_ASSERT(p_callback);
461 FSP_ERROR_RETURN(ULPT_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
462 #endif
463
464 #if BSP_TZ_SECURE_BUILD
465
466 /* Get security state of p_callback */
467 bool callback_is_secure =
468 (NULL == cmse_check_address_range((void *) p_callback, sizeof(void *), CMSE_AU_NONSECURE));
469
470 #if ULPT_CFG_PARAM_CHECKING_ENABLE
471
472 /* In secure projects, p_callback_memory must be provided in non-secure space if p_callback is non-secure */
473 timer_callback_args_t * const p_callback_memory_checked = cmse_check_pointed_object(p_callback_memory,
474 CMSE_AU_NONSECURE);
475 FSP_ERROR_RETURN(callback_is_secure || (NULL != p_callback_memory_checked), FSP_ERR_NO_CALLBACK_MEMORY);
476 #endif
477 #endif
478
479 /* Store callback and context */
480 #if BSP_TZ_SECURE_BUILD
481 p_ctrl->p_callback = callback_is_secure ? p_callback :
482 (void (*)(timer_callback_args_t *))cmse_nsfptr_create(p_callback);
483 #else
484 p_ctrl->p_callback = p_callback;
485 #endif
486 p_ctrl->p_context = p_context;
487 p_ctrl->p_callback_memory = p_callback_memory;
488
489 return FSP_SUCCESS;
490 }
491
492 /*******************************************************************************************************************//**
493 * Stops counter, disables interrupts, disables output pins, and clears internal driver data. Implements
494 * @ref timer_api_t::close.
495 *
496 *
497 *
498 * @retval FSP_SUCCESS Timer closed.
499 * @retval FSP_ERR_ASSERTION p_ctrl is NULL.
500 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
501 **********************************************************************************************************************/
R_ULPT_Close(timer_ctrl_t * const p_ctrl)502 fsp_err_t R_ULPT_Close (timer_ctrl_t * const p_ctrl)
503 {
504 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) p_ctrl;
505
506 fsp_err_t err = r_ulpt_common_preamble(p_instance_ctrl);
507 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
508
509 /* Cleanup the device: Stop counter, disable interrupts, and power down if no other channels are in use. */
510
511 /* Stop timer */
512 p_instance_ctrl->p_reg->ULPTCR = ULPT_PRV_ULPTCR_FORCE_STOP_TIMER;
513
514 /* Clear ULPT output. */
515 p_instance_ctrl->p_reg->ULPTIOC = 0U;
516
517 if (FSP_INVALID_VECTOR != p_instance_ctrl->p_cfg->cycle_end_irq)
518 {
519 NVIC_DisableIRQ(p_instance_ctrl->p_cfg->cycle_end_irq);
520 R_FSP_IsrContextSet(p_instance_ctrl->p_cfg->cycle_end_irq, p_instance_ctrl);
521 }
522
523 p_instance_ctrl->open = 0U;
524
525 return FSP_SUCCESS;
526 }
527
528 /** @} (end addtogroup ULPT) */
529
530 /***********************************************************************************************************************
531 * Private Functions
532 **********************************************************************************************************************/
533
534 #if ULPT_CFG_PARAM_CHECKING_ENABLE
535
536 /*******************************************************************************************************************//**
537 * Parameter checking for R_ULPT_Open.
538 *
539 * @param[in] p_instance_ctrl Pointer to instance control structure.
540 * @param[in] p_cfg Configuration structure for this instance
541 *
542 * @retval FSP_SUCCESS Initialization was successful and timer has started.
543 * @retval FSP_ERR_ASSERTION A required input pointer is NULL or an invalid parameter exists.
544 * @retval FSP_ERR_ALREADY_OPEN R_ULPT_Open has already been called for this p_ctrl.
545 * @retval FSP_ERR_IRQ_BSP_DISABLED A required interrupt has not been enabled in the vector table.
546 * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT Requested channel number is not available on ULPT.
547 **********************************************************************************************************************/
r_ulpt_open_param_checking(ulpt_instance_ctrl_t * p_instance_ctrl,timer_cfg_t const * const p_cfg)548 static fsp_err_t r_ulpt_open_param_checking (ulpt_instance_ctrl_t * p_instance_ctrl, timer_cfg_t const * const p_cfg)
549 {
550 FSP_ASSERT(NULL != p_instance_ctrl);
551 FSP_ASSERT(NULL != p_cfg);
552 FSP_ASSERT(NULL != p_cfg->p_extend);
553 FSP_ERROR_RETURN(ULPT_OPEN != p_instance_ctrl->open, FSP_ERR_ALREADY_OPEN);
554
555 /* Validate channel number. */
556 FSP_ERROR_RETURN(((1U << p_cfg->channel) & BSP_FEATURE_ULPT_VALID_CHANNEL_MASK), FSP_ERR_IP_CHANNEL_NOT_PRESENT);
557
558 /* Enable IRQ if user supplied a callback function,
559 * or if the timer is a one-shot timer (so the driver is able to
560 * turn off the timer after one period. */
561 if ((NULL != p_cfg->p_callback) || (TIMER_MODE_ONE_SHOT == p_cfg->mode))
562 {
563 /* Return error if IRQ is required and not in the vector table. */
564 FSP_ERROR_RETURN(p_cfg->cycle_end_irq >= 0, FSP_ERR_IRQ_BSP_DISABLED);
565 }
566
567 ulpt_extended_cfg_t const * p_extend = (ulpt_extended_cfg_t const *) p_cfg->p_extend;
568
569 /* Validate mode specific settings. */
570 if ((ULPT_CLOCK_LOCO == p_extend->count_source) || (ULPT_CLOCK_SUBCLOCK == p_extend->count_source))
571 {
572 /* Timer mode */
573
574 /* Validate the divider. */
575 FSP_ASSERT(p_cfg->source_div <= TIMER_SOURCE_DIV_128);
576
577 /* Count enable,start,amd restart functions are not allowed in timer mode. */
578 FSP_ASSERT(p_extend->enable_function != ULPT_ENABLE_FUNCTION_ENABLE_LOW);
579 FSP_ASSERT(p_extend->enable_function != ULPT_ENABLE_FUNCTION_ENABLE_HIGH);
580 FSP_ASSERT(p_extend->enable_function != ULPT_ENABLE_FUNCTION_START);
581 FSP_ASSERT(p_extend->enable_function != ULPT_ENABLE_FUNCTION_RESTART);
582 }
583 else
584 {
585 /* Event counter mode */
586 /* No Divider allowed. */
587 FSP_ASSERT(p_cfg->source_div <= TIMER_SOURCE_DIV_1);
588 }
589
590 return FSP_SUCCESS;
591 }
592
593 #endif
594
595 /*******************************************************************************************************************//**
596 * Common code at the beginning of all ULPT functions except open.
597 *
598 * @param[in] p_instance_ctrl Pointer to instance control structure.
599 *
600 * @retval FSP_SUCCESS No invalid conditions detected, timer state matches expected state.
601 * @retval FSP_ERR_ASSERTION p_ctrl is null.
602 * @retval FSP_ERR_NOT_OPEN The instance control structure is not opened.
603 **********************************************************************************************************************/
r_ulpt_common_preamble(ulpt_instance_ctrl_t * p_instance_ctrl)604 static fsp_err_t r_ulpt_common_preamble (ulpt_instance_ctrl_t * p_instance_ctrl)
605 {
606 #if ULPT_CFG_PARAM_CHECKING_ENABLE
607 FSP_ASSERT(NULL != p_instance_ctrl);
608 FSP_ERROR_RETURN(ULPT_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN);
609 #endif
610
611 /* Ensure timer state reflects expected status. */
612 uint32_t ulptcr_tstart = p_instance_ctrl->p_reg->ULPTCR_b.TSTART;
613 FSP_HARDWARE_REGISTER_WAIT(ulptcr_tstart, p_instance_ctrl->p_reg->ULPTCR_b.TCSTF);
614
615 return FSP_SUCCESS;
616 }
617
618 /*******************************************************************************************************************//**
619 * Sets count source, divider, and other hardware registers.
620 *
621 * @note Counter must be stopped before entering this function.
622 *
623 * @param[in] p_instance_ctrl Control block for this instance
624 * @param[in] p_cfg Configuration structure for this instance
625 **********************************************************************************************************************/
626
r_ulpt_hardware_cfg(ulpt_instance_ctrl_t * p_instance_ctrl,timer_cfg_t const * const p_cfg)627 static void r_ulpt_hardware_cfg (ulpt_instance_ctrl_t * p_instance_ctrl, timer_cfg_t const * const p_cfg)
628 {
629 ulpt_extended_cfg_t const * p_extend = (ulpt_extended_cfg_t const *) p_cfg->p_extend;
630
631 /* ULPT register locals */
632 uint32_t ulptmr1 = 0U;
633 uint32_t ulptmr2 = 0U;
634 uint32_t ulptmr3 = 0U;
635 uint32_t ulptioc = 0U;
636 uint32_t ulptisr = 0U;
637 uint32_t ulptcmsr = 0U;
638
639 /* Configure the count source(LOCO or SCK) and mode(event or Timer). */
640 ulptmr1 |= p_extend->count_source & (R_ULPT0_ULPTMR1_TMOD1_Msk | R_ULPT0_ULPTMR1_TCK1_Msk);
641
642 if (TIMER_MODE_ONE_SHOT == p_cfg->mode)
643 {
644 ulptmr3 |= R_ULPT0_ULPTMR3_TCNTCTL_Msk;
645 }
646
647 if (p_extend->count_source != ULPT_CLOCK_ULPTEVI)
648 {
649 /* Timer mode */
650 ulptmr1 &= ~R_ULPT0_ULPTMR1_TMOD1_Msk;
651
652 /* The divider is only used for normal timer operation. */
653 ulptmr2 |= p_cfg->source_div & R_ULPT0_ULPTMR2_CKS_Msk;
654 }
655
656 #if ULPT_CFG_INPUT_SUPPORT_ENABLE
657 else // (p_extend->count_source == ULPT_CLOCK_ULPTEVI)
658 {
659 /* Event counter mode */
660 ulptmr1 |= R_ULPT0_ULPTMR1_TMOD1_Msk;
661
662 /* Set the edge selection for for event pin. */
663 /* For Falling we set it for rising edge and flip the polarity */
664 ulptmr1 |= p_extend->event_pin & R_ULPT0_ULPTMR1_TEDGPL_Msk;
665 ulptmr3 |= p_extend->event_pin & R_ULPT0_ULPTMR3_TEVPOL_Msk;
666
667 /* Configure input filtering */
668 ulptioc |= p_extend->ulptevi_filter & R_ULPT0_ULPTIOC_TIPF_Msk;
669
670 /* Select if the ULPTEE pin should be ignored. */
671 ulptioc |= p_extend->enable_function & R_ULPT0_ULPTIOC_TIOGT0_Msk;
672
673 /* Set the active polarity for ULPTEE. This is only set for count enable function. */
674 ulptisr |= p_extend->enable_function & R_ULPT0_ULPTISR_RCCPSEL2_Msk;
675 }
676 #endif
677
678 /* ULPTEE can be used in either timer or event mode. */
679 /* Configure ULPTEE pin function and edge polarity for start or restart functions. */
680 ulptmr3 |= p_extend->enable_function & R_ULPT0_ULPTMR3_TEECTL_Msk;
681 ulptmr3 |= p_extend->trigger_edge & R_ULPT0_ULPTMR3_TEEPOL_Msk;
682
683 #if ULPT_CFG_OUTPUT_SUPPORT_ENABLE
684
685 /* Set output if requested. */
686 if (p_extend->ulpto != ULPT_PULSE_PIN_CFG_DISABLED)
687 {
688 ulptioc |= R_ULPT0_ULPTIOC_TOE_Msk;
689
690 /* Now set the polarity*/
691 if (p_extend->ulpto == ULPT_PULSE_PIN_CFG_ENABLED_START_LEVEL_HIGH)
692 {
693 ulptmr3 |= R_ULPT0_ULPTMR3_TOPOL_Msk;
694 }
695 else
696 {
697 ulptmr3 &= ~R_ULPT0_ULPTMR3_TOPOL_Msk;
698 }
699 }
700
701 /* set enable match, output, and polarity of both match outputs*/
702 ulptcmsr = p_extend->ulptoab_settings & ULPT_PRV_ULPTCMSR_VALID_BITS;
703
704 /* Set initial duty cycle for PWM mode in open. Duty cycle is set for other modes in r_agt_period_register_set. */
705 if (TIMER_MODE_PWM == p_instance_ctrl->p_cfg->mode)
706 {
707 uint32_t inverted_duty_cycle = p_instance_ctrl->p_cfg->period_counts -
708 p_instance_ctrl->p_cfg->duty_cycle_counts - 1;
709
710 /*In this driver match A and match b have the same duty cycle*/
711 uint32_t ulptcma = p_instance_ctrl->p_cfg->duty_cycle_counts;
712 uint32_t ulptcmb = p_instance_ctrl->p_cfg->duty_cycle_counts;
713 if (ULPT_MATCH_PIN_CFG_DISABLED != p_extend->ulptoab_settings_b.ulptoa)
714 {
715 if (ULPT_MATCH_PIN_CFG_START_LEVEL_HIGH == p_extend->ulptoab_settings_b.ulptoa)
716 {
717 ulptcma = inverted_duty_cycle;
718 }
719
720 p_instance_ctrl->p_reg->ULPTCMA = ulptcma;
721 }
722
723 if (ULPT_MATCH_PIN_CFG_DISABLED != p_extend->ulptoab_settings_b.ulptob)
724 {
725 if (ULPT_MATCH_PIN_CFG_START_LEVEL_HIGH == p_extend->ulptoab_settings_b.ulptob)
726 {
727 ulptcmb = inverted_duty_cycle;
728 }
729
730 p_instance_ctrl->p_reg->ULPTCMB = ulptcmb;
731 }
732 }
733 #endif
734
735 p_instance_ctrl->p_reg->ULPTMR1 = (uint8_t) ulptmr1;
736 p_instance_ctrl->p_reg->ULPTMR2 = (uint8_t) ulptmr2;
737 p_instance_ctrl->p_reg->ULPTMR3 = (uint8_t) ulptmr3;
738 p_instance_ctrl->p_reg->ULPTIOC = (uint8_t) ulptioc;
739 p_instance_ctrl->p_reg->ULPTISR = (uint8_t) ulptisr;
740 p_instance_ctrl->p_reg->ULPTCMSR = (uint8_t) ulptcmsr;
741 }
742
743 /*******************************************************************************************************************//**
744 * Sets period register and updates compare match registers in one-shot and periodic mode.
745 *
746 * @param[in] p_instance_ctrl Control block for this instance
747 * @param[in] period_counts ULPT period in counts
748 **********************************************************************************************************************/
r_ulpt_period_register_set(ulpt_instance_ctrl_t * p_instance_ctrl,uint32_t period_counts)749 static void r_ulpt_period_register_set (ulpt_instance_ctrl_t * p_instance_ctrl, uint32_t period_counts)
750 {
751 /* Store the period value so it can be retrieved later. */
752 p_instance_ctrl->period = period_counts;
753
754 uint32_t period_reg = period_counts - 1U;
755
756 #if ULPT_CFG_OUTPUT_SUPPORT_ENABLE
757 uint32_t duty_cycle_counts = 0U;
758 if (TIMER_MODE_PERIODIC == p_instance_ctrl->p_cfg->mode)
759 {
760 duty_cycle_counts = (period_counts >> 1);
761 }
762 else if (TIMER_MODE_ONE_SHOT == p_instance_ctrl->p_cfg->mode)
763 {
764 duty_cycle_counts = period_reg;
765 }
766 else
767 {
768 /* Do nothing, duty cycle should not be updated in R_ULPT_PeriodSet. */
769 }
770
771 if (TIMER_MODE_PWM != p_instance_ctrl->p_cfg->mode)
772 {
773 p_instance_ctrl->p_reg->ULPTCMA = duty_cycle_counts;
774 p_instance_ctrl->p_reg->ULPTCMB = duty_cycle_counts;
775 }
776 #endif
777
778 /* Set counter to period minus one. */
779 p_instance_ctrl->p_reg->ULPTCNT = period_reg;
780 }
781
782 /*******************************************************************************************************************//**
783 * Obtains the clock frequency of ULPT for all clock sources
784 *
785 * @param[in] p_ulpt_regs Registers of ULPT channel used
786 *
787 * @return Source clock frequency of ULPT in Hz with prescaler divider applied
788 **********************************************************************************************************************/
r_ulpt_clock_frequency_get(R_ULPT0_Type * p_ulpt_regs)789 static uint32_t r_ulpt_clock_frequency_get (R_ULPT0_Type * p_ulpt_regs)
790 {
791 uint32_t clock_freq_hz = 0U;
792 uint8_t count_source_int = p_ulpt_regs->ULPTMR1_b.TCK1;
793 uint8_t divider = p_ulpt_regs->ULPTMR2_b.CKS;
794
795 if (ULPT_CLOCK_SUBCLOCK == (count_source_int & R_ULPT0_ULPTMR1_TCK1_Msk))
796 {
797 clock_freq_hz = BSP_SUBCLOCK_FREQ_HZ;
798 }
799 else
800 {
801 clock_freq_hz = BSP_LOCO_FREQ_HZ;
802 }
803
804 clock_freq_hz >>= divider;
805
806 return clock_freq_hz;
807 }
808
809 /*********************************************************************************************************************
810 * AGT counter underflow interrupt.
811 **********************************************************************************************************************/
ulpt_int_isr(void)812 void ulpt_int_isr (void)
813 {
814 /* Save context if RTOS is used */
815 FSP_CONTEXT_SAVE
816 uint32_t statusMask;
817 IRQn_Type irq = R_FSP_CurrentIrqGet();
818
819 /* Clear pending IRQ to make sure it doesn't fire again after exiting */
820 R_BSP_IrqStatusClear(irq);
821
822 /* Recover ISR context saved in open. */
823 ulpt_instance_ctrl_t * p_instance_ctrl = (ulpt_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
824
825 /* Save ULPTCR to determine the source of the interrupt. */
826 uint32_t ulptcr = p_instance_ctrl->p_reg->ULPTCR;
827
828 /* Invoke the callback function if it is set. */
829 if (NULL != p_instance_ctrl->p_callback)
830 {
831 /* Setup parameters for the user-supplied callback function. */
832 timer_callback_args_t callback_args;
833
834 /* Store callback arguments in memory provided by user if available. This allows callback arguments to be
835 * stored in non-secure memory so they can be accessed by a non-secure callback function. */
836 timer_callback_args_t * p_args = p_instance_ctrl->p_callback_memory;
837 if (NULL == p_args)
838 {
839 /* Store on stack */
840 p_args = &callback_args;
841 }
842 else
843 {
844 /* Save current arguments on the stack in case this is a nested interrupt. */
845 callback_args = *p_args;
846 }
847
848 if (ulptcr & R_ULPT0_ULPTCR_TUNDF_Msk)
849 {
850 p_args->event = TIMER_EVENT_CYCLE_END;
851 }
852 else if (ulptcr & R_ULPT0_ULPTCR_TCMAF_Msk)
853 {
854 p_args->event = TIMER_EVENT_CAPTURE_A;
855 }
856 else if (ulptcr & R_ULPT0_ULPTCR_TCMBF_Msk)
857 {
858 p_args->event = TIMER_EVENT_CAPTURE_B;
859 }
860 else
861 {
862 }
863
864 p_args->p_context = p_instance_ctrl->p_context;
865
866 #if BSP_TZ_SECURE_BUILD
867
868 /* p_callback can point to a secure function or a non-secure function. */
869 if (!cmse_is_nsfptr(p_instance_ctrl->p_callback))
870 {
871 /* If p_callback is secure, then the project does not need to change security state. */
872 p_instance_ctrl->p_callback(p_args);
873 }
874 else
875 {
876 /* If p_callback is Non-secure, then the project must change to Non-secure state in order to call the callback. */
877 ulpt_prv_ns_callback p_callback = (ulpt_prv_ns_callback) (p_instance_ctrl->p_callback);
878 p_callback(p_args);
879 }
880
881 #else
882
883 /* If the project is not Trustzone Secure, then it will never need to change security state in order to call the callback. */
884 p_instance_ctrl->p_callback(p_args);
885 #endif
886
887 if (NULL != p_instance_ctrl->p_callback_memory)
888 {
889 /* Restore callback memory in case this is a nested interrupt. */
890 *p_instance_ctrl->p_callback_memory = callback_args;
891 }
892
893 /* Retreive AGTCR in case it was modified in the callback. */
894 ulptcr = p_instance_ctrl->p_reg->ULPTCR;
895 }
896
897 /* Clear flags in AGTCR. */
898 /* In one shot mode we need to stop the timer*/
899 statusMask = ULPT_PRV_ULPTCR_STATUS_FLAGS;
900 if (p_instance_ctrl->p_reg->ULPTMR3 & R_ULPT0_ULPTMR3_TCNTCTL_Msk)
901 {
902 statusMask |= R_ULPT0_ULPTCR_TSTART_Msk;
903 }
904
905 p_instance_ctrl->p_reg->ULPTCR = (uint8_t) (ulptcr & ~statusMask);
906
907 /* Restore context if RTOS is used */
908 FSP_CONTEXT_RESTORE
909 }
910