chen
2024-11-08 cc432b761c884a0bd8e9d83db0a4e26109fc08b1
keil/include/drivers/mk_sleep_timer.c
对比新文件
@@ -0,0 +1,160 @@
/*
 * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
 * its subsidiaries and affiliates (collectly called MKSEMI).
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into an MKSEMI
 *    integrated circuit in a product or a software update for such product,
 *    must reproduce the above copyright notice, this list of conditions and
 *    the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of MKSEMI nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    MKSEMI integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be
 *    reverse engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "mk_sleep_timer.h"
#include "mk_trace.h"
#include "mk_clock.h"
#include "mk_power.h"
#define SLEEP_TIMER_REG_STDR (RTC_BASE + 0x20)
#define SLEEP_TIMER_REG_STCR (RTC_BASE + 0x2C)
#define SLEEP_TIMER_INT_STATUS (0x80000000)
#define SLEEP_TIMER_INT_CLR (0x00000004)
static struct SLEEP_TIMER_HANDLE_T sleep_timer_handle = {
    .mode = SLEEP_TIMER_MODE_ONESHOT,
    .time = 32768,
    .int_en = true,
    .ppm = 0,
    .callback = NULL,
};
void sleep_timer_open(bool int_en, enum SLEEP_TIMER_MODE_T mode, drv_callback_t callback)
{
    // need open RTC clock
    clock_enable(CLOCK_RTC);
    // disable sleep timer and clear int status
    REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP | SLEEP_TIMER_INT_CLR);
    sleep_timer_handle.callback = callback;
    sleep_timer_handle.int_en = int_en;
    sleep_timer_handle.mode = mode;
    if (sleep_timer_handle.int_en)
    {
        NVIC_SetPriority(SLEEP_TIMER_IRQn, IRQ_PRIORITY_NORMAL);
        NVIC_ClearPendingIRQ(SLEEP_TIMER_IRQn);
        NVIC_EnableIRQ(SLEEP_TIMER_IRQn);
    }
    // enable sleep timer as wakeup source
    power_wakeup_enable(POWER_WAKEUP_BY_SLEEP_TIMER, POWER_WAKEUP_LEVEL_NONE);
}
void sleep_timer_close(void)
{
    // disable sleep timer and clear int status
    REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP | SLEEP_TIMER_INT_CLR);
    if (sleep_timer_handle.int_en)
    {
        NVIC_DisableIRQ(SLEEP_TIMER_IRQn);
        NVIC_ClearPendingIRQ(SLEEP_TIMER_IRQn);
    }
}
void sleep_timer_start(uint32_t time)
{
    sleep_timer_handle.time = (uint32_t)((int32_t)time + (int32_t)((int32_t)time * sleep_timer_handle.ppm / 1000000));
    // disable sleep timer
    REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP);
    // set sleep timer
    REG_WRITE(SLEEP_TIMER_REG_STDR, sleep_timer_handle.time);
    // enable sleep timer
    REG_WRITE(SLEEP_TIMER_REG_STCR, sleep_timer_handle.mode);
}
void sleep_timer_stop(void)
{
    // disable sleep timer
    REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP);
}
uint32_t high_xtal_off_time(void)
{
#ifdef UWB_EN
    uint32_t slp_cnt = REG_READ(0x40000074);
    return (uint32_t)((int32_t)slp_cnt - (int32_t)((int32_t)slp_cnt * sleep_timer_handle.ppm / 1000000));
#else
    return REG_READ(SLEEP_TIMER_REG_STDR);
#endif
}
void sleep_timer_ppm_set(int32_t ppm)
{
    sleep_timer_handle.ppm = ppm;
}
int32_t sleep_timer_ppm_get(void)
{
    return sleep_timer_handle.ppm;
}
void SLEEP_TIMER_IRQHandler(void)
{
    uint32_t int_stat = REG_READ(SLEEP_TIMER_REG_STCR);
    if (int_stat & SLEEP_TIMER_INT_STATUS)
    {
        // clear interrupt status
        if (sleep_timer_handle.mode == SLEEP_TIMER_MODE_ONESHOT)
        {
            REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP | SLEEP_TIMER_INT_CLR);
        }
        else
        {
            REG_WRITE(SLEEP_TIMER_REG_STCR, sleep_timer_handle.mode | SLEEP_TIMER_INT_CLR);
        }
        if (sleep_timer_handle.callback != NULL)
        {
            sleep_timer_handle.callback(NULL, sleep_timer_handle.time);
        }
    }
    else
    {
        ASSERT(0, "Unexpected sleep interrupt");
    }
}