Files
mbed-os/targets/TARGET_Cypress/TARGET_PSOC6/mtb-hal-cat1/source/cyhal_timer.c
Beslan 0ef1717155
Some checks failed
Basic Checks / license-check (push) Has been cancelled
Basic Checks / include-check (push) Has been cancelled
Basic Checks / style-check (push) Has been cancelled
Basic Checks / docs-check (push) Has been cancelled
Basic Checks / python-tests (push) Has been cancelled
Basic Checks / pin-validation (push) Has been cancelled
Basic Checks / cmake-checks (push) Has been cancelled
Basic Checks / frozen-tools-check (push) Has been cancelled
Publish or Update docker image for head of branch / prepare-tags (push) Has been cancelled
Release or update docker image for a released mbed-os version / prepare-tags (push) Has been cancelled
Publish or Update docker image for head of branch / build-container (push) Has been cancelled
Publish or Update docker image for head of branch / test-container (linux/amd64) (push) Has been cancelled
Publish or Update docker image for head of branch / test-container (linux/arm64) (push) Has been cancelled
Publish or Update docker image for head of branch / deploy-container (push) Has been cancelled
Release or update docker image for a released mbed-os version / build-container (push) Has been cancelled
Release or update docker image for a released mbed-os version / test-container (linux/amd64) (push) Has been cancelled
Release or update docker image for a released mbed-os version / test-container (linux/arm64) (push) Has been cancelled
Release or update docker image for a released mbed-os version / deploy-container (push) Has been cancelled
Prune temporary docker images / prune-images (push) Has been cancelled
Mirror mbed-os-6.15.0
2026-07-10 18:42:39 +03:00

300 lines
11 KiB
C

/***************************************************************************//**
* \file cyhal_timer.c
*
* \brief
* Provides a high level interface for interacting with the Cypress Timer/Counter.
* 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.
*******************************************************************************/
#include <string.h>
#include "cy_device_headers.h"
#include "cyhal_timer_impl.h"
#include "cyhal_hwmgr.h"
#include "cyhal_gpio.h"
#include "cyhal_interconnect.h"
#include "cyhal_syspm.h"
#include "cyhal_clock.h"
#if defined(CY_IP_MXTCPWM_INSTANCES) || defined(CY_IP_M0S8TCPWM_INSTANCES)
#if defined(__cplusplus)
extern "C" {
#endif
static const cy_stc_tcpwm_counter_config_t _cyhal_timer_default_config =
{
.period = 32768,
.clockPrescaler = CY_TCPWM_COUNTER_PRESCALER_DIVBY_1,
.runMode = CY_TCPWM_COUNTER_CONTINUOUS,
.countDirection = CY_TCPWM_COUNTER_COUNT_UP,
.compareOrCapture = CY_TCPWM_COUNTER_MODE_CAPTURE,
.compare0 = 16384,
.compare1 = 16384,
.enableCompareSwap = false,
.interruptSources = CY_TCPWM_INT_NONE,
.captureInputMode = 0x3U,
.captureInput = CY_TCPWM_INPUT_0,
.reloadInputMode = 0x3U,
.reloadInput = CY_TCPWM_INPUT_0,
.startInputMode = 0x3U,
.startInput = CY_TCPWM_INPUT_0,
.stopInputMode = 0x3U,
.stopInput = CY_TCPWM_INPUT_0,
.countInputMode = 0x3U,
.countInput = CY_TCPWM_INPUT_1,
};
/** Convert timer direction from the HAL enum to the corresponding PDL constant
*
* @param[in] direction The direction, as a HAL enum value
* @return The direction, as a PDL constant
*/
static inline uint32_t _cyhal_timer_convert_direction(cyhal_timer_direction_t direction)
{
switch (direction)
{
case CYHAL_TIMER_DIR_UP:
return CY_TCPWM_COUNTER_COUNT_UP;
case CYHAL_TIMER_DIR_DOWN:
return CY_TCPWM_COUNTER_COUNT_DOWN;
case CYHAL_TIMER_DIR_UP_DOWN:
return CY_TCPWM_COUNTER_COUNT_UP_DOWN_2;
}
return CY_TCPWM_COUNTER_COUNT_UP;
}
/*******************************************************************************
* Timer HAL Functions
*******************************************************************************/
cy_rslt_t cyhal_timer_init(cyhal_timer_t *obj, cyhal_gpio_t pin, const cyhal_clock_t *clk)
{
CY_ASSERT(NULL != obj);
// No support currently for pin connections on this device
if (CYHAL_NC_PIN_VALUE != pin)
return CYHAL_TIMER_RSLT_ERR_BAD_ARGUMENT;
memset(obj, 0, sizeof(cyhal_timer_t));
cy_rslt_t result = cyhal_hwmgr_allocate(CYHAL_RSC_TCPWM, &obj->tcpwm.resource);
if (CY_RSLT_SUCCESS == result)
{
cyhal_resource_inst_t *timer = &obj->tcpwm.resource;
obj->tcpwm.base = _CYHAL_TCPWM_DATA[timer->block_num].base;
en_clk_dst_t pclk = (en_clk_dst_t)(_CYHAL_TCPWM_DATA[timer->block_num].clock_dst + timer->channel_num);
if (NULL != clk)
{
obj->tcpwm.clock = *clk;
_cyhal_utils_update_clock_format(&obj->tcpwm.clock);
obj->tcpwm.clock_hz = cyhal_clock_get_frequency(&obj->tcpwm.clock);
if (CY_SYSCLK_SUCCESS != Cy_SysClk_PeriphAssignDivider(pclk, (cy_en_divider_types_t)obj->tcpwm.clock.block, obj->tcpwm.clock.channel))
{
result = CYHAL_TIMER_RSLT_ERR_CLOCK_INIT;
}
}
else if (CY_RSLT_SUCCESS == (result = cyhal_clock_allocate(&(obj->tcpwm.clock), CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT)))
{
obj->tcpwm.dedicated_clock = true;
result = cyhal_timer_set_frequency(obj, CYHAL_TIMER_DEFAULT_FREQ);
if (CY_RSLT_SUCCESS == result)
{
if (CY_SYSCLK_SUCCESS != Cy_SysClk_PeriphAssignDivider(pclk, (cy_en_divider_types_t)obj->tcpwm.clock.block, obj->tcpwm.clock.channel))
{
result = CYHAL_TIMER_RSLT_ERR_CLOCK_INIT;
}
}
}
if (CY_RSLT_SUCCESS == result)
{
result = Cy_TCPWM_Counter_Init(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource), &_cyhal_timer_default_config);
}
if (result == CY_RSLT_SUCCESS)
{
_cyhal_tcpwm_init_data(&obj->tcpwm);
Cy_TCPWM_SetInterruptMask(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource), CY_TCPWM_INT_NONE);
Cy_TCPWM_Counter_Enable(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource));
}
else
{
cyhal_timer_free(obj);
}
}
return result;
}
cy_rslt_t cyhal_timer_configure(cyhal_timer_t *obj, const cyhal_timer_cfg_t *cfg)
{
cy_rslt_t rslt;
obj->default_value = cfg->value;
cy_stc_tcpwm_counter_config_t config = _cyhal_timer_default_config;
config.period = cfg->period;
config.compare0 = cfg->compare_value;
config.runMode = cfg->is_continuous ? CY_TCPWM_COUNTER_CONTINUOUS : CY_TCPWM_COUNTER_ONESHOT;
config.compareOrCapture = cfg->is_compare ? CY_TCPWM_COUNTER_MODE_COMPARE : CY_TCPWM_COUNTER_MODE_CAPTURE;
config.countDirection = _cyhal_timer_convert_direction(cfg->direction);
// DeInit will clear the interrupt mask; save it now and restore after we re-nit
uint32_t old_mask = Cy_TCPWM_GetInterruptMask(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource));
Cy_TCPWM_Counter_DeInit(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource), &config);
rslt = (cy_rslt_t)Cy_TCPWM_Counter_Init(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource), &config);
Cy_TCPWM_Counter_Enable(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource));
Cy_TCPWM_SetInterruptMask(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource), old_mask);
// This must be called after Cy_TCPWM_Counter_Init
cyhal_timer_reset(obj);
return rslt;
}
cy_rslt_t cyhal_timer_set_frequency(cyhal_timer_t *obj, uint32_t hz)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
if(!obj->tcpwm.dedicated_clock)
{
result = CYHAL_TIMER_RSLT_ERR_SHARED_CLOCK;
}
const cyhal_clock_tolerance_t tolerance = {
.type = CYHAL_TOLERANCE_PERCENT,
.value = 2,
};
if(CY_RSLT_SUCCESS == result)
{
if((CY_RSLT_SUCCESS == cyhal_clock_set_enabled(&obj->tcpwm.clock, false, false)) &&
(CY_RSLT_SUCCESS == cyhal_clock_set_frequency(&obj->tcpwm.clock, hz, &tolerance)) &&
(CY_RSLT_SUCCESS == cyhal_clock_set_enabled(&obj->tcpwm.clock, true, false)))
{
obj->tcpwm.clock_hz = cyhal_clock_get_frequency(&obj->tcpwm.clock);
}
else
{
result = CYHAL_TIMER_RSLT_ERR_CLOCK_INIT;
}
}
return result;
}
cy_rslt_t cyhal_timer_start(cyhal_timer_t *obj)
{
CY_ASSERT(NULL != obj);
if (_cyhal_tcpwm_pm_transition_pending())
{
return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
}
Cy_TCPWM_Counter_Enable(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource));
#if defined(CY_IP_MXTCPWM) && (CY_IP_MXTCPWM_VERSION >= 2)
Cy_TCPWM_TriggerStart_Single(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource));
#else
Cy_TCPWM_TriggerStart(obj->tcpwm.base, (1 << _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource)));
#endif
return CY_RSLT_SUCCESS;
}
cy_rslt_t cyhal_timer_stop(cyhal_timer_t *obj)
{
CY_ASSERT(NULL != obj);
Cy_TCPWM_Counter_Disable(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource));
return CY_RSLT_SUCCESS;
}
cy_rslt_t cyhal_timer_reset(cyhal_timer_t *obj)
{
CY_ASSERT(NULL != obj);
Cy_TCPWM_Counter_SetCounter(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource), obj->default_value);
return CY_RSLT_SUCCESS;
}
uint32_t cyhal_timer_read(const cyhal_timer_t *obj)
{
CY_ASSERT(NULL != obj);
return Cy_TCPWM_Counter_GetCounter(obj->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(obj->tcpwm.resource));
}
static cyhal_tcpwm_input_t _cyhal_timer_translate_input_signal(cyhal_timer_input_t event)
{
switch(event)
{
case CYHAL_TIMER_INPUT_START:
return CYHAL_TCPWM_INPUT_START;
case CYHAL_TIMER_INPUT_STOP:
return CYHAL_TCPWM_INPUT_STOP;
case CYHAL_TIMER_INPUT_RELOAD:
return CYHAL_TCPWM_INPUT_RELOAD;
case CYHAL_TIMER_INPUT_COUNT:
return CYHAL_TCPWM_INPUT_COUNT;
case CYHAL_TIMER_INPUT_CAPTURE:
return CYHAL_TCPWM_INPUT_CAPTURE;
}
CY_ASSERT(false);
return (cyhal_tcpwm_input_t)0;
}
static cyhal_tcpwm_output_t _cyhal_timer_translate_output_signal(cyhal_timer_output_t signal)
{
switch(signal)
{
case CYHAL_TIMER_OUTPUT_OVERFLOW:
return CYHAL_TCPWM_OUTPUT_OVERFLOW;
case CYHAL_TIMER_OUTPUT_UNDERFLOW:
return CYHAL_TCPWM_OUTPUT_UNDERFLOW;
case CYHAL_TIMER_OUTPUT_COMPARE_MATCH:
return CYHAL_TCPWM_OUTPUT_COMPARE_MATCH;
case CYHAL_TIMER_OUTPUT_TERMINAL_COUNT:
return CYHAL_TCPWM_OUTPUT_TERMINAL_COUNT;
}
CY_ASSERT(false);
return (cyhal_tcpwm_output_t)0;
}
cy_rslt_t cyhal_timer_connect_digital(cyhal_timer_t *obj, cyhal_source_t source, cyhal_timer_input_t signal, cyhal_edge_type_t type)
{
cyhal_tcpwm_input_t tcpwm_signal = _cyhal_timer_translate_input_signal(signal);
return _cyhal_tcpwm_connect_digital(&(obj->tcpwm), source, tcpwm_signal, type);
}
cy_rslt_t cyhal_timer_enable_output(cyhal_timer_t *obj, cyhal_timer_output_t signal, cyhal_source_t *source)
{
cyhal_tcpwm_output_t tcpwm_signal = _cyhal_timer_translate_output_signal(signal);
return _cyhal_tcpwm_enable_output(&(obj->tcpwm), tcpwm_signal, source);
}
cy_rslt_t cyhal_timer_disconnect_digital(cyhal_timer_t *obj, cyhal_source_t source, cyhal_timer_input_t signal)
{
return _cyhal_tcpwm_disconnect_digital(&(obj->tcpwm), source, _cyhal_timer_translate_input_signal(signal));
}
cy_rslt_t cyhal_timer_disable_output(cyhal_timer_t *obj, cyhal_timer_output_t signal)
{
return _cyhal_tcpwm_disable_output(&(obj->tcpwm), _cyhal_timer_translate_output_signal(signal));
}
#if defined(__cplusplus)
}
#endif
#endif /* defined(CY_IP_MXTCPWM_INSTANCES) */