mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
Diff: targets/TARGET_Cypress/TARGET_PSOC6/us_ticker.c
- Revision:
- 188:bcfe06ba3d64
- Child:
- 189:f392fc9709a3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/TARGET_Cypress/TARGET_PSOC6/us_ticker.c Thu Nov 08 11:46:34 2018 +0000 @@ -0,0 +1,215 @@ +/* + * mbed Microcontroller Library + * Copyright (c) 2017-2018 Future Electronics + * + * 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 <stddef.h> +#include <limits.h> +#include "device.h" +#include "PeripheralNames.h" +#include "us_ticker_api.h" +#include "mbed_error.h" +#include "psoc6_utils.h" + +#include "drivers/peripheral/sysint/cy_sysint.h" +#include "drivers/peripheral/sysclk/cy_sysclk.h" +#include "drivers/peripheral/tcpwm/cy_tcpwm_counter.h" +#include "drivers/peripheral/syspm/cy_syspm.h" + +/** Each CPU core in PSoC6 needs its own usec timer. + ** Although each of TCPWM timers have two compare registers, + ** it has only one interrupt line, so we need to allocate + ** two TCPWM counters for the purpose of us_ticker + **/ + + +#if defined(TARGET_MCU_PSOC6_M0) + +#define TICKER_COUNTER_UNIT TCPWM0 +#define TICKER_COUNTER_NUM 0 +#define TICKER_COUNTER_INTERRUPT_SOURCE tcpwm_0_interrupts_0_IRQn +#define TICKER_COUNTER_NVIC_IRQN CY_M0_CORE_IRQ_CHANNEL_US_TICKER +#define TICKER_COUNTER_INTERRUPT_PRIORITY 3 +#define TICKER_CLOCK_DIVIDER_NUM 0 + +#elif defined(TARGET_MCU_PSOC6_M4) + +#define TICKER_COUNTER_UNIT TCPWM0 +#define TICKER_COUNTER_NUM 1 +#define TICKER_COUNTER_INTERRUPT_SOURCE tcpwm_0_interrupts_1_IRQn +#define TICKER_COUNTER_NVIC_IRQN TICKER_COUNTER_INTERRUPT_SOURCE +#define TICKER_COUNTER_INTERRUPT_PRIORITY 6 +#define TICKER_CLOCK_DIVIDER_NUM 1 + +#else +#error "Unknown MCU type." +#endif + + +static const ticker_info_t us_ticker_info = { + .frequency = 1000000UL, + .bits = 32, +}; + +static const cy_stc_sysint_t us_ticker_sysint_cfg = { + .intrSrc = TICKER_COUNTER_NVIC_IRQN, +#if defined(TARGET_MCU_PSOC6_M0) + .cm0pSrc = TICKER_COUNTER_INTERRUPT_SOURCE, +#endif + .intrPriority = TICKER_COUNTER_INTERRUPT_PRIORITY +}; + +static int us_ticker_inited = 0; + +static const cy_stc_tcpwm_counter_config_t cy_counter_config = { + .period = 0xFFFFFFFFUL, + .clockPrescaler = CY_TCPWM_COUNTER_PRESCALER_DIVBY_1, + .runMode = CY_TCPWM_COUNTER_CONTINUOUS, + .countDirection = CY_TCPWM_COUNTER_COUNT_UP, + .compareOrCapture = CY_TCPWM_COUNTER_MODE_COMPARE, + .enableCompareSwap = false, + .interruptSources = CY_TCPWM_INT_ON_CC, + .countInputMode = CY_TCPWM_INPUT_LEVEL, + .countInput = CY_TCPWM_INPUT_1 +}; + +// PM callback to be executed when exiting deep sleep. +static cy_en_syspm_status_t ticker_pm_callback(cy_stc_syspm_callback_params_t *callbackParams); + +static cy_stc_syspm_callback_params_t ticker_pm_callback_params = { + .base = TICKER_COUNTER_UNIT +}; + +static cy_stc_syspm_callback_t ticker_pm_callback_handler = { + .callback = ticker_pm_callback, + .type = CY_SYSPM_DEEPSLEEP, + .skipMode = CY_SYSPM_SKIP_CHECK_READY | CY_SYSPM_SKIP_CHECK_FAIL | CY_SYSPM_SKIP_BEFORE_TRANSITION, + .callbackParams = &ticker_pm_callback_params +}; + + +/* + * Callback handler to restart the timer after deep sleep. + */ +static cy_en_syspm_status_t ticker_pm_callback(cy_stc_syspm_callback_params_t *params) +{ + if (params->mode == CY_SYSPM_AFTER_TRANSITION) { + Cy_TCPWM_Counter_Enable(TICKER_COUNTER_UNIT, TICKER_COUNTER_NUM); + Cy_TCPWM_TriggerStart(TICKER_COUNTER_UNIT, 1UL << TICKER_COUNTER_NUM); + } + return CY_SYSPM_SUCCESS; +} + +/* + * Interrupt handler. + */ +static void local_irq_handler(void) +{ + us_ticker_clear_interrupt(); + us_ticker_disable_interrupt(); + us_ticker_irq_handler(); +} + + +void us_ticker_init(void) +{ + us_ticker_disable_interrupt(); + us_ticker_clear_interrupt(); + + if (us_ticker_inited) + return; + + us_ticker_inited = 1; + + // Configure the clock, us_ticker 1 MHz from PCLK 50 MHz + Cy_SysClk_PeriphAssignDivider(PCLK_TCPWM0_CLOCKS0 + TICKER_COUNTER_NUM, CY_SYSCLK_DIV_8_BIT, TICKER_CLOCK_DIVIDER_NUM); + Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, TICKER_CLOCK_DIVIDER_NUM, (CY_CLK_PERICLK_FREQ_HZ / 1000000UL) - 1); + Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, TICKER_CLOCK_DIVIDER_NUM); + + /* + Configure the counter + */ + + Cy_TCPWM_Counter_Init(TICKER_COUNTER_UNIT, TICKER_COUNTER_NUM, &cy_counter_config); + Cy_TCPWM_Counter_Enable(TICKER_COUNTER_UNIT, TICKER_COUNTER_NUM); + if (!Cy_SysPm_RegisterCallback(&ticker_pm_callback_handler)) { + error("PM callback registration failed!"); + } + Cy_TCPWM_TriggerStart(TICKER_COUNTER_UNIT, 1UL << TICKER_COUNTER_NUM); + +#if defined (TARGET_MCU_PSOC6_M0) + if (cy_m0_nvic_reserve_channel(TICKER_COUNTER_NVIC_IRQN, CY_US_TICKER_IRQN_ID) == (IRQn_Type)(-1)) { + error("Microsecond ticker NVIC channel reservation conflict."); + } +#endif // + + Cy_SysInt_Init(&us_ticker_sysint_cfg, local_irq_handler); +} + +void us_ticker_free(void) +{ + us_ticker_disable_interrupt(); + Cy_TCPWM_Counter_Disable(TICKER_COUNTER_UNIT, TICKER_COUNTER_NUM); + Cy_SysPm_UnregisterCallback(&ticker_pm_callback_handler); +#if defined (TARGET_MCU_PSOC6_M0) + cy_m0_nvic_release_channel(TICKER_COUNTER_NVIC_IRQN, CY_US_TICKER_IRQN_ID); +#endif // + us_ticker_inited = 0; +} + +uint32_t us_ticker_read(void) +{ + if (!us_ticker_inited) + us_ticker_init(); + return Cy_TCPWM_Counter_GetCounter(TICKER_COUNTER_UNIT, TICKER_COUNTER_NUM); +} + +void us_ticker_set_interrupt(timestamp_t timestamp) +{ + uint32_t current_ts = Cy_TCPWM_Counter_GetCounter(TICKER_COUNTER_UNIT, TICKER_COUNTER_NUM); + uint32_t delta = timestamp - current_ts; + + if (!us_ticker_inited) + us_ticker_init(); + + // Set new output compare value + if ((delta < 2) || (delta > (uint32_t)(-3))) { + timestamp = current_ts + 2; + } + Cy_TCPWM_Counter_SetCompare0(TICKER_COUNTER_UNIT, TICKER_COUNTER_NUM, timestamp); + // Enable int + NVIC_EnableIRQ(TICKER_COUNTER_NVIC_IRQN); +} + +void us_ticker_disable_interrupt(void) +{ + NVIC_DisableIRQ(TICKER_COUNTER_NVIC_IRQN); +} + +void us_ticker_clear_interrupt(void) +{ + Cy_TCPWM_ClearInterrupt(TICKER_COUNTER_UNIT, TICKER_COUNTER_NUM, CY_TCPWM_INT_ON_CC); +} + +void us_ticker_fire_interrupt(void) +{ + NVIC_EnableIRQ(TICKER_COUNTER_NVIC_IRQN); + NVIC_SetPendingIRQ(TICKER_COUNTER_NVIC_IRQN); +} + +const ticker_info_t* us_ticker_get_info(void) +{ + return &us_ticker_info; +}