1 /***************************************************************************//**
2 * \file cyhal_tcpwm_common.h
3 *
4 * \brief
5 * Code shared between the Infineon Timer/Counter and PWM.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2019-2021 Cypress Semiconductor Corporation (an Infineon company) or
10 * an affiliate of Cypress Semiconductor Corporation
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 *
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 *     http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 *******************************************************************************/
26 
27 /** \cond INTERNAL */
28 /**
29  * \addtogroup group_hal_impl_tcpwm_common TCPWM Common Functionality
30  * \ingroup group_hal_impl
31  * \{
32  * Code shared between the Infineon Timer / Counter and PWM.
33  */
34 
35 #pragma once
36 
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include "cyhal_hw_types.h"
40 #include "cyhal_interconnect.h"
41 
42 #if defined(__cplusplus)
43 extern "C" {
44 #endif /* __cplusplus */
45 
46 // Value comes from IP limitation
47 #define _CYHAL_TCPWM_MAX_GRPS_PER_IP_BLOCK  (4u)
48 
49 #if defined(CY_IP_MXTCPWM_INSTANCES) || defined(CY_IP_M0S8TCPWM_INSTANCES)
50 
51 #if defined(CY_IP_MXTCPWM_INSTANCES)
52     #if (CY_IP_MXTCPWM_VERSION == 1)
53         // Total number of TCPWM groups
54         #define _CYHAL_TCPWM_INSTANCES     CY_IP_MXTCPWM_INSTANCES
55         // Counter number relative to the start of the IP block
56         #define _CYHAL_TCPWM_CNT_NUMBER(resource) ((resource).channel_num)
57         // Cobvert driver 'block' to IP block
58         #define _CYHAL_TCPWM_GET_IP_BLOCK(block) (block)
59     #else // (CY_IP_MXTCPWM_VERSION >= 2)
60         #define _CYHAL_TCPWM_GET_IP_BLOCK(block) ((block) / _CYHAL_TCPWM_MAX_GRPS_PER_IP_BLOCK)
61         // Used to grab the group index relative to its IP block
62         #define _CYHAL_TCPWM_GET_GRP(block) ((block) % _CYHAL_TCPWM_MAX_GRPS_PER_IP_BLOCK)
63         #if (CY_IP_MXTCPWM_INSTANCES == 1)
64             #define _CYHAL_TCPWM_INSTANCES     TCPWM_GRP_NR
65             #define _CYHAL_TCPWM_CNT_NUMBER(resource) (((resource).block_num << 8) | (resource).channel_num)
66         #elif (CY_IP_MXTCPWM_INSTANCES == 2)
67             #define _CYHAL_TCPWM_INSTANCES     (TCPWM0_GRP_NR + TCPWM1_GRP_NR)
68             // This is based on the model of 4x continuous groups mapping to x IP blocks (0-3 to 1, 4-7 to 2, etc)
69             #define _CYHAL_TCPWM_CNT_NUMBER(resource) ((((resource).block_num % _CYHAL_TCPWM_MAX_GRPS_PER_IP_BLOCK) << 8) | (resource).channel_num)
70         #else
71             #warning Unhandled TCPWM instance count
72         #endif
73     #endif
74 #elif defined(CY_IP_M0S8TCPWM_INSTANCES)
75     #define _CYHAL_TCPWM_CNT_NUMBER(resource) ((resource).channel_num)
76     #define _CYHAL_TCPWM_INSTANCES     CY_IP_M0S8TCPWM_INSTANCES
77     #define _CYHAL_TCPWM_GET_IP_BLOCK(block) (block)
78 #endif
79 
80 // Used to adjust block value for indexing _CYHAL_TCPWM_DATA[] and other arrays which do not include indexes for empty blocks
81 #if (CY_IP_MXTCPWM_VERSION == 2)
82     #if (CY_IP_MXTCPWM_INSTANCES == 1)
83         #define _CYHAL_TCPWM_ADJUST_BLOCK_INDEX(block) (block)
84     #elif (CY_IP_MXTCPWM_INSTANCES == 2)
85         #define _CYHAL_TCPWM_ADJUST_BLOCK_INDEX(block)    ((_CYHAL_TCPWM_GET_IP_BLOCK(block) == 0) ? (block) : (_CYHAL_TCPWM_GET_GRP(block) + TCPWM0_GRP_NR))
86     #else
87         #warning Unhandled TCPWM instance count
88     #endif
89 #else
90     #define _CYHAL_TCPWM_ADJUST_BLOCK_INDEX(block) (block)
91 #endif
92 
93 #if defined(CY_IP_MXTCPWM_INSTANCES)
94 #if (CY_IP_MXTCPWM_VERSION == 1)
95     #if (CY_IP_MXTCPWM_INSTANCES == 0)
96         #define _CYHAL_TCPWM_CHANNELS (0u)
97     #elif (CY_IP_MXTCPWM_INSTANCES == 1)
98         #define _CYHAL_TCPWM_CHANNELS (TCPWM0_CNT_NR)
99     #elif (CY_IP_MXTCPWM_INSTANCES == 2)
100         #define _CYHAL_TCPWM_CHANNELS (TCPWM0_CNT_NR + TCPWM1_CNT_NR)
101     #else
102         #warning Unhandled TCPWM instance count
103     #endif
104 #else // (CY_IP_MXTCPWM_VERSION >= 2)
105     #if (CY_IP_MXTCPWM_INSTANCES == 1)
106         #if (TCPWM_GRP_NR == 0)
107             #define _CYHAL_TCPWM_CHANNELS (0U)
108         #elif (TCPWM_GRP_NR == 1)
109             #define _CYHAL_TCPWM_CHANNELS (TCPWM_GRP_NR0_GRP_GRP_CNT_NR)
110         #elif (TCPWM_GRP_NR == 2)
111             #define _CYHAL_TCPWM_CHANNELS (TCPWM_GRP_NR0_GRP_GRP_CNT_NR + TCPWM_GRP_NR1_GRP_GRP_CNT_NR)
112         #elif (TCPWM_GRP_NR == 3)
113             #define _CYHAL_TCPWM_CHANNELS (TCPWM_GRP_NR0_GRP_GRP_CNT_NR + TCPWM_GRP_NR1_GRP_GRP_CNT_NR + TCPWM_GRP_NR2_GRP_GRP_CNT_NR)
114         #elif (TCPWM_GRP_NR == 4)
115             #define _CYHAL_TCPWM_CHANNELS (TCPWM_GRP_NR0_GRP_GRP_CNT_NR + TCPWM_GRP_NR1_GRP_GRP_CNT_NR + TCPWM_GRP_NR2_GRP_GRP_CNT_NR + TCPWM_GRP_NR3_GRP_GRP_CNT_NR)
116         #endif
117     #elif (CY_IP_MXTCPWM_INSTANCES == 2)
118         #if (TCPWM0_GRP_NR == 0)
119             #define _CYHAL_TCPWM0_CHANNELS (0U)
120         #elif (TCPWM0_GRP_NR == 1)
121             #define _CYHAL_TCPWM0_CHANNELS (TCPWM0_GRP_NR0_GRP_GRP_CNT_NR)
122         #elif (TCPWM0_GRP_NR == 2)
123             #define _CYHAL_TCPWM0_CHANNELS (TCPWM0_GRP_NR0_GRP_GRP_CNT_NR + TCPWM0_GRP_NR1_GRP_GRP_CNT_NR)
124         #elif (TCPWM0_GRP_NR == 3)
125             #define _CYHAL_TCPWM0_CHANNELS (TCPWM0_GRP_NR0_GRP_GRP_CNT_NR + TCPWM0_GRP_NR1_GRP_GRP_CNT_NR + TCPWM0_GRP_NR2_GRP_GRP_CNT_NR)
126         #elif (TCPWM0_GRP_NR == 4)
127             #define _CYHAL_TCPWM0_CHANNELS (TCPWM0_GRP_NR0_GRP_GRP_CNT_NR + TCPWM0_GRP_NR1_GRP_GRP_CNT_NR + TCPWM0_GRP_NR2_GRP_GRP_CNT_NR + TCPWM0_GRP_NR3_GRP_GRP_CNT_NR)
128         #endif
129         #ifndef _CYHAL_TCPWM0_CHANNELS
130             #error "Unhandled TCPWM0_GRP_NR count"
131         #endif
132         #if (TCPWM1_GRP_NR == 0)
133             #define _CYHAL_TCPWM1_CHANNELS (0U)
134         #elif (TCPWM1_GRP_NR == 1)
135             #define _CYHAL_TCPWM1_CHANNELS (TCPWM1_GRP_NR0_GRP_GRP_CNT_NR)
136         #elif (TCPWM1_GRP_NR == 2)
137             #define _CYHAL_TCPWM1_CHANNELS (TCPWM1_GRP_NR0_GRP_GRP_CNT_NR + TCPWM1_GRP_NR1_GRP_GRP_CNT_NR)
138         #elif (TCPWM1_GRP_NR == 3)
139             #define _CYHAL_TCPWM1_CHANNELS (TCPWM1_GRP_NR0_GRP_GRP_CNT_NR + TCPWM1_GRP_NR1_GRP_GRP_CNT_NR + TCPWM1_GRP_NR2_GRP_GRP_CNT_NR)
140         #elif (TCPWM1_GRP_NR == 4)
141             #define _CYHAL_TCPWM1_CHANNELS (TCPWM1_GRP_NR0_GRP_GRP_CNT_NR + TCPWM1_GRP_NR1_GRP_GRP_CNT_NR + TCPWM1_GRP_NR2_GRP_GRP_CNT_NR + TCPWM1_GRP_NR3_GRP_GRP_CNT_NR)
142         #endif
143         #ifndef _CYHAL_TCPWM1_CHANNELS
144             #error "Unhandled TCPWM1_GRP_NR count"
145         #endif
146 
147         #define _CYHAL_TCPWM_CHANNELS (_CYHAL_TCPWM0_CHANNELS + _CYHAL_TCPWM1_CHANNELS)
148     #else
149         #warning Unhandled TCPWM instance count
150     #endif
151 #endif
152 #elif defined(CY_IP_M0S8TCPWM_INSTANCES)
153     #if (CY_IP_M0S8TCPWM_INSTANCES == 1)
154         #define _CYHAL_TCPWM_CHANNELS (TCPWM_CNT_NR)
155     #else
156         #warning Unhandled TCPWM instance count
157     #endif
158 #endif
159 
160 #if (CY_IP_MXTCPWM_VERSION == 1U)
161     #if (CY_IP_MXTCPWM_INSTANCES == 1)
162     extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_IDX_OFFSET[1];
163     extern const uint16_t  _CYHAL_TCPWM_TRIGGER_INPUTS_PER_BLOCK[1];
164     #elif (CY_IP_MXTCPWM_INSTANCES == 2)
165     extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_IDX_OFFSET[2];
166     extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_PER_BLOCK[2];
167     #endif
168 #elif (CY_IP_MXTCPWM_VERSION == 2U)
169     // PSoC™ 6 devices with trigmux vers2 also have a number of reserved input
170     // lines defined by TCPWM_TR_ONE_CNT_NR.
171     #if (CY_IP_MXTCPWM_INSTANCES == 1)
172     extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_IDX_OFFSET[1];
173     extern const uint16_t  _CYHAL_TCPWM_TRIGGER_INPUTS_PER_BLOCK[1];
174     #elif (CY_IP_MXTCPWM_INSTANCES == 2)
175     extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_IDX_OFFSET[2];
176     extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_PER_BLOCK[2];
177     #else
178     #warning Unhandled TCPWM instance count
179     #endif
180 #else // (CY_IP_M0S8TCPWM_VERSION == 2)
181     // PSoC™ 4 devices have a number of reserved input lines coming directly from
182     // GPIO triggers (depending on exact architecture).
183     #if defined(CY_DEVICE_PSOC4AS1)
184         // 12 GPIO trigger lines reserved (but some may be unused, depending on
185         // pin package)
186         extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_IDX_OFFSET[1];
187         extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_PER_BLOCK[1];
188     #else
189         // 7 GPIO trigger lines reserved (but some may be unused, depending on
190         // pin package)
191         extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_IDX_OFFSET[1];
192         extern const uint16_t _CYHAL_TCPWM_TRIGGER_INPUTS_PER_BLOCK[1];
193     #endif
194 #endif
195 
196 /** \addtogroup group_hal_results_tcpwm TCPWM HAL Results
197  *  TCPWM specific return codes
198  *  \ingroup group_hal_results
199  *  \{ *//**
200  */
201 
202 /** Bad argument. eg: null pointer */
203 #define CYHAL_TCPWM_RSLT_ERR_BAD_ARGUMENT                   \
204     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IMPL_TCPWM, 0))
205 /** Failed to find free input signal */
206 #define CYHAL_TCPWM_RSLT_ERR_NO_FREE_INPUT_SIGNALS          \
207     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IMPL_TCPWM, 1))
208 /** Failed to find free output signal */
209 #define CYHAL_TCPWM_RSLT_ERR_NO_FREE_OUTPUT_SIGNALS         \
210     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IMPL_TCPWM, 2))
211 
212 /**
213  * \}
214  */
215 
216 /** TCPWM/counter input signal */
217 typedef enum
218 {
219     CYHAL_TCPWM_INPUT_START,    //!< Start signal
220     CYHAL_TCPWM_INPUT_STOP,     //!< Stop signal
221     CYHAL_TCPWM_INPUT_RELOAD,   //!< Reload signal
222     CYHAL_TCPWM_INPUT_COUNT,    //!< Count signal
223     CYHAL_TCPWM_INPUT_CAPTURE,  //!< Capture signal
224 } cyhal_tcpwm_input_t;
225 
226 /** The number of unique TCPWM inputs as defined by cyhal_tcpwm_input_t */
227 #define _CYHAL_TCPWM_INPUTS     5
228 
229 /** TCPWM/counter output signal */
230 typedef enum
231 {
232     CYHAL_TCPWM_OUTPUT_OVERFLOW,       //!< Overflow signal
233     CYHAL_TCPWM_OUTPUT_UNDERFLOW,      //!< Underflow signal
234     CYHAL_TCPWM_OUTPUT_COMPARE_MATCH,  //!< Compare match signal
235     CYHAL_TCPWM_OUTPUT_TERMINAL_COUNT, //!< Terminal count signal (logical OR of overflow and underflow signal)
236     CYHAL_TCPWM_OUTPUT_LINE_OUT,       //!< Line out signal
237 } cyhal_tcpwm_output_t;
238 
239 /** The number of unique TCPWM outputs as defined by cyhal_tcpwm_output_t */
240 #define _CYHAL_TCPWM_OUTPUTS     5
241 
242 /** Handler for TCPWM interrupts */
243 typedef void(*_cyhal_tcpwm_event_callback_t)(void *callback_arg, int event);
244 
245 /** Holds data about a single TCPWM */
246 typedef struct {
247     TCPWM_Type*  base; //!< TCPWM base
248     en_clk_dst_t clock_dst; //!< TCPWM clock connections base
249     uint32_t     max_count; //!< TCPWM counter width
250     uint8_t      num_channels; //!< Number of channels on the TCPWM
251     uint8_t      channel_offset; //!< Offset from channels on previous TCPWM
252 #if (defined (CPUSS_SYSTEM_INT_NR) && (CPUSS_SYSTEM_INT_NR >= 256))
253     uint16_t     isr_offset; //!< TCPWM base IRQn (channel 0 IRQn)
254 #else
255     uint8_t      isr_offset; //!< TCPWM base IRQn (channel 0 IRQn)
256 #endif
257 } _cyhal_tcpwm_data_t;
258 
259 /** Contains data about all of the TCPWMs */
260 extern const _cyhal_tcpwm_data_t _CYHAL_TCPWM_DATA[_CYHAL_TCPWM_INSTANCES];
261 
262 #ifdef CY_DEVICE_PSOC6A256K
263 /** Contains bitfield of in use data for all TCPWM output trigger lines. There
264  * are 2 available output lines per counter */
265 extern uint8_t _CYHAL_OUTPUT_TRIGGERS_USED[TCPWM_GRP_NR0_GRP_GRP_CNT_NR + TCPWM_GRP_NR1_GRP_GRP_CNT_NR];
266 #endif
267 
268 /**
269  * Free a timer/counter or a PWM object's shared data
270  *
271  * @param[in] obj The timer/counter or the PWM resource
272  */
273 void _cyhal_tcpwm_free(cyhal_tcpwm_t *obj);
274 
275 /** Initialize a timer/counter or PWM object's callback data.
276  *
277  * @param[in,out] tcpwm    The shared data struct between timer/counter and PWM
278  */
279 void _cyhal_tcpwm_init_data(cyhal_tcpwm_t *tcpwm);
280 
281 /** The TCPWM interrupt handler registration
282  *
283  * @param[in] resource      The timer/counter or PWM resource
284  * @param[in] callback      The callback handler which will be invoked when the event occurs
285  * @param[in] callback_arg  Generic argument that will be provided to the callback when called
286  */
287 void _cyhal_tcpwm_register_callback(cyhal_resource_inst_t *resource, cy_israddress callback, void *callback_arg);
288 
289 /** Configure TCPWM event enablement.
290  *
291  * @param[in] tcpwm          The shared data struct between timer/counter and PWM
292  * @param[in] resource      The timer/counter or PWM resource
293  * @param[in] event         The timer/counter or PWM event type
294  * @param[in] intr_priority The priority for NVIC interrupt events
295  * @param[in] enable        True to turn on events, False to turn off
296  */
297 void _cyhal_tcpwm_enable_event(cyhal_tcpwm_t *tcpwm, cyhal_resource_inst_t *resource, uint32_t event, uint8_t intr_priority, bool enable);
298 
299 /** Returns whether power management transition should be allowed.
300  *
301  * @return true if no tcpwm is actively blocking power mode transition
302  */
303 bool _cyhal_tcpwm_pm_transition_pending(void);
304 
305 /** Connects a source signal and configures and enables a TCPWM event to be
306  * triggered from that signal. These TCPWM events can be configured
307  * independently and connect to the same or different source signals.
308  *
309  * @param[in] obj      TCPWM HAL object
310  * @param[in] source   Source signal obtained from another driver's cyhal_<PERIPH>_enable_output
311  * @param[in] signal   The TCPWM input signal
312  * @param[in] type     The edge type of the signal to connect
313  * @return The status of the connection
314  * */
315 cy_rslt_t _cyhal_tcpwm_connect_digital(cyhal_tcpwm_t *obj, cyhal_source_t source, cyhal_tcpwm_input_t signal, cyhal_edge_type_t type);
316 
317 /** Enables the specified output signal from a TCPWM that will be triggered
318  * when the corresponding event occurs. Multiple output signals can be
319  * configured simultaneously.
320  *
321  * @param[in]  obj      TCPWM HAL object
322  * @param[in]  signal   The TCPWM output signal
323  * @param[out] source   Pointer to user-allocated source signal object which
324  * will be initialized by enable_output. source should be passed to
325  * (dis)connect_digital functions to (dis)connect the associated endpoints.
326  * @return The status of the output enable
327  * */
328 cy_rslt_t _cyhal_tcpwm_enable_output(cyhal_tcpwm_t *obj, cyhal_tcpwm_output_t signal, cyhal_source_t *source);
329 
330 /** Disconnects a source signal and disables the corresponding input to a TCPWM
331  *
332  * @param[in] obj      TCPWM HAL object
333  * @param[in] source   Source signal from cyhal_<PERIPH>_enable_output to disable
334  * @param[in] signal   The TCPWM input signal
335  * @return The status of the disconnection
336  * */
337 cy_rslt_t _cyhal_tcpwm_disconnect_digital(cyhal_tcpwm_t *obj, cyhal_source_t source, cyhal_tcpwm_input_t signal);
338 
339 /** Disables the specified output signal from a TCPWM.
340  *
341  * @param[in]  obj      TCPWM HAL object
342  * @param[in]  resource TCPWM resource
343  * @param[in]  signal   The TCPWM output signal
344  * @return The status of the output disable
345  * */
346 cy_rslt_t _cyhal_tcpwm_disable_output(cyhal_tcpwm_t *obj, cyhal_tcpwm_output_t signal);
347 
348 #if (defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI)) && \
349     ((CY_IP_MXTCPWM_VERSION == 1) || (CY_IP_MXTCPWM_VERSION == 2) || (CY_IP_M0S8TCPWM_VERSION == 2))
350 /** Get the destination reference for the provided TCPWM block and trigger
351  *
352  * @param[in]  block        TCPWM block number
353  * @param[in]  trig_index   The trigger index to get the destination for
354  * @return A destination that a signal can be connected to for the specified TCPWM block
355  * */
356 cyhal_dest_t _cyhal_tpwm_calculate_dest(uint8_t block, uint8_t trig_index);
357 #endif
358 
359 #if defined(__cplusplus)
360 }
361 #endif /* __cplusplus */
362 
363 #endif /* defined(CY_IP_MXTCPWM_INSTANCES) || defined(CY_IP_M0S8TCPWM_INSTANCES) */
364 
365 /** \} group_hal_impl_tcpwm_common */
366 /** \endcond */
367