rt-thread/bsp/acm32/acm32f0x0-nucleo/libraries/Device/System_ACM32F0x0.c

618 lines
19 KiB
C

/*
******************************************************************************
* @file System_ACM32F0x0.c
* @version V1.0.0
* @date 2021
* @brief System Source File, includes clock management, reset management
* and IO configuration, ...
******************************************************************************
*/
#include "ACM32Fxx_HAL.h"
uint32_t gu32_SystemClock;
uint32_t gu32_APBClock;
RESET_REASON Reset_Reason_Save;
/* System count in SysTick_Handler */
volatile uint32_t gu32_SystemCount;
/************************* Miscellaneous Configuration ************************/
/*!< Uncomment the following line if you need to relocate your vector Table in
Internal SRAM. */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x0U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
/******************************************************************************/
#if 0
/*********************************************************************************
* Function : HardFault_Handler
* Description : Hard Fault handle, while(1) loop, wait for debug
* Input : none
* Output : none
* Author : xwl
**********************************************************************************/
void HardFault_Handler(void)
{
while(1);
}
/*********************************************************************************
* Function : SysTick_Handler
* Description : System tick handler
* Input : none
* Output : none
* Author : Chris_Kyle
**********************************************************************************/
void SysTick_Handler(void)
{
gu32_SystemCount++;
}
/*********************************************************************************
* Function : System_SysTick_Init
* Description : System Tick Init. Period is 1 ms
* Input : none
* Output : none
* Author : Chris_Kyle
**********************************************************************************/
void System_SysTick_Init(void)
{
gu32_SystemCount = 0;
SysTick_Config(gu32_SystemClock / 1000); //1ms/tick
}
#endif
/*********************************************************************************
* Function : System_SysTick_Off
* Description : Turn off System Tick
* Input : none
* Output : none
* Author : xwl
**********************************************************************************/
void System_SysTick_Off(void)
{
SysTick->CTRL = 0;
}
/*********************************************************************************
* Function : System_Init
* Description : Initialize the system clock
* Input : none
* Outpu : none
* Author : Chris_Kyle Date : 2021
**********************************************************************************/
void System_Init(void)
{
SCU->RCR |= SCU_RCR_REMAP_EN;
System_Set_Buzzer_Divider(80, FUNC_DISABLE); // disable clock out
/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
/* Vector Table Relocation in Internal SRAM */
SCU->VECTOROFFSET = SRAM_BASE | VECT_TAB_OFFSET | SCU_VECTOROFFSET_VOFFSETEN;
#else
/* Vector Table Relocation in Internal FLASH */
SCU->VECTOROFFSET = EFLASH_BASE | VECT_TAB_OFFSET | SCU_VECTOROFFSET_VOFFSETEN;
#endif
/* Initialize the system clock */
if (false == System_Clock_Init(DEFAULT_SYSTEM_CLOCK))
{
while(1);
}
#ifdef HAL_SYSTICK_ENABLED // To activate macro in ACM32Fxx_HAL.h
System_SysTick_Init();
#endif
}
/*********************************************************************************
* Function : System_Clock_Init
* Description : Clock init
* Input : fu32_Clock: System core clock
* Outpu : 0: success, other value: fail reason
* Author : xwl Date : 2021
**********************************************************************************/
bool System_Clock_Init(uint32_t fu32_Clock)
{
uint32_t lu32_DIV, lu32_system_clk_source, lu32_result, lu32_timeout;
lu32_system_clk_source = CLK_SRC_RC64M;
SET_EFC_RD_WAIT(RD_WAIT_SET_DEFAULT)
switch (fu32_Clock)
{
/* 64MHz */
case 64000000: lu32_DIV = 1; break;
/* 32MHz */
case 32000000: lu32_DIV = 2; break;
/* 16MHz */
case 16000000: lu32_DIV = 4; break;
/* 8MHz */
case 8000000: lu32_DIV = 8; break;
default: return false;
}
lu32_result = 0;
if (lu32_system_clk_source == CLK_SRC_XTH_PLL)
{
lu32_timeout = 0;
SCU->XTHCR = SCU_XTHCR_XTH_EN | SCU_XTHCR_READYTIME_32768;
while (0 == (SCU->XTHCR & SCU_XTHCR_XTHRDY))
{
if (lu32_timeout == SYSTEM_TIMEOUT)
{
lu32_result = 1;
break;
}
lu32_timeout++;
}
if (0 == lu32_result)
{
SCU->PLLCR |= SCU_PLLCR_PLL_EN;
SCU->PLLCR &= ~(SCU_PLLCR_PLL_SLEEP);
while(!(SCU->PLLCR & (SCU_PLLCR_PLL_FREE_RUN) )) {}
#ifdef XTH_8M_CRYSTAL
SCU->PLLCR = (SCU->PLLCR &(~(0x1FFFFU << 3))) | (15U << 3) | (1U << 12) | (0U << 16);
#endif
#ifdef XTH_12M_CRYSTAL
SCU->PLLCR = (SCU->PLLCR &(~(0x1FFFFU << 3))) | (15U << 3) | (2U << 12) | (0U << 16);
#endif
SCU->PLLCR = (SCU->PLLCR & (~(0x3U << 1)) ) | (3 << 1);
SCU->PLLCR |= SCU_PLLCR_PLL_UPDATE_EN;
while(!(SCU->PLLCR & (SCU_PLLCR_PLL_FREE_RUN) ) );
/* Division Config */
SCU->CCR2 = (SCU->CCR2 & (~0xFF)) | APB_CLK_DIV_0 | (lu32_DIV - 1);
while((SCU->CCR2 & (1UL << 31)) == 0x00);
/* Clock Select PLL */
SCU->CCR1 = SYS_CLK_SRC_PLLCLK;
}
else
{
SCU->XTHCR &= (~SCU_XTHCR_XTH_EN);
}
}
if ( (lu32_system_clk_source == CLK_SRC_RC64M) || (0 != lu32_result) )
{
/* Division Config */
SCU->CCR2 = (SCU->CCR2 & (~0xFF)) | APB_CLK_DIV_0 | (lu32_DIV - 1);
while((SCU->CCR2 & (1UL << 31)) == 0x00);
/* Clock Select RCH */
SCU->CCR1 = SYS_CLK_SRC_RCH;
}
gu32_SystemClock = fu32_Clock;
gu32_APBClock = fu32_Clock;
/* Eflash Config */
//HAL_EFlash_Init(gu32_SystemClock);
return true;
}
/*********************************************************************************
* Function : System_Get_SystemClock
* Description : get AHB clock frequency
* Input : none
* Outpu : frequency, measured as Hz
* Author : Chris_Kyle Date : 2020
**********************************************************************************/
uint32_t System_Get_SystemClock(void)
{
return gu32_SystemClock;
}
/*********************************************************************************
* Function : System_Get_APBClock
* Description : get APB clock frequency
* Input : none
* Outpu : frequency, measured as Hz
* Author : Chris_Kyle Date : 2021
**********************************************************************************/
uint32_t System_Get_APBClock(void)
{
return gu32_APBClock;
}
/*********************************************************************************
* Function : System_Module_Reset
* Description : reset module
* Input : module id
* Outpu : none
* Author : Chris_Kyle Date : 2021
**********************************************************************************/
void System_Module_Reset(enum_RST_ID_t fe_ID_Index)
{
SCU->IPRST &= (~(1 << fe_ID_Index));
System_Delay(2);
SCU->IPRST |= (1 << fe_ID_Index);
}
/*********************************************************************************
* Function : System_Module_Enable
* Description : enable module clock
* Input : module id
* Outpu : none
* Author : Chris_Kyle Date : 2021
**********************************************************************************/
void System_Module_Enable(enum_Enable_ID_t fe_ID_Index)
{
if (fe_ID_Index > 6)
{
SCU->IPCKENR1 |= (1U << (fe_ID_Index - 7) );
}
else
{
SCU->IPCKENR2 |= (1U << fe_ID_Index);
}
System_Delay(2);
}
/*********************************************************************************
* Function : System_Module_Disable
* Description : disable module clock
* Input : module id
* Outpu : none
* Author : Chris_Kyle Date : 2021
**********************************************************************************/
void System_Module_Disable(enum_Enable_ID_t fe_ID_Index)
{
if (fe_ID_Index > 6)
{
SCU->IPCKENR1 &= ~(1U << (fe_ID_Index - 7));
}
else
{
SCU->IPCKENR2 &= ~(1U << fe_ID_Index);
}
}
/*********************************************************************************
* Function : System_Delay
* Description : NOP delay
* Input : count
* Output : none
* Author : Chris_Kyle
**********************************************************************************/
void System_Delay(volatile uint32_t fu32_Delay)
{
while (fu32_Delay--);
}
/*********************************************************************************
* Function : System_Delay_MS
* Description : ms delay. Use this Function must call System_SysTick_Init()
* Input : delay period, measured as ms
* Output : none
* Author : Chris_Kyle
**********************************************************************************/
void System_Delay_MS(volatile uint32_t fu32_Delay)
{
uint32_t lu32_SystemCountBackup;
lu32_SystemCountBackup = gu32_SystemCount;
while ( (gu32_SystemCount - lu32_SystemCountBackup) < fu32_Delay);
}
/*********************************************************************************
* Function : System_Enable_RC32K
* Description : Enable RC32K, make sure RTC Domain Access is allowed
* Input : none
* Outpu : none
* Author : Chris_Kyle Date : 2021
**********************************************************************************/
void System_Enable_RC32K(void)
{
PMU->ANACR |= RPMU_ANACR_RC32K_EN;
while(!(PMU->ANACR & RPMU_ANACR_RC32K_RDY));
}
/*********************************************************************************
* Function : System_Disable_RC32K
* Description : Disable RC32K
* Input : none
* Outpu : none
* Author : CWT Date : 2021
**********************************************************************************/
void System_Disable_RC32K(void)
{
PMU->ANACR &= (~RPMU_ANACR_RC32K_EN);
}
/*********************************************************************************
* Function : System_Enable_XTAL
* Description : Enable XTAL, make sure RTC Domain Access is allowed
* Input : none
* Outpu : none
* Author : Chris_Kyle Date : 2021
**********************************************************************************/
void System_Enable_XTAL(void)
{
PMU->ANACR = (PMU->ANACR & ~RPMU_ANACR_XTLDRV) | (RPMU_ANACR_XTLDRV_1 | RPMU_ANACR_XTLDRV_0);
PMU->ANACR |= RPMU_ANACR_XTLEN;
while(!(PMU->ANACR & RPMU_ANACR_XTLRDY));
PMU->CR1 |= RTC_CLOCK_XTL;
}
/*********************************************************************************
* Function : System_Disable_XTAL
* Description : Disable XTAL
* Input : none
* Output : none
* Author : CWT
**********************************************************************************/
void System_Disable_XTAL(void)
{
PMU->ANACR &= (~(RPMU_ANACR_XTLEN));
}
/*********************************************************************************
* Function : System_Enable_Disable_RTC_Domain_Access
* Description : Enable or Disable RTC Domain Access.
* Input : enable or disable
* Output : none
* Author : CWT
**********************************************************************************/
void System_Enable_Disable_RTC_Domain_Access(FUNC_DISABLE_ENABLE enable_disable)
{
if (FUNC_DISABLE == enable_disable)
{
SCU->STOPCFG &= (~SCU_STOPCFG_RTC_WE);
}
else
{
SCU->STOPCFG |= SCU_STOPCFG_RTC_WE;
System_Delay(1);
RTC->WP = 0xCA53CA53U;
}
}
/*********************************************************************************
* Function : System_Enable_Disable_Reset
* Description : Enable or Disable System Reset source.
* Input : none
* Output : none
* Author : CWT
**********************************************************************************/
void System_Enable_Disable_Reset(RESET_ENABLE_SOURCE source, FUNC_DISABLE_ENABLE enable_disable)
{
switch(source)
{
/* reset source: from bit0 to bit3 */
case RESET_ENABLE_SOURCE_LVD:
case RESET_ENABLE_SOURCE_WDT:
case RESET_ENABLE_SOURCE_IWDT:
case RESET_ENABLE_SOURCE_LOCKUP:
if (FUNC_DISABLE == enable_disable)
{
SCU->RCR &= (~(1U << source));
}
else
{
SCU->RCR |= (1U << source);
}
break;
default: break;
}
}
/*********************************************************************************
* Function : System_Reset_MCU
* Description : reset mcu
* Input : reset source
* Output : none
* Author : xwl
**********************************************************************************/
void System_Reset_MCU(RESET_SOURCE source)
{
switch(source)
{
case RESET_SOURCE_EFC:
{
SCU->RCR &= (~BIT29);
while(1);
}
case RESET_SOURCE_NVIC_RESET:
{
NVIC_SystemReset();
while(1);
}
case RESET_SOFT_RESET:
{
SCU->RCR &= (~BIT30);
while(1);
}
default: break;
}
}
/*********************************************************************************
* Function : System_Enter_Standby_Mode
* Description : try to enter standby mode
* Input : none
* Output : none
* Author : xwl Date : 2021
**********************************************************************************/
void System_Enter_Standby_Mode(void)
{
__set_PRIMASK(1); // disable interrupt
SysTick->CTRL = 0; // disable systick
SCU->STOPCFG |= BIT11; // set PDDS=1
/* Set SLEEPDEEP bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
__WFI();
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
System_Delay(100);
printfS("Enter Standby Mode Failed! \n"); // should not go here
}
/*********************************************************************************
* Function : System_Clear_Stop_Wakeup
* Description : clear all stop setting and status
* Input : none
* Output : none
* Author : CWT Date : 2021
**********************************************************************************/
void System_Clear_Stop_Wakeup(void)
{
EXTI->IENR = 0;
EXTI->RTENR = 0;
EXTI->FTENR = 0;
EXTI->SWIER = 0;
EXTI->PDR = 0x7FFFFFU;
}
/*********************************************************************************
* Function : System_Enter_Stop_Mode
* Description : try to enter stop mode
* Input : STOPEntry: STOPENTRY_WFI or STOPENTRY_WFE
* Output : none
* Author : CWT Date : 2021
**********************************************************************************/
void System_Enter_Stop_Mode(uint8_t STOPEntry)
{
/* Set SLEEPDEEP bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
SCU->STOPCFG &= (~BIT11); // PDDS=0
System_SysTick_Off();
/* Select Stop mode entry */
if(STOPEntry == STOPENTRY_WFI)
{
/* Wait For Interrupt */
__WFI();
}
else
{
__SEV();
__WFE();
__WFE(); /* Wait For Event */
}
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
#ifdef HAL_SYSTICK_ENABLED // To activate macro in ACM32Fxx_HAL.h
System_SysTick_Init();
#endif
}
/*********************************************************************************
* Function : System_Enter_Sleep_Mode
* Description : try to enter sleep mode
* Input : SleepEntry: SLEEPENTRY_WFI or SLEEPENTRY_WFE
* Output : none
* Author : CWT Date : 2021
**********************************************************************************/
void System_Enter_Sleep_Mode(uint8_t SleepEntry)
{
/* clear SLEEPDEEP bit of Cortex System Control Register */
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
/* Select Stop mode entry */
if(SleepEntry == SLEEPENTRY_WFI)
{
/* Wait For Interrupt */
__WFI();
}
else
{
__SEV();
__WFE();
__WFE(); /*Wait For Event */
}
}
/*********************************************************************************
* Function : System_Return_Last_Reset_Reason
* Description : Get System Last Reset Reason
* Input : none
* Output : RESET_REASON
* Author : CWT Date : 2021
**********************************************************************************/
RESET_REASON System_Return_Last_Reset_Reason(void)
{
RESET_REASON i = RESET_REASON_POR;
Reset_Reason_Save = RESET_REASON_POR;
for(i = RESET_REASON_POR; i >= RESET_REASON_POR12; i--)
{
if ((SCU->RSR) & (1U << i))
{
SCU->RSR |= SCU_RSR_RSTFLAG_CLR; // clear reset reason flags
Reset_Reason_Save = i;
return i;
}
}
for(i = RESET_REASON_LOW_VOLTAGE; i <= RESET_REASON_SOFT; i++)
{
if ((SCU->RSR) & (1U << i))
{
SCU->RSR |= SCU_RSR_RSTFLAG_CLR; // clear reset reason flags
Reset_Reason_Save = i;
return i;
}
}
return RESET_REASON_INVALID; // this should not happen
}
/*********************************************************************************
* Function : System_Return_Saved_Reset_Reason
* Description : Get saved Reset Reason
* Input : none
* Output : RESET_REASON
* Author : CWT Date : 2021
**********************************************************************************/
RESET_REASON System_Return_Saved_Reset_Reason(void)
{
return Reset_Reason_Save;
}
/*********************************************************************************
* Function : System_Set_Buzzer_Divider
* Description : set buzzer divide factor
* Input :
div: div factor, if div = 80 then output buzzer freq=HCLK/80
enable: FUNC_DISABLE and FUNC_ENABLE
* Output : none
* Author : xwl Date : 2021
**********************************************************************************/
void System_Set_Buzzer_Divider(uint32_t div, FUNC_DISABLE_ENABLE enable)
{
if (FUNC_ENABLE == enable)
{
SCU->CLKOCR = (SCU->CLKOCR & (~(0x1FFFFU << 5) ) ) | (div << 5);
SCU->CLKOCR |= BIT23;
}
else
{
SCU->CLKOCR &= (~BIT23);
}
}