Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-hal-cat1 / source / cyhal_quaddec.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 20 KB Fix file modes.
/*******************************************************************************
* File Name: cyhal_quaddec.c
*
* Description:
* Provides a high level interface for interacting with the Quadrature Decoder.
* This is a wrapper around the lower level PDL API.
*
********************************************************************************
* \copyright
* Copyright 2020-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_impl_quaddec QuadDec (Quadrature Decoder)
 * \ingroup group_hal_impl
 * \{
 * \section section_hal_impl_quaddec_pins Selecting Pins for Quadrature Decoding
 * To identify the pins that are available to use with the Quadrature Decoder, open the PSoC
 * device datasheet and navigate to the 'Multiple Alternate Functions' table.  Any pin that has
 * the peri.tr_io_input function can be used.
 *
 * \} group_hal_impl_quaddec
 */

#if defined(COMPONENT_CAT2)
/**
 * \addtogroup group_hal_impl_quaddec QuadDec (Quadrature Decoder)
 * \ingroup group_hal_impl
 * \{
 * \note The cyhal_quaddec_connect_digital() and cyhal_quaddec_disconnect_digital() functions are
 * not supported with this device and will return a CYHAL_QUADDEC_RSLT_ERR_NOT_SUPPORTED error if
 * it is called.  This device does not have the internal circuitry routing that this function is
 * used to configure.
 *
 * \} group_hal_impl_quaddec
 */
#endif

#include "cy_tcpwm.h"
#include "cy_tcpwm_quaddec.h"
#include "cyhal_clock.h"
#include "cyhal_gpio.h"
#include "cyhal_hwmgr.h"
#include "cyhal_interconnect.h"
#include "cyhal_quaddec.h"
#include "cyhal_syspm.h"
#include "cyhal_tcpwm_common.h"
#include "cyhal_utils.h"

#include <string.h>

#if defined(__cplusplus)
extern "C" {
#endif

#define _CYHAL_CNT_NUM _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource)

#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
static cyhal_tcpwm_input_t _cyhal_quaddec_translate_input_signal(cyhal_quaddec_input_t signal);
#endif

static inline cy_rslt_t _cyhal_quaddec_configure_clock(cyhal_tcpwm_t *tcpwm, en_clk_dst_t pclk, uint32_t frequency)
{
    cy_rslt_t rslt;

    const cyhal_clock_tolerance_t tolerance = {
        .type = CYHAL_TOLERANCE_PERCENT,
        .value = 2,
    };

    #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
    rslt = _cyhal_utils_allocate_clock(&tcpwm->clock, &tcpwm->resource, CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
    #elif defined(COMPONENT_CAT2)
    rslt = cyhal_clock_allocate(&tcpwm->clock, CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT);
    #endif

    if (rslt == CY_RSLT_SUCCESS)
    {
        tcpwm->dedicated_clock = true;

        if (cyhal_clock_set_frequency(&tcpwm->clock, frequency, &tolerance) == CY_RSLT_SUCCESS)
        {
            if (Cy_SysClk_PeriphAssignDivider(pclk, (cy_en_divider_types_t)tcpwm->clock.block, tcpwm->clock.channel) ==
                CY_SYSCLK_SUCCESS)
            {
                cyhal_clock_set_enabled(&tcpwm->clock, true, false);
                return CY_RSLT_SUCCESS;
            }
        }
    }

    return CYHAL_QUADDEC_RSLT_ERR_CLOCK_INIT;
}

#if defined(COMPONENT_CAT2)
//--------------------------------------------------------------------------------------------------
// _cyhal_quaddec_connect_pin
//
// NOTE: This function should be called after the pin has been initialized with cyhal_gpio_init().
//--------------------------------------------------------------------------------------------------
cy_rslt_t _cyhal_quaddec_connect_pin(cyhal_quaddec_input_t signal, cyhal_gpio_t pin,
                                     TCPWM_Type* base, uint8_t channel_num)
{
#if defined(CYHAL_PIN_MAP_TCPWM_TR_IN)
    bool found = false;
    uint8_t index;
    uint8_t array_size = sizeof(cyhal_pin_map_tcpwm_tr_in) / sizeof(cyhal_resource_pin_mapping_t);
    cyhal_resource_pin_mapping_t mapping;

    // Search through cyhal_pin_map_tcpwm_tr_in to determine if pin can be
    // used to drive a trigger line.
    for (index = 0; index < array_size; index++)
    {
        mapping = cyhal_pin_map_tcpwm_tr_in[index];

        if (mapping.pin == pin)
        {
            found = true;
            Cy_GPIO_SetHSIOM(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), mapping.hsiom);
            break;
        }
    }

    if (!found)
    {
        return CYHAL_GPIO_RSLT_ERR_NO_OUTPUT_SIGNAL;
    }

    switch (signal)
    {
        case CYHAL_QUADDEC_INPUT_PHI_A:
            TCPWM_CNT_TR_CTRL0(base, channel_num) &= ~TCPWM_CNT_TR_CTRL0_COUNT_SEL_Msk;
            TCPWM_CNT_TR_CTRL0(base, channel_num) |= _VAL2FLD(TCPWM_CNT_TR_CTRL0_COUNT_SEL,
                                                              (uint32_t)(mapping.inst) + 2);
            TCPWM_CNT_TR_CTRL1(base, channel_num) &= ~TCPWM_CNT_TR_CTRL1_COUNT_EDGE_Msk;
            TCPWM_CNT_TR_CTRL1(base, channel_num) |= _VAL2FLD(TCPWM_CNT_TR_CTRL1_COUNT_EDGE,
                                                              CYHAL_EDGE_TYPE_RISING_EDGE);
            break;

        case CYHAL_QUADDEC_INPUT_PHI_B:
            TCPWM_CNT_TR_CTRL0(base, channel_num) &= ~TCPWM_CNT_TR_CTRL0_START_SEL_Msk;
            TCPWM_CNT_TR_CTRL0(base, channel_num) |= _VAL2FLD(TCPWM_CNT_TR_CTRL0_START_SEL,
                                                              (uint32_t)(mapping.inst) + 2);
            TCPWM_CNT_TR_CTRL1(base, channel_num) &= ~TCPWM_CNT_TR_CTRL1_START_EDGE_Msk;
            TCPWM_CNT_TR_CTRL1(base, channel_num) |= _VAL2FLD(TCPWM_CNT_TR_CTRL1_START_EDGE,
                                                              CYHAL_EDGE_TYPE_RISING_EDGE);
            break;

        case CYHAL_QUADDEC_INPUT_INDEX:
            TCPWM_CNT_TR_CTRL0(base, channel_num) &= ~TCPWM_CNT_TR_CTRL0_RELOAD_SEL_Msk;
            TCPWM_CNT_TR_CTRL0(base, channel_num) |= _VAL2FLD(TCPWM_CNT_TR_CTRL0_RELOAD_SEL,
                                                              (uint32_t)(mapping.inst) + 2);
            TCPWM_CNT_TR_CTRL1(base, channel_num) &= ~TCPWM_CNT_TR_CTRL1_RELOAD_EDGE_Msk;
            TCPWM_CNT_TR_CTRL1(base, channel_num) |= _VAL2FLD(TCPWM_CNT_TR_CTRL1_RELOAD_EDGE,
                                                              CYHAL_EDGE_TYPE_RISING_EDGE);
            break;

        default:
            return CYHAL_GPIO_RSLT_ERR_NO_OUTPUT_SIGNAL;
    }

    return CY_RSLT_SUCCESS;
#else
    CY_UNUSED_PARAMETER(signal);
    CY_UNUSED_PARAMETER(pin);
    CY_UNUSED_PARAMETER(base);
    CY_UNUSED_PARAMETER(channel_num);

    return CYHAL_GPIO_RSLT_ERR_NO_OUTPUT_SIGNAL;
#endif /* defined(CYHAL_PIN_MAP_TCPWM_TR_IN) */
}
#endif

cy_rslt_t cyhal_quaddec_init(cyhal_quaddec_t *obj, cyhal_gpio_t phi_a, cyhal_gpio_t phi_b,
                             cyhal_gpio_t index, cyhal_quaddec_resolution_t resolution,
                             const cyhal_clock_t *clk, uint32_t frequency)
{
    CY_ASSERT(obj != NULL);

    cy_rslt_t rslt = CY_RSLT_SUCCESS;

    // Initialize the quadrature object
    // Explicitly marked not allocated resources as invalid to prevent freeing them.
    memset(obj, 0, sizeof(cyhal_quaddec_t));
    obj->phi_a = NC;
    obj->phi_b = NC;
    obj->index = NC;
    obj->tcpwm.resource.type = CYHAL_RSC_INVALID;
    obj->last_counter_value = 1 << (_CYHAL_TCPWM_DATA[obj->tcpwm.resource.block_num].max_count - 1);

    // Allocate TCPWM resource
    rslt = cyhal_hwmgr_allocate(CYHAL_RSC_TCPWM, &obj->tcpwm.resource);

    // Basic configuration of TCPWM for quadrature functionality
    if (rslt == CY_RSLT_SUCCESS)
    {
        cy_stc_tcpwm_quaddec_config_t config;

        obj->tcpwm.base = _CYHAL_TCPWM_DATA[obj->tcpwm.resource.block_num].base;
        _cyhal_tcpwm_init_data(&obj->tcpwm);

        memset(&config, 0, sizeof(cy_stc_tcpwm_quaddec_config_t));

        config.resolution = resolution;

        #if (CY_IP_MXTCPWM_VERSION >= 2U)
        config.phiAInputMode  = CY_TCPWM_INPUT_LEVEL;                // Pass thorugh (no edge detection)
        config.phiBInputMode  = CY_TCPWM_INPUT_LEVEL;                // Pass thorugh (no edge detection)
        config.trigger0Event  = CY_TCPWM_CNT_TRIGGER_ON_DISABLED;    // Disable output trigger0 event generation
        config.trigger1Event  = CY_TCPWM_CNT_TRIGGER_ON_DISABLED;    // Disable output trigger1 event generation
        #endif

        // This function is only used to set the resolution and configure the TCPWM for quadrature mode.
        // It also configures the inputs, but that will be overwritten by cyhal_quaddec_connect_digital().
        // So, this must be called before that function is called.
        rslt = Cy_TCPWM_QuadDec_Init(obj->tcpwm.base, _CYHAL_CNT_NUM, &config);
    }

    // Pin configuration
    if (rslt == CY_RSLT_SUCCESS)
    {
        rslt = cyhal_gpio_init(phi_a, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_NONE, false);

        if (rslt == CY_RSLT_SUCCESS)
        {
            obj->phi_a = phi_a;
            #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
            uint8_t idx = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_PHI_A);
            rslt = cyhal_gpio_enable_output(phi_a, &(obj->tcpwm.inputs[idx]));
            #endif
        }

        if (rslt == CY_RSLT_SUCCESS)
        {
            rslt = cyhal_gpio_init(phi_b, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_NONE, false);
        }

        if (rslt == CY_RSLT_SUCCESS)
        {
            obj->phi_b = phi_b;
            #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
            uint8_t idx = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_PHI_B);
            rslt = cyhal_gpio_enable_output(phi_b, &(obj->tcpwm.inputs[idx]));
            #endif
        }

        if (index != NC)
        {
            if (rslt == CY_RSLT_SUCCESS)
            {
                rslt = cyhal_gpio_init(index, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_NONE, false);
            }

            if (rslt == CY_RSLT_SUCCESS)
            {
                obj->index = index;
                #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
                uint8_t idx = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_INDEX);
                rslt = cyhal_gpio_enable_output(index, &(obj->tcpwm.inputs[idx]));
                #endif
            }
        }
        #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
        else
        {
            uint8_t idx = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_INDEX);
            obj->tcpwm.inputs[idx] = CYHAL_TRIGGER_CPUSS_ZERO;
        }
        #endif

        if (rslt != CY_RSLT_SUCCESS)
        {
            rslt = CYHAL_QUADDEC_RSLT_ERR_BAD_ARGUMENT;
        }
    }

    #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)

    // Internal signal configuration
    if (rslt == CY_RSLT_SUCCESS)
    {
        uint8_t idx = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_PHI_A);
        rslt = cyhal_quaddec_connect_digital(obj, obj->tcpwm.inputs[idx], CYHAL_QUADDEC_INPUT_PHI_A);
        if (rslt != CY_RSLT_SUCCESS)
        {
            obj->tcpwm.inputs[idx] = CYHAL_TRIGGER_CPUSS_ZERO;
        }
    }

    if (rslt == CY_RSLT_SUCCESS)
    {
        uint8_t idx = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_PHI_B);
        rslt = cyhal_quaddec_connect_digital(obj, obj->tcpwm.inputs[idx], CYHAL_QUADDEC_INPUT_PHI_B);
        if (rslt != CY_RSLT_SUCCESS)
        {
            obj->tcpwm.inputs[idx] = CYHAL_TRIGGER_CPUSS_ZERO;
        }
    }

    if ((rslt == CY_RSLT_SUCCESS) && (index != NC))
    {
        uint8_t idx = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_INDEX);
        rslt = cyhal_quaddec_connect_digital(obj, obj->tcpwm.inputs[idx], CYHAL_QUADDEC_INPUT_INDEX);
        if (rslt != CY_RSLT_SUCCESS)
        {
            obj->tcpwm.inputs[idx] = CYHAL_TRIGGER_CPUSS_ZERO;
        }
    }

    #elif defined(COMPONENT_CAT2)

    if (rslt == CY_RSLT_SUCCESS)
    {
        rslt = _cyhal_quaddec_connect_pin(CYHAL_QUADDEC_INPUT_PHI_A, obj->phi_a, obj->tcpwm.base,
                                          obj->tcpwm.resource.channel_num);
    }

    if (rslt == CY_RSLT_SUCCESS)
    {
        rslt = _cyhal_quaddec_connect_pin(CYHAL_QUADDEC_INPUT_PHI_B, obj->phi_b, obj->tcpwm.base,
                                          obj->tcpwm.resource.channel_num);
    }

    if ((rslt == CY_RSLT_SUCCESS) && (index != NC))
    {
        rslt = _cyhal_quaddec_connect_pin(CYHAL_QUADDEC_INPUT_INDEX, obj->index, obj->tcpwm.base,
                                          obj->tcpwm.resource.channel_num);
    }

    #endif

    // Clock configuration
    if (rslt == CY_RSLT_SUCCESS)
    {
        en_clk_dst_t pclk =
            (en_clk_dst_t)(_CYHAL_TCPWM_DATA[obj->tcpwm.resource.block_num].clock_dst +
                           obj->tcpwm.resource.channel_num);

        if (clk != NULL)
        {
            if (frequency != 0)
            {
                rslt = CYHAL_QUADDEC_RSLT_ERR_BAD_ARGUMENT;
            }
            else
            {
                obj->tcpwm.clock = *clk;
                _cyhal_utils_update_clock_format(&obj->tcpwm.clock);

                if (Cy_SysClk_PeriphAssignDivider(pclk, (cy_en_divider_types_t)obj->tcpwm.clock.block,
                                                  obj->tcpwm.clock.channel) != CY_SYSCLK_SUCCESS)
                {
                    rslt = CYHAL_QUADDEC_RSLT_ERR_CLOCK_INIT;
                }
            }
        }
        else
        {
            rslt = _cyhal_quaddec_configure_clock(&obj->tcpwm, pclk, frequency);
        }

        if (rslt == CY_RSLT_SUCCESS)
        {
            obj->tcpwm.clock_hz = cyhal_clock_get_frequency(&obj->tcpwm.clock);
        }
    }

    // Enable the quadrature function
    if (rslt == CY_RSLT_SUCCESS)
    {
        Cy_TCPWM_QuadDec_Enable(obj->tcpwm.base, _CYHAL_CNT_NUM);
    }
    else
    {
        cyhal_quaddec_free(obj);
    }

    return rslt;
}

void cyhal_quaddec_free(cyhal_quaddec_t *obj)
{
    CY_ASSERT(obj != NULL);
    #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
    uint8_t idx_phi_a = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_PHI_A);
    if ((obj->phi_a != NC) && (obj->tcpwm.inputs[idx_phi_a] != CYHAL_TRIGGER_CPUSS_ZERO))
    {
        cyhal_quaddec_disconnect_digital(obj, obj->tcpwm.inputs[idx_phi_a], CYHAL_QUADDEC_INPUT_PHI_A);
    }
    uint8_t idx_phi_b = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_PHI_B);
    if ((obj->phi_b != NC) && (obj->tcpwm.inputs[idx_phi_b] != CYHAL_TRIGGER_CPUSS_ZERO))
    {
        cyhal_quaddec_disconnect_digital(obj, obj->tcpwm.inputs[idx_phi_b], CYHAL_QUADDEC_INPUT_PHI_B);
    }
    uint8_t idx_index = (uint8_t)_cyhal_quaddec_translate_input_signal(CYHAL_QUADDEC_INPUT_INDEX);
    if ((obj->index != NC) && (obj->tcpwm.inputs[idx_index] != CYHAL_TRIGGER_CPUSS_ZERO))
    {
        cyhal_quaddec_disconnect_digital(obj, obj->tcpwm.inputs[idx_index], CYHAL_QUADDEC_INPUT_INDEX);
    }
    #endif
    _cyhal_utils_release_if_used(&obj->phi_a);
    _cyhal_utils_release_if_used(&obj->phi_b);
    _cyhal_utils_release_if_used(&obj->index);
    _cyhal_tcpwm_free(&obj->tcpwm);
}

cy_rslt_t cyhal_quaddec_start(cyhal_quaddec_t *obj)
{
    CY_ASSERT(obj != NULL);
    if (_cyhal_tcpwm_pm_transition_pending())
    {
        return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
    }
    Cy_TCPWM_QuadDec_Enable(obj->tcpwm.base, _CYHAL_CNT_NUM);

    // Trigger reload/index the QuadDec.
    // From the TRM, "A reload trigger must be provided through firmware to start the counter if
    // the hardware reload signal is not enabled."
    #if defined(CY_IP_MXTCPWM) && (CY_IP_MXTCPWM_VERSION >= 2)
    Cy_TCPWM_TriggerReloadOrIndex_Single(obj->tcpwm.base, _CYHAL_CNT_NUM);
    #else
    Cy_TCPWM_TriggerReloadOrIndex(obj->tcpwm.base, 1 << _CYHAL_CNT_NUM);
    #endif

    obj->last_counter_value = 1 << (_CYHAL_TCPWM_DATA[obj->tcpwm.resource.block_num].max_count - 1);

    return CY_RSLT_SUCCESS;
}

cy_rslt_t cyhal_quaddec_stop(cyhal_quaddec_t *obj)
{
    CY_ASSERT(obj != NULL);
    Cy_TCPWM_QuadDec_Disable(obj->tcpwm.base, _CYHAL_CNT_NUM);
    return CY_RSLT_SUCCESS;
}

int32_t cyhal_quaddec_get_delta(cyhal_quaddec_t *obj)
{
    CY_ASSERT(obj != NULL);

    uint32_t midpoint = 1 << (_CYHAL_TCPWM_DATA[obj->tcpwm.resource.block_num].max_count - 1);
    uint32_t max_delta = midpoint >> 1;
    uint32_t max_counter_value = (midpoint == 0x8000) ? 0xFFFF : 0xFFFFFFFF;
    uint32_t current_counter_value = Cy_TCPWM_QuadDec_GetCounter(obj->tcpwm.base, _CYHAL_CNT_NUM);
    int32_t  delta = current_counter_value - obj->last_counter_value;

    // Overflow has occurred
    if (delta < (int32_t)(-max_delta))
    {
        delta = max_counter_value - obj->last_counter_value;
        delta += current_counter_value - midpoint;
    }
    // Underflow has occurred
    else if (delta > (int32_t)max_delta)
    {
        delta = (int32_t)(-obj->last_counter_value);
        delta += current_counter_value - midpoint;
    }

    obj->last_counter_value = current_counter_value;

    return delta;
}

uint32_t cyhal_quaddec_read_counter(const cyhal_quaddec_t *obj)
{
    CY_ASSERT(obj != NULL);
    return Cy_TCPWM_QuadDec_GetCounter(obj->tcpwm.base, _CYHAL_CNT_NUM);
}

uint32_t cyhal_quaddec_read_capture(const cyhal_quaddec_t *obj)
{
    CY_ASSERT(obj != NULL);
    #if defined(CY_IP_MXTCPWM) && (CY_IP_MXTCPWM_VERSION >= 2)
    return Cy_TCPWM_QuadDec_GetCapture0Val(obj->tcpwm.base, _CYHAL_CNT_NUM);
    #else
    return Cy_TCPWM_QuadDec_GetCapture(obj->tcpwm.base, _CYHAL_CNT_NUM);
    #endif
}

#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)

static cyhal_tcpwm_input_t _cyhal_quaddec_translate_input_signal(cyhal_quaddec_input_t signal)
{
    switch (signal)
    {
        case CYHAL_QUADDEC_INPUT_PHI_A:
            return CYHAL_TCPWM_INPUT_COUNT;
        case CYHAL_QUADDEC_INPUT_PHI_B:
            return CYHAL_TCPWM_INPUT_START;
        case CYHAL_QUADDEC_INPUT_STOP:
            return CYHAL_TCPWM_INPUT_STOP;
        case CYHAL_QUADDEC_INPUT_INDEX:
            return CYHAL_TCPWM_INPUT_RELOAD;
    }
    CY_ASSERT(false);
    return (cyhal_tcpwm_input_t)0;
}

cy_rslt_t cyhal_quaddec_connect_digital(cyhal_quaddec_t *obj, cyhal_source_t source, cyhal_quaddec_input_t signal)
{
    cyhal_tcpwm_input_t tcpwm_signal;
    cyhal_edge_type_t input_type;

    switch (signal)
    {
        case CYHAL_QUADDEC_INPUT_PHI_A:
        case CYHAL_QUADDEC_INPUT_PHI_B:
            input_type = CYHAL_EDGE_TYPE_LEVEL;
            break;
        case CYHAL_QUADDEC_INPUT_STOP:
        case CYHAL_QUADDEC_INPUT_INDEX:
            input_type = CYHAL_EDGE_TYPE_RISING_EDGE;
            break;
        default:
            return CYHAL_QUADDEC_RSLT_ERR_BAD_ARGUMENT;
    }

    tcpwm_signal = _cyhal_quaddec_translate_input_signal(signal);

    return _cyhal_tcpwm_connect_digital(&(obj->tcpwm), source, tcpwm_signal, input_type);
}

cy_rslt_t cyhal_quaddec_disconnect_digital(cyhal_quaddec_t *obj, cyhal_source_t source, cyhal_quaddec_input_t signal)
{
    return _cyhal_tcpwm_disconnect_digital(&(obj->tcpwm), source,
                                           _cyhal_quaddec_translate_input_signal(signal));
}

#elif defined(COMPONENT_CAT2)

cy_rslt_t cyhal_quaddec_connect_digital(cyhal_quaddec_t *obj, cyhal_source_t source, cyhal_quaddec_input_t signal)
{
    CY_UNUSED_PARAMETER(obj);
    CY_UNUSED_PARAMETER(source);
    CY_UNUSED_PARAMETER(signal);
    return CYHAL_QUADDEC_RSLT_ERR_NOT_SUPPORTED;
}

cy_rslt_t cyhal_quaddec_disconnect_digital(cyhal_quaddec_t *obj, cyhal_source_t source, cyhal_quaddec_input_t signal)
{
    CY_UNUSED_PARAMETER(obj);
    CY_UNUSED_PARAMETER(source);
    CY_UNUSED_PARAMETER(signal);
    return CYHAL_QUADDEC_RSLT_ERR_NOT_SUPPORTED;
}

#endif

static cyhal_tcpwm_output_t _cyhal_quaddec_translate_output_signal(cyhal_quaddec_output_t signal)
{
    switch (signal)
    {
        case CYHAL_QUADDEC_OUTPUT_COMPARE_MATCH:
            return CYHAL_TCPWM_OUTPUT_COMPARE_MATCH;
    }
    CY_ASSERT(false);
    return (cyhal_tcpwm_output_t)0;
}

cy_rslt_t cyhal_quaddec_enable_output(cyhal_quaddec_t *obj, cyhal_quaddec_output_t signal, cyhal_source_t *source)
{
    if (signal != CYHAL_QUADDEC_OUTPUT_COMPARE_MATCH)
    {
        return CYHAL_QUADDEC_RSLT_ERR_BAD_ARGUMENT;
    }

    return _cyhal_tcpwm_enable_output(&(obj->tcpwm), _cyhal_quaddec_translate_output_signal(signal), source);
}

cy_rslt_t cyhal_quaddec_disable_output(cyhal_quaddec_t *obj, cyhal_quaddec_output_t signal)
{
    if (signal != CYHAL_QUADDEC_OUTPUT_COMPARE_MATCH)
        return CYHAL_QUADDEC_RSLT_ERR_BAD_ARGUMENT;

    return _cyhal_tcpwm_disable_output(&(obj->tcpwm), _cyhal_quaddec_translate_output_signal(signal));
}