mirror of https://github.com/ARMmbed/mbed-os.git
163 lines
4.6 KiB
C
163 lines
4.6 KiB
C
/*
|
|
* 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
|