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