MTB CAT1 Peripheral driver library

General Description

Driver API for PWM.

The functions and other declarations used in this part of the driver are in cy_tcpwm_pwm.h. You can also include cy_pdl.h to get access to all functions and declarations in the PDL.

Use PWM mode when an output square wave is needed with a specific period and duty cycle, such as:

The PWM has the following features:

Configuration Considerations

The PWM configuration can be divided to number of sequential steps listed below:

Configure PWM

To configure PWM, provide the configuration parameters in the cy_stc_tcpwm_pwm_config_t structure. The Configuration structure can be modified through software, but if the configurator in ModusToolbox is used then the configuration structure will be updated with the users input. To initialize the driver, call Cy_TCPWM_PWM_Init function providing a pointer to the populated cy_stc_tcpwm_pwm_config_t structure.

For TCPWM V1 Configuration

/* Scenario: there is need to initialize
* the first (index = 0) PWM of the TCPWM0 block
* with the below configuration settings
*/
cy_stc_tcpwm_pwm_config_t tcpwm_v1_pwm_config =
{
/* .pwmMode = */ CY_TCPWM_PWM_MODE_PWM, /* Simple PWM Mode */
/* .clockPrescaler = */ CY_TCPWM_PWM_PRESCALER_DIVBY_4, /* Clk_counter = Clk_input / 4 */
/* .pwmAlignment = */ CY_TCPWM_PWM_LEFT_ALIGN, /* PWM signal is left aligned, meaning it starts high */
/* .deadTimeClocks = */ 0UL, /* dead time feature is disabled */
/* .runMode = */ CY_TCPWM_PWM_CONTINUOUS, /* Wrap around at terminal count. */
/* .period0 = */ 99UL, /* Period of 100 (0-99). Terminal count event when rolls over back to 0. */
/* .period1 = */ 199UL, /* Period of 200 (0-199). Terminal count event when rolls over back to 0. */
/* .enablePeriodSwap = */ true, /* period swapping feature is enabled */
/* .compare0 = */ 33UL, /* duty cycle 33% (with period 100) */
/* .compare1 = */ 66UL, /* duty cycle 33% (with period 200) */
/* .enableCompareSwap = */ true, /* compare swapping feature is enabled */
/* .interruptSources = */ CY_TCPWM_INT_ON_TC, /* interrupt will rise on terminal count */
/* .invertPWMOut = */ 0UL, /* Not invert */
/* .invertPWMOutN = */ 0UL, /* Not invert */
/* .killMode = */ CY_TCPWM_PWM_STOP_ON_KILL, /* PWM stops counting on kill */
/* .swapInputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default state (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .swapInput = */ CY_TCPWM_INPUT_0,
/* .reloadInputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default state (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .reloadInput = */ CY_TCPWM_INPUT_0,
/* .startInputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default state (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .startInput = */ CY_TCPWM_INPUT_0,
/* .killInputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default state (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .killInput = */ CY_TCPWM_INPUT_0,
/* .countInputMode = */ CY_TCPWM_INPUT_LEVEL, /* Set this input to LEVEL and 1 (high logic level) */
/* .countInput = */ CY_TCPWM_INPUT_1, /* So the PWM will be enabled forever */
/* .swapOverflowUnderflow = */ false, /* Use default overflow/underflow behavior */
};
#define MY_TCPWM_PWM_NUM (0UL)
#define MY_TCPWM_PWM_MASK (1UL << MY_TCPWM_PWM_NUM)
if (CY_TCPWM_SUCCESS != Cy_TCPWM_PWM_Init(TCPWM0, MY_TCPWM_PWM_NUM, &tcpwm_v1_pwm_config))
{
/* Handle possible errors */
}
/* Enable the initialized PWM */
Cy_TCPWM_PWM_Enable(TCPWM0, MY_TCPWM_PWM_NUM);
/* Then start the PWM */
Cy_TCPWM_TriggerStart_Single(TCPWM0, MY_TCPWM_PWM_NUM);

For TCPWM V2 Configuration

/* Scenario: there is need to initialize
* the first (index = 0) PWM of the TCPWM0 block
* with the below configuration settings
*/
cy_stc_tcpwm_pwm_config_t tcpwm_v2_pwm_config =
{
/* .pwmMode = */ CY_TCPWM_PWM_MODE_PWM, /* Simple PWM Mode */
/* .clockPrescaler = */ CY_TCPWM_PWM_PRESCALER_DIVBY_4, /* Clk_counter = Clk_input / 4 */
/* .pwmAlignment = */ CY_TCPWM_PWM_LEFT_ALIGN, /* PWM signal is left aligned, meaning it starts high */
/* .deadTimeClocks = */ 0UL, /* dead time feature is disabled */
/* .runMode = */ CY_TCPWM_PWM_CONTINUOUS, /* Wrap around at terminal count. */
/* .period0 = */ 99UL, /* Period of 100 (0-99). Terminal count event when rolls over back to 0. */
/* .period1 = */ 199UL, /* Period of 200 (0-199). Terminal count event when rolls over back to 0. */
/* .enablePeriodSwap = */ true, /* period swapping feature is enabled */
/* .compare0 = */ 33UL, /* duty cycle 33% (with period 100) */
/* .compare1 = */ 66UL, /* duty cycle 33% (with period 200) */
/* .enableCompareSwap = */ true, /* compare swapping feature is enabled */
/* .interruptSources = */ CY_TCPWM_INT_ON_TC, /* interrupt will rise on terminal count */
/* .invertPWMOut = */ 0UL, /* Not invert */
/* .invertPWMOutN = */ 0UL, /* Not invert */
/* .killMode = */ CY_TCPWM_PWM_STOP_ON_KILL, /* PWM stops counting on kill */
/* .swapInputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default state (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .swapInput = */ CY_TCPWM_INPUT_0,
/* .reloadInputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default state (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .reloadInput = */ CY_TCPWM_INPUT_0,
/* .startInputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default state (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .startInput = */ CY_TCPWM_INPUT_0,
/* .killInputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default state (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .killInput = */ CY_TCPWM_INPUT_0,
/* .countInputMode = */ CY_TCPWM_INPUT_LEVEL, /* Set this input to LEVEL and 1 (high logic level) */
/* .countInput = */ CY_TCPWM_INPUT_1, /* So the PWM will be enabled forever */
/* .swapOverflowUnderflow = */ false, /* Use default overflow/underflow behavior */
/* .immediateKill = */ false, /* Specifies whether the kill event immediately deactivates the dt_line_out and dt_line_compl_out or with the next module clock */
/* .tapsEnabled = */ 0x00UL, /* In pseudo random mode this sets the enabled taps.*/
/* .compare2 = */ 33UL, /* duty cycle 33% (with period 100) */
/* .compare3 = */ 66UL, /* duty cycle 33% (with period 200) */
/* .enableCompare1Swap = */ true, /* Not implemented yet*/
/* .compare0MatchUp = */ true, /* Not implemented yet*/
/* .compare0MatchDown = */ true, /* Not implemented yet*/
/* .compare1MatchUp = */ true, /* Not implemented yet*/
/* .compare1MatchDown = */ true, /* Not implemented yet*/
/* .kill1InputMode = */ CY_TCPWM_INPUT_RISINGEDGE, /* This input is NOT used, leave it in default s tate (CY_TCPWM_INPUT_RISINGEDGE = 0UL) */
/* .kill1Input = */ CY_TCPWM_INPUT_0,
/* .pwmOnDisable = */ CY_TCPWM_PWM_OUTPUT_HIGHZ, /* Default High impedance mode*/
/* .trigger0Event = */ CY_TCPWM_CNT_TRIGGER_ON_DISABLED, /* Disable output trigger0 event generation*/
/* .trigger1Event = */ CY_TCPWM_CNT_TRIGGER_ON_DISABLED, /* Disable output trigger1 event generation*/
/* .reloadLineSelect = */ true, /* Configures how the reload line select */
/* line_out_sel = */ CY_TCPWM_OUTPUT_CONSTANT_0,
/* linecompl_out_sel = */ CY_TCPWM_OUTPUT_CONSTANT_0,
/* line_out_sel_buff = */ CY_TCPWM_OUTPUT_CONSTANT_0,
/* linecompl_out_sel_buff = */ CY_TCPWM_OUTPUT_CONSTANT_0,
/* deadTimeClocks_linecompl_out = */ 5U,
#if defined (CY_IP_MXS40TCPWM)
/* Custom alignment parameters (applied only when pwmAlignment is CY_TCPWM_PWM_CUSTOM_ALIGN) */
/* .countDirectionMode = */ CY_TCPWM_PWM_COUNT_DOWN, /* Count Down */
/* .initialCountVal = */ 1UL, /* Counter starts from 1 */
/* .cc0MatchMode = */ CY_TCPWM_PWM_ACTION_INVERT, /* Invert line_out on CC0 match */
/* .cc1MatchMode = */ CY_TCPWM_PWM_ACTION_NO_CHANGE, /* No change on CC1 match */
/* .overflowMode = */ CY_TCPWM_PWM_ACTION_SET, /* Set line_out on overflow */
/* .underflowMode = */ CY_TCPWM_PWM_ACTION_CLEAR, /* Clear line_out on underflow */
#endif
};
#define MY_TCPWM_PWM_NUM (0UL)
#define MY_TCPWM_PWM_MASK (1UL << MY_TCPWM_PWM_NUM)
if (CY_TCPWM_SUCCESS != Cy_TCPWM_PWM_Init(TCPWM0, MY_TCPWM_PWM_NUM, &tcpwm_v2_pwm_config))
{
/* Handle possible errors */
}
/* Enable the initialized PWM */
Cy_TCPWM_PWM_Enable(TCPWM0, MY_TCPWM_PWM_NUM);
/* Then start the PWM */
Cy_TCPWM_TriggerStart_Single(TCPWM0, MY_TCPWM_PWM_NUM);

Configure Custom Aligned PWM

Set cy_stc_tcpwm_pwm_config_t::pwmAlignment to CY_TCPWM_PWM_CUSTOM_ALIGN to build a non-standard waveform. The predefined alignments (Left, Right, Center, Asymmetric, ...) preset the counter direction, the initial counter value and the per-event line actions for you. The custom alignment instead lets you program those CTRL, COUNTER and TR_PWM_CTRL register fields explicitly. It is available only on the MXS40 TCPWM IP.

The following members of cy_stc_tcpwm_pwm_config_t are consumed only when cy_stc_tcpwm_pwm_config_t::pwmAlignment is CY_TCPWM_PWM_CUSTOM_ALIGN, as listed below:

Each of the four action members takes a PWM CC Match / Overflow / Underflow Actions value (Set, Clear, Invert or No Change) applied to line_out (and inverted onto line_compl_out) when the corresponding event occurs. Together, the counter direction, the initial value and the four event actions fully define the output waveform.

The same fields can also be changed at run time (after Cy_TCPWM_PWM_Init) with the dedicated setters, each performing a single read-modify-write of its CTRL / TR_PWM_CTRL field:

/* Scenario: build a non-standard PWM waveform on the first (index = 0) PWM of the
* TCPWM0 block by programming the counter direction, the initial counter value and the
* per-event line actions explicitly, instead of relying on a predefined alignment.
* Custom alignment is available only on the MXS40 TCPWM IP.
*/
cy_stc_tcpwm_pwm_config_t custom_pwm_config =
{
.pwmMode = CY_TCPWM_PWM_MODE_PWM, /* Simple PWM mode */
.clockPrescaler = CY_TCPWM_PWM_PRESCALER_DIVBY_1, /* Clk_counter = Clk_input */
.pwmAlignment = CY_TCPWM_PWM_CUSTOM_ALIGN, /* Enable custom signal behavior */
.runMode = CY_TCPWM_PWM_CONTINUOUS, /* Wrap around at terminal count */
.period0 = 99UL, /* Period of 100 (0-99) */
.compare0 = 25UL, /* CC0 match at 25 */
.compare1 = 75UL, /* CC1 match at 75 */
.interruptSources = CY_TCPWM_INT_ON_TC, /* Interrupt on terminal count */
.countInputMode = CY_TCPWM_INPUT_LEVEL, /* Keep the PWM enabled ... */
.countInput = CY_TCPWM_INPUT_1, /* ... continuously */
/* Custom-alignment parameters (consumed only because pwmAlignment == CY_TCPWM_PWM_CUSTOM_ALIGN) */
.countDirectionMode = CY_TCPWM_PWM_COUNT_UP, /* Count up from initialCountVal to Period */
.initialCountVal = 0UL, /* Load the counter with 0 at start */
.cc0MatchMode = CY_TCPWM_PWM_ACTION_SET, /* Set line_out on the CC0 match */
.cc1MatchMode = CY_TCPWM_PWM_ACTION_CLEAR, /* Clear line_out on the CC1 match */
.overflowMode = CY_TCPWM_PWM_ACTION_NO_CHANGE, /* Leave line_out unchanged on overflow */
.underflowMode = CY_TCPWM_PWM_ACTION_NO_CHANGE, /* Leave line_out unchanged on underflow */
};
#define MY_CUSTOM_PWM_NUM (0UL)
if (CY_TCPWM_SUCCESS != Cy_TCPWM_PWM_Init(TCPWM0, MY_CUSTOM_PWM_NUM, &custom_pwm_config))
{
/* Handle possible errors */
}
/* Enable and start the custom-aligned PWM */
Cy_TCPWM_PWM_Enable(TCPWM0, MY_CUSTOM_PWM_NUM);
Cy_TCPWM_TriggerStart_Single(TCPWM0, MY_CUSTOM_PWM_NUM);
/* The same custom fields can be reprogrammed at run time on the counter instance.
* Here the waveform is reshaped so that line_out toggles on both compare matches.
*/

In the ModusToolbox Device Configurator, select Custom in the PWM Configurations drop-down of the PWM signal behavior group to unlock the Count Direction, Initial Counter Value and the CC0 / CC1 Match Action and Overflow / Underflow Action fields.

tcpwm_pwm_custom_align_config.png
Custom PWM signal behavior configuration

How each custom parameter shapes the output waveform:

Each action is one of PWM CC Match / Overflow / Underflow Actions - Set drives line_out to 1, Clear drives it to 0, Invert toggles it (useful for center-style waveforms), and No Change leaves it untouched so that event has no effect on the output. Choosing conflicting or overlapping actions (for example a match and an overflow on the same tick) lets you build non-standard waveforms that the predefined alignments cannot express.

Assign Clock Divider

The clock source must be connected to proper working. Any of the peripheral clock dividers could be used. Use the SysClk (System Clock) driver API to do that.

Enable PWM

PWM has to be enabled before starting

/* Scenario: Enable PWM */
#define MY_TCPWM_PWM_NUM (0UL)
Cy_TCPWM_PWM_Enable(TCPWM0, MY_TCPWM_PWM_NUM);

Start PWM

PWM has to be started

/* Scenario: Start PWM operation */
#define MY_TCPWM_PWM_NUM (0UL)
Cy_TCPWM_TriggerStart_Single(TCPWM0, MY_TCPWM_PWM_NUM);

API Reference

 Macros
 
 Functions
 
 Data Structures