增加所有文件
This commit is contained in:
100
middleware/udelay/udelay.c
Normal file
100
middleware/udelay/udelay.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file udelay.c
|
||||
* @brief udelay common source
|
||||
*
|
||||
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include <udelay/udelay.h>
|
||||
#include <armv7-r/pmu.h>
|
||||
#include <sdrv_ckgen.h>
|
||||
#include <clock_ip.h>
|
||||
#include <debug.h>
|
||||
|
||||
static uint32_t core_frequency;
|
||||
static uint32_t cnt_per_us;
|
||||
|
||||
static inline uint32_t udelay_us_to_counter(uint32_t us)
|
||||
{
|
||||
if (us > MAX_UDELAY) {
|
||||
us = MAX_UDELAY;
|
||||
}
|
||||
|
||||
if (cnt_per_us == 0x0) {
|
||||
core_frequency = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_cr5_sf),
|
||||
CKGEN_BUS_CLK_OUT_M);
|
||||
|
||||
cnt_per_us = (uint32_t)(core_frequency / 1000000);
|
||||
}
|
||||
|
||||
return cnt_per_us * us;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize ARM Performance Monitor cycle counter
|
||||
*
|
||||
* sdrv udelay is implement by arm pmu cycle counter, you must
|
||||
* call this function before use udelay().
|
||||
*
|
||||
* note: this function must called after cpu clock has configurated.
|
||||
*/
|
||||
void sdrv_pmu_counter_init(void)
|
||||
{
|
||||
core_frequency = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_cr5_sf),
|
||||
CKGEN_BUS_CLK_OUT_M);
|
||||
|
||||
cnt_per_us = (uint32_t)(core_frequency / 1000000);
|
||||
|
||||
if (!pmu_cycle_cntr_status()) {
|
||||
pmu_enable();
|
||||
pmu_start_cycle_cntr(false);
|
||||
}
|
||||
else {
|
||||
pmu_stop_clear_cycle_cntr();
|
||||
pmu_start_cycle_cntr(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief delay for microseconds
|
||||
*
|
||||
* @param us microseconds
|
||||
*/
|
||||
void udelay(uint32_t us)
|
||||
{
|
||||
#if CONFIG_ARM_WITH_PMU
|
||||
if (!pmu_cycle_cntr_status()) {
|
||||
sdrv_pmu_counter_init();
|
||||
}
|
||||
|
||||
if (pmu_cycle_cntr_status() && (us > 0)) {
|
||||
uint32_t tick_to, start_tick, current_tick;
|
||||
uint32_t tmt = 0u;
|
||||
|
||||
start_tick = pmu_get_cycle_cntr();
|
||||
|
||||
/* make sure cycled information: 100 loops takes ~5us */
|
||||
while ((start_tick == pmu_get_cycle_cntr()) && (tmt++ < 100u));
|
||||
|
||||
/* timeout check is not a must here, just in case the pmccntr abnormal */
|
||||
if (tmt < 100u) {
|
||||
tick_to = start_tick + udelay_us_to_counter(us);
|
||||
|
||||
if (tick_to > start_tick) {
|
||||
/* tick_to not overflowed */
|
||||
do {
|
||||
current_tick = pmu_get_cycle_cntr();
|
||||
} while ((current_tick < tick_to)
|
||||
&& (current_tick > start_tick));
|
||||
} else {
|
||||
/* current_tick overflowed */
|
||||
do {
|
||||
current_tick = pmu_get_cycle_cntr();
|
||||
} while ((current_tick > start_tick) || (current_tick < tick_to));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user