/* ****************************************************************************** * @file system_fr30xx.c * @author FreqChip Firmware Team * @version V1.0.0 * @date 2021 * @brief Device Peripheral Access Layer System Source File. ****************************************************************************** * @attention * * Copyright (c) 2021 FreqChip. * All rights reserved. * ****************************************************************************** */ #include "fr30xx.h" static uint32_t System_CORE_HSCLK = 24000000; static uint32_t System_SPLLCLK; static uint32_t System_AUPLLCLK; uint32_t SystemCoreClock = 24000000; static uint32_t SystemDSPClock = 24000000; static uint32_t System_LPRCCLK = 57000; static uint32_t system_prevent_sleep_label = SYSTEM_PREVENT_SLEEP_TYPE_DISABLE; /********************************************************************* * @fn SystemInit * * @brief System Misc Init. */ 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 /* free counter enable */ __SYSTEM_FREE_COUNTER_CLK_ENABLE(); } /********************************************************************* * @fn System_CORE_HSCLK_CFG * * @brief CORE HSCLK config. */ void System_CORE_HSCLK_config(System_CORE_HSCLKConfig_t *COREHConfig) { if (COREHConfig->CORE_HSCLK_Source == CORE_HSCLK_SEL_HES) { __SYSTEM_CORE_HIGH_CLK_SELECT_OSC(); System_CORE_HSCLK = HSE_VALUE; } else { __SYSTEM_CORE_HIGH_CLK_SELECT_RC(); System_CORE_HSCLK = HSI_VALUE; } } /********************************************************************* * @fn System_SPLL_config * * @brief SPLL config. * * @param PLLConfig : SPLL config parameter. * @param fu32_timeout : Wait for SPLL stable timeout, unit 5us. * * @return -1: SPLL stable timeout. * 0: succeed. */ int System_SPLL_config(System_PLLConfig_t *PLLConfig, uint32_t fu32_timeout) { int PLL_stability_flag = 0; #define SPLL_ANALOG_POWER_ENABLE (0XC04B1820) #define SPLL_ANALOG_POWER_DISABLE (0XC04B1827) #define SPLL_ANALOG_POWER_ENABLE_WITHOUT_M (0X404B1820) if (PLLConfig->PowerEn) { SYSTEM->SPLLConfig3.PLL_N = PLLConfig->PLL_N; SYSTEM->SPLLConfig3.PLL_M = PLLConfig->PLL_M; if (PLLConfig->PLL_M) SYSTEM->SPLLConfig0 = SPLL_ANALOG_POWER_ENABLE; else SYSTEM->SPLLConfig0 = SPLL_ANALOG_POWER_ENABLE_WITHOUT_M; /* Wait for PLL stability timeout, unit 5us */ for (int i = 0; i < fu32_timeout; i++) { system_delay_us(5); if (SYSTEM->SPLLConfig1 & 0x08) { PLL_stability_flag = 1; break; } } if (PLL_stability_flag) { __SYSTEM_SPLL_CLK_DIV2_ENABLE(); System_SPLLCLK = (PLLConfig->PLL_N*HSE_VALUE) + ((double)PLLConfig->PLL_M*HSE_VALUE)/0xFFFF; } else { System_SPLLCLK = 0; return -1; } } else { SYSTEM->SPLLConfig0 = SPLL_ANALOG_POWER_DISABLE; System_SPLLCLK = 0; } return 0; } /********************************************************************* * @fn System_AUPLL_config * * @brief AUPLL config. * * @param PLLConfig : AUPLL config parameter. * @param fu32_timeout : Wait for AUPLL stable timeout, unit 5us. * * @return -1: AUPLL stable timeout. * 0: succeed. */ int System_AUPLL_config(System_PLLConfig_t *PLLConfig, uint32_t fu32_timeout) { int PLL_stability_flag = 0; #define AUPLL_ANALOG_POWER_ENABLE (0XC04B1820) #define AUPLL_ANALOG_POWER_DISABLE (0XC04B1827) #define AUPLL_ANALOG_POWER_ENABLE_WITHOUT_M (0X404B1820) if (PLLConfig->PowerEn) { SYSTEM->AUPLLConfig3.PLL_N = PLLConfig->PLL_N; SYSTEM->AUPLLConfig3.PLL_M = PLLConfig->PLL_M; if (PLLConfig->PLL_M) SYSTEM->AUPLLConfig0 = AUPLL_ANALOG_POWER_ENABLE; else SYSTEM->AUPLLConfig0 = AUPLL_ANALOG_POWER_ENABLE_WITHOUT_M; /* Wait for PLL stability timeout, unit 5us */ for (int i = 0; i < fu32_timeout; i++) { system_delay_us(5); if (SYSTEM->AUPLLConfig1 & 0x08) { PLL_stability_flag = 1; break; } } if (PLL_stability_flag) { System_AUPLLCLK = (PLLConfig->PLL_N*HSE_VALUE) + ((double)PLLConfig->PLL_M*HSE_VALUE)/0xFFFF; } else { System_SPLLCLK = 0; return -1; } } else { SYSTEM->AUPLLConfig0 = AUPLL_ANALOG_POWER_DISABLE; System_AUPLLCLK = 0; } return 0; } /********************************************************************* * @fn System_MCU_clock_Config * * @brief MCU clock congfig. */ void System_MCU_clock_Config(System_ClkConfig_t *ClkConfig) { /* MCU clock source select CORE_HSCLK */ if (ClkConfig->MCU_Clock_Source == MCU_CLK_SEL_CORE_HSCLK) { __SYSTEM_MCU_CLK_DIV(ClkConfig->MCU_DIV); __SYSTEM_MCU_CLK_SELECT_COREH(); SystemDSPClock = System_CORE_HSCLK; SystemCoreClock = System_CORE_HSCLK / ClkConfig->MCU_DIV; } /* MCU clock source select SPLLCLK */ else { __SYSTEM_SOC_CLK_DIV(ClkConfig->SOC_DIV); __SYSTEM_MCU_CLK_DIV(ClkConfig->MCU_DIV); __SYSTEM_MCU_CLK_SELECT_SPLL(); SystemDSPClock = System_SPLLCLK / ClkConfig->SOC_DIV; SystemCoreClock = SystemDSPClock / ClkConfig->MCU_DIV; } __SYSTEM_APB0_CLK_RATIO(ClkConfig->APB0_DIV); __SYSTEM_APB1_CLK_RATIO(ClkConfig->APB1_DIV); __SYSTEM_APB2_CLK_RATIO(ClkConfig->APB2_DIV); __SYSTEM_APB3_CLK_RATIO(ClkConfig->APB3_DIV); } /********************************************************************* * @fn System_get_CoreClock/ * System_get_DSPClock/ * System_get_CORE_HSCLK/ * System_get_SPLLCLK/ * System_get_AUPLLCLK/ * * @brief get system clock.unit HZ. */ __RAM_CODE uint32_t system_get_CoreClock(void) { return SystemCoreClock; } uint32_t system_get_DSPClock(void) { return SystemDSPClock; } uint32_t system_get_CORE_HSCLK(void) { return System_CORE_HSCLK; } uint32_t system_get_SPLLCLK(void) { return System_SPLLCLK; } uint32_t system_get_AUPLLCLK(void) { return System_AUPLLCLK; } uint32_t system_get_LPRCCLK(void) { return System_LPRCCLK; } void system_set_LPRCCLK(uint32_t clk) { System_LPRCCLK = clk; } /********************************************************************* * @fn system_get_peripheral_clock * * @brief get peripheral clock. unit HZ * * @param fe_peripheral : peripheral select. * * @return peripheral clock unit HZ. */ uint32_t system_get_peripheral_clock(per_clock_index_t peripheral) { uint32_t PerClock; switch (peripheral) { case PER_CLK_UARTx: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.UART_CLK_SEL) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV1.UART_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV1.UART_CLK_DIV + 1); }break; case PER_CLK_GPIOx: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.GPIO_CLK_SEL) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV1.GPIO_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV1.GPIO_CLK_DIV + 1); }break; case PER_CLK_I2Cx: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.I2C_CLK_SEL) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV1.I2C_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV1.I2C_CLK_DIV + 1); }break; case PER_CLK_TIMER01:{ PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV2.TIMER01_CLK_DIV + 1); }break; case PER_CLK_TIMER23:{ PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV2.TIMER23_CLK_DIV + 1); }break; case PER_CLK_SPIS: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.SSIS_CLK_SEL) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV0.SSIS_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV0.SSIS_CLK_DIV + 1); }break; case PER_CLK_SPIMX8_0: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.SSIS_CLK_SEL) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV0.MSPI0_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV0.MSPI0_CLK_DIV + 1); }break; case PER_CLK_SPIMX8_1: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.SSIS_CLK_SEL) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV0.MSPI1_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV0.MSPI1_CLK_DIV + 1); }break; case PER_CLK_PWM: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.SSIS_CLK_SEL) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV2.PWM_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV2.PWM_CLK_DIV + 1); }break; case PER_CLK_PDM0: case PER_CLK_PDM1: case PER_CLK_PDM2: { uint32_t PDMx_CLK_SEL, PDMx_CLK_DIV; if (peripheral == PER_CLK_PDM0) { PDMx_CLK_SEL = SYSTEM->ClockSEL1.PDM0_CLK_SEL; PDMx_CLK_DIV = SYSTEM->AudioClockDIV.PDM0_CLK_DIV; } else if (peripheral == PER_CLK_PDM1){ PDMx_CLK_SEL = SYSTEM->ClockSEL1.PDM1_CLK_SEL; PDMx_CLK_DIV = SYSTEM->AudioClockDIV.PDM1_CLK_DIV; } else{ PDMx_CLK_SEL = SYSTEM->ClockSEL1.PDM2_CLK_SEL; PDMx_CLK_DIV = SYSTEM->AudioClockDIV.PDM2_CLK_DIV; } /* clock from HCLK */ if (PDMx_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (PDMx_CLK_DIV + 1); /* clock from AUPLL */ else if (PDMx_CLK_SEL == 1) PerClock = system_get_AUPLLCLK() / (PDMx_CLK_DIV + 1); }break; case PER_CLK_SDIOH0: { /* clock from HCLK */ if (SYSTEM->ClockSEL0.SDIOH0_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV0.SDIOH0_CLK_DIV + 1); /* clock from SPLL */ else if (SYSTEM->ClockSEL0.SDIOH0_CLK_SEL == 1) PerClock = system_get_SPLLCLK() / (SYSTEM->BlockClockDIV0.SDIOH0_CLK_DIV + 1); /* clock from AUPLL */ else PerClock = system_get_AUPLLCLK() / (SYSTEM->BlockClockDIV0.SDIOH0_CLK_DIV + 1); }break; case PER_CLK_SDIOH1: { /* clock from HCLK */ if (SYSTEM->ClockSEL0.SDIOH1_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV0.SDIOH1_CLK_DIV + 1); /* clock from SPLL */ else if (SYSTEM->ClockSEL0.SDIOH1_CLK_SEL == 1) PerClock = system_get_SPLLCLK() / (SYSTEM->BlockClockDIV0.SDIOH1_CLK_DIV + 1); /* clock from AUPLL */ else PerClock = system_get_AUPLLCLK() / (SYSTEM->BlockClockDIV0.SDIOH1_CLK_DIV + 1); }break; case PER_CLK_CANx: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.MCAN_CLK_SEL) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV2.MCAN_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV2.MCAN_CLK_DIV + 1); }break; case PER_CLK_I2Sx: { /* clock from SPLL */ if (SYSTEM->ClockSEL1.I2S_CLK_SEL == 2) PerClock = (system_get_AUPLLCLK()) / (SYSTEM->AudioClockDIV.I2S_CLK_DIV + 1); else if (SYSTEM->ClockSEL1.I2S_CLK_SEL == 1) PerClock = (system_get_SPLLCLK()) / (SYSTEM->AudioClockDIV.I2S_CLK_DIV + 1); else if (SYSTEM->ClockSEL1.I2S_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (SYSTEM->AudioClockDIV.I2S_CLK_DIV + 1); }break; case PER_CLK_OSPI: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.OSPI_CLK_SEL == 2) PerClock = (system_get_AUPLLCLK()) / (SYSTEM->BlockClockDIV0.OSPI_CLK_DIV + 1); else if(SYSTEM->ClockSEL0.OSPI_CLK_SEL == 1) PerClock = system_get_SPLLCLK() / (SYSTEM->BlockClockDIV0.OSPI_CLK_DIV + 1); else if(SYSTEM->ClockSEL0.OSPI_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV0.OSPI_CLK_DIV + 1); }break; case PER_CLK_QSPI0: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.QSPI0_CLK_SEL == 2) PerClock = (system_get_AUPLLCLK()) / (SYSTEM->BlockClockDIV0.QSPI0_CLK_DIV + 1); else if(SYSTEM->ClockSEL0.QSPI0_CLK_SEL == 1) PerClock = system_get_SPLLCLK() / (SYSTEM->BlockClockDIV0.QSPI0_CLK_DIV + 1); else if(SYSTEM->ClockSEL0.QSPI0_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV0.QSPI0_CLK_DIV + 1); }break; case PER_CLK_QSPI1: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.QSPI1_CLK_SEL == 2) PerClock = (system_get_AUPLLCLK()) / (SYSTEM->BlockClockDIV0.QSPI1_CLK_DIV + 1); else if(SYSTEM->ClockSEL0.QSPI1_CLK_SEL == 1) PerClock = system_get_SPLLCLK() / (SYSTEM->BlockClockDIV0.QSPI1_CLK_DIV + 1); else if(SYSTEM->ClockSEL0.QSPI1_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV0.QSPI1_CLK_DIV + 1); }break; case PER_CLK_SPIMx: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.SSIM_CLK_SEL == 1) PerClock = system_get_SPLLCLK() / (SYSTEM->BlockClockDIV1.SSIM_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV1.SSIM_CLK_DIV + 1); }break; case PER_CLK_SBC: { /* clock from SPLL */ if (SYSTEM->ClockSEL1.SBC_CLK_SEL == 1) PerClock = system_get_SPLLCLK() / (SYSTEM->AudioClockDIV.SBC_CLK_DIV + 1); else PerClock = system_get_CORE_HSCLK() / (SYSTEM->AudioClockDIV.SBC_CLK_DIV + 1); }break; case PER_CLK_PARALLEL: { /* clock from SPLL */ if (SYSTEM->ClockSEL0.PARALLEL_CLK_SEL == 2) PerClock = (system_get_AUPLLCLK()/2) / (SYSTEM->BlockClockDIV1.PARALLEL_CLK_DIV + 1); else if (SYSTEM->ClockSEL0.PARALLEL_CLK_SEL == 1) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->BlockClockDIV1.PARALLEL_CLK_DIV + 1); else if (SYSTEM->ClockSEL0.PARALLEL_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (SYSTEM->BlockClockDIV1.PARALLEL_CLK_DIV + 1); }break; case PER_CLK_SPDIF: { /* clock from SPLL */ if (SYSTEM->ClockSEL1.SPDIF_CLK_SEL == 2) PerClock = (system_get_AUPLLCLK()/2) / (SYSTEM->AudioClockDIV.SPDIF_CLK_DIV + 1); else if(SYSTEM->ClockSEL1.SPDIF_CLK_SEL == 1) PerClock = (system_get_SPLLCLK()/2) / (SYSTEM->AudioClockDIV.SPDIF_CLK_DIV + 1); else if(SYSTEM->ClockSEL1.SPDIF_CLK_SEL == 0) PerClock = system_get_CORE_HSCLK() / (SYSTEM->AudioClockDIV.SPDIF_CLK_DIV + 1); }break; default: PerClock = 0;break; } return PerClock; } /********************************************************************* * @fn system_dmac_request_id_config * * @brief dmac request id config. * * @param fe_source : dma request source. * @param fe_id : user select request id. * * @return None. */ void system_dmac_request_id_config(dmac_request_source_t fe_source, dmac_request_id_t fe_id) { uint8_t lu8_RequestSource; uint8_t lu8_RequestIDReg; lu8_RequestIDReg = fe_source / 4; lu8_RequestSource = fe_source % 4; SYSTEM->DmacHsCfg[lu8_RequestIDReg] &= ~(0x1F << lu8_RequestSource * 8); SYSTEM->DmacHsCfg[lu8_RequestIDReg] |= fe_id << (lu8_RequestSource * 8); } /********************************************************************* * @fn system_delay_us * * @brief system delay unit us, use system free counter. * * @param fu32_delay: delay unit us. */ __RAM_CODE void system_delay_us(uint32_t fu32_delay) { uint32_t backups_tack = FREE_COUNTER_VALUE; while(backups_tack - FREE_COUNTER_VALUE < fu32_delay); } /********************************************************************* * @fn system_cache_enable * * @brief cache enable. * * @param invalid_ram : true: invalidating the cache SRAM. * false: hold the cache SRAM. */ __RAM_CODE void system_cache_enable(bool invalid_ram) { uint32_t prim; // manul enable the cache and invalidating the SRAM prim = __get_PRIMASK(); __disable_irq(); switch (*(volatile uint32_t *)(FLASH_CACHE_BASE + 4) & 0x03) { case 0x01: // enabling while(((*(volatile uint32_t *)(FLASH_CACHE_BASE+4)) & 0x03) != 0x02); case 0x02: // enabled break; case 0x03: // disabling while(((*(volatile uint32_t *)(FLASH_CACHE_BASE+4)) & 0x03) != 0x00); default: *(volatile uint32_t *)FLASH_CACHE_BASE = 0x38; *(volatile uint32_t *)FLASH_CACHE_BASE = 0x3c; while(((*(volatile uint32_t *)(FLASH_CACHE_BASE+4)) & 0x10) == 0); if(invalid_ram) { *(volatile uint32_t *)FLASH_CACHE_BASE = 0x3e; while((*(volatile uint32_t *)FLASH_CACHE_BASE) & 0x02); } *(volatile uint32_t *)FLASH_CACHE_BASE = 0x3d; while(((*(volatile uint32_t *)(FLASH_CACHE_BASE+4)) & 0x03) != 0x02); break; } if(!prim) { __enable_irq(); } } /********************************************************************* * @fn system_cache_disable * * @brief cache disable. * */ __RAM_CODE void system_cache_disable(void) { uint32_t prim; // manul disable the cache prim = __get_PRIMASK(); __disable_irq(); *(volatile uint32_t *)FLASH_CACHE_BASE = 0x3c; *(volatile uint32_t *)FLASH_CACHE_BASE = 0x38; while(((*(volatile uint32_t *)(FLASH_CACHE_BASE+0x04)) & 0x03) != 0x00); if(!prim) { __enable_irq(); } } void system_prevent_sleep_set(uint32_t type) { GLOBAL_INT_DISABLE(); system_prevent_sleep_label |= type; GLOBAL_INT_RESTORE(); } void system_prevent_sleep_clear(uint32_t type) { GLOBAL_INT_DISABLE(); system_prevent_sleep_label &= (~type); GLOBAL_INT_RESTORE(); } uint32_t system_prevent_sleep_get(void) { return system_prevent_sleep_label; } void system_reset(void) { __disable_irq(); // reboot iwdt_Init_t iwdt_env; iwdt_env.iwdt_Count = 300; iwdt_env.iwdt_Timeout = 10; iwdt_env.iwdt_int_Enable = WDT_INT_DISABLE; iwdt_init(iwdt_env); iwdt_Enable(); // ool_write(PMU_REG_IOLDO1_CTRL_0, (ool_read(PMU_REG_IOLDO1_CTRL_0) & 0xf0) | 0x01); while(1); } /* ====================================================================================================== */ /* =============================== GLOBAL interrupt controller ===================================== */ /* ====================================================================================================== */ void GLOBAL_INT_START(void) { __asm ( "CPSIE i \n" ); } void GLOBAL_INT_STOP(void) { __asm ( "CPSID i \n" ); } __RAM_CODE void CPU_SR_Restore(uint32_t org_base_pri) { __asm ( "MSR BASEPRI, %[org]\n" : : [org]"r"(org_base_pri) : ); } __RAM_CODE uint32_t CPU_SR_Save(uint32_t new_basepri) { uint32_t old_basepri; __asm ( "MRS R4, BASEPRI\n" "MSR BASEPRI, %[new]\n" "MOV %[old], R4 \n" : [old]"=r"(old_basepri) : [new]"r"(new_basepri) : "r4" ); return old_basepri; }