/*********************************************************
 *Copyright (C), 2015, Shanghai Eastsoft Microelectronics Co., Ltd.
 * @文件名:  lib_scu.c
 * @作  者:  AE Team
 * @版  本:  V1.01
 * @日  期:  2022/07/25
 * @描  述:  SCU模块库函数
 * @note
 *          Change Logs:
 *          Date            Author          Notes
 *          25 July 2022    AE Team         change license to Apache-2.0
 *
 * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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
 *
 * 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 "lib_scu.h"

/***************************************************************
  函数名：SCU_NMISelect
  描  述：设置NMI不可屏蔽中断
  输入值：不可屏蔽中断
  输出值：无
  返回值：无
 ***************************************************************/
void SCU_NMISelect(SCU_TYPE_NMICS NMI_Type)
{
    SCU_RegUnLock();
    SCU->NMICON.NMICS = NMI_Type;
    SCU_RegLock() ;
    return;
}

/***************************************************************
  函数名：SCU_GetPWRCFlagStatus
  描  述：获取PWRC复位状态寄存器标志位状态
  输入值：PWRC寄存器标志位
  输出值：无
  返回值：RESET/SET
 ***************************************************************/
FlagStatus  SCU_GetPWRCFlagStatus(SCU_TYPE_PWRC PWRC_Flag)
{
    FlagStatus bitstatus = RESET;
    SCU_RegUnLock();

    if ((SCU->PWRC.Word & (uint32_t)PWRC_Flag) != (uint32_t)RESET)
        bitstatus = SET;

    SCU_RegLock() ;
    return  bitstatus;
}

/***************************************************************
  函数名：SCU_ClearPWRCFlagBit
  描  述：清除PWRC复位状态寄存器标志位
  输入值：PWRC寄存器标志位
  输出值：无
  返回值：无
 ***************************************************************/
void SCU_ClearPWRCFlagBit(SCU_TYPE_PWRC PWRC_Flag)
{
    SCU_RegUnLock() ;
    SCU->PWRC.Word &= ~((uint32_t)PWRC_Flag);
    SCU_RegLock() ;
    return;
}

/***************************************************************
  函数名：SCU_GetLVDFlagStatus
  描  述：获取LVDD寄存器标志位状态
  输入值：LVD寄存器标志位
  输出值：无
  返回值：RESET/SET
 ***************************************************************/
FlagStatus  SCU_GetLVDFlagStatus(SCU_TYPE_LVDCON LVD_Flag)
{
    FlagStatus bitstatus = RESET;
    SCU_RegLock() ;

    if ((SCU->LVDCON.Word & (uint32_t)LVD_Flag) != (uint32_t)RESET)
        bitstatus = SET;

    return  bitstatus;
}

/***************************************************************
  函数名：SCU_SysClkSelect
  描  述：选择系统时钟
  输入值：时钟源
  输出值：无
  返回值：无
 ***************************************************************/
void SCU_SysClkSelect(SCU_TYPE_SYSCLK Sysclk)
{
    SCU_RegUnLock() ;
    SCU->SCLKEN0.CLK_SEL = Sysclk;
    SCU_RegLock() ;
    return;
}

/***************************************************************
  函数名：SCU_GetSysClk
  描  述：获取系统时钟源
  输入值：无
  输出值：无
  返回值：系统时钟源
 ***************************************************************/
SCU_TYPE_SYSCLK SCU_GetSysClk(void)
{
    return (SCU_TYPE_SYSCLK)(SCU->SCLKEN0.CLK_SEL);
}

/***************************************************************
  函数名：SCU_OpenXTAL
  描  述: 开启外部时钟
  输入值：无
  输出值：无
  返回值：系统时钟源
 ***************************************************************/
void SCU_OpenXTAL(void)
{
    SCU_RegUnLock();

    SCU->WAKEUPTIME.WAKEUPTIME = 0xFFF;

    SCU->SCLKEN1.XTAL_EN = 1;

    while (SCU->SCLKEN1.XTAL_RDY == 0); /* 等待外部时钟稳定 */

    SCU_RegLock() ;
}

/***************************************************************
  函数名：DeviceClockAllEnable
  描  述：打开所有外设时钟
  输入值：无
  输出值：无
  返回值：无
 ***************************************************************/
void DeviceClockAllEnable(void)
{
    uint32_t prot_tmp;

    prot_tmp = SCU->PROT.PROT;

    if (prot_tmp != 0)    /* 写保护了 */
        SCU_RegUnLock();    /* 解锁 */

    SCU->PCLKEN.Word = 0xFFFFFFFF;     /* 打开所有外设时钟 */

    if (prot_tmp != 0)    /* 写保护了 */
        SCU_RegLock();    /* 打开写保护 */

    return;
}

/***************************************************************
  函数名：DeviceClockAllDisable
  描  述：关闭所有外设时钟
  输入值：无
  输出值：无
  返回值：无
 ***************************************************************/
void DeviceClockAllDisable(void)
{
    uint32_t prot_temp;

    prot_temp = SCU->PROT.PROT;

    if (prot_temp != 0)  /* 写保护了 */
        SCU_RegUnLock();  /* 解锁 */

    SCU->PCLKEN.Word = 0x00000000;     /* 关闭所有外设时钟，scu无法关闭 */

    if (prot_temp != 0)  /* 写保护了 */
        SCU_RegLock();   /* 打开写保护 */

    return;
}

/***************************************************************
  函数名: DeviceClockAllEnableButIAP
  描  述: 打开除IAP模块以外所有外设时钟
  输入值: 无
  输出值: 无
  返回值: 无
 ***************************************************************/
void DeviceClockAllEnableButIAP(void)
{
    uint32_t prot_tmp;
    prot_tmp = SCU->PROT.PROT;

    if (prot_tmp != 0)                 /* 写保护已开 */
        SCU_RegUnLock();               /* 解锁写保护 */

    SCU->PCLKEN.Word = 0xFFFFFFFB;     /* 打开除IAP以外所有外设时钟 */

    if (prot_tmp != 0)                 /* 写保护已开 */
        SCU_RegLock();                 /* 打开写保护 */

    return;
}

/***************************************************************
  函数名：DeviceClock_Config
  描  述：配置外设是否使能
  输入值：tppe_periph ：选择的外设类型 ，NewState ：Disable或Enable
  输出值：无
  返回值：无
 ***************************************************************/
void DeviceClock_Config(SUC_TYPE_Periph tppe_periph, TYPE_FUNCEN NewState)
{
    SCU_RegUnLock();

    if (NewState != Disable)
    {
        SCU->PCLKEN.Word |= tppe_periph;
    }
    else
    {
        SCU->PCLKEN.Word &= ~tppe_periph;
    }

    SCU_RegLock();
    return;
}

/***************************************************************
  函数名：HRC_Config
  描  述：HRC时钟配置，芯片上电后HRC默认16MHz
  输入值：
          hrc_en:是否开启HRC，
          hrc_fre：hrc时钟频率选择，
          sys_hrc：系统时钟是否使用HRC时钟
          内部高速时钟频率可配置为2MHz、16MHz、32MHz、48MHz
  输出值：无
  返回值：无
 ***************************************************************/
void HRC_Config(TYPE_FUNCEN hrc_en, SCU_HRC_FRE hrc_fre, TYPE_FUNCEN sys_hrc)
{
    SCU_RegUnLock();

    if (hrc_en == Enable)
    {
        /* 如果内部高速时钟未开启或不稳定，则重新开启HRC等待HRC稳定 */
        if (SCU->SCLKEN1.HRC_RDY == 0)
        {
            SCU->SCLKEN1.XTAL_EN = 0x0;
            SCU->SCLKEN1.HRC_EN = 0x1;

            while (SCU->SCLKEN1.HRC_RDY == 0x0); /* 等待HRC稳定 */
        }

        /* 配置合适的FLASH读取访问等待时间 */
        SCU->FLASHWAIT.ACCT = 0x01; /* 2Tclk完成FLASH读取 */

        if (hrc_fre == SCU_HRC_48M)
        {
            SCU->SCLKEN0.CLKFLT_BY = 0x55;
        }
        else
        {
            SCU->SCLKEN0.CLKFLT_BY = 0x0;
        }

        /* 设置HRC时钟频率 */
        SCU->SCLKEN1.HRC_FRE = hrc_fre;

        /* 设置系统时钟源 */
        if (sys_hrc == Enable)
        {
            SCU->SCLKEN0.CLK_SEL = 0x00;

            while (SCU->SCLKEN1.HRC_RDY == 0); /* 等待HRC稳定 */
        }
        else
        {
            while (SCU->SCLKEN1.HRC_RDY == 0); /* 等待HRC稳定 */
        }
    }
    else
    {
        /* 关闭HRC切换到LRC时钟频率 */
        SCU->SCLKEN1.XTAL_EN = 0x0;
        SCU->SCLKEN1.HRC_EN = 0x0;
        /* 设置系统时钟源 */
        SCU->SCLKEN0.CLK_SEL = 0x01;
    }

    SCU_RegLock();
    return;
}

/***************************************************************
  函数名：SCU_MultTimerEnable
  描  述：多个时钟同时开启(T16N0/1/2/3,P32N0)
  输入值：SCU_TimerMask：可以是T16N0/1/2/3和T32N0的任意组合
  输出值：无
  返回值：无
 ***************************************************************/
void SCU_MultTimerEnable(SCU_TIMEREN_Typedef SCU_TimerMask)
{
    SCU_RegUnLock();
    SCU->TIMEREN.Word = SCU_TimerMask.Word;
    SCU_RegLock();
}

/***************************************************************
  函数名：SCU_MultTimerDisable
  描  述：多个时钟同时关闭(T16N0/1/2/3,P32N0)
  输入值：SCU_TimerMask：可以是T16N0/1/2/3和T32N0的任意组合
  输出值：无
  返回值：无
 ***************************************************************/
void SCU_MultTimerDisable(SCU_TIMERDIS_Typedef SCU_TimerMask)
{
    SCU_RegUnLock();
    SCU->TIMERDIS.Word = SCU_TimerMask.Word;
    SCU_RegLock();
}

 
/*************************END OF FILE**********************/
