mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
Diff: targets/TARGET_Cypress/TARGET_PSOC6/lp_ticker.c
- Revision:
- 188:bcfe06ba3d64
- Child:
- 189:f392fc9709a3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/TARGET_Cypress/TARGET_PSOC6/lp_ticker.c Thu Nov 08 11:46:34 2018 +0000 @@ -0,0 +1,162 @@ +/* + * 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 "device.h" +#include "mbed_error.h" +#include "lp_ticker_api.h" +#include "device/drivers/peripheral/mcwdt/cy_mcwdt.h" +#include "device/drivers/peripheral/sysint/cy_sysint.h" +#include "psoc6_utils.h" + +#if DEVICE_LPTICKER + +/* + * Low Power Timer API on PSoC6 uses MCWD0 timer0 to implement functionality. + */ + +#if defined(TARGET_MCU_PSOC6_M0) +#define LPT_MCWDT_UNIT MCWDT_STRUCT0 +#define LPT_INTERRUPT_PRIORITY 3 +#define LPT_INTERRUPT_SOURCE srss_interrupt_mcwdt_0_IRQn +#else +#define LPT_MCWDT_UNIT MCWDT_STRUCT1 +#define LPT_INTERRUPT_PRIORITY 6 +#define LPT_INTERRUPT_SOURCE srss_interrupt_mcwdt_1_IRQn +#endif +#define LPT_MCWDT_DELAY_WAIT 0 // Recommended value is 93, but then we fail function execution time test. + +static const ticker_info_t lp_ticker_info = { + .frequency = CY_CLK_WCO_FREQ_HZ, + .bits = 16, +}; + +static bool lpt_init_done = false; +// Timer h/w configuration. +static cy_stc_mcwdt_config_t config = { + .c0Match = 0, + .c1Match = 0, + .c0Mode = CY_MCWDT_MODE_INT, + .c1Mode = CY_MCWDT_MODE_NONE, + .c2ToggleBit = 0, + .c2Mode = CY_MCWDT_MODE_NONE, + .c0ClearOnMatch = false, + .c1ClearOnMatch = false, + .c0c1Cascade = false, + .c1c2Cascade = false +}; + +// Interrupt configuration. +static cy_stc_sysint_t lpt_sysint_config = { +#if defined(TARGET_MCU_PSOC6_M0) + .intrSrc = (IRQn_Type)(-1), + .cm0pSrc = LPT_INTERRUPT_SOURCE, +#else + .intrSrc = LPT_INTERRUPT_SOURCE, +#endif + .intrPriority = LPT_INTERRUPT_PRIORITY +}; + + +void lp_ticker_init(void) +{ + lp_ticker_disable_interrupt(); + lp_ticker_clear_interrupt(); + + if (lpt_init_done) { + return; + } + +#ifdef TARGET_MCU_PSOC6_M0 + // Allocate NVIC channel. + lpt_sysint_config.intrSrc = cy_m0_nvic_allocate_channel(CY_LP_TICKER_IRQN_ID); + if (lpt_sysint_config.intrSrc == (IRQn_Type)(-1)) { + // No free NVIC channel. + error("LP_TICKER NVIC channel allocation failed."); + return; + } +#endif + + Cy_MCWDT_Init(LPT_MCWDT_UNIT, &config); + Cy_SysInt_Init(&lpt_sysint_config, lp_ticker_irq_handler); + NVIC_EnableIRQ(lpt_sysint_config.intrSrc); + Cy_MCWDT_Enable(LPT_MCWDT_UNIT, CY_MCWDT_CTR0, LPT_MCWDT_DELAY_WAIT); + lpt_init_done = true; +} + +void lp_ticker_free(void) +{ + NVIC_DisableIRQ(lpt_sysint_config.intrSrc); + Cy_MCWDT_Disable(LPT_MCWDT_UNIT, CY_MCWDT_CTR0, LPT_MCWDT_DELAY_WAIT); +#ifdef TARGET_MCU_PSOC6_M0 + cy_m0_nvic_release_channel(CY_LP_TICKER_IRQN_ID, lpt_sysint_config.intrSrc); + lpt_sysint_config.intrSrc = (IRQn_Type)(-1); +#endif + lpt_init_done = 0; +} + +uint32_t lp_ticker_read(void) +{ + return Cy_MCWDT_GetCount(LPT_MCWDT_UNIT, CY_MCWDT_COUNTER0); +} + +void lp_ticker_set_interrupt(timestamp_t timestamp) +{ + uint16_t delay; + uint16_t current = Cy_MCWDT_GetCount(LPT_MCWDT_UNIT, CY_MCWDT_COUNTER0); + uint16_t new_ts = (uint16_t)timestamp; + delay = new_ts - current; + // Make sure the event is set for the future. Mbed internally will not schedule + // delays longer than 0x7000, so too large delay means it should occur already. + // MCWDT has internal delay of about 1.5 LF clock ticks, so this is the minimum + // that we can schedule. + if ((delay < 3) || (delay > (uint16_t)(-3))) { + // Cheating a bit here. + new_ts = current + 3; + } + + // Cypress PDL manual says that valid match range is 1..65535. + if (new_ts == 0) { + new_ts = 1; + } + + // Set up and enable match interrupt. + Cy_MCWDT_SetMatch(LPT_MCWDT_UNIT, CY_MCWDT_COUNTER0, new_ts, LPT_MCWDT_DELAY_WAIT); + Cy_MCWDT_SetInterruptMask(LPT_MCWDT_UNIT, CY_MCWDT_CTR0); +} + +void lp_ticker_disable_interrupt(void) +{ + Cy_MCWDT_SetInterruptMask(LPT_MCWDT_UNIT, 0); +} + +void lp_ticker_clear_interrupt(void) +{ + Cy_MCWDT_ClearInterrupt(LPT_MCWDT_UNIT, CY_MCWDT_CTR0); +} + +void lp_ticker_fire_interrupt(void) +{ + NVIC_SetPendingIRQ(lpt_sysint_config.intrSrc); +} + +const ticker_info_t* lp_ticker_get_info(void) +{ + return &lp_ticker_info; +} + +#endif // DEVICE_LPTICKER