ADD FLASH(flash.h flash.cpp flash_def.h flash_cfg.h flash_sfdp.cpp)
ADD RunTimer(log.h ticks.h ticks.cpp) ADD sim_key form sdl
This commit is contained in:
@@ -42,11 +42,11 @@
|
||||
////////////////////////
|
||||
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOG_RUN_TIMER_FUN GetSysCnt32()
|
||||
#define LOG_RUN_TIMER_FUN GetTickCount64()
|
||||
#define LOG_RUN_TIMER_FMT "-T(%lums)"
|
||||
#else
|
||||
#define LOG_RUN_TIMER_FUN 0
|
||||
#define LOG_RUN_TIMER_FMT "-T(%lu)"
|
||||
#define LOG_RUN_TIMER_FUN GetTickCount64()
|
||||
#define LOG_RUN_TIMER_FMT "(%llums)"
|
||||
#endif
|
||||
|
||||
#ifdef LOG_LINE_END_CRLF
|
||||
@@ -65,6 +65,9 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LOG_OUT_FUNC printf
|
||||
|
||||
|
||||
#define LOG_BASE_FILENAME \
|
||||
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : \
|
||||
strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
@@ -101,9 +104,9 @@
|
||||
// 带时钟输出
|
||||
#if defined(LOG_TIMER)
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGT(tag, fmt, ...) do{ printf(LOG_COLOR_BLUE "[" tag "]" LOG_RUN_TIMER_FMT ": " fmt LOG_END,LOG_RUN_TIMER_FUN, ##__VA_ARGS__); } while(0)
|
||||
#define LOGT(tag, fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_BLUE "[" tag "]" LOG_RUN_TIMER_FMT ": " fmt LOG_END,LOG_RUN_TIMER_FUN, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGT(tag, fmt, ...) do{ printf(LOG_COLOR_BLUE "[" tag "]: " fmt LOG_END, ##__VA_ARGS__); } while(0)
|
||||
#define LOGT(tag, fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_BLUE "[" tag "]: " fmt LOG_END, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGT(fmt, ...) ((void)0)
|
||||
@@ -112,9 +115,9 @@
|
||||
// 等级输出
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_FATAL
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGF(fmt, ...) do{ printf(LOG_COLOR_CYAN "[F]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0)
|
||||
#define LOGF(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CYAN "[F]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0)
|
||||
#else
|
||||
#define LOGF(fmt, ...) do{ printf(LOG_COLOR_CYAN "[F]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0)
|
||||
#define LOGF(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CYAN "[F]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGF(fmt, ...) ((void)0)
|
||||
@@ -122,9 +125,9 @@
|
||||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_ERROR
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGE(fmt, ...) do{ printf(LOG_COLOR_RED "[E]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#define LOGE(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_RED "[E]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGE(fmt, ...) do{ printf(LOG_COLOR_RED "[E]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#define LOGE(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_RED "[E]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGE(fmt, ...) ((void)0)
|
||||
@@ -132,9 +135,9 @@
|
||||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_WARN
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGW(fmt, ...) do{ printf(LOG_COLOR_CARMINE "[W]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#define LOGW(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CARMINE "[W]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGW(fmt, ...) do{ printf(LOG_COLOR_CARMINE "[W]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#define LOGW(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CARMINE "[W]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGW(fmt, ...) ((void)0)
|
||||
@@ -142,9 +145,9 @@
|
||||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_INFO
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGI(fmt, ...) do{ printf(LOG_COLOR_YELLOW "[I]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGI(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_YELLOW "[I]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGI(fmt, ...) do{ printf(LOG_COLOR_YELLOW "[I]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGI(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_YELLOW "[I]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGI(fmt, ...) ((void)0)
|
||||
@@ -152,9 +155,9 @@
|
||||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_DEBUG
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGD(fmt, ...) do{ printf(LOG_COLOR_DEFAULT "[D]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGD(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[D]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGD(fmt, ...) do{ printf(LOG_COLOR_DEFAULT "[D]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGD(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[D]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGD(fmt, ...) ((void)0)
|
||||
@@ -162,11 +165,164 @@
|
||||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_VERBOSE
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGV(fmt, ...) do{ printf(LOG_COLOR_DEFAULT "[V]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGV(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[V]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGV(fmt, ...) do{ printf(LOG_COLOR_DEFAULT "[V]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGV(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[V]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGV(fmt, ...) ((void)0)
|
||||
#endif
|
||||
#endif //HW_LIB_LOG_H
|
||||
|
||||
|
||||
#ifndef LOG_RUN_TIME
|
||||
#ifndef __PLOOC_VA_NUM_ARGS_IMPL
|
||||
# define __PLOOC_VA_NUM_ARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
|
||||
_12, _13, _14, _15, _16, __N, ...) __N
|
||||
#endif
|
||||
|
||||
#ifndef __PLOOC_VA_NUM_ARGS
|
||||
#define __PLOOC_VA_NUM_ARGS(...) \
|
||||
__PLOOC_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
|
||||
8,7,6,5,4,3,2,1,0)
|
||||
#endif
|
||||
|
||||
#ifndef __ticks_sync_barrier__
|
||||
|
||||
/* default implementation */
|
||||
#if defined(__clang__) || __IS_COMPILER_GCC__
|
||||
# define __ticks_sync_barrier__(...) __sync_synchronize()
|
||||
#else
|
||||
# define __ticks_sync_barrier__(...)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#undef __CONNECT2
|
||||
#undef __CONNECT3
|
||||
#undef __CONNECT4
|
||||
#undef __CONNECT5
|
||||
#undef __CONNECT6
|
||||
#undef __CONNECT7
|
||||
#undef __CONNECT8
|
||||
#undef __CONNECT9
|
||||
|
||||
#undef CONNECT2
|
||||
#undef CONNECT3
|
||||
#undef CONNECT4
|
||||
#undef CONNECT5
|
||||
#undef CONNECT6
|
||||
#undef CONNECT7
|
||||
#undef CONNECT8
|
||||
#undef CONNECT9
|
||||
|
||||
#undef CONNECT
|
||||
|
||||
#undef __MACRO_EXPANDING
|
||||
#define __MACRO_EXPANDING(...) __VA_ARGS__
|
||||
|
||||
#define __CONNECT2(__A, __B) __A##__B
|
||||
#define __CONNECT3(__A, __B, __C) __A##__B##__C
|
||||
#define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
|
||||
#define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
|
||||
#define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F
|
||||
#define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
|
||||
__A##__B##__C##__D##__E##__F##__G
|
||||
#define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
|
||||
__A##__B##__C##__D##__E##__F##__G##__H
|
||||
#define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
|
||||
__A##__B##__C##__D##__E##__F##__G##__H##__I
|
||||
|
||||
#define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B)
|
||||
#define CONNECT2(__A, __B) __CONNECT2(__A, __B)
|
||||
#define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C)
|
||||
#define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D)
|
||||
#define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E)
|
||||
#define CONNECT6(__A, __B, __C, __D, __E, __F) \
|
||||
__CONNECT6(__A, __B, __C, __D, __E, __F)
|
||||
#define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
|
||||
__CONNECT7(__A, __B, __C, __D, __E, __F, __G)
|
||||
#define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
|
||||
__CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
|
||||
#define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
|
||||
__CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
|
||||
|
||||
#define CONNECT(...) \
|
||||
ALT_CONNECT2(CONNECT, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#undef __using1
|
||||
#undef __using2
|
||||
#undef __using3
|
||||
#undef __using4
|
||||
#undef using
|
||||
|
||||
#define __using1(__declare) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
|
||||
)
|
||||
|
||||
#define __using2(__declare, __on_leave_expr) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define __using3(__declare, __on_enter_expr, __on_leave_expr) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
|
||||
((__on_enter_expr),1) : 0; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
|
||||
for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
|
||||
((__on_enter_expr),1) : 0; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define using(...) \
|
||||
CONNECT2(__using, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOG_RUN_TIME(__STR, ...) \
|
||||
using(uint64_t _ = LOG_RUN_TIMER_FUN, __time_count__ = _, \
|
||||
{__ticks_sync_barrier__();}, \
|
||||
{ \
|
||||
__ticks_sync_barrier__(); \
|
||||
_ = LOG_RUN_TIMER_FUN - _; \
|
||||
__time_count__ = _; \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
LOG_OUT_FUNC("\r\n"); \
|
||||
LOG_OUT_FUNC("-[Run Timer]"); \
|
||||
LOG_OUT_FUNC( \
|
||||
"------------------------------------\r\n"); \
|
||||
LOG_OUT_FUNC( \
|
||||
__STR " total run timer: " LOG_RUN_TIMER_FMT LOG_END, \
|
||||
_); \
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
})
|
||||
#else
|
||||
#define LOG_RUN_TIME(__STR, ...) \
|
||||
using(uint64_t _ = LOG_RUN_TIMER_FUN, __time_count__ = _, \
|
||||
{__ticks_sync_barrier__();}, \
|
||||
{ \
|
||||
__ticks_sync_barrier__(); \
|
||||
_ = LOG_RUN_TIMER_FUN - _; \
|
||||
__time_count__ = _; \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
LOG_OUT_FUNC("\r\n"); \
|
||||
LOG_OUT_FUNC("-[Run Timer]"); \
|
||||
LOG_OUT_FUNC( \
|
||||
"------------------------------------\r\n"); \
|
||||
LOG_OUT_FUNC( \
|
||||
__STR " total run timer: " LOG_RUN_TIMER_FMT LOG_END, \
|
||||
_); \
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
})
|
||||
#endif
|
||||
#endif
|
||||
#endif //HW_LIB_LOG_H
|
||||
|
806
lib/utils/inc/ticks.h
Normal file
806
lib/utils/inc/ticks.h
Normal file
@@ -0,0 +1,806 @@
|
||||
//
|
||||
// Created by lydxh on 24-11-27.
|
||||
//
|
||||
|
||||
#ifndef HW_LIB_TICKS_H
|
||||
#define HW_LIB_TICKS_H
|
||||
/*============================ INCLUDES ======================================*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*============================ MACROS ========================================*/
|
||||
|
||||
|
||||
/*!
|
||||
* \addtogroup gHelper 4 Helper
|
||||
* @{
|
||||
*/
|
||||
|
||||
// for IAR
|
||||
#undef __IS_COMPILER_IAR__
|
||||
#if defined(__IAR_SYSTEMS_ICC__)
|
||||
# define __IS_COMPILER_IAR__ 1
|
||||
#endif
|
||||
|
||||
// for arm compiler 5
|
||||
#undef __IS_COMPILER_ARM_COMPILER_5__
|
||||
#if ((__ARMCC_VERSION >= 5000000) && (__ARMCC_VERSION < 6000000))
|
||||
# define __IS_COMPILER_ARM_COMPILER_5__ 1
|
||||
#endif
|
||||
|
||||
|
||||
//for arm compiler 6
|
||||
|
||||
#undef __IS_COMPILER_ARM_COMPILER_6__
|
||||
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||
# define __IS_COMPILER_ARM_COMPILER_6__ 1
|
||||
#endif
|
||||
#undef __IS_COMPILER_ARM_COMPILER__
|
||||
#if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__ \
|
||||
|| defined(__IS_COMPILER_ARM_COMPILER_6__) && __IS_COMPILER_ARM_COMPILER_6__
|
||||
# define __IS_COMPILER_ARM_COMPILER__ 1
|
||||
#endif
|
||||
|
||||
// for clang
|
||||
#undef __IS_COMPILER_LLVM__
|
||||
#if defined(__clang__) && !__IS_COMPILER_ARM_COMPILER_6__
|
||||
# define __IS_COMPILER_LLVM__ 1
|
||||
#else
|
||||
|
||||
// for gcc
|
||||
# undef __IS_COMPILER_GCC__
|
||||
# if defined(__GNUC__) && !(defined(__IS_COMPILER_ARM_COMPILER__) \
|
||||
|| defined(__IS_COMPILER_LLVM__) \
|
||||
|| defined(__IS_COMPILER_IAR__))
|
||||
# define __IS_COMPILER_GCC__ 1
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
|
||||
# include __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
# pragma clang diagnostic ignored "-Wdeclaration-after-statement"
|
||||
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||
# pragma clang diagnostic ignored "-Wgnu-statement-expression"
|
||||
# pragma clang diagnostic ignored "-Wunused-but-set-variable"
|
||||
# pragma clang diagnostic ignored "-Wshadow"
|
||||
# pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
||||
# pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
|
||||
# pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
|
||||
# pragma diag_suppress 550
|
||||
#elif defined(__IS_COMPILER_GCC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wpedantic"
|
||||
# pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
# pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
# pragma GCC diagnostic ignored "-Wformat="
|
||||
#endif
|
||||
|
||||
#ifndef __PLOOC_VA_NUM_ARGS_IMPL
|
||||
# define __PLOOC_VA_NUM_ARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
|
||||
_12, _13, _14, _15, _16, __N, ...) __N
|
||||
#endif
|
||||
|
||||
#ifndef __PLOOC_VA_NUM_ARGS
|
||||
#define __PLOOC_VA_NUM_ARGS(...) \
|
||||
__PLOOC_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
|
||||
8,7,6,5,4,3,2,1,0)
|
||||
#endif
|
||||
|
||||
#ifndef UNUSED_PARAM
|
||||
# define UNUSED_PARAM(__VAR) (void)(__VAR)
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(__a, __b) ((__a) <= (__b) ? (__a) : (__b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(__a, __b) ((__a) >= (__b) ? (__a) : (__b))
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief an attribute for static variables that no initialisation is required
|
||||
* in the C startup process.
|
||||
*/
|
||||
#ifndef PERF_NOINIT
|
||||
# if defined(__IS_COMPILER_ARM_COMPILER_5__)
|
||||
# define PERF_NOINIT __attribute__(( section( ".bss.noinit"),zero_init))
|
||||
# elif defined(__IS_COMPILER_ARM_COMPILER_6__)
|
||||
# define PERF_NOINIT __attribute__(( section( ".bss.noinit")))
|
||||
# elif defined(__IS_COMPILER_IAR__)
|
||||
# define PERF_NOINIT __no_init
|
||||
# elif (defined(__IS_COMPILER_GCC__) || defined(__IS_COMPILER_LLVM__)) && !defined(__APPLE__)
|
||||
# define PERF_NOINIT __attribute__(( section( ".bss.noinit")))
|
||||
# else
|
||||
# define PERF_NOINIT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#undef __CONNECT2
|
||||
#undef __CONNECT3
|
||||
#undef __CONNECT4
|
||||
#undef __CONNECT5
|
||||
#undef __CONNECT6
|
||||
#undef __CONNECT7
|
||||
#undef __CONNECT8
|
||||
#undef __CONNECT9
|
||||
|
||||
#undef CONNECT2
|
||||
#undef CONNECT3
|
||||
#undef CONNECT4
|
||||
#undef CONNECT5
|
||||
#undef CONNECT6
|
||||
#undef CONNECT7
|
||||
#undef CONNECT8
|
||||
#undef CONNECT9
|
||||
|
||||
#undef CONNECT
|
||||
|
||||
#undef __MACRO_EXPANDING
|
||||
#define __MACRO_EXPANDING(...) __VA_ARGS__
|
||||
|
||||
#define __CONNECT2(__A, __B) __A##__B
|
||||
#define __CONNECT3(__A, __B, __C) __A##__B##__C
|
||||
#define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
|
||||
#define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
|
||||
#define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F
|
||||
#define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
|
||||
__A##__B##__C##__D##__E##__F##__G
|
||||
#define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
|
||||
__A##__B##__C##__D##__E##__F##__G##__H
|
||||
#define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
|
||||
__A##__B##__C##__D##__E##__F##__G##__H##__I
|
||||
|
||||
#define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B)
|
||||
#define CONNECT2(__A, __B) __CONNECT2(__A, __B)
|
||||
#define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C)
|
||||
#define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D)
|
||||
#define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E)
|
||||
#define CONNECT6(__A, __B, __C, __D, __E, __F) \
|
||||
__CONNECT6(__A, __B, __C, __D, __E, __F)
|
||||
#define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
|
||||
__CONNECT7(__A, __B, __C, __D, __E, __F, __G)
|
||||
#define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
|
||||
__CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
|
||||
#define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
|
||||
__CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
|
||||
|
||||
#define CONNECT(...) \
|
||||
ALT_CONNECT2(CONNECT, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#undef __using1
|
||||
#undef __using2
|
||||
#undef __using3
|
||||
#undef __using4
|
||||
#undef using
|
||||
|
||||
#define __using1(__declare) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
|
||||
)
|
||||
|
||||
#define __using2(__declare, __on_leave_expr) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define __using3(__declare, __on_enter_expr, __on_leave_expr) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
|
||||
((__on_enter_expr),1) : 0; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
|
||||
for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
|
||||
((__on_enter_expr),1) : 0; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define using(...) \
|
||||
CONNECT2(__using, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
|
||||
#undef __with2
|
||||
#undef __with3
|
||||
#undef with
|
||||
|
||||
#define __with1(__addr) \
|
||||
using(__typeof__(*__addr) *_=(__addr))
|
||||
|
||||
#define __with2(__type, __addr) \
|
||||
using(__type *_=(__addr))
|
||||
#define __with3(__type, __addr, __item) \
|
||||
using(__type *_=(__addr), *__item = _, _=_,_=_ )
|
||||
|
||||
#define with(...) \
|
||||
CONNECT2(__with, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#undef _
|
||||
|
||||
#ifndef dimof
|
||||
# define dimof(__array) (sizeof(__array)/sizeof(__array[0]))
|
||||
#endif
|
||||
|
||||
|
||||
#define SAFE_NAME(__NAME) CONNECT3(__,__NAME,__LINE__)
|
||||
|
||||
#undef foreach2
|
||||
#undef foreach3
|
||||
#undef foreach
|
||||
|
||||
#define foreach1(__array) \
|
||||
using(__typeof__(__array[0]) *_ = __array) \
|
||||
for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
|
||||
SAFE_NAME(count) > 0; \
|
||||
_++, SAFE_NAME(count)-- \
|
||||
)
|
||||
|
||||
#define foreach2(__type, __array) \
|
||||
using(__type *_ = __array) \
|
||||
for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
|
||||
SAFE_NAME(count) > 0; \
|
||||
_++, SAFE_NAME(count)-- \
|
||||
)
|
||||
|
||||
#define foreach3(__type, __array, __item) \
|
||||
using(__type *_ = __array, *__item = _, _ = _, _ = _ ) \
|
||||
for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
|
||||
SAFE_NAME(count) > 0; \
|
||||
_++, __item = _, SAFE_NAME(count)-- \
|
||||
)
|
||||
|
||||
#define foreach(...) \
|
||||
CONNECT2(foreach, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#ifndef safe_atom_code
|
||||
# define safe_atom_code() \
|
||||
using( ticks_global_interrupt_status_t SAFE_NAME(temp) = \
|
||||
ticks_port_disable_global_interrupt(), \
|
||||
ticks_port_resume_global_interrupt(SAFE_NAME(temp)))
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __WEAK
|
||||
# define __WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
#ifndef __STATIC_INLINE
|
||||
# define __STATIC_INLINE static inline
|
||||
#endif
|
||||
|
||||
#ifndef __IRQ_SAFE
|
||||
# define __IRQ_SAFE \
|
||||
using( ticks_global_interrupt_status_t SAFE_NAME(temp) = \
|
||||
ticks_port_disable_global_interrupt(), \
|
||||
ticks_port_resume_global_interrupt(SAFE_NAME(temp)))
|
||||
#endif
|
||||
|
||||
#ifndef __perf_counter_printf__
|
||||
# define __perf_counter_printf__ printf
|
||||
#endif
|
||||
|
||||
/* deprecated macro for backward compatibility */
|
||||
#define user_code_insert_to_systick_handler \
|
||||
ticks_port_insert_to_system_timer_insert_ovf_handler
|
||||
|
||||
#if __PLOOC_VA_NUM_ARGS() != 0
|
||||
#warning Please enable GNU extensions, it is required by __cycleof__() and \
|
||||
__super_loop_monitor__()
|
||||
#endif
|
||||
|
||||
#if defined(__PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__) \
|
||||
&& (!defined(__TICKS_USE_PORTING__) \
|
||||
|| (defined(__TICKS_USE_PORTING__) && (0 == __TICKS_USE_PORTING__)))
|
||||
|
||||
# if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__
|
||||
# pragma import(__ensure_systick_wrapper)
|
||||
# elif (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (!defined(__IS_COMPILER_IAR__) || !__IS_COMPILER_IAR__)
|
||||
__asm(".global __ensure_systick_wrapper\n\t");
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __ticks_sync_barrier__
|
||||
|
||||
/* default implementation */
|
||||
#if defined(__clang__) || __IS_COMPILER_GCC__
|
||||
# define __ticks_sync_barrier__(...) __sync_synchronize()
|
||||
#else
|
||||
# define __ticks_sync_barrier__(...)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*! @} */
|
||||
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasic 1 Basic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief measure the cycle count of a given code segment
|
||||
* \param[in] __STR a description string for the measurement
|
||||
* \param[in] ... an optional code segement, in which we can read the measured
|
||||
* result from __cycle_count__.
|
||||
* \details Here is an example:
|
||||
E.g.
|
||||
\code
|
||||
__cycleof__("printf") {
|
||||
printf("hello world\r\n");
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
#define __cycleof__(__STR, ...) \
|
||||
using(int64_t _ = get_system_ticks(), __cycle_count__ = _, \
|
||||
{__ticks_sync_barrier__();}, \
|
||||
{ \
|
||||
__ticks_sync_barrier__(); \
|
||||
_ = get_system_ticks() - _ - g_nOffset; \
|
||||
__cycle_count__ = _; \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
__perf_counter_printf__("\r\n"); \
|
||||
__perf_counter_printf__("-[Cycle Report]"); \
|
||||
__perf_counter_printf__( \
|
||||
"------------------------------------\r\n"); \
|
||||
__perf_counter_printf__( \
|
||||
__STR " total cycle count: %ld [%08lx]\r\n", \
|
||||
(long)_, (long)_); \
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
})
|
||||
|
||||
/*!
|
||||
* \brief measure the cpu usage for a given code segment and print out the
|
||||
* result in percentage.
|
||||
* \param[in] __CNT generate result on every given iterations
|
||||
* \param[in] ... an optional code segement, in which we can read the measured
|
||||
* result from __usage__ which is a float value.
|
||||
* \details Here is an example, 50% cpu time:
|
||||
E.g.
|
||||
\code
|
||||
while (1) {
|
||||
__cpu_usage__(100) {
|
||||
delay_us(5000);
|
||||
}
|
||||
delay_us(5000);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
#define __cpu_usage__(__CNT, ...) \
|
||||
static int64_t SAFE_NAME(s_lTimestamp) = 0, SAFE_NAME(s_lTotal) = 0; \
|
||||
static uint32_t SAFE_NAME(s_wLoopCounter) = (__CNT); \
|
||||
using(float __usage__ = 0, ({ \
|
||||
if (0 == SAFE_NAME(s_wLoopCounter)) { \
|
||||
__usage__ = (float)((double)SAFE_NAME(s_lTotal) \
|
||||
/ (double)( get_system_ticks() \
|
||||
- SAFE_NAME(s_lTimestamp))); \
|
||||
__usage__ *= 100.0f; \
|
||||
SAFE_NAME(s_lTimestamp) = 0; \
|
||||
SAFE_NAME(s_lTotal) = 0; \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
__perf_counter_printf__("CPU Usage %3.2f%%\r\n", (double)__usage__);\
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
} \
|
||||
if (0 == SAFE_NAME(s_lTimestamp)) { \
|
||||
SAFE_NAME(s_lTimestamp) = get_system_ticks(); \
|
||||
SAFE_NAME(s_wLoopCounter) = (__CNT); \
|
||||
} \
|
||||
start_task_cycle_counter();}), \
|
||||
({SAFE_NAME(s_lTotal) += stop_task_cycle_counter(); \
|
||||
SAFE_NAME(s_wLoopCounter)--;}))
|
||||
|
||||
#define __cpu_time__ __cpu_usage__
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasicTimerService 1.2 Timer Service
|
||||
* \ingroup gBasic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief should not use
|
||||
*/
|
||||
#define ticks_is_time_out_ms0() true
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in ms and check the status
|
||||
*
|
||||
* \param[in] __ms a time period in millisecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
* \param[in] __auto_reload whether starting next period after a timeout event
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_ms3(__ms, __timestamp_ptr, __auto_reload) \
|
||||
({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
|
||||
__ticks_is_time_out(ticks_convert_ms_to_ticks(__ms), \
|
||||
(__timestamp_ptr), (__auto_reload));})
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in ms and check the status
|
||||
*
|
||||
* \param[in] __ms a time period in millisecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_ms2(__ms, __timestamp_ptr) \
|
||||
ticks_is_time_out_ms3((__ms), (__timestamp_ptr), true)
|
||||
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in ms and check the status
|
||||
*
|
||||
* \param[in] __ms a time period in millisecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_ms1(__ms) \
|
||||
ticks_is_time_out_ms3((__ms), &SAFE_NAME(s_lTimestamp), true)
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in ms and check the status
|
||||
*
|
||||
* \param[in] __ms a time period in millisecond
|
||||
* \param[in] ... an optional timestamp holder
|
||||
* \param[in] ... an optional indicator for whether starting next period after a timeout event
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_ms(...) \
|
||||
CONNECT2(ticks_is_time_out_ms, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
|
||||
(__VA_ARGS__)
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in us and check the status
|
||||
*
|
||||
* \param[in] __us a time period in microsecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
* \param[in] __auto_reload whether starting next period after a timeout event
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_us3(__us, __timestamp_ptr, __auto_reload) \
|
||||
({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
|
||||
__ticks_is_time_out(ticks_convert_us_to_ticks(__us), \
|
||||
(__timestamp_ptr), (__auto_reload));})
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in us and check the status
|
||||
*
|
||||
* \param[in] __us a time period in microsecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_us2(__us, __timestamp_ptr) \
|
||||
ticks_is_time_out_us3((__us), (__timestamp_ptr), true)
|
||||
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in us and check the status
|
||||
*
|
||||
* \param[in] __us a time period in microsecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_us1(__us) \
|
||||
ticks_is_time_out_us3((__us), &SAFE_NAME(s_lTimestamp), true)
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in us and check the status
|
||||
*
|
||||
* \param[in] __us a time period in microsecond
|
||||
* \param[in] ... an optional timestamp holder
|
||||
* \param[in] ... an optional indicator for whether starting next period after a timeout event
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_us(...) \
|
||||
CONNECT2(ticks_is_time_out_us, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
|
||||
(__VA_ARGS__)
|
||||
|
||||
/*============================ TYPES =========================================*/
|
||||
typedef struct {
|
||||
int64_t lStart;
|
||||
int64_t lUsedTotal;
|
||||
int32_t nUsedRecent;
|
||||
uint16_t hwActiveCount;
|
||||
uint16_t : 15;
|
||||
uint16_t bEnabled: 1;
|
||||
} task_cycle_info_t;
|
||||
|
||||
typedef struct task_cycle_info_agent_t task_cycle_info_agent_t;
|
||||
|
||||
struct task_cycle_info_agent_t {
|
||||
task_cycle_info_t *ptInfo;
|
||||
task_cycle_info_agent_t *ptNext;
|
||||
task_cycle_info_agent_t *ptPrev;
|
||||
};
|
||||
|
||||
extern volatile int64_t g_lLastTimeStamp;
|
||||
extern volatile int32_t g_nOffset;
|
||||
|
||||
|
||||
__attribute__((noinline))
|
||||
extern int64_t get_system_ticks(void);
|
||||
|
||||
|
||||
#ifdef __TICKS_USE_LONG_CLOCK__
|
||||
/*! \note the prototype of this clock() is different from the one defined in
|
||||
*! time.h. As clock_t is usually defined as unsigned int, it is
|
||||
*! not big enough in Cortex-M system to hold a time-stamp. clock()
|
||||
*! defined here returns the timestamp since the begining of main()
|
||||
*! and its unit is clock cycle (rather than 1ms). Hence, for a system
|
||||
*! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
|
||||
*! NXP, it is very easy to see a counter overflow as clock_t is
|
||||
*! defined as uint32_t in timer.h.
|
||||
*! Since we are not allowed to change the defintion of clock_t in
|
||||
*! official header file, i.e. time.h, I use a compatible prototype
|
||||
*! after I checked the AAPCS spec. So, the return of the clock() is
|
||||
*! int64_t, which will use the R0 to store the lower 32bits and R1
|
||||
*! to store the higher 32bits. When you are using the prototype from
|
||||
*! timer.h, caller will only take the lower 32bits stored in R0 and
|
||||
*! the higher 32bits stored in R1 will be ignored.
|
||||
*!
|
||||
*! If you want to use the non-overflow version of this clock(), please
|
||||
*! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
|
||||
*! and 2) do not include system header file <time.h>
|
||||
*!
|
||||
*/
|
||||
#if !defined(__IS_COMPILER_IAR__)
|
||||
__attribute__((nothrow))
|
||||
#endif
|
||||
__attribute__((noinline))
|
||||
extern int64_t clock(void);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief try to set a start pointer for the performance counter
|
||||
*/
|
||||
static inline
|
||||
void start_cycle_counter(void) {
|
||||
g_lLastTimeStamp = get_system_ticks();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief calculate the elapsed cycle count since the last start point
|
||||
* \note you can have multiple stop_cycle_counter following one start point
|
||||
* \return int32_t the elapsed cycle count
|
||||
*/
|
||||
static inline
|
||||
int64_t stop_cycle_counter(void) {
|
||||
int64_t lTemp = (get_system_ticks() - g_lLastTimeStamp);
|
||||
|
||||
return lTemp - g_nOffset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasicTimerService 1.2 Timer Service
|
||||
* \ingroup gBasic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief get the system timer frequency
|
||||
* \return uint32_t the system timer frequency in Hz
|
||||
*/
|
||||
extern uint32_t ticks_get_systimer_frequency(void);
|
||||
|
||||
/*!
|
||||
* \brief get the elapsed milliseconds since perf_counter is initialised
|
||||
* \return int64_t the elapsed milliseconds
|
||||
*/
|
||||
extern int64_t get_system_ms(void);
|
||||
|
||||
/*!
|
||||
* \brief get the elapsed microsecond since perf_counter is initialised
|
||||
* \return int64_t the elapsed microsecond
|
||||
*/
|
||||
extern int64_t get_system_us(void);
|
||||
|
||||
/*!
|
||||
* \brief delay specified time in microsecond
|
||||
* \param[in] wUs time in microsecond
|
||||
*/
|
||||
extern void delay_us(uint32_t wUs);
|
||||
|
||||
/*!
|
||||
* \brief delay specified time in millisecond
|
||||
* \param[in] wMs time in millisecond
|
||||
*/
|
||||
extern void delay_ms(uint32_t nMs);
|
||||
|
||||
/*!
|
||||
* \brief convert ticks of a reference timer to millisecond
|
||||
*
|
||||
* \param[in] lTick the tick count
|
||||
* \return int64_t the millisecond
|
||||
*/
|
||||
extern
|
||||
int64_t ticks_convert_ticks_to_ms(int64_t lTick);
|
||||
|
||||
/*!
|
||||
* \brief convert millisecond into ticks of the reference timer
|
||||
*
|
||||
* \param[in] wMS the target time in millisecond
|
||||
* \return int64_t the ticks
|
||||
*/
|
||||
extern
|
||||
int64_t ticks_convert_ms_to_ticks(uint32_t wMS);
|
||||
|
||||
/*!
|
||||
* \brief convert ticks of a reference timer to microsecond
|
||||
*
|
||||
* \param[in] lTick the tick count
|
||||
* \return int64_t the microsecond
|
||||
*/
|
||||
extern
|
||||
int64_t ticks_convert_ticks_to_us(int64_t lTick);
|
||||
|
||||
/*!
|
||||
* \brief convert microsecond into ticks of the reference timer
|
||||
*
|
||||
* \param[in] wUS the target time in microsecond
|
||||
* \return int64_t the ticks
|
||||
*/
|
||||
extern
|
||||
int64_t ticks_convert_us_to_ticks(uint32_t wUS);
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period and check the status
|
||||
*
|
||||
* \param[in] lPeriod a time period in ticks
|
||||
* \param[in] plTimestamp a pointer points to an int64_t integer, if NULL is
|
||||
* passed, an static local variable inside the function will be used
|
||||
* \param[in] bAutoReload whether starting next period after a timeout event.
|
||||
* \return bool whether it is timeout or not
|
||||
*/
|
||||
extern
|
||||
bool __ticks_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload);
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasic 1 Basic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------*
|
||||
* Please ignore the following APIs unless you have encountered some known *
|
||||
* special conditions *
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/*! \brief initialise cycle counter service
|
||||
* \note - don't forget to tell the function whether the systick is already
|
||||
* used by user applications.
|
||||
* Don't worry, this cycle counter service won't affect your existing
|
||||
* systick service.
|
||||
*
|
||||
* \note - Usually the perf_counter can initialise itself with the help of
|
||||
* __attribute__((constructor(255))), this works fine in Arm Compiler
|
||||
* 5 (armcc), Arm Compiler 6 (armclang), arm gcc and llvm. It doesn't
|
||||
* work for IAR. So, when you are using IAR, please call this function
|
||||
* manually to initialise the perf_counter service.
|
||||
*
|
||||
* \note - Perf_counter library assumes that:
|
||||
* 1. Your project has already using SysTick
|
||||
* 2. It assumes that you have already implemented the SysTick_Handler
|
||||
* 3. It assumes that you have enabled the exception handling for
|
||||
* SysTick.
|
||||
* If these are not the case, please:
|
||||
* 1. Add an empty SysTick_Handler to your project if you don't have
|
||||
* one
|
||||
* 2. Make sure you have the SysTick Exception handling enabled
|
||||
* 3. And call function init_cycle_counter(false) if you doesn't
|
||||
* use SysTick in your project at all.
|
||||
*
|
||||
* \param[in] bIsSysTickOccupied A boolean value which indicates whether SysTick
|
||||
* is already used by user application.
|
||||
*
|
||||
* \return false Failed to initialize the timer counter, as the timer is not
|
||||
* available or IO error.
|
||||
* \return true initialization is successful.
|
||||
*/
|
||||
extern bool init_cycle_counter(bool bIsSysTickOccupied);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief a system timer overflow handler
|
||||
*
|
||||
* \note - if you are using a compiler other than armcc or armclang, e.g. iar,
|
||||
* arm gcc etc, the systick_wrapper_ual.o doesn't work with the linker
|
||||
* of your target toolchain as it use the $Super$$ which is only supported
|
||||
* by armlink. For this condition, you have to manually put this function
|
||||
* into your existing SysTick_Handler to make the perf_counter library
|
||||
* work.
|
||||
*
|
||||
* \note - if you are using Arm Compiler 5 (armcc) or Arm Compiler 6 (armclang)
|
||||
* you do NOT have to insert this function into your SysTick_Handler,
|
||||
* the systick_wrapper_ual.s will do the work for you.
|
||||
*/
|
||||
extern void ticks_port_insert_to_system_timer_insert_ovf_handler(void);
|
||||
|
||||
/*!
|
||||
* \brief update perf_counter as SystemCoreClock has been updated.
|
||||
*/
|
||||
extern void update_perf_counter(void);
|
||||
|
||||
/*!
|
||||
* \brief prepare for reconfiguration of SysTick timer.
|
||||
*
|
||||
* \note some systems (e.g. FreeRTOS) might reconfigure the systick timer to
|
||||
* fulfil the requirement of their feature. To support this, just
|
||||
* before the reconfiguration, please call this function in order
|
||||
* to make the perf_counter works correctly later.
|
||||
*
|
||||
* \note after the reconfiguration, please call update_perf_counter() to apply
|
||||
* the changes to perf_counter.
|
||||
*
|
||||
* \note this function will stop the SysTick, clear the pending bit and set
|
||||
* the Load register and Current Value register to zero.
|
||||
*/
|
||||
extern void before_cycle_counter_reconfiguration(void);
|
||||
|
||||
|
||||
#ifndef __ticks_sync_barrier__
|
||||
# define __ticks_sync_barrier__(...) do {__DSB();__ISB();} while(0)
|
||||
#endif
|
||||
|
||||
typedef uint32_t ticks_global_interrupt_status_t;
|
||||
|
||||
__STATIC_INLINE
|
||||
ticks_global_interrupt_status_t ticks_port_disable_global_interrupt(void);
|
||||
//{
|
||||
// ticks_global_interrupt_status_t tStatus = __get_PRIMASK();
|
||||
// __disable_irq();
|
||||
//
|
||||
// return tStatus;
|
||||
//}
|
||||
|
||||
__STATIC_INLINE
|
||||
void ticks_port_resume_global_interrupt(ticks_global_interrupt_status_t tStatus);
|
||||
//{
|
||||
// __set_PRIMASK(tStatus);
|
||||
//}
|
||||
|
||||
|
||||
//#if defined(__clang__)
|
||||
//# pragma clang diagnostic pop
|
||||
//#elif defined(__IS_COMPILER_GCC__)
|
||||
//# pragma GCC diagnostic pop
|
||||
//#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif //HW_LIB_TICKS_H
|
@@ -48,9 +48,9 @@ typedef enum { // 定义枚举类型Type_t,包含不同数据类型
|
||||
default: ((void)0))
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) // 计算数组的元素个数
|
||||
//#define in , // 定义逗号为in
|
||||
|
||||
#define _foreach(e, a) for(size_t e = 0; e < ARRAY_SIZE(a); e++) // 实现foreach宏,遍历数组a,e为当前元素下标
|
||||
#define foreach(exp) _foreach(exp) // 定义foreach宏,用于遍历数组
|
||||
|
||||
|
||||
#define _VA_ARGS_N(_9, _8, _7, _6, _5, _4, _3, _2, _1, _0, N, ...) N
|
||||
#define VA_ARGS_N(...) _VA_ARGS_N(0 __VA_OPT__(,) __VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
@@ -60,6 +60,7 @@ typedef enum { // 定义枚举类型Type_t,包含不同数据类型
|
||||
#define _range_n_cat(a, b) a ## b
|
||||
#define _range_n(n) _range_n_cat(_range_, n)
|
||||
#define _range(...) _range_n(VA_ARGS_N(__VA_ARGS__)) // 根据传入参数个数选择对应的范围循环宏
|
||||
|
||||
/**
|
||||
* @Name 范围循环
|
||||
* @brief 根据传入参数个数生成不同范围的遍历
|
||||
@@ -125,7 +126,7 @@ float Str2Float(char *str);
|
||||
* @param fmt: [输入] 格式化字段
|
||||
* @param frame: [输入] 断帧大小
|
||||
* @return void
|
||||
* @example BufPrint("TX", buf, 8, 64, 16); //将长64的8位buf以16个数据断帧打印
|
||||
* @example PRINT_ARRAY(buf, " 0x%02x", 16); //将长64的8位buf以16个数据断帧打印
|
||||
**/
|
||||
#define PRINT_ARRAY(arr, fmt, frame) do { \
|
||||
printf("\n"#arr ":\n"); \
|
||||
@@ -143,9 +144,41 @@ int :"[int]-> "#v"=%d" END, \
|
||||
float :"[float]-> "#v"=%.2f" END , \
|
||||
double :"[double]-> "#v"=%.2f" END, \
|
||||
default: "[err]-> "#v"=%p" END)
|
||||
|
||||
#define POUT(s) printf(TYPE_F(s) ,s)
|
||||
|
||||
#ifndef GET_BIT
|
||||
#define GET_BIT(x, bit) ((x & (1 << bit)) >> bit)
|
||||
#endif
|
||||
#ifndef SWAP
|
||||
#ifdef __cplusplus
|
||||
#define SWAP(x, y) do { \
|
||||
decltype(x) temp = x; \
|
||||
x = y; \
|
||||
y = temp; \
|
||||
} while(0)
|
||||
#else
|
||||
#define SWAP(x, y) do { \
|
||||
typeof(x) temp = x; \
|
||||
x = y; \
|
||||
y = temp; \
|
||||
} while(0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(__a, __b) ((__a) <= (__b) ? (__a) : (__b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(__a, __b) ((__a) >= (__b) ? (__a) : (__b))
|
||||
#endif
|
||||
|
||||
#ifndef __WEAK
|
||||
# define __WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
631
lib/utils/ticks.cpp
Normal file
631
lib/utils/ticks.cpp
Normal file
@@ -0,0 +1,631 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __IMPLEMENT_PERF_COUNTER
|
||||
|
||||
#include "ticks.h"
|
||||
|
||||
#if defined(__IS_COMPILER_GCC__)
|
||||
# pragma GCC diagnostic ignored "-Wattributes"
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
# pragma clang diagnostic ignored "-Wconditional-uninitialized"
|
||||
# pragma clang diagnostic ignored "-Wcast-align"
|
||||
# pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
#endif
|
||||
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
#ifndef PERF_CNT_COMPENSATION_THRESHOLD
|
||||
# define PERF_CNT_COMPENSATION_THRESHOLD 16
|
||||
#endif
|
||||
|
||||
#ifndef PERF_CNT_DELAY_US_COMPENSATION
|
||||
# define PERF_CNT_DELAY_US_COMPENSATION 90
|
||||
#endif
|
||||
|
||||
#define MAGIC_WORD_AGENT_LIST_VALID 0x8492A53C
|
||||
#define MAGIC_WORD_CANARY 0xDEADBEEF
|
||||
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
/*============================ TYPES =========================================*/
|
||||
|
||||
struct __task_cycle_info_t {
|
||||
task_cycle_info_t tInfo; //!< cycle information
|
||||
int64_t lLastTimeStamp; //!< previous timestamp
|
||||
task_cycle_info_agent_t tList; //!< the root of the agent list
|
||||
uint32_t wMagicWord; //!< an magic word for validation
|
||||
};
|
||||
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
volatile int64_t g_lLastTimeStamp = 0;
|
||||
volatile static int64_t s_lOldTimestamp;
|
||||
volatile int32_t g_nOffset = 0;
|
||||
volatile static uint32_t s_wUSUnit = 1;
|
||||
volatile static uint32_t s_wMSUnit = 1;
|
||||
volatile static uint32_t s_wMSResidule = 0;
|
||||
volatile static uint32_t s_wUSResidule = 0;
|
||||
volatile static int64_t s_lSystemMS = 0;
|
||||
volatile static int64_t s_lSystemUS = 0;
|
||||
|
||||
volatile static int64_t s_lSystemClockCounts = 0;
|
||||
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
|
||||
/* low level interface for porting */
|
||||
extern
|
||||
uint32_t ticks_port_get_system_timer_freq(void);
|
||||
|
||||
extern
|
||||
int64_t ticks_port_get_system_timer_top(void);
|
||||
|
||||
extern
|
||||
bool ticks_port_is_system_timer_ovf_pending(void);
|
||||
|
||||
extern
|
||||
bool ticks_port_init_system_timer(bool bTimerOccupied);
|
||||
|
||||
extern
|
||||
int64_t ticks_port_get_system_timer_elapsed(void);
|
||||
|
||||
extern
|
||||
void ticks_port_clear_system_timer_ovf_pending(void);
|
||||
|
||||
extern
|
||||
void ticks_port_stop_system_timer_counting(void);
|
||||
|
||||
extern
|
||||
void ticks_port_clear_system_timer_counter(void);
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
void ticks_port_insert_to_system_timer_insert_ovf_handler(void) {
|
||||
int64_t lLoad = ticks_port_get_system_timer_top() + 1;
|
||||
s_lSystemClockCounts += lLoad;
|
||||
|
||||
// update system ms counter
|
||||
do {
|
||||
int64_t lTemp = s_wMSResidule + lLoad;
|
||||
|
||||
int64_t lMS = lTemp / s_wMSUnit;
|
||||
s_lSystemMS += lMS;
|
||||
s_wMSResidule = (uint32_t) ((int64_t) lTemp - (int64_t) lMS * s_wMSUnit);
|
||||
|
||||
} while (0);
|
||||
|
||||
// update system us counter
|
||||
do {
|
||||
int64_t lTemp = s_wUSResidule + lLoad;
|
||||
|
||||
int64_t lUS = lTemp / s_wUSUnit;
|
||||
s_lSystemUS += lUS;
|
||||
|
||||
s_wUSResidule = (uint32_t) ((int64_t) lTemp - (int64_t) lUS * s_wUSUnit);
|
||||
|
||||
} while (0);
|
||||
|
||||
}
|
||||
|
||||
uint32_t ticks_get_systimer_frequency(void) {
|
||||
return ticks_port_get_system_timer_freq();
|
||||
}
|
||||
|
||||
__WEAK
|
||||
void __perf_os_patch_init(void) {
|
||||
}
|
||||
|
||||
|
||||
void update_perf_counter(void) {
|
||||
uint32_t wSystemFrequency = ticks_port_get_system_timer_freq();
|
||||
s_wUSUnit = wSystemFrequency / 1000000ul;
|
||||
s_wMSUnit = wSystemFrequency / 1000ul;
|
||||
|
||||
__IRQ_SAFE {
|
||||
g_lLastTimeStamp = get_system_ticks();
|
||||
__ticks_sync_barrier__();
|
||||
g_nOffset = get_system_ticks() - g_lLastTimeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
bool init_cycle_counter(bool bIsSysTickOccupied) {
|
||||
bool bResult = false;
|
||||
__IRQ_SAFE {
|
||||
bResult = ticks_port_init_system_timer(bIsSysTickOccupied); // use the longest period
|
||||
ticks_port_clear_system_timer_ovf_pending();
|
||||
}
|
||||
|
||||
update_perf_counter();
|
||||
s_lSystemClockCounts = 0; // reset system cycle counter
|
||||
s_lSystemMS = 0; // reset system millisecond counter
|
||||
s_lSystemUS = 0; // reset system microsecond counter
|
||||
s_lOldTimestamp = 0;
|
||||
|
||||
__perf_os_patch_init();
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
/*! \note this function should only be called when irq is disabled
|
||||
* hence SysTick-LOAD and (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)
|
||||
* won't change.
|
||||
*/
|
||||
__STATIC_INLINE int64_t check_systick(void) {
|
||||
int64_t lLoad = ticks_port_get_system_timer_top() + 1;
|
||||
int64_t lTemp = ticks_port_get_system_timer_elapsed();
|
||||
|
||||
/* Since we cannot stop counting temporarily, there are several
|
||||
* conditions which we should take into consideration:
|
||||
* - Condition 1: when assigning nTemp with the register value (LOAD-VAL),
|
||||
* the underflow didn't happen but when we check the PENDSTSET bit,
|
||||
* the underflow happens, for this condition, we should not
|
||||
* do any compensation. When this happens, the (LOAD-nTemp) is
|
||||
* smaller than PERF_CNT_COMPENSATION_THRESHOLD (a small value) as
|
||||
* long as LOAD is bigger than (or equals to) the
|
||||
* PERF_CNT_COMPENSATION_THRESHOLD;
|
||||
* - Condition 2: when assigning nTemp with the register value (LOAD-VAL),
|
||||
* the VAL is zero and underflow happened and the PENDSTSET bit
|
||||
* is set, for this condition, we should not do any compensation.
|
||||
* When this happens, the (LOAD-nTemp) is equals to zero.
|
||||
* - Condition 3: when assigning nTemp with the register value (LOAD-VAL),
|
||||
* the underflow has already happened, hence the PENDSTSET
|
||||
* is set, for this condition, we should compensate the return
|
||||
* value. When this happens, the (LOAD-nTemp) is bigger than (or
|
||||
* equals to) PERF_CNT_COMPENSATION_THRESHOLD.
|
||||
* The following code implements an equivalent logic.
|
||||
*/
|
||||
if (ticks_port_is_system_timer_ovf_pending()) {
|
||||
if ((lLoad - lTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
|
||||
lTemp += lLoad;
|
||||
}
|
||||
}
|
||||
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
void before_cycle_counter_reconfiguration(void) {
|
||||
__IRQ_SAFE {
|
||||
ticks_port_stop_system_timer_counting();
|
||||
|
||||
if (ticks_port_is_system_timer_ovf_pending()) {
|
||||
ticks_port_clear_system_timer_ovf_pending(); /* clear pending bit */
|
||||
|
||||
ticks_port_insert_to_system_timer_insert_ovf_handler(); /* manually handle exception */
|
||||
|
||||
}
|
||||
s_lSystemClockCounts = get_system_ticks(); /* get the final cycle counter value */
|
||||
|
||||
ticks_port_clear_system_timer_counter();
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
void __perf_counter_init(void) {
|
||||
init_cycle_counter(true);
|
||||
}
|
||||
|
||||
|
||||
void delay_us(uint32_t wUs) {
|
||||
int64_t lUs = (int64_t) wUs * (int64_t) s_wUSUnit;
|
||||
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
|
||||
? g_nOffset
|
||||
: PERF_CNT_DELAY_US_COMPENSATION;
|
||||
|
||||
if (lUs <= iCompensate) {
|
||||
return;
|
||||
}
|
||||
|
||||
lUs -= iCompensate;
|
||||
|
||||
lUs += get_system_ticks();
|
||||
while (get_system_ticks() < lUs);
|
||||
}
|
||||
|
||||
void delay_ms(uint32_t wMs) {
|
||||
int64_t lMs = (int64_t) wMs * (int64_t) s_wMSUnit;
|
||||
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
|
||||
? g_nOffset
|
||||
: PERF_CNT_DELAY_US_COMPENSATION;
|
||||
|
||||
if (lMs <= iCompensate) {
|
||||
return;
|
||||
}
|
||||
|
||||
lMs -= iCompensate;
|
||||
|
||||
lMs += get_system_ticks();
|
||||
while (get_system_ticks() < lMs);
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
int64_t get_system_ticks(void) {
|
||||
int64_t lTemp = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
lTemp = check_systick() + s_lSystemClockCounts;
|
||||
|
||||
/* When calling get_system_ticks() in an exception handler that has a
|
||||
* higher priority than the SysTick_Handler, in some rare cases, the
|
||||
* lTemp might be temporarily smaller than the previous value (i.e.
|
||||
* s_lOldTimestamp), to mitigate the adverse effects of this problem,
|
||||
* we use the following code to avoid time-rolling-back issue.
|
||||
*
|
||||
* NOTE: the issue mentioned above doesn't accumulate or have long-lasting
|
||||
* effects.
|
||||
*/
|
||||
if (lTemp < s_lOldTimestamp) {
|
||||
lTemp = s_lOldTimestamp;
|
||||
} else {
|
||||
s_lOldTimestamp = lTemp;
|
||||
}
|
||||
}
|
||||
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
/*! \note the prototype of this clock() is different from the one defined in
|
||||
*! time.h. As clock_t is usually defined as unsigned int, it is
|
||||
*! not big enough in Cortex-M system to hold a time-stamp. clock()
|
||||
*! defined here returns the timestamp since the begining of main()
|
||||
*! and its unit is clock cycle (rather than 1ms). Hence, for a system
|
||||
*! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
|
||||
*! NXP, it is very easy to see a counter overflow as clock_t is
|
||||
*! defined as uint32_t in timer.h.
|
||||
*! Since we are not allowed to change the defintion of clock_t in
|
||||
*! official header file, i.e. time.h, I use a compatible prototype
|
||||
*! after I checked the AAPCS spec. So, the return of the clock() is
|
||||
*! int64_t, which will use the R0 to store the lower 32bits and R1
|
||||
*! to store the higher 32bits. When you are using the prototype from
|
||||
*! timer.h, caller will only take the lower 32bits stored in R0 and
|
||||
*! the higher 32bits stored in R1 will be ignored.
|
||||
*!
|
||||
*! If you want to use the non-overflow version of this clock(), please
|
||||
*! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
|
||||
*! and 2) do not include system header file <time.h>
|
||||
*!
|
||||
*/
|
||||
#if !defined(__IS_COMPILER_IAR__)
|
||||
|
||||
__attribute__((nothrow))
|
||||
#endif
|
||||
__attribute__((noinline))
|
||||
int64_t clock(void) {
|
||||
return get_system_ticks();
|
||||
}
|
||||
|
||||
int64_t get_system_ms(void) {
|
||||
int64_t lTemp = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
lTemp = s_lSystemMS + ((check_systick() + (int64_t) s_wMSResidule) / s_wMSUnit);
|
||||
}
|
||||
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
int64_t get_system_us(void) {
|
||||
int64_t lTemp = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
lTemp = s_lSystemUS + ((check_systick() + (int64_t) s_wUSResidule) / s_wUSUnit);
|
||||
}
|
||||
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
int64_t ticks_convert_ticks_to_ms(int64_t lTick) {
|
||||
return lTick / (int64_t) s_wMSUnit;
|
||||
}
|
||||
|
||||
int64_t ticks_convert_ms_to_ticks(uint32_t wMS) {
|
||||
int64_t lResult = (int64_t) s_wMSUnit * (int64_t) wMS;
|
||||
return lResult ? lResult : 1;
|
||||
}
|
||||
|
||||
int64_t ticks_convert_ticks_to_us(int64_t lTick) {
|
||||
return lTick / (int64_t) s_wUSUnit;
|
||||
}
|
||||
|
||||
int64_t ticks_convert_us_to_ticks(uint32_t wMS) {
|
||||
int64_t lResult = (int64_t) s_wUSUnit * (int64_t) wMS;
|
||||
return lResult ? lResult : 1;
|
||||
}
|
||||
|
||||
|
||||
bool __ticks_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload) {
|
||||
if (NULL == plTimestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t lTimestamp = get_system_ticks();
|
||||
|
||||
|
||||
if (0 == *plTimestamp) {
|
||||
*plTimestamp = lPeriod;
|
||||
*plTimestamp += lTimestamp;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lTimestamp >= *plTimestamp) {
|
||||
if (bAutoReload) {
|
||||
*plTimestamp = lPeriod + lTimestamp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// Setup timer hardware.
|
||||
/// \return status (1=Success, 0=Failure)
|
||||
uint32_t EventRecorderTimerSetup(void) {
|
||||
/* doing nothing at all */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Get timer frequency.
|
||||
/// \return timer frequency in Hz
|
||||
uint32_t EventRecorderTimerGetFreq(void) {
|
||||
return ticks_port_get_system_timer_freq();
|
||||
}
|
||||
|
||||
/// Get timer count.
|
||||
/// \return timer count (32-bit)
|
||||
uint32_t EventRecorderTimerGetCount(void) {
|
||||
return get_system_ticks();
|
||||
}
|
||||
|
||||
|
||||
__WEAK
|
||||
task_cycle_info_t *get_rtos_task_cycle_info(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_task_cycle_counter(void) {
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
if (NULL == ptRootAgent) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(ptRootAgent, 0, sizeof(struct __task_cycle_info_t));
|
||||
|
||||
ptRootAgent->tList.ptInfo = &(ptRootAgent->tInfo);
|
||||
ptRootAgent->tInfo.lStart = get_system_ticks();
|
||||
ptRootAgent->wMagicWord = MAGIC_WORD_CANARY;
|
||||
}
|
||||
|
||||
bool ticks_check_task_stack_canary_safe(void) {
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
do {
|
||||
if (NULL == ptRootAgent) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((MAGIC_WORD_CANARY == ptRootAgent->wMagicWord)
|
||||
|| (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord)) {
|
||||
return true;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
task_cycle_info_t *init_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||||
do {
|
||||
if (NULL == ptInfo) {
|
||||
break;
|
||||
}
|
||||
|
||||
memset(ptInfo, 0, sizeof(task_cycle_info_t));
|
||||
|
||||
ptInfo->bEnabled = true;
|
||||
} while (0);
|
||||
|
||||
return ptInfo;
|
||||
}
|
||||
|
||||
bool enable_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||||
if (NULL == ptInfo) {
|
||||
return false;
|
||||
}
|
||||
bool bOrig;
|
||||
__IRQ_SAFE {
|
||||
bOrig = ptInfo->bEnabled;
|
||||
ptInfo->bEnabled = true;
|
||||
}
|
||||
return bOrig;
|
||||
}
|
||||
|
||||
bool disable_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||||
if (NULL == ptInfo) {
|
||||
return false;
|
||||
}
|
||||
bool bOrig;
|
||||
__IRQ_SAFE {
|
||||
bOrig = ptInfo->bEnabled;
|
||||
ptInfo->bEnabled = false;
|
||||
}
|
||||
return bOrig;
|
||||
}
|
||||
|
||||
void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus) {
|
||||
if (NULL == ptInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
ptInfo->bEnabled = bEnabledStatus;
|
||||
}
|
||||
|
||||
|
||||
task_cycle_info_agent_t *register_task_cycle_agent(task_cycle_info_t *ptInfo,
|
||||
task_cycle_info_agent_t *ptAgent) {
|
||||
__IRQ_SAFE {
|
||||
do {
|
||||
if (NULL == ptAgent || NULL == ptInfo) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
if (NULL == ptRootAgent) {
|
||||
break;
|
||||
}
|
||||
|
||||
ptRootAgent->wMagicWord = MAGIC_WORD_AGENT_LIST_VALID;
|
||||
|
||||
ptAgent->ptInfo = ptInfo;
|
||||
|
||||
// push to the stack
|
||||
do {
|
||||
// set next-list
|
||||
ptAgent->ptNext = ptRootAgent->tList.ptNext;
|
||||
ptRootAgent->tList.ptNext = ptAgent;
|
||||
|
||||
// set prev-list
|
||||
ptAgent->ptPrev = &(ptRootAgent->tList);
|
||||
if (NULL != ptAgent->ptNext) {
|
||||
ptAgent->ptNext->ptPrev = ptAgent;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
} while (0);
|
||||
}
|
||||
|
||||
return ptAgent;
|
||||
}
|
||||
|
||||
task_cycle_info_agent_t *
|
||||
unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent) {
|
||||
__IRQ_SAFE {
|
||||
do {
|
||||
if (NULL == ptAgent) {
|
||||
break;
|
||||
}
|
||||
|
||||
task_cycle_info_agent_t *ptPrev = ptAgent->ptPrev;
|
||||
if (NULL == ptPrev) {
|
||||
break; /* this should not happen */
|
||||
}
|
||||
if (ptPrev->ptNext != ptAgent) {
|
||||
// already removed
|
||||
break;
|
||||
}
|
||||
|
||||
//! remove agent from the next-list
|
||||
ptPrev->ptNext = ptAgent->ptNext;
|
||||
|
||||
if (NULL != ptAgent->ptNext) {
|
||||
// remove agent from the prev-list
|
||||
ptAgent->ptNext->ptPrev = ptPrev;
|
||||
}
|
||||
|
||||
ptAgent->ptNext = NULL;
|
||||
ptAgent->ptPrev = NULL;
|
||||
|
||||
} while (0);
|
||||
}
|
||||
|
||||
return ptAgent;
|
||||
}
|
||||
|
||||
|
||||
void __on_context_switch_in(uint32_t *pwStack) {
|
||||
struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *) pwStack;
|
||||
int64_t lTimeStamp = get_system_ticks();
|
||||
|
||||
ptRootAgent->lLastTimeStamp = lTimeStamp;
|
||||
ptRootAgent->tInfo.hwActiveCount++;
|
||||
|
||||
if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
|
||||
// update all agents
|
||||
task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
|
||||
while (NULL != ptAgent) {
|
||||
if (NULL != ptAgent->ptInfo) {
|
||||
if (ptAgent->ptInfo->bEnabled) {
|
||||
ptAgent->ptInfo->hwActiveCount++;
|
||||
}
|
||||
}
|
||||
ptAgent = ptAgent->ptNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __on_context_switch_out(uint32_t *pwStack) {
|
||||
struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *) pwStack;
|
||||
int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
|
||||
|
||||
ptRootAgent->tInfo.nUsedRecent = lCycleUsed;
|
||||
ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
|
||||
|
||||
if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
|
||||
// update all agents
|
||||
task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
|
||||
while (NULL != ptAgent) {
|
||||
if (NULL != ptAgent->ptInfo) {
|
||||
if (ptAgent->ptInfo->bEnabled) {
|
||||
ptAgent->ptInfo->nUsedRecent = lCycleUsed;
|
||||
ptAgent->ptInfo->lUsedTotal += lCycleUsed;
|
||||
}
|
||||
}
|
||||
ptAgent = ptAgent->ptNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void __start_task_cycle_counter(task_cycle_info_t *ptInfo) {
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
if (NULL == ptRootAgent) {
|
||||
return;
|
||||
}
|
||||
|
||||
__IRQ_SAFE {
|
||||
ptRootAgent->lLastTimeStamp = get_system_ticks();
|
||||
ptRootAgent->tInfo.lUsedTotal = 0;
|
||||
|
||||
if (NULL != ptInfo) {
|
||||
ptInfo->lUsedTotal = 0;
|
||||
ptInfo->bEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo) {
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
if (NULL == ptRootAgent) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t lCycles = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
|
||||
ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
|
||||
|
||||
if (NULL != ptInfo) {
|
||||
if (ptInfo->bEnabled) {
|
||||
ptInfo->nUsedRecent = lCycleUsed;
|
||||
ptInfo->lUsedTotal += lCycleUsed;
|
||||
ptInfo->bEnabled = false;
|
||||
}
|
||||
|
||||
lCycles = ptInfo->lUsedTotal;
|
||||
} else {
|
||||
lCycles = ptRootAgent->tInfo.lUsedTotal;
|
||||
}
|
||||
}
|
||||
|
||||
return lCycles;
|
||||
}
|
Reference in New Issue
Block a user