/* * Copyright (c) 2016 Nordic Semiconductor ASA * Copyright (c) 2016 Vinayak Kariappa Chettimada * Copyright 2019 NXP * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include "hal/cntr.h" #include "hal/debug.h" #include "ll_irqs.h" #include #define PCS_SOURCE_RTC 2 void cntr_init(void) { /* RTC config */ /* * Reset all RTC registers except for the SWR bit * and the RTC_WAR and RTC_RAR */ RTC->CR |= RTC_CR_SWR_MASK; RTC->CR &= ~RTC_CR_SWR_MASK; /* * Set TSR register to 0x1 to avoid the timer invalid (TIF) bit being * set in the SR register */ RTC->TSR = 1; /* Enable the RTC 32.768 kHz oscillator and clock on RTC_CLKOUT */ RTC->CR |= (RTC_CR_CPS(1) | RTC_CR_OSCE(1)); /* LPTMR config */ /* Disable the timer and clear any pending IRQ. */ LPTMR1->CSR = LPTMR_CSR_TEN(0); /* * TMS = 0: time counter mode, not pulse counter * TFC = 1: reset counter on overflow * TIE = 1: enable interrupt */ LPTMR1->CSR = (LPTMR_CSR_TFC(1) | LPTMR_CSR_TIE(1)); /* * PCS = 2: clock source is RTC - 32 kHz clock (SoC dependent) * PBYP = 1: bypass the prescaler */ LPTMR1->PSR = (LPTMR_PSR_PBYP(1) | LPTMR_PSR_PCS(PCS_SOURCE_RTC)); irq_enable(LL_RTC0_IRQn_2nd_lvl); } static uint8_t refcount; static uint32_t cnt_diff; uint32_t cntr_start(void) { if (refcount++) { return 1; } LPTMR1->CMR = 0xFFFFFFFF; LPTMR1->CSR |= LPTMR_CSR_TEN(1); return 0; } uint32_t cntr_stop(void) { LL_ASSERT(refcount); if (--refcount) { return 1; } cnt_diff = cntr_cnt_get(); /* * When TEN is clear, it resets the LPTMR internal logic, * including the CNR and TCF. */ LPTMR1->CSR &= ~LPTMR_CSR_TEN_MASK; return 0; } uint32_t cntr_cnt_get(void) { /* * On each read of the CNR, * software must first write to the CNR with any value. */ LPTMR1->CNR = 0; return (LPTMR1->CNR + cnt_diff); } void cntr_cmp_set(uint8_t cmp, uint32_t value) { /* * When the LPTMR is enabled, the first increment will take an * additional one or two prescaler clock cycles due to * synchronization logic. */ cnt_diff = cntr_cnt_get() + 1; LPTMR1->CSR &= ~LPTMR_CSR_TEN_MASK; value -= cnt_diff; /* * If the CMR is 0, the hardware trigger will remain asserted until * the LPTMR is disabled. If the LPTMR is enabled, the CMR must be * altered only when TCF is set. */ if (value == 0) { value = 1; } LPTMR1->CMR = value; LPTMR1->CSR |= LPTMR_CSR_TEN(1); }