xref: /btstack/port/renesas-tb-s1ja-cc256x/template/btstack_example/synergy/ssp/src/driver/r_gpt/r_gpt.c (revision 3b5c872a8c45689e8cc17891f01530f5aa5e911c)
1 /***********************************************************************************************************************
2  * Copyright [2015-2017] Renesas Electronics Corporation and/or its licensors. All Rights Reserved.
3  *
4  * This file is part of Renesas SynergyTM Software Package (SSP)
5  *
6  * The contents of this file (the "contents") are proprietary and confidential to Renesas Electronics Corporation
7  * and/or its licensors ("Renesas") and subject to statutory and contractual protections.
8  *
9  * This file is subject to a Renesas SSP license agreement. Unless otherwise agreed in an SSP license agreement with
10  * Renesas: 1) you may not use, copy, modify, distribute, display, or perform the contents; 2) you may not use any name
11  * or mark of Renesas for advertising or publicity purposes or in connection with your use of the contents; 3) RENESAS
12  * MAKES NO WARRANTY OR REPRESENTATIONS ABOUT THE SUITABILITY OF THE CONTENTS FOR ANY PURPOSE; THE CONTENTS ARE PROVIDED
13  * "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT; AND 4) RENESAS SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, OR
15  * CONSEQUENTIAL DAMAGES, INCLUDING DAMAGES RESULTING FROM LOSS OF USE, DATA, OR PROJECTS, WHETHER IN AN ACTION OF
16  * CONTRACT OR TORT, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE CONTENTS. Third-party contents
17  * included in this file may be subject to different terms.
18  **********************************************************************************************************************/
19 
20 /***********************************************************************************************************************
21  * File Name    : r_gpt.c
22  * Description  : GPT functions used to implement various timer interfaces.
23  **********************************************************************************************************************/
24 
25 /***********************************************************************************************************************
26  * Includes
27  **********************************************************************************************************************/
28 #include "r_gpt.h"
29 #include "r_gpt_cfg.h"
30 #include "hw/hw_gpt_private.h"
31 #include "r_gpt_private_api.h"
32 #include "r_cgc.h"
33 
34 /***********************************************************************************************************************
35  * Macro definitions
36  **********************************************************************************************************************/
37 /** Maximum number of clock counts in 32 bit timer */
38 #define GPT_MAX_CLOCK_COUNTS_32 (0xFFFFFFFFULL)
39 
40 /** Maximum number of clock counts in 16 bit timer */
41 #define GPT_MAX_CLOCK_COUNTS_16 (0xFFFFUL)
42 
43 /** "GPT" in ASCII, used to determine if channel is open. */
44 #define GPT_OPEN                (0x00475054ULL)
45 
46 /** Macro for error logger. */
47 #ifndef GPT_ERROR_RETURN
48 /*LDRA_INSPECTED 77 S This macro does not work when surrounded by parentheses. */
49 #define GPT_ERROR_RETURN(a, err) SSP_ERROR_RETURN((a), (err), &g_module_name[0], &g_gpt_version)
50 #endif
51 
52 /** Variant data mask to determine if GPT is 16-bit (0) or 32-bit (1). */
53 #define GPT_VARIANT_TIMER_SIZE_MASK  (0x4U)
54 
55 /** Variant data bit to determine if GPT is base (0) or matsu (1). */
56 #define GPT_VARIANT_BASE_MATSU_BIT   (3)
57 
58 /***********************************************************************************************************************
59  * Typedef definitions
60  **********************************************************************************************************************/
61 
62 /***********************************************************************************************************************
63  * Private function prototypes
64  **********************************************************************************************************************/
65 static void gpt_hardware_initialize (gpt_instance_ctrl_t * const p_ctrl,
66                                      timer_cfg_t   const * const p_cfg,
67                                      gpt_pclk_div_t        const pclk_divisor,
68                                      timer_size_t          const pclk_counts,
69                                      timer_size_t          const duty_cycle);
70 
71 static ssp_err_t gpt_period_to_pclk (gpt_instance_ctrl_t * const p_ctrl,
72                                      timer_size_t          const period,
73                                      timer_unit_t          const unit,
74                                      timer_size_t        * const p_period_pclk,
75                                      gpt_pclk_div_t      * const p_divisor);
76 
77 static ssp_err_t gpt_duty_cycle_to_pclk (gpt_shortest_level_t  shortest_pwm_signal,
78                                          timer_size_t     const duty_cycle,
79                                          timer_pwm_unit_t const unit,
80                                          timer_size_t     const period,
81                                          timer_size_t   * const p_duty_cycle_pclk);
82 
83 static void gpt_set_duty_cycle (gpt_instance_ctrl_t * const p_ctrl,
84                                 timer_size_t          const duty_cycle_counts,
85                                 uint8_t               const pin);
86 
87 static ssp_err_t gpt_common_open (gpt_instance_ctrl_t * const p_ctrl,
88                                   timer_cfg_t   const * const p_cfg,
89                                   ssp_feature_t const * const p_ssp_feature,
90                                   gpt_pclk_div_t      * const p_pclk_divisor,
91                                   timer_size_t        * const p_pclk_counts,
92                                   uint16_t            * const p_variant);
93 
94 static void gpt_set_output_pin (gpt_instance_ctrl_t * const p_ctrl,
95                                 gpt_gtioc_t           const gtio,
96                                 gpt_pin_level_t       const level,
97                                 timer_mode_t          const mode,
98                                 timer_size_t          const duty_cycle);
99 
100 static ssp_err_t gpt_divisor_select(gpt_instance_ctrl_t * const p_ctrl,
101                                     uint64_t            *       p_period_counts,
102                                     gpt_pclk_div_t      * const p_divisor);
103 
104 static uint32_t gpt_clock_frequency_get(gpt_instance_ctrl_t * const p_ctrl);
105 
106 /***********************************************************************************************************************
107  * ISR prototypes
108  **********************************************************************************************************************/
109 void gpt_counter_overflow_isr (void);
110 
111 /***********************************************************************************************************************
112  * Private global variables
113  **********************************************************************************************************************/
114 /** Name of module used by error logger macro */
115 #if BSP_CFG_ERROR_LOG != 0
116 static const char g_module_name[] = "gpt";
117 #endif
118 
119 #if defined(__GNUC__)
120 /* This structure is affected by warnings from a GCC compiler bug.  This pragma suppresses the warnings in this
121  * structure only. */
122 /*LDRA_INSPECTED 69 S */
123 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
124 #endif
125 /** Version data structure used by error logger macro. */
126 static const ssp_version_t g_gpt_version =
127 {
128     .api_version_minor  = TIMER_API_VERSION_MINOR,
129     .api_version_major  = TIMER_API_VERSION_MAJOR,
130     .code_version_major = GPT_CODE_VERSION_MAJOR,
131     .code_version_minor = GPT_CODE_VERSION_MINOR
132 };
133 #if defined(__GNUC__)
134 /* Restore warning settings for 'missing-field-initializers' to as specified on command line. */
135 /*LDRA_INSPECTED 69 S */
136 #pragma GCC diagnostic pop
137 #endif
138 
139 /***********************************************************************************************************************
140  * Global Variables
141  **********************************************************************************************************************/
142 /** GPT Implementation of General Timer Driver  */
143 /*LDRA_INSPECTED 27 D This structure must be accessible in user code. It cannot be static. */
144 const timer_api_t g_timer_on_gpt =
145 {
146     .open            = R_GPT_TimerOpen,
147     .stop            = R_GPT_Stop,
148     .start           = R_GPT_Start,
149     .reset           = R_GPT_Reset,
150     .periodSet       = R_GPT_PeriodSet,
151     .counterGet      = R_GPT_CounterGet,
152     .dutyCycleSet    = R_GPT_DutyCycleSet,
153     .infoGet         = R_GPT_InfoGet,
154     .close           = R_GPT_Close,
155     .versionGet      = R_GPT_VersionGet
156 };
157 
158 /*******************************************************************************************************************//**
159  * @addtogroup GPT
160  * @{
161  **********************************************************************************************************************/
162 
163 /***********************************************************************************************************************
164  * Functions
165  **********************************************************************************************************************/
166 
167 /*******************************************************************************************************************//**
168  * @brief  Powers on GPT, handles required initialization described in hardware manual. Implements timer_api_t::open.
169  *
170  * The Open function configures a single GPT channel, starts the channel, and provides a handle for use with the GPT API
171  * Control and Close functions. This function must be called once prior to calling any other GPT API functions. After a
172  * channel is opened, the Open function should not be called again for the same channel without first calling the
173  * associated Close function.
174  *
175  * GPT hardware does not support one-shot functionality natively.  When using one-shot mode, the timer will be stopped
176  * in an ISR after the requested period has elapsed.
177  *
178  * The GPT implementation of the general timer can accept a ::timer_on_gpt_cfg_t extension parameter.
179  *
180  * @retval SSP_SUCCESS           Initialization was successful and timer has started.
181  * @retval SSP_ERR_ASSERTION     One of the following parameters is incorrect.  Either
182  *                                 - p_cfg is NULL, OR
183  *                                 - p_ctrl is NULL, OR
184  * @retval SSP_ERR_INVALID_ARGUMENT  One of the following parameters is invalid:
185  *                                 - p_cfg->period: must be in the following range:
186  *                                     - Lower bound: (1 / (PCLK frequency)
187  *                                     - Upper bound: (0xFFFFFFFF * 1024 / (PCLK frequency))
188  *                                 - p_cfg->p_callback not NULL, but ISR is not enabled. ISR must be enabled to
189  *                                   use callback function.  Enable channel's overflow ISR in bsp_irq_cfg.h.
190  * @retval SSP_ERR_IN_USE        The channel specified has already been opened. No configurations were changed. Call
191  *                               the associated Close function or use associated Control commands to reconfigure the
192  *                               channel.
193  * @retval SSP_ERR_IRQ_BSP_DISABLED  - p_cfg->mode is ::TIMER_MODE_ONE_SHOT, but ISR is not enabled.  ISR must be
194  *                                     enabled to use one-shot mode.
195  * @retval SSP_ERR_IP_CHANNEL_NOT_PRESENT - The channel requested in the p_cfg parameter is not available on this device.
196  *
197  * @note This function is reentrant for different channels.  It is not reentrant for the same channel.
198  **********************************************************************************************************************/
R_GPT_TimerOpen(timer_ctrl_t * const p_api_ctrl,timer_cfg_t const * const p_cfg)199 ssp_err_t R_GPT_TimerOpen  (timer_ctrl_t * const      p_api_ctrl,
200                             timer_cfg_t const * const p_cfg)
201 {
202     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
203 #if GPT_CFG_PARAM_CHECKING_ENABLE
204     SSP_ASSERT(NULL != p_cfg);
205     SSP_ASSERT(NULL != p_ctrl);
206 #endif /* if GPT_CFG_PARAM_CHECKING_ENABLE */
207 
208     /** Calculate period and store internal variables */
209     gpt_pclk_div_t pclk_divisor = GPT_PCLK_DIV_BY_1;
210     timer_size_t pclk_counts = 0;
211     uint16_t variant = 0;
212     ssp_feature_t ssp_feature = {{(ssp_ip_t) 0}};
213     ssp_feature.channel = p_cfg->channel;
214     ssp_feature.unit = 0U;
215     ssp_feature.id = SSP_IP_GPT;
216     ssp_err_t err = gpt_common_open(p_ctrl, p_cfg, &ssp_feature, &pclk_divisor, &pclk_counts, &variant);
217     GPT_ERROR_RETURN((SSP_SUCCESS == err), err);
218 
219     /** Save the configuration  */
220     timer_on_gpt_cfg_t * p_ext = (timer_on_gpt_cfg_t *) p_cfg->p_extend;
221     p_ctrl->gtioca_output_enabled = p_ext->gtioca.output_enabled;
222     p_ctrl->gtiocb_output_enabled = p_ext->gtiocb.output_enabled;
223     p_ctrl->shortest_pwm_signal = p_ext->shortest_pwm_signal;
224 
225     /** Calculate duty cycle */
226     timer_size_t duty_cycle = 0;
227     if (TIMER_MODE_PWM == p_cfg->mode)
228     {
229         err = gpt_duty_cycle_to_pclk(p_ctrl->shortest_pwm_signal, p_cfg->duty_cycle, p_cfg->duty_cycle_unit,
230                                          pclk_counts, &duty_cycle);
231         GPT_ERROR_RETURN((SSP_SUCCESS == err), err);
232     }
233 
234     /** Verify channel is not already used */
235     ssp_err_t     bsp_err = R_BSP_HardwareLock(&ssp_feature);
236     GPT_ERROR_RETURN((SSP_SUCCESS == bsp_err), SSP_ERR_IN_USE);
237 
238     /** Power on GPT before setting any hardware registers. Make sure the counter is stopped before setting mode
239        register, PCLK divisor register, and counter register. */
240     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
241     R_BSP_ModuleStart(&ssp_feature);
242     HW_GPT_CounterStartStop(p_gpt_reg, GPT_STOP);
243     HW_GPT_RegisterInit(p_gpt_reg, (variant >> GPT_VARIANT_BASE_MATSU_BIT) & 0xFFFE);
244 
245     gpt_hardware_initialize(p_ctrl, p_cfg, pclk_divisor, pclk_counts, duty_cycle);
246 
247     p_ctrl->open = GPT_OPEN;
248 
249     return SSP_SUCCESS;
250 } /* End of function R_GPT_TimerOpen */
251 
252 /*******************************************************************************************************************//**
253  * @brief  Stops timer. Implements timer_api_t::stop.
254  *
255  * @retval SSP_SUCCESS           Timer successfully stopped.
256  * @retval SSP_ERR_ASSERTION     The p_ctrl parameter was null.
257  * @retval SSP_ERR_NOT_OPEN      The channel is not opened.
258  **********************************************************************************************************************/
R_GPT_Stop(timer_ctrl_t * const p_api_ctrl)259 ssp_err_t R_GPT_Stop (timer_ctrl_t * const p_api_ctrl)
260 {
261     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
262 #if GPT_CFG_PARAM_CHECKING_ENABLE
263     /** Make sure handle is valid. */
264     SSP_ASSERT(NULL != p_ctrl);
265     SSP_ASSERT(NULL != p_ctrl->p_reg);
266 #endif
267 
268     GPT_ERROR_RETURN(GPT_OPEN == p_ctrl->open, SSP_ERR_NOT_OPEN);
269     /** Stop timer */
270     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
271     HW_GPT_CounterStartStop(p_gpt_reg, GPT_STOP);
272     return SSP_SUCCESS;
273 } /* End of function R_GPT_Stop */
274 
275 /*******************************************************************************************************************//**
276  * @brief  Starts timer. Implements timer_api_t::start.
277  *
278  * @retval SSP_SUCCESS           Timer successfully started.
279  * @retval SSP_ERR_ASSERTION     The p_ctrl parameter was null.
280  * @retval SSP_ERR_NOT_OPEN      The channel is not opened.
281  **********************************************************************************************************************/
R_GPT_Start(timer_ctrl_t * const p_api_ctrl)282 ssp_err_t R_GPT_Start (timer_ctrl_t * const p_api_ctrl)
283 {
284     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
285 #if GPT_CFG_PARAM_CHECKING_ENABLE
286     /** Make sure handle is valid. */
287     SSP_ASSERT(NULL != p_ctrl);
288     SSP_ASSERT(NULL != p_ctrl->p_reg);
289 #endif
290 
291     GPT_ERROR_RETURN(GPT_OPEN == p_ctrl->open, SSP_ERR_NOT_OPEN);
292     /** Start timer */
293     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
294     HW_GPT_CounterStartStop(p_gpt_reg, GPT_START);
295     return SSP_SUCCESS;
296 } /* End of function R_GPT_Start */
297 
298 /*******************************************************************************************************************//**
299  * @brief  Sets counter value in provided p_value pointer. Implements timer_api_t::counterGet.
300  *
301  * @retval SSP_SUCCESS           Counter value read, p_value is valid.
302  * @retval SSP_ERR_ASSERTION     The p_ctrl or p_value parameter was null.
303  * @retval SSP_ERR_NOT_OPEN      The channel is not opened.
304  **********************************************************************************************************************/
R_GPT_CounterGet(timer_ctrl_t * const p_api_ctrl,timer_size_t * const p_value)305 ssp_err_t R_GPT_CounterGet (timer_ctrl_t * const p_api_ctrl,
306                             timer_size_t * const p_value)
307 {
308     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
309 #if GPT_CFG_PARAM_CHECKING_ENABLE
310     /** Make sure parameters are valid */
311     SSP_ASSERT(NULL != p_ctrl);
312     SSP_ASSERT(NULL != p_value);
313     SSP_ASSERT(NULL != p_ctrl->p_reg);
314 #endif
315 
316     GPT_ERROR_RETURN(GPT_OPEN == p_ctrl->open, SSP_ERR_NOT_OPEN);
317     /** Read counter value */
318     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
319     *p_value = HW_GPT_CounterGet(p_gpt_reg);
320     return SSP_SUCCESS;
321 } /* End of function R_GPT_CounterGet */
322 
323 /*******************************************************************************************************************//**
324  * @brief  Resets the counter value to 0. Implements timer_api_t::reset.
325  *
326  * @retval SSP_SUCCESS           Counter value written successfully.
327  * @retval SSP_ERR_ASSERTION     The p_ctrl parameter was null.
328  * @retval SSP_ERR_NOT_OPEN      The channel is not opened.
329  **********************************************************************************************************************/
R_GPT_Reset(timer_ctrl_t * const p_api_ctrl)330 ssp_err_t R_GPT_Reset (timer_ctrl_t * const p_api_ctrl)
331 {
332     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
333 #if GPT_CFG_PARAM_CHECKING_ENABLE
334     /** Make sure handle is valid. */
335     SSP_ASSERT(NULL != p_ctrl);
336     SSP_ASSERT(NULL != p_ctrl->p_reg);
337 #endif
338 
339     GPT_ERROR_RETURN(GPT_OPEN == p_ctrl->open, SSP_ERR_NOT_OPEN);
340     /** Write the counter value */
341     SSP_CRITICAL_SECTION_DEFINE;
342     SSP_CRITICAL_SECTION_ENTER;
343 
344     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
345     gpt_start_status_t status = HW_GPT_CounterStartBitGet(p_gpt_reg);
346     HW_GPT_CounterStartStop(p_gpt_reg, GPT_STOP);
347     /* Reset the gpt counter value to 0 */
348     HW_GPT_ClearCounter (p_gpt_reg, p_ctrl->channel);
349     HW_GPT_CounterStartStop(p_gpt_reg, status);
350 
351     SSP_CRITICAL_SECTION_EXIT;
352     return SSP_SUCCESS;
353 } /* End of function R_GPT_Reset */
354 
355 /*******************************************************************************************************************//**
356  * @brief  Sets period value provided. Implements timer_api_t::periodSet.
357  *
358  * @retval SSP_SUCCESS           Period value written successfully.
359  * @retval SSP_ERR_ASSERTION     The p_ctrl parameter was null.
360  * @retval SSP_ERR_INVALID_ARGUMENT   One of the following is invalid:
361  *                                    - p_period->unit: must be one of the options from timer_unit_t
362  *                                    - p_period->value: must result in a period in the following range:
363  *                                        - Lower bound: (1 / (PCLK frequency))
364  *                                        - Upper bound: (0xFFFFFFFF * 1024 / (PCLK frequency))
365  * @retval SSP_ERR_NOT_OPEN      The channel is not opened.
366  **********************************************************************************************************************/
R_GPT_PeriodSet(timer_ctrl_t * const p_api_ctrl,timer_size_t const period,timer_unit_t const unit)367 ssp_err_t R_GPT_PeriodSet (timer_ctrl_t * const p_api_ctrl,
368                            timer_size_t   const period,
369                            timer_unit_t const   unit)
370 {
371     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
372 #if GPT_CFG_PARAM_CHECKING_ENABLE
373     /** Make sure handle is valid. */
374     SSP_ASSERT(NULL != p_ctrl);
375     SSP_ASSERT(NULL != p_ctrl->p_reg);
376     GPT_ERROR_RETURN((0 != period), SSP_ERR_INVALID_ARGUMENT);
377 #endif
378 
379     GPT_ERROR_RETURN(GPT_OPEN == p_ctrl->open, SSP_ERR_NOT_OPEN);
380     /** Delay must be converted to PCLK counts before it can be set in registers */
381     ssp_err_t     err          = SSP_SUCCESS;
382     timer_size_t      pclk_counts  = 0;
383     gpt_pclk_div_t pclk_divisor = GPT_PCLK_DIV_BY_1;
384     err = gpt_period_to_pclk(p_ctrl, period, unit, &pclk_counts, &pclk_divisor);
385 
386     /** Make sure period is valid. */
387     GPT_ERROR_RETURN((SSP_SUCCESS == err), err);
388 
389     /** Store current status, then stop timer before setting divisor register */
390     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
391     gpt_start_status_t status = HW_GPT_CounterStartBitGet(p_gpt_reg);
392     HW_GPT_CounterStartStop(p_gpt_reg, GPT_STOP);
393     HW_GPT_DivisorSet(p_gpt_reg, pclk_divisor);
394     HW_GPT_TimerCycleSet(p_gpt_reg, pclk_counts - 1);
395 
396     /** Reset counter in case new cycle is less than current count value, then restore state (counting or stopped). */
397     HW_GPT_CounterSet(p_gpt_reg, 0);
398     HW_GPT_CounterStartStop(p_gpt_reg, status);
399 
400     return SSP_SUCCESS;
401 } /* End of function R_GPT_PeriodSet */
402 
403 /*******************************************************************************************************************//**
404  * @brief  Sets status in provided p_status pointer. Implements pwm_api_t::dutyCycleSet.
405  *
406  * @retval SSP_SUCCESS                Counter value written successfully.
407  * @retval SSP_ERR_ASSERTION          The p_ctrl parameter was null.
408  * @retval SSP_ERR_NOT_OPEN           The channel is not opened.
409  * @retval SSP_ERR_INVALID_ARGUMENT   The pin value is out of range; Should be either 0 (for GTIOCA) or 1 (for GTIOCB).
410  **********************************************************************************************************************/
R_GPT_DutyCycleSet(timer_ctrl_t * const p_api_ctrl,timer_size_t const duty_cycle,timer_pwm_unit_t const unit,uint8_t const pin)411 ssp_err_t R_GPT_DutyCycleSet (timer_ctrl_t   * const p_api_ctrl,
412                               timer_size_t     const duty_cycle,
413                               timer_pwm_unit_t const unit,
414                               uint8_t          const pin)
415 {
416     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
417 #if GPT_CFG_PARAM_CHECKING_ENABLE
418     /** Make sure handle is valid. */
419     SSP_ASSERT(NULL != p_ctrl);
420     SSP_ASSERT(NULL != p_ctrl->p_reg);
421     GPT_ERROR_RETURN(((pin == GPT_GTIOCA) || (pin == GPT_GTIOCB)), SSP_ERR_INVALID_ARGUMENT);
422 #endif
423 
424     GPT_ERROR_RETURN(GPT_OPEN == p_ctrl->open, SSP_ERR_NOT_OPEN);
425     /** Converted duty cycle to PCLK counts before it can be set in registers */
426     timer_size_t duty_cycle_counts = 0;
427     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
428     ssp_err_t err = gpt_duty_cycle_to_pclk(p_ctrl->shortest_pwm_signal, duty_cycle, unit,
429                                                HW_GPT_TimerCycleGet(p_gpt_reg) + 1, &duty_cycle_counts);
430     GPT_ERROR_RETURN((SSP_SUCCESS == err), err);
431 
432     /** Set duty cycle. */
433     gpt_set_duty_cycle(p_ctrl, duty_cycle_counts, pin);
434     return SSP_SUCCESS;
435 } /* End of function R_GPT_DutyCycleSet */
436 
437 /*******************************************************************************************************************//**
438  * @brief  Get timer information and store it in provided pointer p_info.
439  * Implements timer_api_t::infoGet.
440  *
441  * @retval SSP_SUCCESS           Period, count direction, frequency, and status value written to caller's
442  *                               structure successfully.
443  * @retval SSP_ERR_ASSERTION     The p_ctrl or p_info parameter was null.
444  * @retval SSP_ERR_NOT_OPEN      The channel is not opened.
445  **********************************************************************************************************************/
R_GPT_InfoGet(timer_ctrl_t * const p_api_ctrl,timer_info_t * const p_info)446 ssp_err_t R_GPT_InfoGet (timer_ctrl_t * const p_api_ctrl, timer_info_t * const p_info)
447 {
448     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
449 #if GPT_CFG_PARAM_CHECKING_ENABLE
450     /** Make sure parameters are valid. */
451     SSP_ASSERT(NULL != p_ctrl);
452     SSP_ASSERT(NULL != p_info);
453     SSP_ASSERT(NULL != p_ctrl->p_reg);
454 #endif
455 
456     GPT_ERROR_RETURN(GPT_OPEN == p_ctrl->open, SSP_ERR_NOT_OPEN);
457     /** Get and store period */
458     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
459     p_info->period_counts = HW_GPT_TimerCycleGet(p_gpt_reg) + 1;
460 
461     /** Get and store clock frequency */
462     p_info->clock_frequency = gpt_clock_frequency_get(p_ctrl);
463 
464     /** Get and store clock counting direction */
465     p_info->count_direction = HW_GPT_DirectionGet(p_gpt_reg);
466 
467     bool status = HW_GPT_CounterStartBitGet(p_gpt_reg);
468     if (status)
469     {
470         p_info->status = TIMER_STATUS_COUNTING;
471     }
472     else
473     {
474         p_info->status = TIMER_STATUS_STOPPED;
475     }
476 
477     p_info->elc_event = HW_GPT_GetCounterOverFlowEvent(p_ctrl->channel);
478 
479     return SSP_SUCCESS;
480 } /* End of function R_GPT_InfoGet */
481 
482 /*******************************************************************************************************************//**
483  * @brief      Stops counter, disables output pins, and clears internal driver data.
484  *
485  * @retval     SSP_SUCCESS          Successful close.
486  * @retval     SSP_ERR_ASSERTION    The parameter p_ctrl is NULL.
487  * @retval     SSP_ERR_NOT_OPEN     The channel is not opened.
488  **********************************************************************************************************************/
R_GPT_Close(timer_ctrl_t * const p_api_ctrl)489 ssp_err_t R_GPT_Close (timer_ctrl_t * const p_api_ctrl)
490 {
491     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) p_api_ctrl;
492     ssp_err_t err = SSP_SUCCESS;
493 
494 #if GPT_CFG_PARAM_CHECKING_ENABLE
495     /** Make sure channel is open.  If not open, return. */
496     SSP_ASSERT(NULL != p_ctrl);
497     SSP_ASSERT(NULL != p_ctrl->p_reg);
498 #endif
499 
500     /** Cleanup. Stop counter and disable output. */
501     GPT_ERROR_RETURN(GPT_OPEN == p_ctrl->open, SSP_ERR_NOT_OPEN);
502     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
503     HW_GPT_CounterStartStop(p_gpt_reg, GPT_STOP);
504     if (SSP_INVALID_VECTOR != p_ctrl->irq)
505     {
506         NVIC_DisableIRQ(p_ctrl->irq);
507     }
508 
509     gtior_t * p_reg = HW_GPT_GTIOCRegLookup(p_gpt_reg, GPT_GTIOCA);
510     HW_GPT_GTIOCPinOutputEnable(p_reg, false);
511     p_reg = HW_GPT_GTIOCRegLookup(p_gpt_reg, GPT_GTIOCB);
512     HW_GPT_GTIOCPinOutputEnable(p_reg, false);
513 
514     /** Unlock channel */
515     ssp_feature_t ssp_feature = {{(ssp_ip_t) 0}};
516     ssp_feature.channel = p_ctrl->channel;
517     ssp_feature.unit = 0U;
518     ssp_feature.id = SSP_IP_GPT;
519     R_BSP_HardwareUnlock(&ssp_feature);
520 
521     /** Clear stored internal driver data */
522     p_ctrl->one_shot = false;
523     ssp_vector_info_t * p_vector_info;
524     if (SSP_INVALID_VECTOR != p_ctrl->irq)
525     {
526         R_SSP_VectorInfoGet(p_ctrl->irq, &p_vector_info);
527         (*p_vector_info->pp_ctrl) = NULL;
528     }
529     p_ctrl->open              = 0U;
530 
531     return err;
532 } /* End of function R_GPT_Close */
533 
534 /*******************************************************************************************************************//**
535  * @brief      Sets driver version based on compile time macros.
536  *
537  * @retval     SSP_SUCCESS          Successful close.
538  * @retval     SSP_ERR_ASSERTION    The parameter p_version is NULL.
539  **********************************************************************************************************************/
R_GPT_VersionGet(ssp_version_t * const p_version)540 ssp_err_t R_GPT_VersionGet (ssp_version_t * const p_version)
541 {
542 #if GPT_CFG_PARAM_CHECKING_ENABLE
543     /** Verify parameters are valid */
544     SSP_ASSERT(NULL != p_version);
545 #endif
546 
547     p_version->version_id = g_gpt_version.version_id;
548 
549     return SSP_SUCCESS;
550 } /* End of function R_GPT_VersionGet */
551 
552 /** @} (end addtogroup GPT) */
553 
554 /*********************************************************************************************************************//**
555  * Private Functions
556  **********************************************************************************************************************/
557 
558 /*******************************************************************************************************************//**
559  * Performs calculations required to set configure GPT.
560  *
561  * @param[in]  p_ctrl          Instance control block.
562  * @param[in]  p_cfg           Pointer to timer configuration.
563  * @param[in]  p_ssp_feature   Pointer to ssp_feature_t structure for this channel.
564  * @param[out] p_pclk_divisor  Divisor applied to GPT clock set here.
565  * @param[out] p_pclk_counts   Counts before timer expires set here.
566  * @param[out] p_variant       Variant data set here.
567  *
568  * @retval     SSP_SUCCESS                 Calculation of parameters required for configuration of timer is successful
569  * @retval     SSP_ERR_IRQ_BSP_DISABLED    IRQ not enabled in BSP
570  * @return                       See @ref Common_Error_Codes or functions called by this function for other possible
571  *                               return codes. This function calls:
572  *                                   * fmi_api_t::productFeatureGet
573  **********************************************************************************************************************/
gpt_common_open(gpt_instance_ctrl_t * const p_ctrl,timer_cfg_t const * const p_cfg,ssp_feature_t const * const p_ssp_feature,gpt_pclk_div_t * const p_pclk_divisor,timer_size_t * const p_pclk_counts,uint16_t * const p_variant)574 static ssp_err_t gpt_common_open (gpt_instance_ctrl_t * const p_ctrl,
575                                   timer_cfg_t   const * const p_cfg,
576                                   ssp_feature_t const * const p_ssp_feature,
577                                   gpt_pclk_div_t      * const p_pclk_divisor,
578                                   timer_size_t        * const p_pclk_counts,
579                                   uint16_t            * const p_variant)
580 {
581     fmi_feature_info_t info = {0U};
582     ssp_err_t     err          = SSP_SUCCESS;
583     err = g_fmi_on_fmi.productFeatureGet(p_ssp_feature, &info);
584     GPT_ERROR_RETURN(SSP_SUCCESS == err, err);
585     p_ctrl->p_reg = info.ptr;
586     *p_variant = (uint16_t) info.variant_data;
587 
588     fmi_event_info_t event_info = {(IRQn_Type) 0U};
589     g_fmi_on_fmi.eventInfoGet(p_ssp_feature, SSP_SIGNAL_GPT_COUNTER_OVERFLOW, &event_info);
590     p_ctrl->irq = event_info.irq;
591 
592     if (0U == (info.variant_data & GPT_VARIANT_TIMER_SIZE_MASK))
593     {
594         p_ctrl->variant = TIMER_VARIANT_16_BIT;
595     }
596     else
597     {
598         p_ctrl->variant = TIMER_VARIANT_32_BIT;
599     }
600 
601     /** Convert the period into PCLK counts and clock divisor */
602     err = gpt_period_to_pclk(p_ctrl, p_cfg->period, p_cfg->unit, p_pclk_counts, p_pclk_divisor);
603     GPT_ERROR_RETURN(SSP_SUCCESS == err, err);
604 
605     /** If callback is not null or timer mode is one shot, make sure the IRQ is enabled and store callback in the
606      *  control block.
607      *  @note The GPT hardware does not support one-shot mode natively.  To support one-shot mode, the timer will be
608      *  stopped and cleared using software in the ISR. */
609     if ((p_cfg->p_callback) || (TIMER_MODE_ONE_SHOT == p_cfg->mode))
610     {
611         GPT_ERROR_RETURN(SSP_INVALID_VECTOR != p_ctrl->irq, SSP_ERR_IRQ_BSP_DISABLED);
612 
613         p_ctrl->p_callback = p_cfg->p_callback;
614         p_ctrl->p_context  = p_cfg->p_context;
615     }
616 
617     /** Initialize channel and one_shot in control block. */
618     p_ctrl->channel          = p_cfg->channel;
619     if (TIMER_MODE_ONE_SHOT == p_cfg->mode)
620     {
621         p_ctrl->one_shot = true;
622     }
623     else
624     {
625         p_ctrl->one_shot = false;
626     }
627 
628     return SSP_SUCCESS;
629 } /* End of function gpt_common_open */
630 
631 /*******************************************************************************************************************//**
632  * Performs hardware initialization of the GPT.
633  *
634  * @pre    All parameter checking and calculations should be done prior to calling this function.
635  *
636  * @param[in]  p_ctrl        Instance control block.
637  * @param[in]  p_cfg         Pointer to timer configuration.
638  * @param[in]  pclk_divisor  Divisor applied to GPT clock.
639  * @param[in]  pclk_counts   Counts before timer expires.
640  * @param[in]  duty_cycle    Duty cycle for this implementation.
641  **********************************************************************************************************************/
gpt_hardware_initialize(gpt_instance_ctrl_t * const p_ctrl,timer_cfg_t const * const p_cfg,gpt_pclk_div_t const pclk_divisor,timer_size_t const pclk_counts,timer_size_t const duty_cycle)642 static void gpt_hardware_initialize (gpt_instance_ctrl_t * const p_ctrl,
643                                      timer_cfg_t   const * const p_cfg,
644                                      gpt_pclk_div_t        const pclk_divisor,
645                                      timer_size_t          const pclk_counts,
646                                      timer_size_t          const duty_cycle)
647 {
648     /** Initialization following flowchart in hardware manual (Figure 24.4 in NoSecurity_r01uh0488ej0040_sc32.pdf) */
649     /** In one-shot mode, timer will be stopped and reset in the ISR. */
650     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
651     HW_GPT_ModeSet(p_gpt_reg, GPT_MODE_PERIODIC);      ///< In one-shot mode, ISR will stop and reset timer.
652     HW_GPT_DirectionSet(p_gpt_reg, GPT_DIR_COUNT_UP);
653     HW_GPT_DivisorSet(p_gpt_reg, pclk_divisor);
654     HW_GPT_TimerCycleSet(p_gpt_reg, pclk_counts - 1);
655     HW_GPT_CounterSet(p_gpt_reg, 0);
656 
657     /** Set output if requested */
658     if (p_cfg->p_extend)
659     {
660         timer_on_gpt_cfg_t * p_ext = (timer_on_gpt_cfg_t *) p_cfg->p_extend;
661         if (p_ext->gtioca.output_enabled)
662         {
663             gpt_set_output_pin(p_ctrl, GPT_GTIOCA, p_ext->gtioca.stop_level, p_cfg->mode, duty_cycle);
664         }
665 
666         if (p_ext->gtiocb.output_enabled)
667         {
668             gpt_set_output_pin(p_ctrl, GPT_GTIOCB, p_ext->gtiocb.stop_level, p_cfg->mode, duty_cycle);
669         }
670     }
671 
672     /** Enable CPU interrupts if callback is not null.  Also enable interrupts for one shot mode.
673      *  @note The GPT hardware does not support one-shot mode natively.  To support one-shot mode, the timer will be
674      *  stopped and cleared using software in the ISR. */
675     if ((p_cfg->p_callback) || (TIMER_MODE_ONE_SHOT == p_cfg->mode))
676     {
677         ssp_vector_info_t * p_vector_info;
678         R_SSP_VectorInfoGet(p_ctrl->irq, &p_vector_info);
679         NVIC_SetPriority(p_ctrl->irq, p_cfg->irq_ipl);
680         *(p_vector_info->pp_ctrl) = p_ctrl;
681 
682         R_BSP_IrqStatusClear(p_ctrl->irq);
683         NVIC_ClearPendingIRQ(p_ctrl->irq);
684         NVIC_EnableIRQ(p_ctrl->irq);
685     }
686 
687     /** Start the timer if requested by user */
688     if (p_cfg->autostart)
689     {
690         HW_GPT_CounterStartStop(p_gpt_reg, GPT_START);
691     }
692 } /* End of function gpt_hardware_initialize */
693 
694 /*******************************************************************************************************************//**
695  * Uses divisor to ensure period fits in 32 bits.
696  *
697  * @param[in]      p_ctrl           Instance control block
698  * @param[in,out]  p_period_counts  GPT period in counts stored here
699  * @param[out]     p_divisor        GPT divisor stored here
700  *
701  * @retval         SSP_SUCCESS                    Divisor is set successsfully
702  * @retval         SSP_ERR_INVALID_ARGUMENT       Period counts is greater than the maximum number of clock counts
703  **********************************************************************************************************************/
gpt_divisor_select(gpt_instance_ctrl_t * const p_ctrl,uint64_t * p_period_counts,gpt_pclk_div_t * const p_divisor)704 static ssp_err_t gpt_divisor_select(gpt_instance_ctrl_t * const p_ctrl,
705                                     uint64_t            *       p_period_counts,
706                                     gpt_pclk_div_t      * const p_divisor)
707 {
708     /** temp_period now represents PCLK counts, but it could potentially overflow 32 bits.  If so, convert it here and
709      *  set divisor appropriately.
710      */
711     gpt_pclk_div_t temp_div = GPT_PCLK_DIV_BY_1;
712     uint64_t max_counts     = GPT_MAX_CLOCK_COUNTS_32;
713 
714     if (TIMER_VARIANT_16_BIT == p_ctrl->variant)
715     {
716         max_counts = GPT_MAX_CLOCK_COUNTS_16;
717     }
718     while ((*p_period_counts > max_counts) && (temp_div < GPT_PCLK_DIV_BY_1024))
719     {
720         *p_period_counts >>= 2;
721         temp_div++;
722     }
723 
724     /** If period is still too large, return error */
725     GPT_ERROR_RETURN((*p_period_counts <= max_counts), SSP_ERR_INVALID_ARGUMENT);
726 
727     *p_divisor = temp_div;
728 
729     return SSP_SUCCESS;
730 }
731 
732 
733 /*******************************************************************************************************************//**
734  * Converts period from input value to PCLK counts
735  *
736  * @param[in]  p_ctrl        Instance control block.
737  * @param[in]  period        Period configured by user.
738  * @param[in]  unit          Period unit configured by user.
739  * @param[out] p_period_pclk Period in clock counts set here.
740  * @param[out] p_divisor     Clock divisor set here.
741  *
742  * @retval     SSP_SUCCESS          Successful conversion
743  * @retval     SSP_ERR_INVALID_ARGUMENT  One of the following is invalid:
744  *                                    - p_period->unit: must be one of the options from timer_unit_t
745  *                                    - p_period->value: must result in a period in the following range:
746  *                                        - Lower bound: (1 / (PCLK frequency))
747  *                                        - Upper bound: (0xFFFFFFFF * 1024 / (PCLK frequency))
748  **********************************************************************************************************************/
gpt_period_to_pclk(gpt_instance_ctrl_t * const p_ctrl,timer_size_t const period,timer_unit_t const unit,timer_size_t * const p_period_pclk,gpt_pclk_div_t * const p_divisor)749 static ssp_err_t gpt_period_to_pclk (gpt_instance_ctrl_t * const p_ctrl,
750                                      timer_size_t          const period,
751                                      timer_unit_t          const unit,
752                                      timer_size_t        * const p_period_pclk,
753                                      gpt_pclk_div_t      * const p_divisor)
754 {
755     uint64_t temp_period = period;
756     ssp_err_t err = SSP_SUCCESS;
757 
758     /** Read the current PCLK frequency from the clock module. */
759     uint32_t pclk_freq_hz = 0;
760     g_cgc_on_cgc.systemClockFreqGet(CGC_SYSTEM_CLOCKS_PCLKD, &pclk_freq_hz);
761 
762     /** Convert period to PCLK counts so it can be set in hardware. */
763     switch (unit)
764     {
765         case TIMER_UNIT_PERIOD_RAW_COUNTS:
766             temp_period = period;
767             break;
768         case TIMER_UNIT_FREQUENCY_KHZ:
769             temp_period = (pclk_freq_hz * 1ULL) / (1000 * period);
770             break;
771         case TIMER_UNIT_FREQUENCY_HZ:
772             temp_period = (pclk_freq_hz * 1ULL) / period;
773             break;
774         case TIMER_UNIT_PERIOD_NSEC:
775             temp_period = (period * (pclk_freq_hz * 1ULL)) / 1000000000;
776             break;
777         case TIMER_UNIT_PERIOD_USEC:
778             temp_period = (period * (pclk_freq_hz * 1ULL)) / 1000000;
779             break;
780         case TIMER_UNIT_PERIOD_MSEC:
781             temp_period = (period * (pclk_freq_hz * 1ULL)) / 1000;
782             break;
783         case TIMER_UNIT_PERIOD_SEC:
784             temp_period = period * (pclk_freq_hz * 1ULL);
785             break;
786         default:
787             err = SSP_ERR_INVALID_ARGUMENT;
788             break;
789     }
790     GPT_ERROR_RETURN(SSP_SUCCESS == err, err);
791 
792     err = gpt_divisor_select(p_ctrl, &temp_period, p_divisor);
793     GPT_ERROR_RETURN(SSP_SUCCESS == err, err);
794 
795     /** If the period is valid, return to caller. */
796     *p_period_pclk = (timer_size_t) temp_period;
797 
798     return SSP_SUCCESS;
799 } /* End of function gpt_period_to_pclk */
800 
801 /*******************************************************************************************************************//**
802  * Converts user input duty cycle to PCLK counts, then sets duty cycle value.
803  *
804  * @param[in]  p_ctrl  Instance Control
805  * @param[in]  duty_cycle_counts  Duty cycle to set.
806  * @param[in]  pin                Which pin to update (0 = A or 1 = B).
807  *
808  * @retval     SSP_SUCCESS          Delay and divisor were set successfully.
809  * @retval     SSP_ERR_INVALID_ARGUMENT  One of the following is invalid:
810  *                                    - p_period->unit: must be one of the options from timer_pwm_unit_t
811  *                                    - p_period->value: must result in a period in the following range:
812  *                                        - Lower bound: (1 / (PCLK frequency))
813  *                                        - Upper bound: (0xFFFFFFFF * 1024 / (PCLK frequency))
814  **********************************************************************************************************************/
gpt_set_duty_cycle(gpt_instance_ctrl_t * const p_ctrl,timer_size_t const duty_cycle_counts,uint8_t const pin)815 static void gpt_set_duty_cycle (gpt_instance_ctrl_t * const p_ctrl,
816                                 timer_size_t          const duty_cycle_counts,
817                                 uint8_t               const pin)
818 {
819     /* Pin is represented by gpt_gtioc_t internally for readability. */
820     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
821     if (0U == duty_cycle_counts)
822     {
823         HW_GPT_DutyCycleModeSet(p_gpt_reg, (gpt_gtioc_t) pin, GPT_DUTY_CYCLE_MODE_0_PERCENT);
824     }
825     else if (GPT_MAX_CLOCK_COUNTS_32 == duty_cycle_counts)
826     {
827         HW_GPT_DutyCycleModeSet(p_gpt_reg, (gpt_gtioc_t) pin, GPT_DUTY_CYCLE_MODE_100_PERCENT);
828     }
829     else
830     {
831         HW_GPT_DutyCycleModeSet(p_gpt_reg, (gpt_gtioc_t) pin, GPT_DUTY_CYCLE_MODE_REGISTER);
832         HW_GPT_CompareMatchSet(p_gpt_reg, (gpt_gtioc_t) pin, duty_cycle_counts);
833     }
834 } /* End of function gpt_set_duty_cycle */
835 
836 /*******************************************************************************************************************//**
837  * Lookup function for clock frequency of GPT counter.  Divides GPT clock by GPT clock divisor.
838  *
839  * @param[in]  p_ctrl     Instance control block
840  *
841  * @return     Clock frequency of the GPT counter.
842  **********************************************************************************************************************/
gpt_clock_frequency_get(gpt_instance_ctrl_t * const p_ctrl)843 static uint32_t gpt_clock_frequency_get(gpt_instance_ctrl_t * const p_ctrl)
844 {
845     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
846     uint32_t pclk_freq_hz  = 0;
847     gpt_pclk_div_t pclk_divisor = HW_GPT_DivisorGet(p_gpt_reg);
848     uint32_t divisor = 1U << (2 * (uint32_t) pclk_divisor);
849     g_cgc_on_cgc.systemClockFreqGet(CGC_SYSTEM_CLOCKS_PCLKD, &pclk_freq_hz);
850     return (pclk_freq_hz / divisor);
851 }
852 
853 /*******************************************************************************************************************//**
854  * Converts duty cycle from input value to PCLK counts
855  *
856  * @param[in]  shortest_pwm_signal  Shortest PWM signal to generate
857  * @param[in]  duty_cycle         Duty cycle configured by user.
858  * @param[in]  unit               Duty cycle unit configured by user.
859  * @param[in]  period             Period in GPT clock counts.
860  * @param[out] p_duty_cycle_pclk  Duty cycle in clock counts set here.
861  *
862  * @retval     SSP_SUCCESS          Successful conversion
863  * @retval     SSP_ERR_INVALID_ARGUMENT  One of the following is invalid:
864  *                                    - unit: must be one of the options from timer_pwm_unit_t
865  *                                    - duty_cycle: must result in a period in the following range:
866  *                                        - Lower bound: (1 / (PCLK frequency))
867  *                                        - Upper bound: period
868  **********************************************************************************************************************/
gpt_duty_cycle_to_pclk(gpt_shortest_level_t shortest_pwm_signal,timer_size_t const duty_cycle,timer_pwm_unit_t const unit,timer_size_t const period,timer_size_t * const p_duty_cycle_pclk)869 static ssp_err_t gpt_duty_cycle_to_pclk (gpt_shortest_level_t  shortest_pwm_signal,
870                                          timer_size_t     const duty_cycle,
871                                          timer_pwm_unit_t const unit,
872                                          timer_size_t     const period,
873                                          timer_size_t   * const p_duty_cycle_pclk)
874 {
875     /** Initially set to an invalid value */
876     uint64_t temp_duty_cycle = 0xFFFFFFFEULL;
877     ssp_err_t err = SSP_SUCCESS;
878 
879     /** Convert duty cycle to PCLK counts so it can be set in hardware. */
880     switch (unit)
881     {
882         case TIMER_PWM_UNIT_RAW_COUNTS:
883             temp_duty_cycle = duty_cycle;
884             break;
885         case TIMER_PWM_UNIT_PERCENT:
886             temp_duty_cycle = ((uint64_t) period * duty_cycle) / 100ULL;
887             break;
888         case TIMER_PWM_UNIT_PERCENT_X_1000:
889             temp_duty_cycle = ((uint64_t) period * duty_cycle) / 100000ULL;
890             break;
891         default:
892             err = SSP_ERR_INVALID_ARGUMENT;
893             break;
894     }
895     GPT_ERROR_RETURN(SSP_SUCCESS == err, err);
896 
897     if(GPT_SHORTEST_LEVEL_ON == shortest_pwm_signal)
898     {
899         temp_duty_cycle = (uint64_t)period - temp_duty_cycle - 1ULL;
900     }
901 
902     if (temp_duty_cycle == period)
903     {
904         /** If duty cycle and period are equal, set to maximum period to use 100% duty cycle setting. */
905         temp_duty_cycle = GPT_MAX_CLOCK_COUNTS_32;
906     }
907 
908     /** If duty_cycle is valid, set it.  Otherwise return error */
909     GPT_ERROR_RETURN(((GPT_MAX_CLOCK_COUNTS_32 == temp_duty_cycle) || (temp_duty_cycle <= period)), SSP_ERR_INVALID_ARGUMENT);
910     *p_duty_cycle_pclk = (timer_size_t) temp_duty_cycle;
911 
912     return SSP_SUCCESS;
913 } /* End of function gpt_duty_cycle_to_pclk */
914 
915 /*******************************************************************************************************************//**
916  * Sets output pin to toggle at cycle end.
917  *
918  * @param[in]  p_ctrl      Instance control block
919  * @param[in]  gtio        Which pin to toggle
920  * @param[in]  level       Output level after timer stops
921  * @param[in]  mode        PWM or timer interface
922  * @param[in]  duty_cycle  Initial duty cycle
923  **********************************************************************************************************************/
gpt_set_output_pin(gpt_instance_ctrl_t * const p_ctrl,gpt_gtioc_t const gtio,gpt_pin_level_t const level,timer_mode_t const mode,timer_size_t const duty_cycle)924 static void gpt_set_output_pin (gpt_instance_ctrl_t * const p_ctrl,
925                                 gpt_gtioc_t           const gtio,
926                                 gpt_pin_level_t       const level,
927                                 timer_mode_t          const mode,
928                                 timer_size_t          const duty_cycle)
929 {
930     /** When the counter starts, set the output pin to the default state */
931     GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
932     gtior_t * p_reg = HW_GPT_GTIOCRegLookup(p_gpt_reg, gtio);
933     HW_GPT_GTIOCInitialOutputSet(p_reg, level);
934 
935     /** Configure pin to toggle at each overflow */
936     HW_GPT_GTIOCPinLevelStoppedSet(p_reg, level);
937     HW_GPT_GTIOCCycleEndOutputSet(p_reg, GPT_OUTPUT_TOGGLED);
938 
939     if (TIMER_MODE_ONE_SHOT == mode)
940     {
941         HW_GPT_InitialCompareMatchSet(p_gpt_reg, gtio, 0);
942         HW_GPT_SingleBufferEnable(p_gpt_reg, gtio);
943 
944         /** Compare match register must be loaded with a value that exceeds the timer cycle end value so that second compare match event
945          * would never occur and hence there will be only a single pulse*/
946         if (TIMER_VARIANT_16_BIT == p_ctrl->variant)
947         {
948             HW_GPT_CompareMatchSet(p_gpt_reg, gtio, GPT_MAX_CLOCK_COUNTS_16);
949         }
950         else
951         {
952             HW_GPT_CompareMatchSet(p_gpt_reg, gtio, GPT_MAX_CLOCK_COUNTS_32);
953         }
954         if (0 == level)
955         {
956             HW_GPT_GTIOCCompareMatchOutputSet(p_reg, GPT_OUTPUT_HIGH);
957             HW_GPT_GTIOCCycleEndOutputSet(p_reg, GPT_OUTPUT_LOW);
958         }
959         else
960         {
961             HW_GPT_GTIOCCompareMatchOutputSet(p_reg, GPT_OUTPUT_LOW);
962             HW_GPT_GTIOCCycleEndOutputSet(p_reg, GPT_OUTPUT_HIGH);
963         }
964     }
965     else if (TIMER_MODE_PERIODIC == mode)
966     {
967         HW_GPT_GTIOCCompareMatchOutputSet(p_reg, GPT_OUTPUT_RETAINED);
968     }
969     else // (TIMER_MODE_PWM == mode)
970     {
971         if (GPT_SHORTEST_LEVEL_OFF == p_ctrl->shortest_pwm_signal)
972         {
973             HW_GPT_GTIOCCompareMatchOutputSet(p_reg, GPT_OUTPUT_LOW);
974             HW_GPT_GTIOCCycleEndOutputSet(p_reg, GPT_OUTPUT_HIGH);
975         }
976         else
977         {
978             HW_GPT_GTIOCCompareMatchOutputSet(p_reg, GPT_OUTPUT_HIGH);
979             HW_GPT_GTIOCCycleEndOutputSet(p_reg, GPT_OUTPUT_LOW);
980         }
981         HW_GPT_SingleBufferEnable(p_gpt_reg, gtio);
982         gpt_set_duty_cycle(p_ctrl, duty_cycle, gtio);
983     }
984 
985     HW_GPT_GTIOCPinOutputEnable(p_reg, true);
986 } /* End of function gpt_set_output_pin */
987 
988 /*******************************************************************************************************************//**
989  * Stops the timer if one-shot mode, clears interrupts, and calls callback if one was provided in the open function.
990  **********************************************************************************************************************/
gpt_counter_overflow_isr(void)991 void gpt_counter_overflow_isr (void)
992 {
993     /* Save context if RTOS is used */
994     SF_CONTEXT_SAVE;
995 
996     ssp_vector_info_t * p_vector_info = NULL;
997     R_SSP_VectorInfoGet(R_SSP_CurrentIrqGet(), &p_vector_info);
998     gpt_instance_ctrl_t * p_ctrl = (gpt_instance_ctrl_t *) *(p_vector_info->pp_ctrl);
999 
1000     /** Clear pending IRQ to make sure it doesn't fire again after exiting */
1001     R_BSP_IrqStatusClear(R_SSP_CurrentIrqGet());
1002 
1003     if (NULL != p_ctrl)
1004     {
1005         GPT_BASE_PTR p_gpt_reg = (GPT_BASE_PTR) p_ctrl->p_reg;
1006 
1007         /** If one-shot mode is selected, stop the timer since period has expired. */
1008         if (p_ctrl->one_shot)
1009         {
1010             HW_GPT_CounterStartStop(p_gpt_reg, GPT_STOP);
1011 
1012             /** Clear the GPT counter, compare match registers and the overflow flag after the one shot pulse has being generated */
1013             HW_GPT_CounterSet(p_gpt_reg, 0);
1014 
1015             if (p_ctrl->gtioca_output_enabled)
1016             {
1017                 HW_GPT_InitialCompareMatchSet(p_gpt_reg, GPT_GTIOCA, 0);
1018             }
1019             if (p_ctrl->gtiocb_output_enabled)
1020             {
1021                 HW_GPT_InitialCompareMatchSet(p_gpt_reg, GPT_GTIOCB, 0);
1022             }
1023 
1024             HW_GPT_InterruptClear(p_gpt_reg);
1025         }
1026 
1027         if (NULL != p_ctrl->p_callback)
1028         {
1029             /** Set data to identify callback to user, then call user callback. */
1030             timer_callback_args_t cb_data;
1031             cb_data.p_context = p_ctrl->p_context;
1032             cb_data.event     = TIMER_EVENT_EXPIRED;
1033             p_ctrl->p_callback(&cb_data);
1034         }
1035     }
1036 
1037     /* Restore context if RTOS is used */
1038     SF_CONTEXT_RESTORE;
1039 } /* End of function gpt_counter_overflow_isr */
1040