/***************************************************************************//** * \file cyhal_pwm.h * * \brief * Provides a high level interface for interacting with the Cypress PWM. * This interface abstracts out the chip specific details. If any chip specific * functionality is necessary, or performance is critical the low level functions * can be used directly. * ******************************************************************************** * \copyright * Copyright 2018-2021 Cypress Semiconductor Corporation * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ /** * \addtogroup group_hal_pwm PWM (Pulse Width Modulator) * \ingroup group_hal * \{ * High level interface for interacting with the pulse width modulator (PWM) hardware resource * * The PWM driver can be used to generate periodic digital waveforms with configurable frequency and duty cycle. * The driver allows assigning the PWM output and an optional inverted output to supplied pins. * The driver supports interrupt generation on PWM terminal count and compare events. * * \section section_pwm_features Features * * Configurable pin assignment for the PWM output * * Optional complementary (inverted) PWM output to a second pin * * Configurable dead time between normal and inverted PWM outputs * * Configurable alignment: left, right or center * * Continuous or One-shot operation * * Option to instantiate and use a new clock or use pre-allocated clock for clock input * * Configurable interrupt and callback assignment on PWM events: terminal count, compare match or combination of both * * \section section_pwm_quickstart Quick Start * * 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. * * \section section_pwm_snippets Code snippets * * \subsection subsection_pwm_snippet_1 Snippet 1: Simple PWM initialization and output to pin * The following snippet initializes a PWM resource and assigns the output to the supplied <b>pin</b> using \ref cyhal_pwm_init. <br> * 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> * The clock frequency and the duty cycle is set using \ref cyhal_pwm_set_duty_cycle. <br> * \ref cyhal_pwm_start starts the PWM output on the pin. * * \snippet hal_pwm.c snippet_cyhal_pwm_simple_init * * * \subsection subsection_pwm_snippet_2 Snippet 2: Starting and stopping the PWM output * \ref cyhal_pwm_start and \ref cyhal_pwm_stop functions can be used after PWM initialization to start and stop the PWM output. * * \snippet hal_pwm.c snippet_cyhal_pwm_start_stop * * * \subsection subsection_pwm_snippet_3 Snippet 3: Advanced PWM output to pin * \ref cyhal_pwm_init_adv can be used to specify advanced PWM options like an additional inverted PWM output, pulse alignment * (left, right, center) and run mode (one-shot or continuous). The following snippet initializes a left-aligned, continuous running PWM * assigned to the supplied pin. The inverted output is assigned to a second pin (<b>compl_pin</b>). * * \snippet hal_pwm.c snippet_cyhal_pwm_adv_init * * * \subsection subsection_pwm_snippet_4 Snippet 4: Interrupts on PWM events * PWM events like hitting the terminal count or a compare event can be used to trigger a callback function. <br> * \ref cyhal_pwm_enable_event() can be used to enable one or more events to trigger the callback function. * * \snippet hal_pwm.c snippet_cyhal_pwm_events */ #pragma once #include <stdint.h> #include <stdbool.h> #include "cy_result.h" #include "cyhal_hw_types.h" #if defined(__cplusplus) extern "C" { #endif /** \addtogroup group_hal_results_pwm PWM HAL Results * PWM specific return codes * \ingroup group_hal_results * \{ *//** */ /** Bad argument */ #define CYHAL_PWM_RSLT_BAD_ARGUMENT \ (CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_PWM, 0)) /** Failed to initialize PWM clock */ #define CYHAL_PWM_RSLT_FAILED_CLOCK_INIT \ (CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_PWM, 1)) /** Failed to initialize PWM */ #define CYHAL_PWM_RSLT_FAILED_INIT \ (CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_PWM, 2)) /** * \} */ /** Initialize the PWM out peripheral and configure the pin * This is similar to the \ref cyhal_pwm_init_adv() but uses defaults for some of the * more advanced setup options. See \ref subsection_pwm_snippet_1. * * @param[out] obj Pointer to a PWM object. The caller must allocate the memory * for this object but the init function will initialize its contents. * @param[in] pin The PWM pin to initialize. This pin is required, it cannot be \ref NC (No Connect). * @param[in] clk An optional, pre-allocated clock to use, if NULL a new clock will be allocated * @return The status of the init request. */ #define cyhal_pwm_init(obj, pin, clk) (cyhal_pwm_init_adv(obj, pin, NC, (pin & 1) ? CYHAL_PWM_RIGHT_ALIGN : CYHAL_PWM_LEFT_ALIGN, true, 0u, (bool)(pin & 1), clk)) /** PWM interrupt triggers */ typedef enum { CYHAL_PWM_IRQ_NONE = 0, /**< No interrupts */ CYHAL_PWM_IRQ_TERMINAL_COUNT = 1 << 0, /**< Interrupt on terminal count match event */ CYHAL_PWM_IRQ_COMPARE = 1 << 1, /**< Interrupt on compare match event */ CYHAL_PWM_IRQ_ALL = (1 << 2) - 1, /**< Interrupt on any events */ /** \cond INTERNAL */ CYHAL_PWM_IRQ_CAPTURE_COMPARE /* __attribute__ ((deprecated)) */ = CYHAL_PWM_IRQ_COMPARE, /** \endcond */ } cyhal_pwm_event_t; /** PWM alignment */ typedef enum { CYHAL_PWM_LEFT_ALIGN = 0, /**< PWM is left aligned (signal starts high and goes low after compare match) */ CYHAL_PWM_RIGHT_ALIGN = 1, /**< PWM is right aligned (signal starts low and goes high after compare match) */ CYHAL_PWM_CENTER_ALIGN = 2, /**< PWM is centered aligned (signal starts and ends low with a center aligned pulse) */ } cyhal_pwm_alignment_t; /** PWM input signal */ typedef enum { CYHAL_PWM_INPUT_START, //!< Start signal CYHAL_PWM_INPUT_STOP, //!< Stop signal CYHAL_PWM_INPUT_RELOAD, //!< Reload signal CYHAL_PWM_INPUT_COUNT, //!< Count signal CYHAL_PWM_INPUT_CAPTURE, //!< Capture/swap signal } cyhal_pwm_input_t; /** PWM output signal */ typedef enum { CYHAL_PWM_OUTPUT_OVERFLOW, //!< Overflow signal CYHAL_PWM_OUTPUT_UNDERFLOW, //!< Underflow signal CYHAL_PWM_OUTPUT_COMPARE_MATCH, //!< Compare Match signal CYHAL_PWM_OUTPUT_LINE_OUT, //!< PWM line out signal } cyhal_pwm_output_t; /** Handler for PWM interrupts */ typedef void(*cyhal_pwm_event_callback_t)(void *callback_arg, cyhal_pwm_event_t event); /** Initialize the PWM out peripheral and configure the pin. * This is similar to the \ref cyhal_pwm_init() but provides additional setup options. <br> * See \ref subsection_pwm_snippet_3. * * @param[out] obj Pointer to a PWM object. The caller must allocate the memory * for this object but the init function will initialize its contents. * @param[in] pin The PWM pin to initialize. This pin is required, it cannot be \ref NC (No Connect). * @param[in] compl_pin An optional, additional inverted output pin. <br> * If supplied, this must be connected to the same PWM instance as <b>pin</b>, see * \ref section_hal_impl_pwm_compl_pins.<br> * If this output is not needed, use \ref NC (No Connect). * @param[in] pwm_alignment PWM alignment: left, right, or center. * @param[in] continuous PWM run type: continuous (true) or one shot (false). * @param[in] dead_time_us The number of micro-seconds for dead time. This is * only meaningful if both <b>pin</b> and <b>compl_pin</b> are provided. * @param[in] invert An option for the user to invert the PWM output * @param[in] clk An optional, pre-allocated clock to use, if NULL a * new clock will be allocated. * @return The status of the init request * * @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. */ 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); /** Deinitialize the PWM object * * @param[in,out] obj The PWM object */ void cyhal_pwm_free(cyhal_pwm_t *obj); /** Set the number of microseconds for the PWM period & pulse width * * @param[in] obj The PWM object * @param[in] period_us The period in microseconds * @param[in] pulse_width_us The pulse width in microseconds * @return The status of the period request */ cy_rslt_t cyhal_pwm_set_period(cyhal_pwm_t *obj, uint32_t period_us, uint32_t pulse_width_us); /** Set the PWM duty cycle and frequency * * @param[in] obj The PWM object * @param[in] duty_cycle The percentage of time the output is high * @param[in] frequencyhal_hz The frequency of the PWM in Hz * @return The status of the duty cycle request */ cy_rslt_t cyhal_pwm_set_duty_cycle(cyhal_pwm_t *obj, float duty_cycle, uint32_t frequencyhal_hz); /** Starts the PWM generation and outputs on <b>pin</b> and <b>compl_pin</b>. * * @param[in] obj The PWM object * @return The status of the start request */ cy_rslt_t cyhal_pwm_start(cyhal_pwm_t *obj); /** Stops the PWM generation and outputs on <b>pin</b> and <b>compl_pin</b>. * * @param[in] obj The PWM object * @return The status of the stop request */ cy_rslt_t cyhal_pwm_stop(cyhal_pwm_t *obj); /** Register a PWM interrupt handler * * This function will be called when one of the events enabled by \ref cyhal_pwm_enable_event occurs. * * @param[in] obj The PWM object * @param[in] callback The callback handler which will be invoked when the event occurs * @param[in] callback_arg Generic argument that will be provided to the callback when called */ void cyhal_pwm_register_callback(cyhal_pwm_t *obj, cyhal_pwm_event_callback_t callback, void *callback_arg); /** Configure PWM event enablement. * * When an enabled event occurs, the function specified by \ref cyhal_pwm_register_callback will be called. * * @param[in] obj The PWM object * @param[in] event The PWM event type * @param[in] intr_priority The priority for NVIC interrupt events * @param[in] enable True to turn on events, False to turn off */ void cyhal_pwm_enable_event(cyhal_pwm_t *obj, cyhal_pwm_event_t event, uint8_t intr_priority, bool enable); /** Connects a source signal and configures and enables a PWM event to be * triggered from that signal. These PWM events can be configured * independently and connect to the same or different source signals. * * @param[in] obj PWM obj * @param[in] source Source signal obtained from another driver's cyhal_<PERIPH>_enable_output * @param[in] signal The PWM input signal * @param[in] type The PWM input signal edge type * @return The status of the connection * */ cy_rslt_t cyhal_pwm_connect_digital(cyhal_pwm_t *obj, cyhal_source_t source, cyhal_pwm_input_t signal, cyhal_edge_type_t type); /** Enables the specified output signal from a PWM that will be triggered * when the corresponding event occurs. Multiple output signals can be * configured simultaneously. * * @param[in] obj PWM obj * @param[in] signal The PWM output signal * @param[out] source Pointer to user-allocated source signal object which * will be initialized by enable_output. \p source should be passed to * (dis)connect_digital functions to (dis)connect the associated endpoints. * @return The status of the output enable * */ cy_rslt_t cyhal_pwm_enable_output(cyhal_pwm_t *obj, cyhal_pwm_output_t signal, cyhal_source_t *source); /** Disconnects a source signal and disables the PWM event. * * @param[in] obj PWM obj * @param[in] source Source signal from cyhal_<PERIPH>_enable_output to disable * @param[in] signal The PWM input signal * @return The status of the disconnection * */ cy_rslt_t cyhal_pwm_disconnect_digital(cyhal_pwm_t *obj, cyhal_source_t source, cyhal_pwm_input_t signal); /** Disables the specified output signal from a PWM. * * @param[in] obj PWM obj * @param[in] signal The PWM output signal * @return The status of the output disable * */ cy_rslt_t cyhal_pwm_disable_output(cyhal_pwm_t *obj, cyhal_pwm_output_t signal); #if defined(__cplusplus) } #endif #ifdef CYHAL_PWM_IMPL_HEADER #include CYHAL_PWM_IMPL_HEADER #endif /* CYHAL_PWM_IMPL_HEADER */ /** \} group_hal_pwm */