You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
421 lines
13 KiB
421 lines
13 KiB
/***************************************************************************** |
|
* Copyright (c) 2019, Nations Technologies Inc. |
|
* |
|
* All rights reserved. |
|
* **************************************************************************** |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are met: |
|
* |
|
* - Redistributions of source code must retain the above copyright notice, |
|
* this list of conditions and the disclaimer below. |
|
* |
|
* Nations' name may not be used to endorse or promote products derived from |
|
* this software without specific prior written permission. |
|
* |
|
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR |
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE |
|
* DISCLAIMED. IN NO EVENT SHALL NATIONS 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. |
|
* ****************************************************************************/ |
|
|
|
/** |
|
* @file system_n32g45x.c |
|
* @author Nations |
|
* @version v1.0.1 |
|
* |
|
* @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved. |
|
*/ |
|
#include "n32g45x.h" |
|
|
|
/* Uncomment the line corresponding to the desired System clock (SYSCLK) |
|
frequency (after reset the HSI is used as SYSCLK source) |
|
|
|
IMPORTANT NOTE: |
|
============== |
|
1. After each device reset the HSI is used as System clock source. |
|
|
|
2. Please make sure that the selected System clock doesn't exceed your |
|
device's maximum frequency. |
|
|
|
3. If none of the define below is enabled, the HSI is used as System clock |
|
source. |
|
|
|
4. The System clock configuration functions provided within this file assume |
|
that: |
|
- For Low, Medium and High density Value line devices an external 8MHz |
|
crystal is used to drive the System clock. |
|
- For Low, Medium and High density devices an external 8MHz crystal is |
|
used to drive the System clock. |
|
- For Connectivity line devices an external 25MHz crystal is used to |
|
drive the System clock. If you are using different crystal you have to adapt |
|
those functions accordingly. |
|
*/ |
|
|
|
#define SYSCLK_USE_HSI 0 |
|
#define SYSCLK_USE_HSE 1 |
|
#define SYSCLK_USE_HSI_PLL 2 |
|
#define SYSCLK_USE_HSE_PLL 3 |
|
|
|
#ifndef SYSCLK_FREQ |
|
#define SYSCLK_FREQ 144000000 |
|
#endif |
|
|
|
#ifndef SYSCLK_SRC |
|
#define SYSCLK_SRC SYSCLK_USE_HSE_PLL |
|
#endif |
|
|
|
#if SYSCLK_SRC == SYSCLK_USE_HSI |
|
|
|
#if SYSCLK_FREQ != HSI_VALUE |
|
#error SYSCL_FREQ must be set to HSI_VALUE |
|
#endif |
|
|
|
#elif SYSCLK_SRC == SYSCLK_USE_HSE |
|
|
|
#ifndef HSE_VALUE |
|
#error HSE_VALUE must be defined! |
|
#endif |
|
|
|
#if SYSCLK_FREQ != HSE_VALUE |
|
#error SYSCL_FREQ must be set to HSE_VALUE |
|
#endif |
|
|
|
#elif SYSCLK_SRC == SYSCLK_USE_HSI_PLL |
|
|
|
#if (SYSCLK_FREQ % (HSI_VALUE / 2) == 0) && (SYSCLK_FREQ / (HSI_VALUE / 2) >= 2) \ |
|
&& (SYSCLK_FREQ / (HSI_VALUE / 2) <= 32) |
|
|
|
#define PLLSRC_DIV 2 |
|
#define PLL_MUL (SYSCLK_FREQ / (HSI_VALUE / 2)) |
|
|
|
#else |
|
#error Cannot make a PLL multiply factor to SYSCLK_FREQ. |
|
#endif |
|
|
|
#elif SYSCLK_SRC == SYSCLK_USE_HSE_PLL |
|
|
|
#ifndef HSE_VALUE |
|
#error HSE_VALUE must be defined! |
|
#endif |
|
|
|
#if ((SYSCLK_FREQ % (HSE_VALUE / 2)) == 0) && (SYSCLK_FREQ / (HSE_VALUE / 2) >= 2) \ |
|
&& (SYSCLK_FREQ / (HSE_VALUE / 2) <= 32) |
|
|
|
#define PLLSRC_DIV 2 |
|
#define PLL_MUL (SYSCLK_FREQ / (HSE_VALUE / 2)) |
|
|
|
#elif (SYSCLK_FREQ % HSE_VALUE == 0) && (SYSCLK_FREQ / HSE_VALUE >= 2) && (SYSCLK_FREQ / HSE_VALUE <= 32) |
|
|
|
#define PLLSRC_DIV 1 |
|
#define PLL_MUL (SYSCLK_FREQ / HSE_VALUE) |
|
|
|
#else |
|
#error Cannot make a PLL multiply factor to SYSCLK_FREQ. |
|
#endif |
|
|
|
#else |
|
#error wrong value for SYSCLK_SRC |
|
#endif |
|
|
|
/* #define VECT_TAB_SRAM */ |
|
#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */ |
|
|
|
/******************************************************************************* |
|
* Clock Definitions |
|
*******************************************************************************/ |
|
uint32_t SystemCoreClock = SYSCLK_FREQ; /*!< System Clock Frequency (Core Clock) */ |
|
|
|
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; |
|
|
|
static void SetSysClock(void); |
|
|
|
#ifdef DATA_IN_ExtSRAM |
|
static void SystemInit_ExtMemCtl(void); |
|
#endif /* DATA_IN_ExtSRAM */ |
|
|
|
/** |
|
* @brief Setup the microcontroller system |
|
* Initialize the Embedded Flash Interface, the PLL and update the |
|
* SystemCoreClock variable. |
|
* @note This function should be used only after reset. |
|
*/ |
|
void SystemInit(void) |
|
{ |
|
/* FPU settings |
|
* ------------------------------------------------------------*/ |
|
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1) |
|
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */ |
|
#endif |
|
|
|
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */ |
|
/* Set HSIEN bit */ |
|
RCC->CTRL |= (uint32_t)0x00000001; |
|
|
|
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */ |
|
RCC->CFG &= (uint32_t)0xF8FFC000; |
|
|
|
/* Reset HSEON, CLKSSEN and PLLEN bits */ |
|
RCC->CTRL &= (uint32_t)0xFEF6FFFF; |
|
|
|
/* Reset HSEBYP bit */ |
|
RCC->CTRL &= (uint32_t)0xFFFBFFFF; |
|
|
|
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRES/OTGFSPRE bits */ |
|
RCC->CFG &= (uint32_t)0xF700FFFF; |
|
|
|
/* Reset CFG2 register */ |
|
RCC->CFG2 = 0x00000000; |
|
|
|
/* Reset CFG3 register */ |
|
RCC->CFG3 = 0x00000000; |
|
|
|
/* Disable all interrupts and clear pending bits */ |
|
RCC->CLKINT = 0x009F0000; |
|
|
|
/* Enable ex mode */ |
|
RCC->APB1PCLKEN |= RCC_APB1PCLKEN_PWREN; |
|
PWR->CTRL3 |= 0x00000001; |
|
RCC->APB1PCLKEN &= (uint32_t)(~RCC_APB1PCLKEN_PWREN); |
|
|
|
/* Enable ICACHE and Prefetch Buffer */ |
|
FLASH->AC |= (uint32_t)(FLASH_AC_ICAHEN | FLASH_AC_PRFTBFEN); |
|
|
|
#ifdef DATA_IN_ExtSRAM |
|
SystemInit_ExtMemCtl(); |
|
#endif /* DATA_IN_ExtSRAM */ |
|
|
|
/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */ |
|
/* Configure the Flash Latency cycles and enable prefetch buffer */ |
|
SetSysClock(); |
|
|
|
#ifdef VECT_TAB_SRAM |
|
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ |
|
#else |
|
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ |
|
#endif |
|
} |
|
|
|
/** |
|
* @brief Update SystemCoreClock variable according to Clock Register Values. |
|
* The SystemCoreClock variable contains the core clock (HCLK), it can |
|
* be used by the user application to setup the SysTick timer or |
|
* configure other parameters. |
|
* |
|
* @note Each time the core clock (HCLK) changes, this function must be called |
|
* to update SystemCoreClock variable value. Otherwise, any |
|
* configuration based on this variable will be incorrect. |
|
* |
|
* @note - The system frequency computed by this function is not the real |
|
* frequency in the chip. It is calculated based on the predefined |
|
* constant and the selected clock source: |
|
* |
|
* - If SYSCLK source is HSI, SystemCoreClock will contain the |
|
* HSI_VALUE(*) |
|
* |
|
* - If SYSCLK source is HSE, SystemCoreClock will contain the |
|
* HSE_VALUE(**) |
|
* |
|
* - If SYSCLK source is PLL, SystemCoreClock will contain the |
|
* HSE_VALUE(**) or HSI_VALUE(*) multiplied by the PLL factors. |
|
* |
|
* (*) HSI_VALUE is a constant defined in n32g45x.h file (default value |
|
* 8 MHz) but the real value may vary depending on the variations |
|
* in voltage and temperature. |
|
* |
|
* (**) HSE_VALUE is a constant defined in N32G45X.h file (default value |
|
* 8 MHz or 25 MHz, depedning on the product used), user has to |
|
* ensure that HSE_VALUE is same as the real frequency of the crystal used. |
|
* Otherwise, this function may have wrong result. |
|
* |
|
* - The result of this function could be not correct when using |
|
* fractional value for HSE crystal. |
|
*/ |
|
void SystemCoreClockUpdate(void) |
|
{ |
|
uint32_t tmp = 0, pllmull = 0, pllsource = 0; |
|
|
|
/* Get SYSCLK source |
|
* -------------------------------------------------------*/ |
|
tmp = RCC->CFG & RCC_CFG_SCLKSTS; |
|
|
|
switch (tmp) |
|
{ |
|
case 0x00: /* HSI used as system clock */ |
|
SystemCoreClock = HSI_VALUE; |
|
break; |
|
case 0x04: /* HSE used as system clock */ |
|
SystemCoreClock = HSE_VALUE; |
|
break; |
|
case 0x08: /* PLL used as system clock */ |
|
|
|
/* Get PLL clock source and multiplication factor |
|
* ----------------------*/ |
|
pllmull = RCC->CFG & RCC_CFG_PLLMULFCT; |
|
pllsource = RCC->CFG & RCC_CFG_PLLSRC; |
|
|
|
if ((pllmull & RCC_CFG_PLLMULFCT_4) == 0) |
|
{ |
|
pllmull = (pllmull >> 18) + 2; // PLLMUL[4]=0 |
|
} |
|
else |
|
{ |
|
pllmull = ((pllmull >> 18) - 496) + 1; // PLLMUL[4]=1 |
|
} |
|
|
|
if (pllsource == 0x00) |
|
{ |
|
/* HSI oscillator clock divided by 2 selected as PLL clock entry */ |
|
SystemCoreClock = (HSI_VALUE >> 1) * pllmull; |
|
} |
|
else |
|
{ |
|
/* HSE selected as PLL clock entry */ |
|
if ((RCC->CFG & RCC_CFG_PLLHSEPRES) != (uint32_t)RESET) |
|
{ /* HSE oscillator clock divided by 2 */ |
|
SystemCoreClock = (HSE_VALUE >> 1) * pllmull; |
|
} |
|
else |
|
{ |
|
SystemCoreClock = HSE_VALUE * pllmull; |
|
} |
|
} |
|
|
|
break; |
|
|
|
default: |
|
SystemCoreClock = HSI_VALUE; |
|
break; |
|
} |
|
|
|
/* Compute HCLK clock frequency ----------------*/ |
|
/* Get HCLK prescaler */ |
|
tmp = AHBPrescTable[((RCC->CFG & RCC_CFG_AHBPRES) >> 4)]; |
|
/* HCLK clock frequency */ |
|
SystemCoreClock >>= tmp; |
|
} |
|
|
|
/** |
|
* @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 |
|
* prescalers. |
|
*/ |
|
static void SetSysClock(void) |
|
{ |
|
uint32_t rcc_cfgr = 0; |
|
bool HSEStatus = 0; |
|
uint32_t StartUpCounter = 0; |
|
|
|
#if SYSCLK_SRC == SYSCLK_USE_HSE || SYSCLK_SRC == SYSCLK_USE_HSE_PLL |
|
|
|
/* Enable HSE */ |
|
RCC->CTRL |= ((uint32_t)RCC_CTRL_HSEEN); |
|
|
|
/* Wait till HSE is ready and if Time out is reached exit */ |
|
do |
|
{ |
|
HSEStatus = RCC->CTRL & RCC_CTRL_HSERDF; |
|
StartUpCounter++; |
|
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); |
|
|
|
HSEStatus = ((RCC->CTRL & RCC_CTRL_HSERDF) != RESET); |
|
if (!HSEStatus) |
|
{ |
|
/* If HSE fails to start-up, the application will have wrong clock |
|
* configuration. User can add here some code to deal with this error */ |
|
SystemCoreClock = HSI_VALUE; |
|
return; |
|
} |
|
#endif |
|
|
|
/* Flash wait state |
|
0: HCLK <= 32M |
|
1: HCLK <= 64M |
|
2: HCLK <= 96M |
|
3: HCLK <= 128M |
|
4: HCLK <= 144M |
|
*/ |
|
FLASH->AC &= (uint32_t)((uint32_t)~FLASH_AC_LATENCY); |
|
FLASH->AC |= (uint32_t)((SYSCLK_FREQ - 1) / 32000000); |
|
|
|
/* HCLK = SYSCLK */ |
|
RCC->CFG |= (uint32_t)RCC_CFG_AHBPRES_DIV1; |
|
|
|
/* PCLK2 max 72M */ |
|
if (SYSCLK_FREQ > 72000000) |
|
{ |
|
RCC->CFG |= (uint32_t)RCC_CFG_APB2PRES_DIV2; |
|
} |
|
else |
|
{ |
|
RCC->CFG |= (uint32_t)RCC_CFG_APB2PRES_DIV1; |
|
} |
|
|
|
/* PCLK1 max 36M */ |
|
if (SYSCLK_FREQ > 72000000) |
|
{ |
|
RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV4; |
|
} |
|
else if (SYSCLK_FREQ > 36000000) |
|
{ |
|
RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV2; |
|
} |
|
else |
|
{ |
|
RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV1; |
|
} |
|
|
|
#if SYSCLK_SRC == SYSCLK_USE_HSE |
|
/* Select HSE as system clock source */ |
|
RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_SCLKSW)); |
|
RCC->CFG |= (uint32_t)RCC_CFG_SCLKSW_HSE; |
|
|
|
/* Wait till HSE is used as system clock source */ |
|
while ((RCC->CFG & (uint32_t)RCC_CFG_SCLKSTS) != (uint32_t)0x04) |
|
{ |
|
} |
|
#elif SYSCLK_SRC == SYSCLK_USE_HSI_PLL || SYSCLK_SRC == SYSCLK_USE_HSE_PLL |
|
|
|
/* clear bits */ |
|
RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_PLLSRC | RCC_CFG_PLLHSEPRES | RCC_CFG_PLLMULFCT)); |
|
|
|
/* set PLL source */ |
|
rcc_cfgr = RCC->CFG; |
|
rcc_cfgr |= (SYSCLK_SRC == SYSCLK_USE_HSI_PLL ? RCC_CFG_PLLSRC_HSI_DIV2 : RCC_CFG_PLLSRC_HSE); |
|
|
|
#if SYSCLK_SRC == SYSCLK_USE_HSE_PLL |
|
rcc_cfgr |= (PLLSRC_DIV == 1 ? RCC_CFG_PLLHSEPRES_HSE : RCC_CFG_PLLHSEPRES_HSE_DIV2); |
|
#endif |
|
|
|
/* set PLL multiply factor */ |
|
#if PLL_MUL <= 16 |
|
rcc_cfgr |= (PLL_MUL - 2) << 18; |
|
#else |
|
rcc_cfgr |= ((PLL_MUL - 17) << 18) | (1 << 27); |
|
#endif |
|
|
|
RCC->CFG = rcc_cfgr; |
|
|
|
/* Enable PLL */ |
|
RCC->CTRL |= RCC_CTRL_PLLEN; |
|
|
|
/* Wait till PLL is ready */ |
|
while ((RCC->CTRL & RCC_CTRL_PLLRDF) == 0) |
|
{ |
|
} |
|
|
|
/* Select PLL as system clock source */ |
|
RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_SCLKSW)); |
|
RCC->CFG |= (uint32_t)RCC_CFG_SCLKSW_PLL; |
|
|
|
/* Wait till PLL is used as system clock source */ |
|
while ((RCC->CFG & (uint32_t)RCC_CFG_SCLKSTS) != (uint32_t)0x08) |
|
{ |
|
} |
|
#endif |
|
}
|
|
|