1 /***************************************************************************//** 2 * \file cyhal_pwm.h 3 * 4 * \brief 5 * Provides a high level interface for interacting with the Infineon PWM. 6 * This interface abstracts out the chip specific details. If any chip specific 7 * functionality is necessary, or performance is critical the low level functions 8 * can be used directly. 9 * 10 ******************************************************************************** 11 * \copyright 12 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or 13 * an affiliate of Cypress Semiconductor Corporation 14 * 15 * SPDX-License-Identifier: Apache-2.0 16 * 17 * Licensed under the Apache License, Version 2.0 (the "License"); 18 * you may not use this file except in compliance with the License. 19 * You may obtain a copy of the License at 20 * 21 * http://www.apache.org/licenses/LICENSE-2.0 22 * 23 * Unless required by applicable law or agreed to in writing, software 24 * distributed under the License is distributed on an "AS IS" BASIS, 25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 * See the License for the specific language governing permissions and 27 * limitations under the License. 28 *******************************************************************************/ 29 30 /** 31 * \addtogroup group_hal_pwm PWM (Pulse Width Modulator) 32 * \ingroup group_hal 33 * \{ 34 * High level interface for interacting with the pulse width modulator (PWM) hardware resource 35 * 36 * The PWM driver can be used to generate periodic digital waveforms with configurable frequency and duty cycle. 37 * The driver allows assigning the PWM output and an optional inverted output to supplied pins. 38 * The driver supports interrupt generation on PWM terminal count and compare events. 39 * 40 * \section section_pwm_features Features 41 * * Configurable pin assignment for the PWM output 42 * * Optional complementary (inverted) PWM output to a second pin 43 * * Configurable dead time between normal and inverted PWM outputs 44 * * Configurable alignment: left, right or center 45 * * Continuous or One-shot operation 46 * * Option to instantiate and use a new clock or use pre-allocated clock for clock input 47 * * Configurable interrupt and callback assignment on PWM events: terminal count, compare match or combination of both 48 * 49 * \section section_pwm_quickstart Quick Start 50 * 51 * See \ref subsection_pwm_snippet_1 for a code snippet that generates a signal with the specified frequency and duty cycle on the specified pin. 52 * 53 * \section section_pwm_snippets Code snippets 54 * 55 * \subsection subsection_pwm_snippet_1 Snippet 1: Simple PWM initialization and output to pin 56 * The following snippet initializes a PWM resource and assigns the output to the supplied <b>pin</b> using \ref cyhal_pwm_init. <br> 57 * The clock parameter <b>clk</b> is optional and need not be provided (NULL), to generate and use an available clock resource with a default frequency. <br> 58 * The clock frequency and the duty cycle is set using \ref cyhal_pwm_set_duty_cycle. <br> 59 * \ref cyhal_pwm_start starts the PWM output on the pin. 60 * 61 * \snippet hal_pwm.c snippet_cyhal_pwm_simple_init 62 * 63 * 64 * \subsection subsection_pwm_snippet_2 Snippet 2: Starting and stopping the PWM output 65 * \ref cyhal_pwm_start and \ref cyhal_pwm_stop functions can be used after PWM initialization to start and stop the PWM output. 66 * 67 * \snippet hal_pwm.c snippet_cyhal_pwm_start_stop 68 * 69 * 70 * \subsection subsection_pwm_snippet_3 Snippet 3: Advanced PWM output to pin 71 * \ref cyhal_pwm_init_adv can be used to specify advanced PWM options like an additional inverted PWM output, pulse alignment 72 * (left, right, center) and run mode (one-shot or continuous). The following snippet initializes a left-aligned, continuous running PWM 73 * assigned to the supplied pin. The inverted output is assigned to a second pin (<b>compl_pin</b>). 74 * 75 * \snippet hal_pwm.c snippet_cyhal_pwm_adv_init 76 * 77 * 78 * \subsection subsection_pwm_snippet_4 Snippet 4: Interrupts on PWM events 79 * PWM events like hitting the terminal count or a compare event can be used to trigger a callback function. <br> 80 * \ref cyhal_pwm_enable_event() can be used to enable one or more events to trigger the callback function. 81 * 82 * \snippet hal_pwm.c snippet_cyhal_pwm_events 83 */ 84 85 #pragma once 86 87 #include <stdint.h> 88 #include <stdbool.h> 89 90 #include "cy_result.h" 91 #include "cyhal_hw_types.h" 92 93 #if defined(__cplusplus) 94 extern "C" { 95 #endif 96 97 /** \addtogroup group_hal_results_pwm PWM HAL Results 98 * PWM specific return codes 99 * \ingroup group_hal_results 100 * \{ *//** 101 */ 102 103 /** Bad argument */ 104 #define CYHAL_PWM_RSLT_BAD_ARGUMENT \ 105 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_PWM, 0)) 106 /** Failed to initialize PWM clock */ 107 #define CYHAL_PWM_RSLT_FAILED_CLOCK_INIT \ 108 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_PWM, 1)) 109 /** Failed to initialize PWM */ 110 #define CYHAL_PWM_RSLT_FAILED_INIT \ 111 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_PWM, 2)) 112 113 /** 114 * \} 115 */ 116 117 /** Initialize the PWM out peripheral and configure the pin 118 * This is similar to the \ref cyhal_pwm_init_adv() but uses defaults for some of the 119 * more advanced setup options. See \ref subsection_pwm_snippet_1. 120 * 121 * @param[out] obj Pointer to a PWM object. The caller must allocate the memory 122 * for this object but the init function will initialize its contents. 123 * @param[in] pin The PWM pin to initialize. This pin is required, it cannot be \ref NC (No Connect). 124 * @param[in] clk An optional, pre-allocated clock to use, if NULL a new clock will be allocated 125 * @return The status of the init request. 126 */ 127 #define cyhal_pwm_init(obj, pin, clk) (cyhal_pwm_init_adv(obj, pin, NC, CYHAL_PWM_LEFT_ALIGN, true, 0u, false, clk)) 128 129 /** PWM interrupt triggers */ 130 typedef enum { 131 CYHAL_PWM_IRQ_NONE = 0, /**< No interrupts */ 132 CYHAL_PWM_IRQ_TERMINAL_COUNT = 1 << 0, /**< Interrupt on terminal count match event */ 133 CYHAL_PWM_IRQ_COMPARE = 1 << 1, /**< Interrupt on compare match event */ 134 CYHAL_PWM_IRQ_ALL = (1 << 2) - 1, /**< Interrupt on any events */ 135 136 /** \cond INTERNAL */ 137 CYHAL_PWM_IRQ_CAPTURE_COMPARE /* __attribute__ ((deprecated)) */ = CYHAL_PWM_IRQ_COMPARE, 138 /** \endcond */ 139 } cyhal_pwm_event_t; 140 141 /** PWM alignment */ 142 typedef enum { 143 CYHAL_PWM_LEFT_ALIGN = 0, /**< PWM is left aligned (signal starts high and goes low after compare match) */ 144 CYHAL_PWM_RIGHT_ALIGN = 1, /**< PWM is right aligned (signal starts low and goes high after compare match) */ 145 CYHAL_PWM_CENTER_ALIGN = 2, /**< PWM is centered aligned (signal starts and ends low with a center aligned pulse) */ 146 } cyhal_pwm_alignment_t; 147 148 /** PWM input signal */ 149 typedef enum 150 { 151 CYHAL_PWM_INPUT_START, //!< Start signal 152 CYHAL_PWM_INPUT_STOP, //!< Stop signal 153 CYHAL_PWM_INPUT_RELOAD, //!< Reload signal 154 CYHAL_PWM_INPUT_COUNT, //!< Count signal 155 CYHAL_PWM_INPUT_CAPTURE, //!< Capture/swap signal 156 } cyhal_pwm_input_t; 157 158 /** PWM output signal */ 159 typedef enum 160 { 161 CYHAL_PWM_OUTPUT_OVERFLOW, //!< Overflow signal 162 CYHAL_PWM_OUTPUT_UNDERFLOW, //!< Underflow signal 163 CYHAL_PWM_OUTPUT_COMPARE_MATCH, //!< Compare Match signal 164 CYHAL_PWM_OUTPUT_LINE_OUT, //!< PWM line out signal 165 } cyhal_pwm_output_t; 166 167 /** Handler for PWM interrupts */ 168 typedef void(*cyhal_pwm_event_callback_t)(void *callback_arg, cyhal_pwm_event_t event); 169 170 /** Initialize the PWM out peripheral and configure the pin. 171 * This is similar to the \ref cyhal_pwm_init() but provides additional setup options. <br> 172 * See \ref subsection_pwm_snippet_3. 173 * 174 * @param[out] obj Pointer to a PWM object. The caller must allocate the memory 175 * for this object but the init function will initialize its contents. 176 * @param[in] pin The PWM pin to initialize. This pin is required, it cannot be \ref NC (No Connect). 177 * @param[in] compl_pin An optional, additional inverted output pin. <br> 178 * If supplied, this must be connected to the same or related PWM instance as <b>pin</b>, see 179 * \ref section_hal_impl_pwm_compl_pins for details.<br> 180 * If this output is not needed, use \ref NC (No Connect). 181 * @param[in] pwm_alignment PWM alignment: left, right, or center. 182 * @param[in] continuous PWM run type: continuous (true) or one shot (false). 183 * @param[in] dead_time_us The number of micro-seconds for dead time. This is 184 * only meaningful if both <b>pin</b> and <b>compl_pin</b> are provided. 185 * @param[in] invert An option for the user to invert the PWM output 186 * @param[in] clk An optional, pre-allocated clock to use, if NULL a 187 * new clock will be allocated. 188 * @return The status of the init request 189 * 190 * @note In some cases, it is possible to use a pin designated for non-inverting output as an inverting output and vice versa. Whether this is possible is dependent on the HAL implementation and operating mode. See the implementation specific documentation for details. 191 */ 192 cy_rslt_t cyhal_pwm_init_adv(cyhal_pwm_t *obj, cyhal_gpio_t pin, cyhal_gpio_t compl_pin, cyhal_pwm_alignment_t pwm_alignment, bool continuous, uint32_t dead_time_us, bool invert, const cyhal_clock_t *clk); 193 194 /** Initialize the PWM out peripheral using a configurator generated configuration struct 195 * 196 * @param[out] obj Pointer to a PWM object. The caller must allocate the memory 197 * for this object but the init function will initialize its contents. 198 * @param[in] cfg Configuration structure generated by a configurator. 199 * @return The status of the init request 200 */ 201 cy_rslt_t cyhal_pwm_init_cfg(cyhal_pwm_t *obj, const cyhal_pwm_configurator_t *cfg); 202 203 /** Deinitialize the PWM object 204 * 205 * @param[in,out] obj The PWM object 206 */ 207 void cyhal_pwm_free(cyhal_pwm_t *obj); 208 209 /** Set the number of microseconds for the PWM period & pulse width 210 * 211 * @param[in] obj The PWM object 212 * @param[in] period_us The period in microseconds 213 * @param[in] pulse_width_us The pulse width in microseconds 214 * @return The status of the period request 215 */ 216 cy_rslt_t cyhal_pwm_set_period(cyhal_pwm_t *obj, uint32_t period_us, uint32_t pulse_width_us); 217 218 /** Set the PWM duty cycle and frequency 219 * 220 * @param[in] obj The PWM object 221 * @param[in] duty_cycle The percentage of time the output is high (0 - 100%) 222 * @param[in] frequencyhal_hz The frequency of the PWM in Hz 223 * @return The status of the duty cycle request 224 */ 225 cy_rslt_t cyhal_pwm_set_duty_cycle(cyhal_pwm_t *obj, float duty_cycle, uint32_t frequencyhal_hz); 226 227 /** Starts the PWM generation and outputs on <b>pin</b> and <b>compl_pin</b>. 228 * 229 * @param[in] obj The PWM object 230 * @return The status of the start request 231 */ 232 cy_rslt_t cyhal_pwm_start(cyhal_pwm_t *obj); 233 234 /** Stops the PWM generation and outputs on <b>pin</b> and <b>compl_pin</b>. 235 * 236 * @param[in] obj The PWM object 237 * @return The status of the stop request 238 */ 239 cy_rslt_t cyhal_pwm_stop(cyhal_pwm_t *obj); 240 241 /** Register a PWM interrupt handler 242 * 243 * This function will be called when one of the events enabled by \ref cyhal_pwm_enable_event occurs. 244 * 245 * @param[in] obj The PWM object 246 * @param[in] callback The callback handler which will be invoked when the event occurs 247 * @param[in] callback_arg Generic argument that will be provided to the callback when called 248 */ 249 void cyhal_pwm_register_callback(cyhal_pwm_t *obj, cyhal_pwm_event_callback_t callback, void *callback_arg); 250 251 /** Configure PWM event enablement. 252 * 253 * When an enabled event occurs, the function specified by \ref cyhal_pwm_register_callback will be called. 254 * 255 * @param[in] obj The PWM object 256 * @param[in] event The PWM event type 257 * @param[in] intr_priority The priority for NVIC interrupt events 258 * @param[in] enable True to turn on events, False to turn off 259 */ 260 void cyhal_pwm_enable_event(cyhal_pwm_t *obj, cyhal_pwm_event_t event, uint8_t intr_priority, bool enable); 261 262 /** Connects a source signal and configures and enables a PWM event to be 263 * triggered from that signal. These PWM events can be configured 264 * independently and connect to the same or different source signals. 265 * @note For "edge" signals, this function will default to rising edge. To control the edge type, 266 * use @ref cyhal_pwm_connect_digital2 267 * 268 * @param[in] obj PWM obj 269 * @param[in] source Source signal obtained from another driver's cyhal_<PERIPH>_enable_output 270 * @param[in] signal The PWM input signal 271 * @return The status of the connection 272 * */ 273 cy_rslt_t cyhal_pwm_connect_digital(cyhal_pwm_t *obj, cyhal_source_t source, cyhal_pwm_input_t signal); 274 275 /** Connects a source signal and configures and enables a PWM event to be 276 * triggered from that signal with a configurable edge type. These PWM events 277 * can be configured independently and connect to the same or different source signals. 278 * 279 * @param[in] obj PWM obj 280 * @param[in] source Source signal obtained from another driver's cyhal_<PERIPH>_enable_output 281 * @param[in] signal The PWM input signal 282 * @param[in] edge_type The edge type that should trigger the event. This must be consistent with the 283 * edge type of `source`. If `source` produces a "level" signal, the only valid 284 * value is @ref CYHAL_EDGE_TYPE_LEVEL. If `source` produces an "edge" signal, then 285 * @ref CYHAL_EDGE_TYPE_LEVEL is not a valid value. 286 * @return The status of the connection 287 * */ 288 cy_rslt_t cyhal_pwm_connect_digital2(cyhal_pwm_t *obj, cyhal_source_t source, cyhal_pwm_input_t signal, cyhal_edge_type_t edge_type); 289 290 /** Enables the specified output signal from a PWM that will be triggered 291 * when the corresponding event occurs. Multiple output signals can be 292 * configured simultaneously. 293 * 294 * @param[in] obj PWM obj 295 * @param[in] signal The PWM output signal 296 * @param[out] source Pointer to user-allocated source signal object which 297 * will be initialized by enable_output. \p source should be passed to 298 * (dis)connect_digital functions to (dis)connect the associated endpoints. 299 * @return The status of the output enable 300 * */ 301 cy_rslt_t cyhal_pwm_enable_output(cyhal_pwm_t *obj, cyhal_pwm_output_t signal, cyhal_source_t *source); 302 303 /** Disconnects a source signal and disables the PWM event. 304 * 305 * @param[in] obj PWM obj 306 * @param[in] source Source signal from cyhal_<PERIPH>_enable_output to disable 307 * @param[in] signal The PWM input signal 308 * @return The status of the disconnection 309 * */ 310 cy_rslt_t cyhal_pwm_disconnect_digital(cyhal_pwm_t *obj, cyhal_source_t source, cyhal_pwm_input_t signal); 311 312 /** Disables the specified output signal from a PWM. 313 * 314 * @param[in] obj PWM obj 315 * @param[in] signal The PWM output signal 316 * @return The status of the output disable 317 * */ 318 cy_rslt_t cyhal_pwm_disable_output(cyhal_pwm_t *obj, cyhal_pwm_output_t signal); 319 320 #if defined(__cplusplus) 321 } 322 #endif 323 324 #ifdef CYHAL_PWM_IMPL_HEADER 325 #include CYHAL_PWM_IMPL_HEADER 326 #endif /* CYHAL_PWM_IMPL_HEADER */ 327 328 /** \} group_hal_pwm */ 329