| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /* SPDX-License-Identifier: BSD-3-Clause */
- /*
- * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
- */
- #include "hal_base.h"
- /** @addtogroup RK_HAL_Driver
- * @{
- */
- /** @addtogroup HAL_BASE
- * @{
- */
- /** @defgroup HAL_BASE_How_To_Use How To Use
- * @{
- HAL system support is including delay system, HAL tick system and global system clock,
- HAL system tick setting:
- - Attach HAL_IncTick() to system tick interrupt handler;
- - Notify the HAL system the system's tick frequency by calling HAL_SetTickFreq() unless
- it is the same as default value HAL_TICK_FREQ_1KHZ;
- - If you need a more accurate delay system, specify SYS_TIMER in hal_conf.h.
- Init HAL system:
- - Initialize the HAL system by calling HAL_Init():
- Reset when SOC system is changed:
- - Update system with new core clock and new SysTick clock source by calling HAL_SystemCoreClockUpdate();
- APIs:
- - Get system time by calling HAL_GetTick();
- - Delay for a certain length of time, HAL_DelayMs(), HAL_DelayUs(), and HAL_CPUDelayUs().
- - Blocking for a certain period of time to continuously query HW status, use HAL_GetTick()
- to do timeout, this will be more accurate.
- @} */
- /** @defgroup HAL_BASE_Private_Definition Private Definition
- * @{
- */
- /********************* Private MACRO Definition ******************************/
- #define HAL_TICK_FREQ_DEFAULT HAL_TICK_FREQ_1KHZ
- /********************* Private Structure Definition **************************/
- /********************* Private Variable Definition ***************************/
- static __IO uint32_t uwTick;
- static eHAL_tickFreq uwTickFreq = HAL_TICK_FREQ_DEFAULT;
- /********************* Private Function Definition ***************************/
- #if defined(__CORTEX_A) || defined(__CORTEX_M)
- #if __CORTEX_M == 0U || !defined(__GNUC__)
- static void CPUCycleLoop(uint32_t cycles)
- {
- uint32_t count;
- if (cycles < 100U) {
- return;
- }
- count = cycles / 3;
- while (count-- > 0) {
- __asm volatile ("nop");
- }
- }
- #else
- static void CPUCycleLoop(uint32_t cycles)
- {
- __ASM volatile (
- "mov r0, %0\n\t"
- "adds r0, r0, #2\n\t" // 1 2 Round to the nearest multiple of 4.
- "lsrs r0, r0, #2\n\t" // 1 2 Divide by 4 and set flags.
- "beq 2f\n\t" // 2 2 Skip if 0.
- ".align 4\n\t"
- "1:\n\t"
- "adds r0, r0, #1\n\t" // 1 2 Increment the counter.
- "subs r0, r0, #2\n\t" // 1 2 Decrement the counter by 2.
- "bne 1b\n\t" // (1)2 2 2 CPU cycles (if branch is taken).
- "nop\n\t" // 1 2 Loop alignment padding.
- "2:"
- : : "r" (cycles)
- );
- }
- #endif
- #elif defined(__RISC_V)
- static void CPUCycleLoop(uint32_t cycles)
- {
- asm volatile (
- "mv a0, %0\n\t"
- "addi a0, a0, 2\n\t" // 1 2 Round to the nearest multiple of 4.
- "li a1, 4\n\t"
- "div a0, a0, a1\n\t" // 1 2 Divide by 4 and set flags.
- "li a1, 2\n\t"
- "bnez a0, 1f\n\t" // 2 2 Skip if 0.
- "j 2f\n\t"
- ".align 6\n\t"
- "1:\n\t"
- "addi a0, a0, 1\n\t" // 1 2 Increment the counter.
- "sub a0, a0, a1\n\t" // 1 2 Decrement the counter by 2.
- "bnez a0, 1b\n\t" // (1)2 2 2 CPU cycles (if branch is taken).
- "nop\n\t" // 1 2 Loop alignment padding.
- "2:"
- : : "r" (cycles)
- );
- }
- #endif
- #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
- __STATIC_FORCEINLINE HAL_Status TimerDelayUs(uint32_t us)
- {
- uint64_t count, from, now, pass;
- from = HAL_TIMER_GetCount(SYS_TIMER);
- count = PLL_INPUT_OSC_RATE / 1000000 * us;
- do {
- now = HAL_TIMER_GetCount(SYS_TIMER);
- pass = now > from ? now - from : from - now;
- } while (pass < count);
- return HAL_OK;
- }
- #endif
- /** @} */
- /********************* Public Function Definition ***************************/
- /** @defgroup HAL_BASE_Exported_Functions_Group4 Init and DeInit Functions
- This section provides functions allowing to init and deinit the module:
- * @{
- */
- /**
- * @brief Init HAL driver basic code.
- * @return HAL_OK.
- */
- HAL_Status HAL_Init(void)
- {
- #ifdef __CORTEX_M
- #ifdef HAL_NVIC_MODULE_ENABLED
- /* Set Interrupt Group Priority */
- HAL_NVIC_Init();
- /* Set Interrupt Group Priority */
- HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_DEFAULT);
- #endif
- #endif
- #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
- HAL_TIMER_SysTimerInit(SYS_TIMER);
- #endif
- #ifdef RK_BSP_TEMP
- #ifdef HAL_PINCTRL_MODULE_ENABLED
- HAL_PINCTRL_Init();
- #endif
- #endif
- return HAL_OK;
- }
- /**
- * @brief HAL system update with new core clock and systick clock source.
- * @param hz: new core clock.
- * @param clkSource: new systick clock source.
- * @return HAL_OK.
- */
- HAL_Status HAL_SystemCoreClockUpdate(uint32_t hz, eHAL_systickClkSource clkSource)
- {
- uint32_t rate = hz;
- HAL_Status ret = HAL_OK;
- #if defined(__CORTEX_M) && defined(HAL_SYSTICK_MODULE_ENABLED)
- ret = HAL_SYSTICK_CLKSourceConfig(clkSource);
- if (ret == HAL_OK && clkSource == HAL_SYSTICK_CLKSRC_EXT) {
- rate = PLL_INPUT_OSC_RATE;
- }
- HAL_SYSTICK_Config(rate / (1000 / HAL_GetTickFreq()));
- ret = HAL_OK;
- #endif
- if (ret == HAL_OK) {
- SystemCoreClock = rate; /* Update global SystemCoreClock */
- }
- return ret;
- }
- /**
- * @brief HAL deinit.
- * @return HAL_Status: HAL_OK.
- */
- HAL_Status HAL_DeInit(void)
- {
- /* TO-DO */
- return HAL_OK;
- }
- /** @} */
- /** @defgroup HAL_BASE_Exported_Functions_Group5 Other Functions
- * @{
- */
- /**
- * @brief Count plus tickFreq when interrupt occurs.
- * @return HAL_Status: HAL_OK.
- */
- HAL_Status HAL_IncTick(void)
- {
- uwTick += uwTickFreq;
- return HAL_OK;
- }
- /**
- * @brief Provides tick value in millisecond.
- * @return uint32_t: tick value in millisecond.
- * @attention this API allow direct use in the HAL layer.
- */
- uint32_t HAL_GetTick(void)
- {
- #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
- uint64_t tick = HAL_TIMER_GetCount(SYS_TIMER);
- uint32_t base = PLL_INPUT_OSC_RATE / 1000;
- if (tick >> 62) {
- tick = ~tick;
- }
- return (uint32_t)HAL_DivU64(tick, base);
- #else
- return uwTick;
- #endif
- }
- /**
- * @brief Provides system timer count.
- * @return uint64_t: timer count.
- * @attention this API allow direct use in the HAL layer.
- */
- uint64_t HAL_GetSysTimerCount(void)
- {
- #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
- uint64_t count = HAL_TIMER_GetCount(SYS_TIMER);
- if (count >> 62) {
- count = ~count;
- }
- return count;
- #else
- return 0LLU;
- #endif
- }
- /**
- * @brief Set new tick frequency.
- * @return HAL_Status.
- */
- HAL_Status HAL_SetTickFreq(eHAL_tickFreq freq)
- {
- HAL_ASSERT(IS_TICKFREQ(freq));
- uwTickFreq = freq;
- return HAL_OK;
- }
- /**
- * @brief Return tick frequency.
- * @return uint32_t: tick period in Hz.
- * @attention this API allow direct use in the HAL layer.
- */
- eHAL_tickFreq HAL_GetTickFreq(void)
- {
- return uwTickFreq;
- }
- /**
- * @brief SysTick mdelay.
- * @param ms: mdelay count.
- * @return HAL_Status: HAL_OK.
- * @attention this API allow direct use in the HAL layer. Blocking for a
- * certain period of time to continuously query HW status, use HAL_GetTick
- * to do timeout, that will be more accurate.
- */
- __WEAK HAL_Status HAL_DelayMs(uint32_t ms)
- {
- for (uint32_t i = 0; i < ms; i++) {
- HAL_DelayUs(1000);
- }
- return HAL_OK;
- }
- /**
- * @brief SysTick udelay.
- * @param us: udelay count.
- * @return HAL_Status: HAL_OK.
- * @attention this API allow direct use in the HAL layer. The longer the delay,
- * the more accurate. Actual delay is greater than the parameter.
- */
- HAL_Status HAL_DelayUs(uint32_t us)
- {
- #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
- return TimerDelayUs(us);
- #else
- return HAL_CPUDelayUs(us);
- #endif
- }
- /**
- * @brief CPU loop udelay.
- * @param us: udelay count.
- * @return HAL_Status: HAL_OK.
- * @attention this API allow direct use in the HAL layer. The longer the delay,
- * the more accurate. Actual delay is greater than the parameter.
- * During delay, CPU rate change result in delay imprecise, so call it in
- * following case:
- * 1.IRQ disable
- * 2.CRU code
- */
- HAL_Status HAL_CPUDelayUs(uint32_t us)
- {
- volatile uint32_t cycles;
- #if (__CORTEX_M == 0)
- cycles = (uint32_t)HAL_DivU64((uint64_t)SystemCoreClock, 1000000) * us; /* Add few cycles penalty */
- #else
- cycles = SystemCoreClock / 1000000 * us; /* Add few cycles penalty */
- #endif
- CPUCycleLoop(cycles);
- return HAL_OK;
- }
- /** @} */
- /** @} */
- /** @} */
|