mirror of
https://github.com/GorgonMeducer/perf_counter.git
synced 2025-01-31 19:33:04 +08:00
Merge branch 'developing' into CMSIS-Pack
This commit is contained in:
commit
d037eac004
@ -6,7 +6,7 @@
|
||||
<description>A dedicated performance counter for the Cortex-M Systick. It shares the SysTick with users' original SysTick function without interfering with it. This library will bring new functionalities, such as performance counter, APIs for delay, clock() defined in time.h etc.</description>
|
||||
<url>https://raw.githubusercontent.com/GorgonMeducer/perf_counter/CMSIS-Pack/cmsis-pack/</url>
|
||||
<supportContact>https://github.com/GorgonMeducer/perf_counter/issues</supportContact>
|
||||
<license>lib/LICENSE</license>
|
||||
<license>LICENSE</license>
|
||||
<!-- optional license file -->
|
||||
<!--
|
||||
<license>
|
||||
@ -175,6 +175,17 @@
|
||||
<require Cclass="Utilities" Cgroup="perf_counter" Csub="Core"/>
|
||||
</condition>
|
||||
|
||||
<condition id="PMU Devices">
|
||||
<description>Require Perf_Counter Core</description>
|
||||
<require condition="perf_counter" />
|
||||
<accept Dcore="ARMV8MML"/>
|
||||
<accept Dcore="ARMV81MML"/>
|
||||
<accept Dcore="Cortex-M33"/>
|
||||
<accept Dcore="Cortex-M35P"/>
|
||||
<accept Dcore="Cortex-M55"/>
|
||||
<accept Dcore="Cortex-M85"/>
|
||||
</condition>
|
||||
|
||||
<condition id="Cortex-M Arm GCC">
|
||||
<description>Compile Cortex-M Processors with GNU Tools for Arm Embedded Processors.</description>
|
||||
<require condition="Arm GCC"/>
|
||||
@ -257,29 +268,12 @@
|
||||
-->
|
||||
|
||||
<components>
|
||||
<component Cclass="Utilities" Cversion="2.2.5" Cgroup="perf_counter" Csub="Core" Cvariant="Library" condition="CMSIS-CORE">
|
||||
<description>A dedicated performance counter for Cortex-M systick.</description>
|
||||
<files>
|
||||
<file category="header" name="perf_counter.h"/>
|
||||
<file category="library" name="lib/perf_counter.lib" condition="Cortex-M Arm Compiler"/>
|
||||
<file category="library" name="lib/libperf_counter_gcc.a" condition="Cortex-M Arm GCC"/>
|
||||
</files>
|
||||
<RTE_Components_h>
|
||||
|
||||
#define __PERF_COUNTER__ 1
|
||||
</RTE_Components_h>
|
||||
|
||||
|
||||
<Pre_Include_Global_h>
|
||||
|
||||
#define __PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__ 1
|
||||
</Pre_Include_Global_h>
|
||||
</component>
|
||||
<component Cclass="Utilities" Cversion="2.2.5" Cgroup="perf_counter" Csub="Core" Cvariant="Source" isDefaultVariant="true" condition="CMSIS-CORE">
|
||||
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="Core" Cvariant="Source" isDefaultVariant="true" condition="CMSIS-CORE">
|
||||
<description>A dedicated performance counter for Cortex-M systick.</description>
|
||||
<files>
|
||||
<file category="header" name="perf_counter.h"/>
|
||||
<file category="sourceC" name="perf_counter.c" />
|
||||
<file category="sourceC" name="perfc_port_default.c" />
|
||||
<file category="sourceAsm" name="systick_wrapper_ual.s" condition="Previous Generation Cortex-M Arm Compiler CMSIS-CORE"/>
|
||||
<file category="sourceAsm" name="systick_wrapper_gcc.S" condition="Cortex-M Arm GCC CMSIS-CORE"/>
|
||||
<file category="sourceAsm" name="systick_wrapper_gnu.s" condition="Armv8-M Arm Compiler CMSIS-CORE"/>
|
||||
@ -295,11 +289,12 @@
|
||||
</Pre_Include_Global_h>
|
||||
</component>
|
||||
|
||||
<component Cclass="Utilities" Cversion="2.2.5" Cgroup="perf_counter" Csub="Core" Cvariant="SourceNoWrapper" isDefaultVariant="false" condition="CMSIS-CORE">
|
||||
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="Core" Cvariant="SourceNoWrapper" isDefaultVariant="false" condition="CMSIS-CORE">
|
||||
<description>A dedicated performance counter for Cortex-M systick.</description>
|
||||
<files>
|
||||
<file category="header" name="perf_counter.h"/>
|
||||
<file category="sourceC" name="perf_counter.c" />
|
||||
<file category="sourceC" name="perfc_port_default.c" />
|
||||
</files>
|
||||
<RTE_Components_h>
|
||||
|
||||
@ -307,13 +302,53 @@
|
||||
</RTE_Components_h>
|
||||
</component>
|
||||
|
||||
<component Cclass="Utilities" Cversion="1.0.2" Cgroup="perf_counter" Csub="Porting" Cvariant="User Defined" isDefaultVariant="false" condition="perf_counter">
|
||||
<description>A user define system timer</description>
|
||||
<files>
|
||||
<file category="sourceC" name="template/perfc_port_user.c" attr="config" version="1.0.2"/>
|
||||
<file category="header" name="template/perfc_port_user.h" attr="config" version="1.0.2"/>
|
||||
</files>
|
||||
<RTE_Components_h>
|
||||
|
||||
<component Cclass="Utilities" Cgroup="perf_counter" Csub="Benchmark" Cvariant="Coremark" Cversion="1.1.2" condition="perf_counter">
|
||||
#define __RTE_PERFC_PORTING_USER_DEFINED__ 1
|
||||
</RTE_Components_h>
|
||||
|
||||
<Pre_Include_Global_h>
|
||||
|
||||
#define __PERFC_USE_USER_CUSTOM_PORTING__ 1
|
||||
#define __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__ 1
|
||||
#define __PERFC_CFG_PORTING_INCLUDE__ "perfc_port_user.h"
|
||||
|
||||
</Pre_Include_Global_h>
|
||||
</component>
|
||||
|
||||
<component Cclass="Utilities" Cversion="1.1.0" Cgroup="perf_counter" Csub="Porting" Cvariant="PMU" isDefaultVariant="true" condition="PMU Devices">
|
||||
<description>Using the Performande Monitor Unit</description>
|
||||
<files>
|
||||
<file category="sourceC" name="perfc_port_pmu.c"/>
|
||||
<file category="header" name="perfc_port_pmu.h"/>
|
||||
</files>
|
||||
<RTE_Components_h>
|
||||
|
||||
#define __RTE_PERFC_PORTING_PMU__ 1
|
||||
</RTE_Components_h>
|
||||
|
||||
<Pre_Include_Global_h>
|
||||
|
||||
#define __PERFC_USE_PMU_PORTING__ 1
|
||||
#define __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__ 1
|
||||
#define __PERFC_CFG_PORTING_INCLUDE__ "perfc_port_pmu.h"
|
||||
|
||||
</Pre_Include_Global_h>
|
||||
</component>
|
||||
|
||||
|
||||
<component Cclass="Utilities" Cgroup="perf_counter" Csub="Benchmark" Cvariant="Coremark" Cversion="1.1.3" condition="perf_counter">
|
||||
<description>Coremark</description>
|
||||
<files>
|
||||
<file category="sourceC" name="benchmark/coremark_port/core_main.c"/>
|
||||
<file category="sourceC" name="benchmark/coremark_port/core_portme.c" attr="config" version="1.1.2" />
|
||||
<file category="header" name="benchmark/coremark_port/core_portme.h" attr="config" version="1.1.2" />
|
||||
<file category="sourceC" name="benchmark/coremark_port/core_portme.c" attr="config" version="1.1.3" />
|
||||
<file category="header" name="benchmark/coremark_port/core_portme.h" attr="config" version="1.1.3" />
|
||||
|
||||
<file category="include" name="benchmark/coremark/" />
|
||||
<file category="sourceC" name="benchmark/coremark/core_list_join.c"/>
|
||||
@ -331,7 +366,7 @@
|
||||
</Pre_Include_Global_h>
|
||||
</component>
|
||||
|
||||
<component Cclass="Utilities" Cversion="2.2.3" Cgroup="perf_counter" Csub="RTX5 Patch" condition="RTX5 Patch">
|
||||
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="RTX5 Patch" condition="RTX5 Patch">
|
||||
<description>A Patch for RTX5</description>
|
||||
<files>
|
||||
<file category="source" name="os/perf_os_patch_rtx5.c"/>
|
||||
@ -343,7 +378,7 @@
|
||||
</Pre_Include_Global_h>
|
||||
</component>
|
||||
|
||||
<component Cclass="Utilities" Cversion="2.2.3" Cgroup="perf_counter" Csub="FreeRTOS Patch" condition="perf_counter">
|
||||
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="FreeRTOS Patch" condition="perf_counter">
|
||||
<description>A Patch for FreeRTOS</description>
|
||||
<files>
|
||||
<file category="sourceC" name="os/perf_os_patch_freertos.c"/>
|
||||
@ -366,7 +401,7 @@ extern void __freertos_evr_on_task_switched_in(void *ptTCB, unsigned int uxTopPr
|
||||
</Pre_Include_Global_h>
|
||||
</component>
|
||||
|
||||
<component Cclass="Utilities" Cversion="2.2.3" Cgroup="perf_counter" Csub="RT-Thread Patch" condition="perf_counter">
|
||||
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="RT-Thread Patch" condition="perf_counter">
|
||||
<description>A Patch for RT-Thread</description>
|
||||
<files>
|
||||
<file category="sourceC" name="os/perf_os_patch_rt_thread.c"/>
|
||||
@ -384,7 +419,7 @@ extern void __rt_thread_scheduler_hook(struct rt_thread *from, struct rt_thread
|
||||
</Pre_Include_Global_h>
|
||||
</component>
|
||||
|
||||
<component Cclass="Utilities" Cversion="2.2.3" Cgroup="perf_counter" Csub="ThreadX Patch" condition="perf_counter">
|
||||
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="ThreadX Patch" condition="perf_counter">
|
||||
<description>A Patch for ThreadX</description>
|
||||
<files>
|
||||
<file category="sourceC" name="os/perf_os_patch_threadx.c"/>
|
||||
|
155
README.md
155
README.md
@ -1,4 +1,4 @@
|
||||
# perf_counter (v2.2.4)
|
||||
# perf_counter (v2.3.0)
|
||||
A dedicated performance counter for Cortex-M Systick. It shares the SysTick with users' original SysTick function(s) without interfering with it. This library will bring new functionalities, such as performance counter,` delay_us` and `clock()` service defined in `time.h`.
|
||||
|
||||
### Features:
|
||||
@ -10,10 +10,15 @@ A dedicated performance counter for Cortex-M Systick. It shares the SysTick with
|
||||
- Measures **RAW / True** cycles used for specified code segment inside a thread, **i.e. scheduling cost are removed**.
|
||||
- Measure **RAW/True** cycles used for a data-process-path across multiple threads.
|
||||
- **Easy to use**
|
||||
- Helper macros: `__cycleof__()` , `__super_loop_monitor__()` etc.
|
||||
- Helper macros: `__cycleof__()` , `__super_loop_monitor__()` , `__cpu_usage__()`, `__cpu_perf__()` etc.
|
||||
- Helper functions: `start_cycle_counter()`, `stop_cycle_counter()` etc.
|
||||
- **Support ALL Cortex-M processors**
|
||||
- Including **Cortex-M85** and Star-MC1
|
||||
- Enable a broader processor architecture support
|
||||
- **Support ALL Cortex-M processors**
|
||||
- SysTick
|
||||
- **[new]**Performance Monitor Unit (PMU)
|
||||
|
||||
- **[new]**Easy to port to a different architecture with a porting template
|
||||
|
||||
- **Provide Free Services**
|
||||
- Do **NOT** interfer with existing SysTick based applications
|
||||
- **Support ALL arm compilers**
|
||||
@ -26,13 +31,12 @@ A dedicated performance counter for Cortex-M Systick. It shares the SysTick with
|
||||
- **CMSIS-Pack is available**
|
||||
- **RT-Thread package is avaialble**
|
||||
- **Time based services**
|
||||
- `delay_us()` and `delay_ms()`
|
||||
- **[new]**`delay_us()` and `delay_ms()` with **64bit return value**.
|
||||
- Provides Timestamp services via `get_system_ticks()`, `get_system_us` and `get_system_ms()`.
|
||||
- **Support both RTOS and bare-metal environments**
|
||||
- Support SysTick Reconfiguration
|
||||
- Support changing System Frequency
|
||||
- **[new]** Support stack-overflow detection in RTOS environment via `perfc_check_task_stack_canary_safe()`
|
||||
|
||||
- Support stack-overflow detection in RTOS environment via `perfc_check_task_stack_canary_safe()`
|
||||
- **Utilities for C language enhancement**
|
||||
- Macros to detect compilers, e.g. `__IS_COMPILER_ARM_COMPILER_6__`, `__IS_COMPILER_LLVM__` etc.
|
||||
- Macro to create atomicity for specified code block, i.e. `__IRQ_SAFE{...}`
|
||||
@ -60,7 +64,7 @@ __cycleof__(<Description String for the target>, [User Code, see ref 1]) {
|
||||
}
|
||||
```
|
||||
|
||||
Here, [**ref 1**] is a small user code to read the measurement result via a local variable `__cycle_count__` for perl lovers, you can also use "`_`" to read the result. This User Code is optional. If you don't put anything here, the measured result will be shown with a `printf()`.
|
||||
Here, [**ref 1**] is a small user code to read the measurement result via a local variable `__cycle_count__` . This User Code is optional. If you don't put anything here, the measured result will be shown with a `__perf_counter_printf__`.
|
||||
|
||||
#### **Example 1:** Simple measurement with printf
|
||||
|
||||
@ -99,9 +103,123 @@ The result is read out from `__cycle_count__`and used in other place:
|
||||
|
||||
![image-20220509004714845](./documents/pictures/__cycleof___output_non_printf)
|
||||
|
||||
### 1.2 Performance Analysis
|
||||
|
||||
#### 1.2.1 CPU Usage
|
||||
|
||||
For both bare-metal and OS environment, you can measure the CPU Usage with macro `__cpu_usage__()` for a given code segment as long as it is executed repeatedly.
|
||||
|
||||
**Syntax**
|
||||
|
||||
```c
|
||||
__cycleof__(<Iteration Count before getting an average result>, [User Code, see ref 1]) {
|
||||
//! target code segment of measurement
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Here, [**ref 1**] is a small user code to read the measurement result via a local variable `__usage__`. This User Code is optional. If you don't put anything here, the measured result will be shown with a `__perf_counter_printf__`.
|
||||
|
||||
##### **Example 1: the following code will show 30% of CPU Usage:**
|
||||
|
||||
```c
|
||||
void main(void)
|
||||
{
|
||||
...
|
||||
while (1) {
|
||||
__cpu_usage__(10) {
|
||||
delay_us(30000);
|
||||
}
|
||||
delay_us(70000);
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
##### Example 2: Read measurement result via `__usage__`
|
||||
|
||||
```c
|
||||
void main(void)
|
||||
{
|
||||
...
|
||||
while (1) {
|
||||
|
||||
float fUsage = 0.0f;
|
||||
__cpu_usage__(10, {
|
||||
fUsage = __usage__; /*< "__usage__" stores the result */
|
||||
}) {
|
||||
delay_us(30000);
|
||||
}
|
||||
printf("task 1 cpu usage %3.2f %%\r\n", (double)fUsage);
|
||||
|
||||
delay_us(70000);
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
NOTE: The `__usage__` stores the percentage information.
|
||||
|
||||
|
||||
### 1.2 Timestamp
|
||||
|
||||
#### 1.2.2 Cycle per Instruction and L1 DCache Miss Rate
|
||||
|
||||
For **Armv8.1-m** processors that implement the **PMU**, it is easy to measure the **CPI** (Cycle per Instruction) and **L1 DCache miss rate** with the macro `__cpu_perf__()`.
|
||||
|
||||
**Syntax**:
|
||||
|
||||
```c
|
||||
__cpu_perf__(<Description String for the target>, [User Code, see ref 1]) {
|
||||
//! target code segment of measurement
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Here, [**ref 1**] is a small user code to read the measurement result via a local **struct** variable `__PERF_INFO__` . This User Code is optional. If you don't put anything here, the measured result will be shown with a `__perf_counter_printf__`. The prototype of the `__PERF_INFO__` is shown below:
|
||||
|
||||
```c
|
||||
struct {
|
||||
uint64_t dwNoInstr; /* number of instruction executed */
|
||||
uint64_t dwNoMemAccess; /* number of memory access */
|
||||
uint64_t dwNoL1DCacheRefill; /* number of L1 DCache Refill */
|
||||
int64_t lCycles; /* number of CPU cycles */
|
||||
uint32_t wInstrCalib;
|
||||
uint32_t wMemAccessCalib;
|
||||
float fCPI; /* Cycle per Instruction */
|
||||
float fDCacheMissRate; /* L1 DCache miss rate in percentage */
|
||||
} __PERF_INFO__;
|
||||
```
|
||||
|
||||
For example, when insert user code, you can read CPI from `__PERF_INFO__.fCPI`.
|
||||
|
||||
**Example 1: measure the Coremark**
|
||||
|
||||
```c
|
||||
void main(void)
|
||||
{
|
||||
init_cycle_counter(false);
|
||||
|
||||
printf("Run coremark\r\n");
|
||||
|
||||
#ifdef __PERF_COUNTER_COREMARK__
|
||||
__cpu_perf__("Coremark") {
|
||||
coremark_main();
|
||||
}
|
||||
#endif
|
||||
|
||||
while(1) {
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The result might look like the following:
|
||||
|
||||
![](./documents/pictures/__cpu_perf__output.png)
|
||||
|
||||
|
||||
|
||||
### 1.3 Timestamp
|
||||
|
||||
You can get the system timestamp (since the initialization of perf_counter service) via function `get_system_ticks()` and `get_system_ms()`.
|
||||
|
||||
@ -172,7 +290,7 @@ This example shows how to use the delta value of `get_system_ticks()` to measure
|
||||
|
||||
|
||||
|
||||
### 1.3 Timer Services
|
||||
### 1.4 Timer Services
|
||||
|
||||
perf_counter provides the basic timer services for delaying a given period of time and polling-for-timeout. For example:
|
||||
|
||||
@ -193,7 +311,7 @@ while(1) {
|
||||
|
||||
|
||||
|
||||
### 1.4 Work with EventRecorder in MDK
|
||||
### 1.5 Work with EventRecorder in MDK
|
||||
|
||||
If you are using EventRecorder in MDK, once you deployed the `perf_counter`, it will provide the timer service for EventRecorder by implenting the following functions: `EventRecorderTimerSetup()`, `EventRecorderTimerGetFreq()` and `EventRecorderTimerGetCount()`.
|
||||
|
||||
@ -213,9 +331,9 @@ Please set the macro `EVENT_TIMESTAMP_SOURCE` to `3` to suppress it.
|
||||
|
||||
|
||||
|
||||
### 1.5 On System Environment Changing
|
||||
### 1.6 On System Environment Changing
|
||||
|
||||
#### 1.5.1 System Frequency Changing
|
||||
#### 1.6.1 System Frequency Changing
|
||||
|
||||
If you want to change the System Frequency, **after** the change, make sure:
|
||||
|
||||
@ -225,7 +343,7 @@ If you want to change the System Frequency, **after** the change, make sure:
|
||||
|
||||
|
||||
|
||||
#### 1.5.2 Reconfigure the SysTick
|
||||
#### 1.6.2 Reconfigure the SysTick
|
||||
|
||||
Some systems (e.g. FreeRTOS) might reconfigure the systick timer to fulfil the requirement of their feature. To support this:
|
||||
|
||||
@ -250,7 +368,10 @@ git clone https://github.com/GorgonMeducer/perf_counter.git
|
||||
```
|
||||
|
||||
2. Add including path for `perf_counter` folder
|
||||
3. Add `perf_counter.c` to your compilation
|
||||
3. Add `perf_counter.c` to your compilation.
|
||||
|
||||
> **NOTE**: Please do **NOT** add any assembly source files of this `perf_counter` library to your compilation, i.e. `systick_wrapper_gcc.S`, `systick_wrapper_gnu.s` or `systick_wrapper_ual.s`.
|
||||
|
||||
4. Include `perf_counter.h` in corresponding c source file:
|
||||
|
||||
```c
|
||||
@ -259,13 +380,13 @@ git clone https://github.com/GorgonMeducer/perf_counter.git
|
||||
|
||||
|
||||
5. Make sure your system contains the CMSIS (with a version 5.7.0 or above) as `perf_counter.h` includes `cmsis_compiler.h`.
|
||||
6. Call the function `user_code_insert_to_systick_handler()` in your `SysTick_Handler()`
|
||||
6. Call the function `perfc_port_insert_to_system_timer_insert_ovf_handler()` in your `SysTick_Handler()`
|
||||
|
||||
```c
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
...
|
||||
user_code_insert_to_systick_handler();
|
||||
perfc_port_insert_to_system_timer_insert_ovf_handler();
|
||||
...
|
||||
}
|
||||
```
|
||||
|
@ -22,6 +22,15 @@ Original Author: Shay Gal-on
|
||||
*/
|
||||
#include "coremark.h"
|
||||
|
||||
#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 "-Wsign-conversion"
|
||||
# pragma clang diagnostic ignored "-Wimplicit-int-conversion"
|
||||
#endif
|
||||
|
||||
|
||||
/* Function: iterate
|
||||
Run the benchmark for a specified number of iterations.
|
||||
|
||||
@ -104,6 +113,9 @@ char *mem_name[3] = { "Static", "Heap", "Stack" };
|
||||
|
||||
*/
|
||||
|
||||
__attribute__((used))
|
||||
volatile double dfCoremarkScore = 0.0f;
|
||||
|
||||
#if MAIN_HAS_NOARGC
|
||||
MAIN_RETURN_TYPE
|
||||
coremark_main(void)
|
||||
@ -409,6 +421,8 @@ for (i = 0; i < MULTITHREAD; i++)
|
||||
double dfResult = (double)((double)1000000
|
||||
* (double)default_num_contexts*results[0].iterations
|
||||
/ (double)total_time);
|
||||
dfCoremarkScore = dfResult;
|
||||
|
||||
ee_printf( "CoreMark 1.0 : %f / %s %s",
|
||||
dfResult,
|
||||
COMPILER_VERSION,
|
||||
|
BIN
documents/pictures/__cpu_perf__output.png
Normal file
BIN
documents/pictures/__cpu_perf__output.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
80
example/RTE/Device/ARMCM0/ARMCM0_ac6.sct
Normal file
80
example/RTE/Device/ARMCM0/ARMCM0_ac6.sct
Normal file
@ -0,0 +1,80 @@
|
||||
#! armclang -E --target=arm-arm-none-eabi -mcpu=cortex-m0 -xc
|
||||
; command above MUST be in first line (no comment above!)
|
||||
|
||||
/*
|
||||
;-------- <<< Use Configuration Wizard in Context Menu >>> -------------------
|
||||
*/
|
||||
|
||||
/*--------------------- Flash Configuration ----------------------------------
|
||||
; <h> Flash Configuration
|
||||
; <o0> Flash Base Address <0x0-0xFFFFFFFF:8>
|
||||
; <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||
; </h>
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define __ROM_BASE 0x00000000
|
||||
#define __ROM_SIZE 0x00080000
|
||||
|
||||
/*--------------------- Embedded RAM Configuration ---------------------------
|
||||
; <h> RAM Configuration
|
||||
; <o0> RAM Base Address <0x0-0xFFFFFFFF:8>
|
||||
; <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||
; </h>
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define __RAM_BASE 0x20000000
|
||||
#define __RAM_SIZE 0x00040000
|
||||
|
||||
/*--------------------- Stack / Heap Configuration ---------------------------
|
||||
; <h> Stack / Heap Configuration
|
||||
; <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||
; <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||
; </h>
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define __STACK_SIZE 0x00000200
|
||||
#define __HEAP_SIZE 0x00000C00
|
||||
|
||||
/*
|
||||
;------------- <<< end of configuration section >>> ---------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
User Stack & Heap boundary definition
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define __STACK_TOP (__RAM_BASE + __RAM_SIZE) /* starts at end of RAM */
|
||||
#define __HEAP_BASE (AlignExpr(+0, 8)) /* starts after RW_RAM section, 8 byte aligned */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Scatter File Definitions definition
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define __RO_BASE __ROM_BASE
|
||||
#define __RO_SIZE __ROM_SIZE
|
||||
|
||||
#define __RW_BASE __RAM_BASE
|
||||
#define __RW_SIZE (__RAM_SIZE - __STACK_SIZE - __HEAP_SIZE)
|
||||
|
||||
|
||||
LR_ROM __RO_BASE __RO_SIZE { ; load region size_region
|
||||
ER_ROM __RO_BASE __RO_SIZE { ; load address = execution address
|
||||
*.o (RESET, +First)
|
||||
*(InRoot$$Sections)
|
||||
.ANY (+RO)
|
||||
.ANY (+XO)
|
||||
}
|
||||
|
||||
RW_NOINIT __RW_BASE UNINIT __RW_SIZE {
|
||||
*(.bss.noinit)
|
||||
}
|
||||
|
||||
RW_RAM AlignExpr(+0, 8) (__RW_SIZE - AlignExpr(ImageLength(RW_NOINIT), 8)) {
|
||||
*(+RW +ZI)
|
||||
}
|
||||
|
||||
#if __HEAP_SIZE > 0
|
||||
ARM_LIB_HEAP __HEAP_BASE EMPTY __HEAP_SIZE { ; Reserve empty region for heap
|
||||
}
|
||||
#endif
|
||||
|
||||
ARM_LIB_STACK __STACK_TOP EMPTY -__STACK_SIZE { ; Reserve empty region for stack
|
||||
}
|
||||
}
|
146
example/RTE/Device/ARMCM0/startup_ARMCM0.c
Normal file
146
example/RTE/Device/ARMCM0/startup_ARMCM0.c
Normal file
@ -0,0 +1,146 @@
|
||||
/******************************************************************************
|
||||
* @file startup_ARMCM0.c
|
||||
* @brief CMSIS-Core(M) Device Startup File for a Cortex-M0 Device
|
||||
* @version V2.0.3
|
||||
* @date 31. March 2020
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Copyright (c) 2009-2020 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined (ARMCM0)
|
||||
#include "ARMCM0.h"
|
||||
#else
|
||||
#error device not specified!
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
External References
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern uint32_t __INITIAL_SP;
|
||||
|
||||
extern __NO_RETURN void __PROGRAM_START(void);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Internal References
|
||||
*----------------------------------------------------------------------------*/
|
||||
__NO_RETURN void Reset_Handler (void);
|
||||
void Default_Handler(void);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Exception / Interrupt Handler
|
||||
*----------------------------------------------------------------------------*/
|
||||
/* Exceptions */
|
||||
void NMI_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void HardFault_Handler (void) __attribute__ ((weak));
|
||||
void SVC_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void PendSV_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void SysTick_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
|
||||
void Interrupt0_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt1_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt2_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt3_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt4_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt5_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt6_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt7_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt8_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
void Interrupt9_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Exception / Interrupt Vector table
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined ( __GNUC__ )
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
#endif
|
||||
|
||||
extern const VECTOR_TABLE_Type __VECTOR_TABLE[48];
|
||||
const VECTOR_TABLE_Type __VECTOR_TABLE[48] __VECTOR_TABLE_ATTRIBUTE = {
|
||||
(VECTOR_TABLE_Type)(&__INITIAL_SP), /* Initial Stack Pointer */
|
||||
Reset_Handler, /* Reset Handler */
|
||||
NMI_Handler, /* -14 NMI Handler */
|
||||
HardFault_Handler, /* -13 Hard Fault Handler */
|
||||
0, /* Reserved */
|
||||
0, /* Reserved */
|
||||
0, /* Reserved */
|
||||
0, /* Reserved */
|
||||
0, /* Reserved */
|
||||
0, /* Reserved */
|
||||
0, /* Reserved */
|
||||
SVC_Handler, /* -5 SVCall Handler */
|
||||
0, /* Reserved */
|
||||
0, /* Reserved */
|
||||
PendSV_Handler, /* -2 PendSV Handler */
|
||||
SysTick_Handler, /* -1 SysTick Handler */
|
||||
|
||||
/* Interrupts */
|
||||
Interrupt0_Handler, /* 0 Interrupt 0 */
|
||||
Interrupt1_Handler, /* 1 Interrupt 1 */
|
||||
Interrupt2_Handler, /* 2 Interrupt 2 */
|
||||
Interrupt3_Handler, /* 3 Interrupt 3 */
|
||||
Interrupt4_Handler, /* 4 Interrupt 4 */
|
||||
Interrupt5_Handler, /* 5 Interrupt 5 */
|
||||
Interrupt6_Handler, /* 6 Interrupt 6 */
|
||||
Interrupt7_Handler, /* 7 Interrupt 7 */
|
||||
Interrupt8_Handler, /* 8 Interrupt 8 */
|
||||
Interrupt9_Handler /* 9 Interrupt 9 */
|
||||
/* Interrupts 10..31 are left out */
|
||||
};
|
||||
|
||||
#if defined ( __GNUC__ )
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Reset Handler called on controller reset
|
||||
*----------------------------------------------------------------------------*/
|
||||
__NO_RETURN void Reset_Handler(void)
|
||||
{
|
||||
SystemInit(); /* CMSIS System Initialization */
|
||||
__PROGRAM_START(); /* Enter PreMain (C library entry point) */
|
||||
}
|
||||
|
||||
|
||||
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-noreturn"
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Hard Fault Handler
|
||||
*----------------------------------------------------------------------------*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
while(1);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Default Handler for Exceptions / Interrupts
|
||||
*----------------------------------------------------------------------------*/
|
||||
void Default_Handler(void)
|
||||
{
|
||||
while(1);
|
||||
}
|
||||
|
||||
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
<Header>### uVision Project, (C) Keil Software</Header>
|
||||
|
||||
<WorkspaceName>WorkSpace</WorkspaceName>
|
||||
<WorkspaceName>Y:\Work\git\perf_counter\example\example.uvmpw</WorkspaceName>
|
||||
|
||||
<project>
|
||||
<PathAndName>.\example.uvprojx</PathAndName>
|
||||
@ -15,7 +15,6 @@
|
||||
|
||||
<project>
|
||||
<PathAndName>.\gcc_example.uvprojx</PathAndName>
|
||||
<NodeIsExpanded>1</NodeIsExpanded>
|
||||
</project>
|
||||
|
||||
</ProjectWorkspace>
|
||||
|
@ -75,7 +75,7 @@
|
||||
<OPTFL>
|
||||
<tvExp>1</tvExp>
|
||||
<tvExpOptDlg>0</tvExpOptDlg>
|
||||
<IsCurrentTarget>0</IsCurrentTarget>
|
||||
<IsCurrentTarget>1</IsCurrentTarget>
|
||||
</OPTFL>
|
||||
<CpuCode>7</CpuCode>
|
||||
<DebugOpt>
|
||||
@ -130,7 +130,7 @@
|
||||
<SetRegEntry>
|
||||
<Number>0</Number>
|
||||
<Key>DbgFM</Key>
|
||||
<Name>-I -S"System Generator:FVP_MPS2_Cortex_M0_MDK" -L"armcortexm0ct" -O4102 -C0 -MC".\FVP\MPS2_Cortex-M\FVP_MPS2_Cortex-M0_MDK.exe" -MF -PF -MA</Name>
|
||||
<Name>-I -S"System Generator:cpu_core" -L"armcortexm0ct" -O4102 -C0 -MC".\VHT\VHT_MPS2_Cortex-M0.exe" -MF -PF -MA</Name>
|
||||
</SetRegEntry>
|
||||
<SetRegEntry>
|
||||
<Number>0</Number>
|
||||
@ -195,7 +195,7 @@
|
||||
</MemoryWindow4>
|
||||
<ScvdPack>
|
||||
<Filename>C:\Users\gabriel\AppData\Local\Arm\Packs\Keil\ARM_Compiler\1.7.2\EventRecorder.scvd</Filename>
|
||||
<Type>Keil.ARM_Compiler.1.7.2</Type>
|
||||
<Type>Keil::ARM_Compiler@1.7.2</Type>
|
||||
<SubType>1</SubType>
|
||||
</ScvdPack>
|
||||
<Tracepoint>
|
||||
@ -204,7 +204,7 @@
|
||||
<DebugFlag>
|
||||
<trace>0</trace>
|
||||
<periodic>1</periodic>
|
||||
<aLwin>0</aLwin>
|
||||
<aLwin>1</aLwin>
|
||||
<aCover>0</aCover>
|
||||
<aSer1>0</aSer1>
|
||||
<aSer2>0</aSer2>
|
||||
@ -297,7 +297,7 @@
|
||||
<OPTFL>
|
||||
<tvExp>1</tvExp>
|
||||
<tvExpOptDlg>0</tvExpOptDlg>
|
||||
<IsCurrentTarget>1</IsCurrentTarget>
|
||||
<IsCurrentTarget>0</IsCurrentTarget>
|
||||
</OPTFL>
|
||||
<CpuCode>7</CpuCode>
|
||||
<DebugOpt>
|
||||
@ -768,12 +768,24 @@
|
||||
<File>
|
||||
<GroupNumber>2</GroupNumber>
|
||||
<FileNumber>7</FileNumber>
|
||||
<FileType>4</FileType>
|
||||
<FileType>1</FileType>
|
||||
<tvExp>0</tvExp>
|
||||
<tvExpOptDlg>0</tvExpOptDlg>
|
||||
<bDave2>0</bDave2>
|
||||
<PathWithFileName>..\lib\perf_counter.lib</PathWithFileName>
|
||||
<FilenameWithoutPath>perf_counter.lib</FilenameWithoutPath>
|
||||
<PathWithFileName>..\perfc_port_default.c</PathWithFileName>
|
||||
<FilenameWithoutPath>perfc_port_default.c</FilenameWithoutPath>
|
||||
<RteFlg>0</RteFlg>
|
||||
<bShared>0</bShared>
|
||||
</File>
|
||||
<File>
|
||||
<GroupNumber>2</GroupNumber>
|
||||
<FileNumber>8</FileNumber>
|
||||
<FileType>5</FileType>
|
||||
<tvExp>0</tvExp>
|
||||
<tvExpOptDlg>0</tvExpOptDlg>
|
||||
<bDave2>0</bDave2>
|
||||
<PathWithFileName>..\perfc_port_default.h</PathWithFileName>
|
||||
<FilenameWithoutPath>perfc_port_default.h</FilenameWithoutPath>
|
||||
<RteFlg>0</RteFlg>
|
||||
<bShared>0</bShared>
|
||||
</File>
|
||||
|
@ -10,7 +10,7 @@
|
||||
<TargetName>example_arm_compiler_6</TargetName>
|
||||
<ToolsetNumber>0x4</ToolsetNumber>
|
||||
<ToolsetName>ARM-ADS</ToolsetName>
|
||||
<pCCUsed>6210000::V6.21::.\ArmCompilerforEmbedded6.21</pCCUsed>
|
||||
<pCCUsed>6210000::V6.21::ARMCLANG</pCCUsed>
|
||||
<uAC6>1</uAC6>
|
||||
<TargetOption>
|
||||
<TargetCommonOption>
|
||||
@ -408,57 +408,6 @@
|
||||
<FileName>perf_counter.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\perf_counter.c</FilePath>
|
||||
<FileOption>
|
||||
<CommonProperty>
|
||||
<UseCPPCompiler>2</UseCPPCompiler>
|
||||
<RVCTCodeConst>0</RVCTCodeConst>
|
||||
<RVCTZI>0</RVCTZI>
|
||||
<RVCTOtherData>0</RVCTOtherData>
|
||||
<ModuleSelection>0</ModuleSelection>
|
||||
<IncludeInBuild>0</IncludeInBuild>
|
||||
<AlwaysBuild>2</AlwaysBuild>
|
||||
<GenerateAssemblyFile>2</GenerateAssemblyFile>
|
||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||
<PublicsOnly>2</PublicsOnly>
|
||||
<StopOnExitCode>11</StopOnExitCode>
|
||||
<CustomArgument></CustomArgument>
|
||||
<IncludeLibraryModules></IncludeLibraryModules>
|
||||
<ComprImg>1</ComprImg>
|
||||
</CommonProperty>
|
||||
<FileArmAds>
|
||||
<Cads>
|
||||
<interw>2</interw>
|
||||
<Optim>0</Optim>
|
||||
<oTime>2</oTime>
|
||||
<SplitLS>2</SplitLS>
|
||||
<OneElfS>2</OneElfS>
|
||||
<Strict>2</Strict>
|
||||
<EnumInt>2</EnumInt>
|
||||
<PlainCh>2</PlainCh>
|
||||
<Ropi>2</Ropi>
|
||||
<Rwpi>2</Rwpi>
|
||||
<wLevel>0</wLevel>
|
||||
<uThumb>2</uThumb>
|
||||
<uSurpInc>2</uSurpInc>
|
||||
<uC99>2</uC99>
|
||||
<uGnu>2</uGnu>
|
||||
<useXO>2</useXO>
|
||||
<v6Lang>0</v6Lang>
|
||||
<v6LangP>0</v6LangP>
|
||||
<vShortEn>2</vShortEn>
|
||||
<vShortWch>2</vShortWch>
|
||||
<v6Lto>2</v6Lto>
|
||||
<v6WtE>2</v6WtE>
|
||||
<v6Rtti>2</v6Rtti>
|
||||
<VariousControls>
|
||||
<MiscControls></MiscControls>
|
||||
<Define></Define>
|
||||
<Undefine></Undefine>
|
||||
<IncludePath></IncludePath>
|
||||
</VariousControls>
|
||||
</Cads>
|
||||
</FileArmAds>
|
||||
</FileOption>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perf_counter.h</FileName>
|
||||
@ -469,49 +418,16 @@
|
||||
<FileName>systick_wrapper_ual.s</FileName>
|
||||
<FileType>2</FileType>
|
||||
<FilePath>..\systick_wrapper_ual.s</FilePath>
|
||||
<FileOption>
|
||||
<CommonProperty>
|
||||
<UseCPPCompiler>2</UseCPPCompiler>
|
||||
<RVCTCodeConst>0</RVCTCodeConst>
|
||||
<RVCTZI>0</RVCTZI>
|
||||
<RVCTOtherData>0</RVCTOtherData>
|
||||
<ModuleSelection>0</ModuleSelection>
|
||||
<IncludeInBuild>0</IncludeInBuild>
|
||||
<AlwaysBuild>2</AlwaysBuild>
|
||||
<GenerateAssemblyFile>2</GenerateAssemblyFile>
|
||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||
<PublicsOnly>2</PublicsOnly>
|
||||
<StopOnExitCode>11</StopOnExitCode>
|
||||
<CustomArgument></CustomArgument>
|
||||
<IncludeLibraryModules></IncludeLibraryModules>
|
||||
<ComprImg>1</ComprImg>
|
||||
</CommonProperty>
|
||||
<FileArmAds>
|
||||
<Aads>
|
||||
<interw>2</interw>
|
||||
<Ropi>2</Ropi>
|
||||
<Rwpi>2</Rwpi>
|
||||
<thumb>2</thumb>
|
||||
<SplitLS>2</SplitLS>
|
||||
<SwStkChk>2</SwStkChk>
|
||||
<NoWarn>2</NoWarn>
|
||||
<uSurpInc>2</uSurpInc>
|
||||
<useXO>2</useXO>
|
||||
<ClangAsOpt>0</ClangAsOpt>
|
||||
<VariousControls>
|
||||
<MiscControls></MiscControls>
|
||||
<Define></Define>
|
||||
<Undefine></Undefine>
|
||||
<IncludePath></IncludePath>
|
||||
</VariousControls>
|
||||
</Aads>
|
||||
</FileArmAds>
|
||||
</FileOption>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perf_counter.lib</FileName>
|
||||
<FileType>4</FileType>
|
||||
<FilePath>..\lib\perf_counter.lib</FilePath>
|
||||
<FileName>perfc_port_default.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\perfc_port_default.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perfc_port_default.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\perfc_port_default.h</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
@ -533,14 +449,14 @@
|
||||
<TargetName>library</TargetName>
|
||||
<ToolsetNumber>0x4</ToolsetNumber>
|
||||
<ToolsetName>ARM-ADS</ToolsetName>
|
||||
<pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
|
||||
<pCCUsed>6210000::V6.21::ARMCLANG</pCCUsed>
|
||||
<uAC6>1</uAC6>
|
||||
<TargetOption>
|
||||
<TargetCommonOption>
|
||||
<Device>ARMCM0</Device>
|
||||
<Vendor>ARM</Vendor>
|
||||
<PackID>ARM.CMSIS.5.9.0</PackID>
|
||||
<PackURL>http://www.keil.com/pack/</PackURL>
|
||||
<PackID>ARM.Cortex_DFP.1.0.0</PackID>
|
||||
<PackURL>https://www.keil.com/pack/</PackURL>
|
||||
<Cpu>IRAM(0x20000000,0x00020000) IROM(0x00000000,0x00040000) CPUTYPE("Cortex-M0") CLOCK(12000000) ESEL ELITTLE</Cpu>
|
||||
<FlashUtilSpec></FlashUtilSpec>
|
||||
<StartupFile></StartupFile>
|
||||
@ -860,7 +776,7 @@
|
||||
<v6WtE>0</v6WtE>
|
||||
<v6Rtti>0</v6Rtti>
|
||||
<VariousControls>
|
||||
<MiscControls></MiscControls>
|
||||
<MiscControls>-Wno-undef</MiscControls>
|
||||
<Define></Define>
|
||||
<Undefine></Undefine>
|
||||
<IncludePath></IncludePath>
|
||||
@ -1012,28 +928,14 @@
|
||||
<FilePath>..\systick_wrapper_ual.s</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perf_counter.lib</FileName>
|
||||
<FileType>4</FileType>
|
||||
<FilePath>..\lib\perf_counter.lib</FilePath>
|
||||
<FileOption>
|
||||
<CommonProperty>
|
||||
<UseCPPCompiler>2</UseCPPCompiler>
|
||||
<RVCTCodeConst>0</RVCTCodeConst>
|
||||
<RVCTZI>0</RVCTZI>
|
||||
<RVCTOtherData>0</RVCTOtherData>
|
||||
<ModuleSelection>0</ModuleSelection>
|
||||
<IncludeInBuild>0</IncludeInBuild>
|
||||
<AlwaysBuild>2</AlwaysBuild>
|
||||
<GenerateAssemblyFile>2</GenerateAssemblyFile>
|
||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||
<PublicsOnly>2</PublicsOnly>
|
||||
<StopOnExitCode>11</StopOnExitCode>
|
||||
<CustomArgument></CustomArgument>
|
||||
<IncludeLibraryModules></IncludeLibraryModules>
|
||||
<ComprImg>1</ComprImg>
|
||||
</CommonProperty>
|
||||
<FileArmAds/>
|
||||
</FileOption>
|
||||
<FileName>perfc_port_default.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\perfc_port_default.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perfc_port_default.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\perfc_port_default.h</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
@ -1692,9 +1594,14 @@
|
||||
</FileOption>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perf_counter.lib</FileName>
|
||||
<FileType>4</FileType>
|
||||
<FilePath>..\lib\perf_counter.lib</FilePath>
|
||||
<FileName>perfc_port_default.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\perfc_port_default.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perfc_port_default.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\perfc_port_default.h</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
@ -1757,17 +1664,27 @@
|
||||
<component Cclass="CMSIS" Cgroup="CORE" Cvendor="ARM" Cversion="5.6.0" condition="ARMv6_7_8-M Device">
|
||||
<package name="CMSIS" schemaVersion="1.7.7" url="http://www.keil.com/pack/" vendor="ARM" version="5.9.0"/>
|
||||
<targetInfos>
|
||||
<targetInfo name="example_arm compiler_5"/>
|
||||
<targetInfo name="example_arm_compiler_6"/>
|
||||
</targetInfos>
|
||||
</component>
|
||||
<component Cclass="CMSIS" Cgroup="CORE" Cvendor="ARM" Cversion="6.0.0" condition="ARMv6_7_8-M Device">
|
||||
<package name="CMSIS" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="6.0.0"/>
|
||||
<targetInfos>
|
||||
<targetInfo name="example_arm compiler_5"/>
|
||||
<targetInfo name="library"/>
|
||||
</targetInfos>
|
||||
</component>
|
||||
<component Cclass="Device" Cgroup="Startup" Cvariant="C Startup" Cvendor="ARM" Cversion="2.2.0" condition="ARMCM0 CMSIS">
|
||||
<package name="Cortex_DFP" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="1.0.0"/>
|
||||
<targetInfos>
|
||||
<targetInfo name="example_arm compiler_5"/>
|
||||
<targetInfo name="library"/>
|
||||
</targetInfos>
|
||||
</component>
|
||||
<component Cclass="Device" Cgroup="Startup" Cvendor="ARM" Cversion="1.2.2" condition="ARMCM0 CMSIS">
|
||||
<package name="CMSIS" schemaVersion="1.7.7" url="http://www.keil.com/pack/" vendor="ARM" version="5.9.0"/>
|
||||
<targetInfos>
|
||||
<targetInfo name="example_arm compiler_5"/>
|
||||
<targetInfo name="example_arm_compiler_6"/>
|
||||
<targetInfo name="library"/>
|
||||
</targetInfos>
|
||||
</component>
|
||||
<component Cbundle="ARM Compiler" Cclass="Compiler" Cgroup="Event Recorder" Cvariant="DAP" Cvendor="Keil" Cversion="1.5.1" condition="Cortex-M Device">
|
||||
@ -1798,20 +1715,36 @@
|
||||
<targetInfo name="example_arm_compiler_6"/>
|
||||
</targetInfos>
|
||||
</file>
|
||||
<file attr="config" category="linkerScript" condition="ARMCC6" name="Device\ARMCM0\Config\ARMCM0_ac6.sct" version="1.0.0">
|
||||
<instance index="0">RTE\Device\ARMCM0\ARMCM0_ac6.sct</instance>
|
||||
<component Cclass="Device" Cgroup="Startup" Cvariant="C Startup" Cvendor="ARM" Cversion="2.2.0" condition="ARMCM0 CMSIS" isDefaultVariant="1"/>
|
||||
<package name="Cortex_DFP" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="1.0.0"/>
|
||||
<targetInfos>
|
||||
<targetInfo name="example_arm compiler_5"/>
|
||||
<targetInfo name="library"/>
|
||||
</targetInfos>
|
||||
</file>
|
||||
<file attr="config" category="sourceC" name="Device\ARMCM0\Source\startup_ARMCM0.c" version="2.0.3">
|
||||
<instance index="0">RTE\Device\ARMCM0\startup_ARMCM0.c</instance>
|
||||
<component Cclass="Device" Cgroup="Startup" Cvariant="C Startup" Cvendor="ARM" Cversion="2.2.0" condition="ARMCM0 CMSIS" isDefaultVariant="1"/>
|
||||
<package name="Cortex_DFP" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="1.0.0"/>
|
||||
<targetInfos>
|
||||
<targetInfo name="example_arm compiler_5"/>
|
||||
<targetInfo name="library"/>
|
||||
</targetInfos>
|
||||
</file>
|
||||
<file attr="config" category="sourceAsm" condition="ARMCC" name="Device\ARM\ARMCM0\Source\ARM\startup_ARMCM0.s" version="1.0.1">
|
||||
<instance index="0">RTE\Device\ARMCM0\startup_ARMCM0.s</instance>
|
||||
<component Cclass="Device" Cgroup="Startup" Cvendor="ARM" Cversion="1.2.2" condition="ARMCM0 CMSIS"/>
|
||||
<package name="CMSIS" schemaVersion="1.7.7" url="http://www.keil.com/pack/" vendor="ARM" version="5.9.0"/>
|
||||
<targetInfos>
|
||||
<targetInfo name="example_arm compiler_5"/>
|
||||
<targetInfo name="example_arm_compiler_6"/>
|
||||
<targetInfo name="library"/>
|
||||
</targetInfos>
|
||||
</file>
|
||||
<file attr="config" category="sourceC" name="Device\ARM\ARMCM0\Source\system_ARMCM0.c" version="1.0.0">
|
||||
<file attr="config" category="sourceC" name="Device\ARMCM0\Source\system_ARMCM0.c" version="1.0.0">
|
||||
<instance index="0">RTE\Device\ARMCM0\system_ARMCM0.c</instance>
|
||||
<component Cclass="Device" Cgroup="Startup" Cvendor="ARM" Cversion="1.2.2" condition="ARMCM0 CMSIS"/>
|
||||
<package name="CMSIS" schemaVersion="1.7.7" url="http://www.keil.com/pack/" vendor="ARM" version="5.9.0"/>
|
||||
<component Cclass="Device" Cgroup="Startup" Cvariant="C Startup" Cvendor="ARM" Cversion="2.2.0" condition="ARMCM0 CMSIS" isDefaultVariant="1"/>
|
||||
<package name="Cortex_DFP" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="1.0.0"/>
|
||||
<targetInfos>
|
||||
<targetInfo name="example_arm compiler_5"/>
|
||||
<targetInfo name="example_arm_compiler_6"/>
|
||||
|
@ -561,6 +561,30 @@
|
||||
<RteFlg>0</RteFlg>
|
||||
<bShared>0</bShared>
|
||||
</File>
|
||||
<File>
|
||||
<GroupNumber>3</GroupNumber>
|
||||
<FileNumber>10</FileNumber>
|
||||
<FileType>1</FileType>
|
||||
<tvExp>0</tvExp>
|
||||
<tvExpOptDlg>0</tvExpOptDlg>
|
||||
<bDave2>0</bDave2>
|
||||
<PathWithFileName>..\perfc_port_default.c</PathWithFileName>
|
||||
<FilenameWithoutPath>perfc_port_default.c</FilenameWithoutPath>
|
||||
<RteFlg>0</RteFlg>
|
||||
<bShared>0</bShared>
|
||||
</File>
|
||||
<File>
|
||||
<GroupNumber>3</GroupNumber>
|
||||
<FileNumber>11</FileNumber>
|
||||
<FileType>5</FileType>
|
||||
<tvExp>0</tvExp>
|
||||
<tvExpOptDlg>0</tvExpOptDlg>
|
||||
<bDave2>0</bDave2>
|
||||
<PathWithFileName>..\perfc_port_default.h</PathWithFileName>
|
||||
<FilenameWithoutPath>perfc_port_default.h</FilenameWithoutPath>
|
||||
<RteFlg>0</RteFlg>
|
||||
<bShared>0</bShared>
|
||||
</File>
|
||||
</Group>
|
||||
|
||||
<Group>
|
||||
|
@ -403,6 +403,16 @@
|
||||
<FileType>4</FileType>
|
||||
<FilePath>..\lib\libperf_counter_gcc.a</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perfc_port_default.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\perfc_port_default.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perfc_port_default.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\perfc_port_default.h</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
<Group>
|
||||
@ -852,6 +862,16 @@
|
||||
<FileArm/>
|
||||
</FileOption>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perfc_port_default.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\perfc_port_default.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>perfc_port_default.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\perfc_port_default.h</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
<Group>
|
||||
|
@ -190,14 +190,25 @@ int main (void)
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
if (perfc_is_time_out_ms(1000)) {
|
||||
printf("\r[%010d]", get_system_ms());
|
||||
if (perfc_is_time_out_ms(10000)) {
|
||||
printf("\r[%010lld]", get_system_ms());
|
||||
}
|
||||
|
||||
__cpu_time__(10) {
|
||||
__cpu_usage__(10) {
|
||||
delay_us(30000);
|
||||
}
|
||||
delay_us(70000);
|
||||
|
||||
float fUsage = 0;
|
||||
__cpu_usage__(10, {
|
||||
fUsage = __usage__;
|
||||
printf("task 1 cpu usage %3.2f %%\r\n", (double)fUsage);
|
||||
}) {
|
||||
delay_us(50000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
delay_us(20000);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ DEFAULT_ARGS=(-c "v")
|
||||
benchmark
|
||||
documents
|
||||
os
|
||||
lib
|
||||
template
|
||||
"
|
||||
|
||||
# Specify file names to be added to pack base directory
|
||||
@ -42,6 +42,10 @@ DEFAULT_ARGS=(-c "v")
|
||||
LICENSE
|
||||
perf_counter.c
|
||||
perf_counter.h
|
||||
perfc_port_default.c
|
||||
perfc_port_default.h
|
||||
perfc_port_pmu.c
|
||||
perfc_port_pmu.h
|
||||
README.md
|
||||
systick_wrapper_gcc.S
|
||||
systick_wrapper_gnu.s
|
||||
|
201
lib/LICENSE
201
lib/LICENSE
@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
Binary file not shown.
@ -1,947 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __PERFORMANCE_COUNTER_H__
|
||||
#define __PERFORMANCE_COUNTER_H__
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*============================ MACROS ========================================*/
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasic 1 Basic
|
||||
* @{
|
||||
*/
|
||||
#define __PERF_COUNTER_VER_MAJOR__ 2
|
||||
#define __PERF_COUNTER_VER_MINOR__ 2
|
||||
#define __PERF_COUNTER_VER_REVISE__ 4
|
||||
|
||||
#define __PERF_COUNTER_VER_STR__ ""
|
||||
|
||||
#define __PER_COUNTER_VER__ (__PERF_COUNTER_VER_MAJOR__ * 10000ul \
|
||||
+__PERF_COUNTER_VER_MINOR__ * 100ul \
|
||||
+__PERF_COUNTER_VER_REVISE__)
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*!
|
||||
* \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
|
||||
|
||||
#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 __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 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( uint32_t SAFE_NAME(temp) = \
|
||||
({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
|
||||
__disable_irq(); \
|
||||
SAFE_NAME(temp2);}), \
|
||||
__set_PRIMASK(SAFE_NAME(temp)))
|
||||
#endif
|
||||
|
||||
#ifndef __IRQ_SAFE
|
||||
# define __IRQ_SAFE \
|
||||
using( uint32_t SAFE_NAME(temp) = \
|
||||
({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
|
||||
__disable_irq(); \
|
||||
SAFE_NAME(temp2);}), \
|
||||
__set_PRIMASK(SAFE_NAME(temp)))
|
||||
#endif
|
||||
|
||||
#ifndef __perf_counter_printf__
|
||||
# define __perf_counter_printf__ printf
|
||||
#endif
|
||||
|
||||
#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__)
|
||||
# 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
|
||||
/*! @} */
|
||||
|
||||
/*============================ 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__ = _, \
|
||||
_=_, { \
|
||||
_ = 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 [%016lx]\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_time__(100) {
|
||||
delay_us(5000);
|
||||
}
|
||||
delay_us(5000);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
#define __cpu_time__(__CNT, ...) \
|
||||
static int64_t SAFE_NAME(s_lTimestamp) = 0, SAFE_NAME(s_lTotal) = 0; \
|
||||
static uint32_t s_wLoopCounter = (__CNT); \
|
||||
using(float __usage__ = 0, ({ \
|
||||
if (0 == 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(); \
|
||||
s_wLoopCounter = (__CNT); \
|
||||
} \
|
||||
start_task_cycle_counter();}), \
|
||||
({SAFE_NAME(s_lTotal) += stop_task_cycle_counter(); \
|
||||
s_wLoopCounter--;}))
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasicTimerService 1.2 Timer Service
|
||||
* \ingroup gBasic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief should not use
|
||||
*/
|
||||
#define perfc_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 perfc_is_time_out_ms3(__ms, __timestamp_ptr, __auto_reload) \
|
||||
({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
|
||||
__perfc_is_time_out(perfc_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 perfc_is_time_out_ms2(__ms, __timestamp_ptr) \
|
||||
perfc_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 perfc_is_time_out_ms1(__ms) \
|
||||
perfc_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 perfc_is_time_out_ms(...) \
|
||||
CONNECT2(perfc_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 perfc_is_time_out_us3(__us, __timestamp_ptr, __auto_reload) \
|
||||
({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
|
||||
__perfc_is_time_out(perfc_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 perfc_is_time_out_us2(__us, __timestamp_ptr) \
|
||||
perfc_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 perfc_is_time_out_us1(__us) \
|
||||
perfc_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 perfc_is_time_out_us(...) \
|
||||
CONNECT2(perfc_is_time_out_us, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
|
||||
(__VA_ARGS__)
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*!
|
||||
* \addtogroup gRTOS 2 RTOS Support
|
||||
* @{
|
||||
*/
|
||||
#define __super_loop_monitor__(__N, ...) \
|
||||
using( \
|
||||
struct { \
|
||||
int64_t lStart; \
|
||||
int64_t lTaskUsedCycles; \
|
||||
int64_t lTimeElapsed; \
|
||||
} __cpu_usage__ = {.lStart = get_system_ticks()}) \
|
||||
using(int SAFE_NAME(cnt) = (__N)) \
|
||||
for(start_task_cycle_counter();; ({ \
|
||||
if (!(--SAFE_NAME(cnt))) { \
|
||||
__cpu_usage__.lTimeElapsed \
|
||||
= get_system_ticks() - __cpu_usage__.lStart - g_nOffset; \
|
||||
__cpu_usage__.lTaskUsedCycles = stop_task_cycle_counter(); \
|
||||
\
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
__perf_counter_printf__( \
|
||||
"%s CPU Usage %2.3f%%\r\n", __func__, \
|
||||
(float)((double)__cpu_usage__.lTaskUsedCycles * 100.0 / \
|
||||
(double)__cpu_usage__.lTimeElapsed)); \
|
||||
} else { \
|
||||
__VA_ARGS__; \
|
||||
} \
|
||||
SAFE_NAME(cnt) = (__N); \
|
||||
__cpu_usage__.lStart = get_system_ticks(); \
|
||||
start_task_cycle_counter(); \
|
||||
}; \
|
||||
}))
|
||||
|
||||
/*============================ 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;
|
||||
};
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
extern volatile int64_t g_lLastTimeStamp;
|
||||
extern volatile int32_t g_nOffset;
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasicTicks 1.1 Ticks APIs
|
||||
* \ingroup gBasic
|
||||
* @{
|
||||
*/
|
||||
/*!
|
||||
* \brief get the elapsed cycles since perf_counter is initialised
|
||||
* \return int64_t the elpased cycles
|
||||
*/
|
||||
__attribute__((noinline))
|
||||
extern int64_t get_system_ticks(void);
|
||||
|
||||
|
||||
#ifdef __PERF_CNT_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 elapsed milliseconds since perf_counter is initialised
|
||||
* \return int32_t the elapsed milliseconds
|
||||
*/
|
||||
extern int32_t get_system_ms(void);
|
||||
|
||||
/*!
|
||||
* \brief get the elapsed microsecond since perf_counter is initialised
|
||||
* \return int32_t the elapsed microsecond
|
||||
*/
|
||||
extern int32_t get_system_us(void);
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* \brief delay specified time in microsecond
|
||||
* \param[in] nUs time in microsecond
|
||||
*/
|
||||
extern void delay_us(int32_t nUs);
|
||||
|
||||
/*!
|
||||
* \brief delay specified time in millisecond
|
||||
* \param[in] nMs time in millisecond
|
||||
*/
|
||||
extern void delay_ms(int32_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 perfc_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 perfc_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 perfc_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 perfc_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 __perfc_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload);
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* \addtogroup gRTOS 2 RTOS Support
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined(__PERF_CNT_USE_RTOS__)
|
||||
|
||||
/*! \brief initialize the default virtual cycle counter for the current task
|
||||
*/
|
||||
extern void init_task_cycle_counter(void);
|
||||
|
||||
/*! \brief check whether the task stack canary is safe or not
|
||||
* \retval false likely to be a stack-overflow
|
||||
* \retval true task stack is safe
|
||||
*/
|
||||
extern
|
||||
bool perfc_check_task_stack_canary_safe(void);
|
||||
|
||||
/*! \brief provide cycle information for target task
|
||||
* \details Support RTOS List:
|
||||
* - RTX5
|
||||
* - RT-Thread
|
||||
* - ThreadX
|
||||
* - FreeRTOS
|
||||
*
|
||||
* \return task_cycle_info_t* the cycle info object passed to this function
|
||||
*/
|
||||
extern task_cycle_info_t * get_rtos_task_cycle_info(void);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief intialize a given task_cycle_info_t object and enable it before
|
||||
* registering it.
|
||||
* \return task_cycle_info_t* the cycle info object passed to this function
|
||||
*/
|
||||
extern task_cycle_info_t *init_task_cycle_info(task_cycle_info_t *ptInfo);
|
||||
|
||||
/*! \brief enable a given task_cycle_info_t object
|
||||
*
|
||||
* \param[in] ptInfo the address of target task_cycle_info_t object
|
||||
* \return bool previous status
|
||||
*/
|
||||
extern bool enable_task_cycle_info(task_cycle_info_t *ptInfo);
|
||||
|
||||
/*! \brief disable a given task_cycle_info_t object
|
||||
*
|
||||
* \param[in] ptInfo the address of target task_cycle_info_t object
|
||||
* \return bool previous status
|
||||
*/
|
||||
extern bool disable_task_cycle_info(task_cycle_info_t *ptInfo);
|
||||
|
||||
/*! \brief resume the enabled status of a given task_cycle_info_t object
|
||||
*
|
||||
* \param[in] ptInfo the address of target task_cycle_info_t object
|
||||
* \param[in] bEnabledStatus the previous status
|
||||
*/
|
||||
extern
|
||||
void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus);
|
||||
|
||||
/*!
|
||||
* \brief register a global virtual cycle counter agent to the current task
|
||||
* \param[in] ptInfo the address of target task_cycle_info_t object
|
||||
* \param[in] ptAgent an list node for the task_cycle_info_t object
|
||||
* \note the ptAgent it is better to be allocated as a static variable, global
|
||||
* variable or comes from heap or pool
|
||||
*
|
||||
* \return task_cycle_info_agent_t* the agent passed to this function
|
||||
*/
|
||||
extern
|
||||
task_cycle_info_agent_t *register_task_cycle_agent(
|
||||
task_cycle_info_t *ptInfo,
|
||||
task_cycle_info_agent_t *ptAgent);
|
||||
|
||||
/*!
|
||||
* \brief remove a global virtual cycle counter agent from the current task
|
||||
* \param[in] ptAgent the list node currently in use
|
||||
* \return task_cycle_info_agent_t* the agent passed to this function
|
||||
*/
|
||||
extern
|
||||
task_cycle_info_agent_t *
|
||||
unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent);
|
||||
|
||||
/*! \brief reset and start the virtual cycle counter for the current task
|
||||
*
|
||||
* \param[in] ptInfo the target task_cycle_info_t object
|
||||
*/
|
||||
__attribute__((noinline))
|
||||
extern void __start_task_cycle_counter(task_cycle_info_t *ptInfo);
|
||||
|
||||
/*! \brief calculate the elapsed cycle count for current task since the last
|
||||
* start point
|
||||
*
|
||||
* \note you can call stop_cycle_counter() multiple times following one
|
||||
* start_task_cycle_counter()
|
||||
*
|
||||
* \param[in] ptInfo the target task_cycle_info_t object
|
||||
*
|
||||
* \note When ptInfo is NULL, it returns current task cycle info, when ptInfo
|
||||
* is non-NULL, it returns the total used cycles of the specified
|
||||
* task_cycle_info_t object.
|
||||
*
|
||||
* \return int64_t the elapsed cycle count.
|
||||
*/
|
||||
__attribute__((noinline))
|
||||
extern int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo);
|
||||
|
||||
|
||||
#define start_task_cycle_counter(...) \
|
||||
__start_task_cycle_counter((NULL,##__VA_ARGS__))
|
||||
|
||||
#define stop_task_cycle_counter(...) \
|
||||
__stop_task_cycle_counter((NULL,##__VA_ARGS__))
|
||||
|
||||
#elif !defined(__IMPLEMENT_PERF_COUNTER)
|
||||
# define start_task_cycle_counter(...) start_cycle_counter()
|
||||
# define stop_task_cycle_counter(...) stop_cycle_counter()
|
||||
# define init_task_cycle_counter()
|
||||
# define register_task_cycle_agent(...)
|
||||
# define unregister_task_cycle_agent(...)
|
||||
# define init_task_cycle_info(...) (NULL)
|
||||
# define enable_task_cycle_info(...) (false)
|
||||
# define disable_task_cycle_info(...) (false)
|
||||
# define resume_task_cycle_info(...)
|
||||
# define perfc_check_task_stack_canary_safe() (false)
|
||||
#endif
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*!
|
||||
* \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.
|
||||
*/
|
||||
extern void init_cycle_counter(bool bIsSysTickOccupied);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief a system timer handler inserted to the SysTick_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 user_code_insert_to_systick_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);
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*!
|
||||
* \addtogroup gBenchmark 3 Benchmark
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __PERF_COUNTER_COREMARK__
|
||||
|
||||
/*!
|
||||
* \brief entry for coremark
|
||||
*/
|
||||
void coremark_main(void);
|
||||
#endif
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
//#if defined(__clang__)
|
||||
//# pragma clang diagnostic pop
|
||||
//#elif defined(__IS_COMPILER_GCC__)
|
||||
//# pragma GCC diagnostic pop
|
||||
//#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Binary file not shown.
@ -1,240 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "stack_macros.h"
|
||||
|
||||
/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
|
||||
because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
|
||||
for the header files above, but not in this file, in order to generate the
|
||||
correct privileged Vs unprivileged linkage and placement. */
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
|
||||
|
||||
#include "perf_counter.h"
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
|
||||
#undef __WRAP_FUNC
|
||||
#undef WRAP_FUNC
|
||||
#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__
|
||||
|
||||
# define __WRAP_FUNC(__NAME) $Sub$$##__NAME
|
||||
# define __ORIG_FUNC(__NAME) $Super$$##__NAME
|
||||
|
||||
#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \
|
||||
|| (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__)
|
||||
|
||||
# define __WRAP_FUNC(__NAME) __wrap_##__NAME
|
||||
# define __ORIG_FUNC(__NAME) __real_##__NAME
|
||||
|
||||
#endif
|
||||
#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME)
|
||||
#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME)
|
||||
|
||||
struct __task_cycle_info_t {
|
||||
task_cycle_info_t tInfo;
|
||||
int64_t lLastTimeStamp;
|
||||
task_cycle_info_agent_t tList;
|
||||
uint32_t wMagicWord;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
/*============================ TYPES =========================================*/
|
||||
|
||||
/*
|
||||
* Task control block. A task control block (TCB) is allocated for each task,
|
||||
* and stores task state information, including a pointer to the task's context
|
||||
* (the task's run time environment, including register values)
|
||||
*/
|
||||
typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */
|
||||
{
|
||||
volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
|
||||
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
|
||||
#endif
|
||||
|
||||
ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
|
||||
ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
|
||||
UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
|
||||
StackType_t *pxStack; /*< Points to the start of the stack. */
|
||||
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
|
||||
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
||||
StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
|
||||
#endif
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
|
||||
#endif
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
|
||||
UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
|
||||
#endif
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
|
||||
UBaseType_t uxMutexesHeld;
|
||||
#endif
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
TaskHookFunction_t pxTaskTag;
|
||||
#endif
|
||||
|
||||
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
|
||||
void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
|
||||
#endif
|
||||
|
||||
#if( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
|
||||
#endif
|
||||
|
||||
#if ( configUSE_NEWLIB_REENTRANT == 1 )
|
||||
/* Allocate a Newlib reent structure that is specific to this task.
|
||||
Note Newlib support has been included by popular demand, but is not
|
||||
used by the FreeRTOS maintainers themselves. FreeRTOS is not
|
||||
responsible for resulting newlib operation. User must be familiar with
|
||||
newlib and must provide system-wide implementations of the necessary
|
||||
stubs. Be warned that (at the time of writing) the current newlib design
|
||||
implements a system-wide malloc() that must be provided with locks.
|
||||
|
||||
See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
|
||||
for additional information. */
|
||||
struct _reent xNewLib_reent;
|
||||
#endif
|
||||
|
||||
#if( configUSE_TASK_NOTIFICATIONS == 1 )
|
||||
volatile uint32_t ulNotifiedValue;
|
||||
volatile uint8_t ucNotifyState;
|
||||
#endif
|
||||
|
||||
/* See the comments in FreeRTOS.h with the definition of
|
||||
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
|
||||
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
|
||||
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
|
||||
#endif
|
||||
|
||||
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||
uint8_t ucDelayAborted;
|
||||
#endif
|
||||
|
||||
#if( configUSE_POSIX_ERRNO == 1 )
|
||||
int iTaskErrno;
|
||||
#endif
|
||||
|
||||
} tskTCB;
|
||||
|
||||
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
|
||||
below to enable the use of older kernel aware debuggers. */
|
||||
typedef tskTCB TCB_t;
|
||||
|
||||
/*lint -save -e956 A manual analysis and inspection has been used to determine
|
||||
which static variables must be declared volatile. */
|
||||
PRIVILEGED_DATA
|
||||
extern TCB_t * volatile pxCurrentTCB;
|
||||
|
||||
/*! \note if you aren't using perf_counter inside KEIL with RTE, please create
|
||||
*! a header file called "Pre_Include_Global.h", copy the following
|
||||
*! content into the header file and and put following option
|
||||
*! to your command line (supposing you are using arm compiler 6):
|
||||
*! -include "Pre_Include_Global.h"
|
||||
*/
|
||||
|
||||
/*
|
||||
//! \brief Enable RTOS Patch for perf_counter
|
||||
#define __PERF_CNT_USE_RTOS__
|
||||
|
||||
#define traceTASK_SWITCHED_OUT_DISABLE
|
||||
#define traceTASK_SWITCHED_IN_DISABLE
|
||||
|
||||
extern void __freertos_evr_on_task_switched_out (void *ptTCB);
|
||||
extern void __freertos_evr_on_task_switched_in(void *ptTCB, unsigned int uxTopPriority) ;
|
||||
|
||||
# define traceTASK_SWITCHED_OUT() \
|
||||
__freertos_evr_on_task_switched_out(pxCurrentTCB)
|
||||
# define traceTASK_SWITCHED_IN() \
|
||||
__freertos_evr_on_task_switched_in(pxCurrentTCB, uxTopReadyPriority)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
extern void __on_context_switch_in(uint32_t *pwStack);
|
||||
extern void __on_context_switch_out(uint32_t *pwStack);
|
||||
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
|
||||
|
||||
#if defined(RTE_Compiler_EventRecorder)
|
||||
|
||||
# include "EventRecorder.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define EvtFreeRTOSTasksNo (0xF0U)
|
||||
|
||||
#define EvtFreeRTOSTasks_TaskSwitchedOut \
|
||||
EventID(EventLevelOp, EvtFreeRTOSTasksNo, 0x0BU)
|
||||
#define EvtFreeRTOSTasks_TaskSwitchedIn \
|
||||
EventID(EventLevelOp, EvtFreeRTOSTasksNo, 0x0CU)
|
||||
|
||||
void __freertos_evr_on_task_switched_out (void *ptTCB) {
|
||||
#if defined(RTE_Compiler_EventRecorder)
|
||||
EventRecord2(EvtFreeRTOSTasks_TaskSwitchedOut, (uint32_t)ptTCB, 0U);
|
||||
#else
|
||||
(void)pxCurrentTCB;
|
||||
#endif
|
||||
|
||||
__on_context_switch_out(((TCB_t *)ptTCB)->pxStack);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void __freertos_evr_on_task_switched_in(void *ptTCB, uint32_t uxTopPriority) {
|
||||
#if defined(RTE_Compiler_EventRecorder)
|
||||
EventRecord2(EvtFreeRTOSTasks_TaskSwitchedIn, (uint32_t)ptTCB, uxTopPriority);
|
||||
#else
|
||||
(void)pxCurrentTCB;
|
||||
(void)uxTopPriority;
|
||||
#endif
|
||||
|
||||
__on_context_switch_in(((TCB_t *)ptTCB)->pxStack);
|
||||
}
|
||||
|
||||
|
||||
task_cycle_info_t * get_rtos_task_cycle_info(void)
|
||||
{
|
||||
return &(((struct __task_cycle_info_t *)pxCurrentTCB->pxStack)->tInfo);
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "perf_counter.h"
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
|
||||
#undef __WRAP_FUNC
|
||||
#undef WRAP_FUNC
|
||||
#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__
|
||||
|
||||
# define __WRAP_FUNC(__NAME) $Sub$$##__NAME
|
||||
# define __ORIG_FUNC(__NAME) $Super$$##__NAME
|
||||
|
||||
#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \
|
||||
|| (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__)
|
||||
|
||||
# define __WRAP_FUNC(__NAME) __wrap_##__NAME
|
||||
# define __ORIG_FUNC(__NAME) __real_##__NAME
|
||||
|
||||
#endif
|
||||
#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME)
|
||||
#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME)
|
||||
|
||||
struct __task_cycle_info_t {
|
||||
task_cycle_info_t tInfo;
|
||||
int64_t lLastTimeStamp;
|
||||
task_cycle_info_agent_t tList;
|
||||
uint32_t wMagicWord;
|
||||
} ;
|
||||
|
||||
#ifndef RT_USING_HOOK
|
||||
#error "In order to use perf_counter:RT-Thread-Patch, please define RT_USING_HOOK \
|
||||
in rtconfig.h. If you don't want to use this patch, please un-select it in RTE."
|
||||
#endif
|
||||
|
||||
|
||||
/*============================ TYPES =========================================*/
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
extern void __on_context_switch_in(uint32_t *pwStack);
|
||||
extern void __on_context_switch_out(uint32_t *pwStack);
|
||||
extern struct rt_thread *rt_current_thread;
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
|
||||
void __rt_thread_scheduler_hook(struct rt_thread *from, struct rt_thread *to)
|
||||
{
|
||||
if (NULL != from) {
|
||||
__on_context_switch_out(from->stack_addr);
|
||||
}
|
||||
|
||||
__on_context_switch_in(to->stack_addr);
|
||||
}
|
||||
|
||||
task_cycle_info_t * get_rtos_task_cycle_info(void)
|
||||
{
|
||||
return &(((struct __task_cycle_info_t *)rt_current_thread->stack_addr)->tInfo);
|
||||
}
|
||||
|
||||
void __perf_os_patch_init(void)
|
||||
{
|
||||
#if defined(RTTHREAD_VERSION) && (RTTHREAD_VERSION >= (4 * 10000))
|
||||
rt_tick_sethook(user_code_insert_to_systick_handler);
|
||||
#endif
|
||||
|
||||
#if !defined(PKG_USING_PERF_COUNTER) || (defined(PKG_PERF_COUNTER_USING_THREAD_STATISTIC))
|
||||
rt_scheduler_sethook(__rt_thread_scheduler_hook);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PKG_USING_PERF_COUNTER
|
||||
|
||||
#if defined(RTTHREAD_VERSION) && (RTTHREAD_VERSION >= (4 * 10000))
|
||||
void __ensure_systick_wrapper(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DBG_TAG "perf_counter"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static int _perf_counter_init(void)
|
||||
{
|
||||
extern uint32_t SystemCoreClock;
|
||||
init_cycle_counter(true);
|
||||
LOG_I("perf_counter init, SystemCoreClock:%d", SystemCoreClock);
|
||||
return 0;
|
||||
}
|
||||
INIT_PREV_EXPORT(_perf_counter_init);
|
||||
#endif /* PKG_USING_PERF_COUNTER */
|
@ -1,99 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
|
||||
#include "rtx_os.h"
|
||||
#include "perf_counter.h"
|
||||
#include "cmsis_compiler.h"
|
||||
#include "rtx_evr.h" // RTX Event Recorder definitions
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
|
||||
#undef __WRAP_FUNC
|
||||
#undef WRAP_FUNC
|
||||
#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__
|
||||
|
||||
# define __WRAP_FUNC(__NAME) $Sub$$##__NAME
|
||||
# define __ORIG_FUNC(__NAME) $Super$$##__NAME
|
||||
|
||||
#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \
|
||||
|| (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__)
|
||||
|
||||
# define __WRAP_FUNC(__NAME) __wrap_##__NAME
|
||||
# define __ORIG_FUNC(__NAME) __real_##__NAME
|
||||
|
||||
#endif
|
||||
#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME)
|
||||
#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME)
|
||||
|
||||
struct __task_cycle_info_t {
|
||||
task_cycle_info_t tInfo;
|
||||
int64_t lLastTimeStamp;
|
||||
task_cycle_info_agent_t tList;
|
||||
uint32_t wMagicWord;
|
||||
} ;
|
||||
|
||||
|
||||
/*============================ TYPES =========================================*/
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
extern void __on_context_switch_in(uint32_t *pwStack);
|
||||
extern void __on_context_switch_out(uint32_t *pwStack);
|
||||
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
|
||||
|
||||
/*! \brief wrapper function for rtos context switching */
|
||||
void __on_context_switch (osRtxThread_t *thread)
|
||||
{
|
||||
if (NULL != osRtxInfo.thread.run.curr) {
|
||||
__on_context_switch_out(osRtxInfo.thread.run.curr->stack_mem);
|
||||
}
|
||||
|
||||
__on_context_switch_in(thread->stack_mem);
|
||||
}
|
||||
|
||||
__attribute__((used))
|
||||
void EvrRtxThreadSwitched (osThreadId_t thread_id)
|
||||
{
|
||||
__on_context_switch((osRtxThread_t *)thread_id);
|
||||
|
||||
#if defined(RTE_Compiler_EventRecorder)
|
||||
# define EvtRtxThreadSwitched \
|
||||
EventID(EventLevelOp, EvtRtxThreadNo, 0x19U)
|
||||
|
||||
(void)EventRecord2(EvtRtxThreadSwitched, (uint32_t)thread_id, 0U);
|
||||
#else
|
||||
(void)thread_id;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
task_cycle_info_t * get_rtos_task_cycle_info(void)
|
||||
{
|
||||
osRtxThread_t *curr = osRtxInfo.thread.run.curr;
|
||||
if (NULL == curr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &(((struct __task_cycle_info_t *)curr->stack_mem)->tInfo);
|
||||
}
|
||||
|
@ -1,128 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
#include "perf_counter.h"
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
|
||||
#undef __WRAP_FUNC
|
||||
#undef WRAP_FUNC
|
||||
#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__
|
||||
|
||||
# define __WRAP_FUNC(__NAME) $Sub$$##__NAME
|
||||
# define __ORIG_FUNC(__NAME) $Super$$##__NAME
|
||||
|
||||
#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \
|
||||
|| (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__)
|
||||
|
||||
# define __WRAP_FUNC(__NAME) __wrap_##__NAME
|
||||
# define __ORIG_FUNC(__NAME) __real_##__NAME
|
||||
|
||||
#endif
|
||||
#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME)
|
||||
#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME)
|
||||
|
||||
|
||||
#if defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) && defined(TX_EXECUTION_PROFILE_ENABLE)
|
||||
#error In order to use perf_counter:ThreadX-Patch, please define \
|
||||
TX_ENABLE_EXECUTION_CHANGE_NOTIFY or TX_EXECUTION_PROFILE_ENABLE \
|
||||
in the project configuration, according to the version of thread.\
|
||||
If you don't want to use this patch, please un-select it in RTE\
|
||||
or remove this patch from the compilation.
|
||||
#endif
|
||||
|
||||
|
||||
/*============================ TYPES =========================================*/
|
||||
struct __task_cycle_info_t {
|
||||
task_cycle_info_t tInfo;
|
||||
int64_t lLastTimeStamp;
|
||||
task_cycle_info_agent_t tList;
|
||||
uint32_t wMagicWord;
|
||||
} ;
|
||||
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
extern void __on_context_switch_in(uint32_t *pwStack);
|
||||
extern void __on_context_switch_out(uint32_t *pwStack);
|
||||
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
|
||||
#if defined(TX_EXECUTION_PROFILE_ENABLE)
|
||||
void WRAP_FUNC(_tx_execution_thread_enter)(void)
|
||||
#else
|
||||
void _tx_execution_thread_enter (void)
|
||||
#endif
|
||||
{
|
||||
TX_THREAD * ptThread = NULL;
|
||||
TX_THREAD_GET_CURRENT(ptThread);
|
||||
|
||||
__on_context_switch_in(ptThread->tx_thread_stack_start);
|
||||
|
||||
#if defined(TX_EXECUTION_PROFILE_ENABLE)
|
||||
extern void ORIG_FUNC(_tx_execution_thread_enter)(void);
|
||||
|
||||
ORIG_FUNC(_tx_execution_thread_enter)();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TX_EXECUTION_PROFILE_ENABLE)
|
||||
void WRAP_FUNC(_tx_execution_thread_exit)(void)
|
||||
#else
|
||||
void _tx_execution_thread_exit(void)
|
||||
#endif
|
||||
{
|
||||
TX_THREAD * ptThread = NULL;
|
||||
TX_THREAD_GET_CURRENT(ptThread);
|
||||
|
||||
if (NULL != ptThread) {
|
||||
__on_context_switch_out(ptThread->tx_thread_stack_start);
|
||||
}
|
||||
#if defined(TX_EXECUTION_PROFILE_ENABLE)
|
||||
extern void ORIG_FUNC(_tx_execution_thread_exit)(void);
|
||||
|
||||
ORIG_FUNC(_tx_execution_thread_exit)();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(TX_EXECUTION_PROFILE_ENABLE)
|
||||
void _tx_execution_isr_exit(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void _tx_execution_isr_enter(void)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
task_cycle_info_t * get_rtos_task_cycle_info(void)
|
||||
{
|
||||
TX_THREAD * ptThread = NULL;
|
||||
TX_THREAD_GET_CURRENT(ptThread);
|
||||
|
||||
return &(((struct __task_cycle_info_t *)ptThread->tx_thread_stack_start)->tInfo);
|
||||
}
|
@ -76,7 +76,7 @@ void EvrRtxThreadSwitched (osThreadId_t thread_id)
|
||||
{
|
||||
__on_context_switch((osRtxThread_t *)thread_id);
|
||||
|
||||
#if defined(RTE_Compiler_EventRecorder)
|
||||
#if defined(RTE_Compiler_EventRecorder) || defined(RTE_CMSIS_View_EventRecorder)
|
||||
# define EvtRtxThreadSwitched \
|
||||
EventID(EventLevelOp, EvtRtxThreadNo, 0x19U)
|
||||
|
||||
|
274
perf_counter.c
274
perf_counter.c
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
@ -48,114 +48,12 @@
|
||||
# define PERF_CNT_DELAY_US_COMPENSATION 90
|
||||
#endif
|
||||
|
||||
|
||||
/* IO definitions (access restrictions to peripheral registers) */
|
||||
#ifdef __cplusplus
|
||||
#define __I volatile /*!< Defines 'read only' permissions */
|
||||
#else
|
||||
#define __I volatile const /*!< Defines 'read only' permissions */
|
||||
#endif
|
||||
#define __O volatile /*!< Defines 'write only' permissions */
|
||||
#define __IO volatile /*!< Defines 'read / write' permissions */
|
||||
|
||||
/* following defines should be used for structure members */
|
||||
#define __IM volatile const /*! Defines 'read only' structure member permissions */
|
||||
#define __OM volatile /*! Defines 'write only' structure member permissions */
|
||||
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
|
||||
|
||||
/* Memory mapping of Core Hardware */
|
||||
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
|
||||
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
|
||||
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
|
||||
|
||||
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
|
||||
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
|
||||
|
||||
/* SysTick Control / Status Register Definitions */
|
||||
#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
|
||||
#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
|
||||
|
||||
#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
|
||||
#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
|
||||
|
||||
#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
|
||||
#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
|
||||
|
||||
#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
|
||||
#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */
|
||||
|
||||
/* SysTick Reload Register Definitions */
|
||||
#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
|
||||
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */
|
||||
|
||||
/* SysTick Current Register Definitions */
|
||||
#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
|
||||
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */
|
||||
|
||||
/* SysTick Calibration Register Definitions */
|
||||
#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
|
||||
#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
|
||||
|
||||
#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
|
||||
#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
|
||||
|
||||
#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
|
||||
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */
|
||||
|
||||
/*@} end of group CMSIS_SysTick */
|
||||
|
||||
#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */
|
||||
#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
|
||||
|
||||
#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */
|
||||
#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
|
||||
|
||||
|
||||
#define MAGIC_WORD_AGENT_LIST_VALID 0x8492A53C
|
||||
#define MAGIC_WORD_CANARY 0xDEADBEEF
|
||||
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
/*============================ TYPES =========================================*/
|
||||
|
||||
/*!
|
||||
\brief Structure type to access the System Timer (SysTick).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
|
||||
__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
|
||||
__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
|
||||
__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
|
||||
} SysTick_Type;
|
||||
|
||||
/*!
|
||||
\brief Structure type to access the System Control Block (SCB).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
__IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
|
||||
__IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
|
||||
__IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
|
||||
__IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
|
||||
__IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
|
||||
__IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
|
||||
__IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */
|
||||
__IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
|
||||
__IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */
|
||||
__IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */
|
||||
__IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */
|
||||
__IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */
|
||||
__IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */
|
||||
__IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */
|
||||
__IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */
|
||||
__IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */
|
||||
__IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */
|
||||
__IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */
|
||||
__IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */
|
||||
uint32_t RESERVED0[5U];
|
||||
__IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */
|
||||
} SCB_Type;
|
||||
|
||||
struct __task_cycle_info_t {
|
||||
task_cycle_info_t tInfo; //!< cycle information
|
||||
int64_t lLastTimeStamp; //!< previous timestamp
|
||||
@ -165,66 +63,66 @@ struct __task_cycle_info_t {
|
||||
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
volatile int64_t g_lLastTimeStamp = 0;
|
||||
volatile static int64_t s_lOldTimestamp;
|
||||
volatile int32_t g_nOffset = 0;
|
||||
volatile static int32_t s_nUSUnit = 1;
|
||||
volatile static int32_t s_nMSUnit = 1;
|
||||
volatile static int32_t s_nMSResidule = 0;
|
||||
volatile static int32_t s_nUSResidule = 0;
|
||||
volatile static int32_t s_nSystemMS = 0;
|
||||
volatile static int32_t s_nSystemUS = 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 perfc_port_get_system_timer_freq(void);
|
||||
extern
|
||||
int64_t perfc_port_get_system_timer_top(void);
|
||||
extern
|
||||
bool perfc_port_is_system_timer_ovf_pending(void);
|
||||
extern
|
||||
bool perfc_port_init_system_timer(bool bTimerOccupied);
|
||||
extern
|
||||
int64_t perfc_port_get_system_timer_elapsed(void);
|
||||
extern
|
||||
void perfc_port_clear_system_timer_ovf_pending(void);
|
||||
extern
|
||||
void perfc_port_stop_system_timer_counting(void);
|
||||
extern
|
||||
void perfc_port_clear_system_timer_counter(void);
|
||||
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
|
||||
void perfc_port_insert_to_system_timer_insert_ovf_handler(void)
|
||||
{
|
||||
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
|
||||
{
|
||||
return (1UL); /* Reload value impossible */
|
||||
}
|
||||
|
||||
//__IRQ_SAFE {
|
||||
SysTick->CTRL = 0;
|
||||
|
||||
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
|
||||
//NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
|
||||
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
|
||||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
|
||||
SysTick_CTRL_TICKINT_Msk |
|
||||
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
|
||||
//SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
|
||||
//}
|
||||
return (0UL); /* Function successful */
|
||||
}
|
||||
|
||||
void user_code_insert_to_systick_handler(void)
|
||||
{
|
||||
uint32_t wLoad = SysTick->LOAD + 1;
|
||||
s_lSystemClockCounts += wLoad;
|
||||
int64_t lLoad = perfc_port_get_system_timer_top() + 1;
|
||||
s_lSystemClockCounts += lLoad;
|
||||
|
||||
// update system ms counter
|
||||
do {
|
||||
s_nMSResidule += wLoad;
|
||||
int32_t nMS = s_nMSResidule / s_nMSUnit;
|
||||
s_nMSResidule -= nMS * s_nMSUnit;
|
||||
s_nSystemMS += nMS;
|
||||
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 {
|
||||
s_nUSResidule += wLoad;
|
||||
int32_t nUS = s_nUSResidule / s_nUSUnit;
|
||||
s_nUSResidule -= nUS * s_nUSUnit;
|
||||
s_nSystemUS += nUS;
|
||||
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);
|
||||
|
||||
}
|
||||
@ -237,8 +135,9 @@ void __perf_os_patch_init(void)
|
||||
|
||||
void update_perf_counter(void)
|
||||
{
|
||||
s_nUSUnit = SystemCoreClock / 1000000ul;
|
||||
s_nMSUnit = SystemCoreClock / 1000ul;
|
||||
uint32_t wSystemFrequency = perfc_port_get_system_timer_freq();
|
||||
s_wUSUnit = wSystemFrequency / 1000000ul;
|
||||
s_wMSUnit = wSystemFrequency / 1000ul;
|
||||
|
||||
__IRQ_SAFE {
|
||||
g_lLastTimeStamp = get_system_ticks();
|
||||
@ -246,31 +145,32 @@ void update_perf_counter(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_cycle_counter(bool bIsSysTickOccupied)
|
||||
bool init_cycle_counter(bool bIsSysTickOccupied)
|
||||
{
|
||||
bool bResult = false;
|
||||
__IRQ_SAFE {
|
||||
if (!bIsSysTickOccupied) {
|
||||
SysTick_Config(0x01000000); // use the longest period
|
||||
}
|
||||
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
|
||||
bResult = perfc_port_init_system_timer(bIsSysTickOccupied); // use the longest period
|
||||
perfc_port_clear_system_timer_ovf_pending();
|
||||
}
|
||||
|
||||
update_perf_counter();
|
||||
s_lSystemClockCounts = 0; // reset system cycle counter
|
||||
s_nSystemMS = 0; // reset system millisecond counter
|
||||
s_nSystemUS = 0; // reset system microsecond counter
|
||||
s_lSystemMS = 0; // reset system millisecond counter
|
||||
s_lSystemUS = 0; // reset system microsecond counter
|
||||
|
||||
__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 int32_t check_systick(void)
|
||||
__STATIC_INLINE int64_t check_systick(void)
|
||||
{
|
||||
int32_t nTemp = (int32_t)SysTick->LOAD - (int32_t)SysTick->VAL;
|
||||
int64_t lLoad = perfc_port_get_system_timer_top() + 1;
|
||||
int64_t lTemp = perfc_port_get_system_timer_elapsed();
|
||||
|
||||
/* Since we cannot stop counting temporarily, there are several
|
||||
* conditions which we should take into consideration:
|
||||
@ -292,35 +192,32 @@ __STATIC_INLINE int32_t check_systick(void)
|
||||
* equals to) PERF_CNT_COMPENSATION_THRESHOLD.
|
||||
* The following code implements an equivalent logic.
|
||||
*/
|
||||
if (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk){
|
||||
if (((int32_t)SysTick->LOAD - nTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
|
||||
nTemp += SysTick->LOAD + 1;
|
||||
if (perfc_port_is_system_timer_ovf_pending()){
|
||||
if ((lLoad - lTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
|
||||
lTemp += lLoad;
|
||||
}
|
||||
}
|
||||
|
||||
return nTemp;
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
void before_cycle_counter_reconfiguration(void)
|
||||
{
|
||||
__IRQ_SAFE {
|
||||
SysTick->CTRL = 0; /* disable SysTick first */
|
||||
perfc_port_stop_system_timer_counting();
|
||||
|
||||
if (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) { /* pending SysTick exception */
|
||||
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk; /* clear pending bit */
|
||||
if (perfc_port_is_system_timer_ovf_pending()) {
|
||||
perfc_port_clear_system_timer_ovf_pending(); /* clear pending bit */
|
||||
|
||||
user_code_insert_to_systick_handler(); /* manually handle exception */
|
||||
|
||||
}
|
||||
s_lSystemClockCounts = get_system_ticks(); /* get the final cycle counter value */
|
||||
|
||||
SysTick->LOAD = 0UL;
|
||||
SysTick->VAL = 0UL; /* clear the Current Value Register */
|
||||
perfc_port_clear_system_timer_counter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
__attribute__((constructor))
|
||||
void __perf_counter_init(void)
|
||||
{
|
||||
@ -328,9 +225,9 @@ void __perf_counter_init(void)
|
||||
}
|
||||
|
||||
|
||||
void delay_us(int32_t nUs)
|
||||
void delay_us(uint32_t wUs)
|
||||
{
|
||||
int64_t lUs = (int64_t)nUs * (int64_t)s_nUSUnit;
|
||||
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;
|
||||
@ -345,22 +242,21 @@ void delay_us(int32_t nUs)
|
||||
while(get_system_ticks() < lUs);
|
||||
}
|
||||
|
||||
|
||||
void delay_ms(int32_t nMs)
|
||||
void delay_ms(uint32_t wMs)
|
||||
{
|
||||
int64_t lUs = (int64_t)nMs * (int64_t)s_nMSUnit;
|
||||
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 (lUs <= iCompensate) {
|
||||
if (lMs <= iCompensate) {
|
||||
return ;
|
||||
}
|
||||
|
||||
lUs -= iCompensate;
|
||||
lMs -= iCompensate;
|
||||
|
||||
lUs += get_system_ticks();
|
||||
while(get_system_ticks() < lUs);
|
||||
lMs += get_system_ticks();
|
||||
while(get_system_ticks() < lMs);
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
@ -420,47 +316,47 @@ int64_t clock(void)
|
||||
return get_system_ticks();
|
||||
}
|
||||
|
||||
int32_t get_system_ms(void)
|
||||
int64_t get_system_ms(void)
|
||||
{
|
||||
int32_t nTemp = 0;
|
||||
int64_t lTemp = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
nTemp = s_nSystemMS + (check_systick() + s_nMSResidule) / s_nMSUnit;
|
||||
lTemp = s_lSystemMS + ((check_systick() + (int64_t)s_wMSResidule) / s_wMSUnit);
|
||||
}
|
||||
|
||||
return nTemp;
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
int32_t get_system_us(void)
|
||||
int64_t get_system_us(void)
|
||||
{
|
||||
int32_t nTemp = 0;
|
||||
int64_t lTemp = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
nTemp = s_nSystemUS + (check_systick() + s_nUSResidule) / s_nUSUnit;
|
||||
lTemp = s_lSystemUS + ((check_systick() + (int64_t)s_wUSResidule) / s_wUSUnit);
|
||||
}
|
||||
|
||||
return nTemp;
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
int64_t perfc_convert_ticks_to_ms(int64_t lTick)
|
||||
{
|
||||
return lTick / (int64_t)s_nMSUnit;
|
||||
return lTick / (int64_t)s_wMSUnit;
|
||||
}
|
||||
|
||||
int64_t perfc_convert_ms_to_ticks(uint32_t wMS)
|
||||
{
|
||||
int64_t lResult = (int64_t)s_nMSUnit * (int64_t)wMS;
|
||||
int64_t lResult = (int64_t)s_wMSUnit * (int64_t)wMS;
|
||||
return lResult ? lResult : 1;
|
||||
}
|
||||
|
||||
int64_t perfc_convert_ticks_to_us(int64_t lTick)
|
||||
{
|
||||
return lTick / (int64_t)s_nUSUnit;
|
||||
return lTick / (int64_t)s_wUSUnit;
|
||||
}
|
||||
|
||||
int64_t perfc_convert_us_to_ticks(uint32_t wMS)
|
||||
{
|
||||
int64_t lResult = (int64_t)s_nUSUnit * (int64_t)wMS;
|
||||
int64_t lResult = (int64_t)s_wUSUnit * (int64_t)wMS;
|
||||
return lResult ? lResult : 1;
|
||||
}
|
||||
|
||||
@ -504,7 +400,7 @@ uint32_t EventRecorderTimerSetup (void)
|
||||
/// \return timer frequency in Hz
|
||||
uint32_t EventRecorderTimerGetFreq (void)
|
||||
{
|
||||
return SystemCoreClock;
|
||||
return perfc_port_get_system_timer_freq();
|
||||
}
|
||||
|
||||
/// Get timer count.
|
||||
|
112
perf_counter.h
112
perf_counter.h
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
@ -22,7 +22,12 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
#ifndef __PERFC_CFG_PORTING_INCLUDE__
|
||||
# include "perfc_port_default.h"
|
||||
#else
|
||||
# include __PERFC_CFG_PORTING_INCLUDE__
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -34,8 +39,8 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
#define __PERF_COUNTER_VER_MAJOR__ 2
|
||||
#define __PERF_COUNTER_VER_MINOR__ 2
|
||||
#define __PERF_COUNTER_VER_REVISE__ 4
|
||||
#define __PERF_COUNTER_VER_MINOR__ 3
|
||||
#define __PERF_COUNTER_VER_REVISE__ 0
|
||||
|
||||
#define __PERF_COUNTER_VER_STR__ ""
|
||||
|
||||
@ -134,6 +139,33 @@ extern "C" {
|
||||
# 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
|
||||
@ -265,26 +297,26 @@ extern "C" {
|
||||
|
||||
#ifndef safe_atom_code
|
||||
# define safe_atom_code() \
|
||||
using( uint32_t SAFE_NAME(temp) = \
|
||||
({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
|
||||
__disable_irq(); \
|
||||
SAFE_NAME(temp2);}), \
|
||||
__set_PRIMASK(SAFE_NAME(temp)))
|
||||
using( perfc_global_interrupt_status_t SAFE_NAME(temp) = \
|
||||
perfc_port_disable_global_interrupt(), \
|
||||
perfc_port_resume_global_interrupt(SAFE_NAME(temp)))
|
||||
#endif
|
||||
|
||||
#ifndef __IRQ_SAFE
|
||||
# define __IRQ_SAFE \
|
||||
using( uint32_t SAFE_NAME(temp) = \
|
||||
({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
|
||||
__disable_irq(); \
|
||||
SAFE_NAME(temp2);}), \
|
||||
__set_PRIMASK(SAFE_NAME(temp)))
|
||||
using( perfc_global_interrupt_status_t SAFE_NAME(temp) = \
|
||||
perfc_port_disable_global_interrupt(), \
|
||||
perfc_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 \
|
||||
perfc_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__()
|
||||
@ -331,7 +363,7 @@ __asm(".global __ensure_systick_wrapper\n\t");
|
||||
__perf_counter_printf__( \
|
||||
"--------------------------------------------\r\n"); \
|
||||
__perf_counter_printf__( \
|
||||
__STR " total cycle count: %ld [%016lx]\r\n", \
|
||||
__STR " total cycle count: %ld [%08lx]\r\n", \
|
||||
(long)_, (long)_); \
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
@ -348,18 +380,18 @@ __asm(".global __ensure_systick_wrapper\n\t");
|
||||
E.g.
|
||||
\code
|
||||
while (1) {
|
||||
__cpu_time__(100) {
|
||||
__cpu_usage__(100) {
|
||||
delay_us(5000);
|
||||
}
|
||||
delay_us(5000);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
#define __cpu_time__(__CNT, ...) \
|
||||
#define __cpu_usage__(__CNT, ...) \
|
||||
static int64_t SAFE_NAME(s_lTimestamp) = 0, SAFE_NAME(s_lTotal) = 0; \
|
||||
static uint32_t s_wLoopCounter = (__CNT); \
|
||||
static uint32_t SAFE_NAME(s_wLoopCounter) = (__CNT); \
|
||||
using(float __usage__ = 0, ({ \
|
||||
if (0 == s_wLoopCounter) { \
|
||||
if (0 == SAFE_NAME(s_wLoopCounter)) { \
|
||||
__usage__ = (float)((double)SAFE_NAME(s_lTotal) \
|
||||
/ (double)( get_system_ticks() \
|
||||
- SAFE_NAME(s_lTimestamp))); \
|
||||
@ -367,18 +399,20 @@ __asm(".global __ensure_systick_wrapper\n\t");
|
||||
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__); \
|
||||
__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(); \
|
||||
s_wLoopCounter = (__CNT); \
|
||||
SAFE_NAME(s_wLoopCounter) = (__CNT); \
|
||||
} \
|
||||
start_task_cycle_counter();}), \
|
||||
({SAFE_NAME(s_lTotal) += stop_task_cycle_counter(); \
|
||||
s_wLoopCounter--;}))
|
||||
SAFE_NAME(s_wLoopCounter)--;}))
|
||||
|
||||
#define __cpu_time__ __cpu_usage__
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasicTimerService 1.2 Timer Service
|
||||
@ -555,7 +589,6 @@ extern volatile int32_t g_nOffset;
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasicTicks 1.1 Ticks APIs
|
||||
* \ingroup gBasic
|
||||
@ -601,7 +634,7 @@ extern int64_t clock(void);
|
||||
/*!
|
||||
* \brief try to set a start pointer for the performance counter
|
||||
*/
|
||||
__STATIC_INLINE
|
||||
static inline
|
||||
void start_cycle_counter(void)
|
||||
{
|
||||
g_lLastTimeStamp = get_system_ticks();
|
||||
@ -612,7 +645,7 @@ void start_cycle_counter(void)
|
||||
* \note you can have multiple stop_cycle_counter following one start point
|
||||
* \return int32_t the elapsed cycle count
|
||||
*/
|
||||
__STATIC_INLINE
|
||||
static inline
|
||||
int64_t stop_cycle_counter(void)
|
||||
{
|
||||
int64_t lTemp = (get_system_ticks() - g_lLastTimeStamp);
|
||||
@ -634,29 +667,27 @@ int64_t stop_cycle_counter(void)
|
||||
|
||||
/*!
|
||||
* \brief get the elapsed milliseconds since perf_counter is initialised
|
||||
* \return int32_t the elapsed milliseconds
|
||||
* \return int64_t the elapsed milliseconds
|
||||
*/
|
||||
extern int32_t get_system_ms(void);
|
||||
extern int64_t get_system_ms(void);
|
||||
|
||||
/*!
|
||||
* \brief get the elapsed microsecond since perf_counter is initialised
|
||||
* \return int32_t the elapsed microsecond
|
||||
* \return int64_t the elapsed microsecond
|
||||
*/
|
||||
extern int32_t get_system_us(void);
|
||||
|
||||
|
||||
extern int64_t get_system_us(void);
|
||||
|
||||
/*!
|
||||
* \brief delay specified time in microsecond
|
||||
* \param[in] nUs time in microsecond
|
||||
* \param[in] wUs time in microsecond
|
||||
*/
|
||||
extern void delay_us(int32_t nUs);
|
||||
extern void delay_us(uint32_t wUs);
|
||||
|
||||
/*!
|
||||
* \brief delay specified time in millisecond
|
||||
* \param[in] nMs time in millisecond
|
||||
* \param[in] wMs time in millisecond
|
||||
*/
|
||||
extern void delay_ms(int32_t nMs);
|
||||
extern void delay_ms(uint32_t nMs);
|
||||
|
||||
/*!
|
||||
* \brief convert ticks of a reference timer to millisecond
|
||||
@ -875,12 +906,16 @@ extern int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo);
|
||||
*
|
||||
* \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 void init_cycle_counter(bool bIsSysTickOccupied);
|
||||
extern bool init_cycle_counter(bool bIsSysTickOccupied);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief a system timer handler inserted to the SysTick_Handler
|
||||
* \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
|
||||
@ -893,7 +928,7 @@ extern void init_cycle_counter(bool bIsSysTickOccupied);
|
||||
* 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 user_code_insert_to_systick_handler(void);
|
||||
extern void perfc_port_insert_to_system_timer_insert_ovf_handler(void);
|
||||
|
||||
/*!
|
||||
* \brief update perf_counter as SystemCoreClock has been updated.
|
||||
@ -943,5 +978,4 @@ void coremark_main(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
230
perfc_port_default.c
Normal file
230
perfc_port_default.c
Normal file
@ -0,0 +1,230 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
#undef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
#define __IMPLEMENT_PERF_COUNTER
|
||||
#include "perf_counter.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 ========================================*/
|
||||
|
||||
/* IO definitions (access restrictions to peripheral registers) */
|
||||
#ifdef __cplusplus
|
||||
#define __I volatile /*!< Defines 'read only' permissions */
|
||||
#else
|
||||
#define __I volatile const /*!< Defines 'read only' permissions */
|
||||
#endif
|
||||
#define __O volatile /*!< Defines 'write only' permissions */
|
||||
#define __IO volatile /*!< Defines 'read / write' permissions */
|
||||
|
||||
/* following defines should be used for structure members */
|
||||
#define __IM volatile const /*! Defines 'read only' structure member permissions */
|
||||
#define __OM volatile /*! Defines 'write only' structure member permissions */
|
||||
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
|
||||
|
||||
/* Memory mapping of Core Hardware */
|
||||
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
|
||||
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
|
||||
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
|
||||
|
||||
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
|
||||
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
|
||||
|
||||
/* SysTick Control / Status Register Definitions */
|
||||
#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
|
||||
#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
|
||||
|
||||
#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
|
||||
#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
|
||||
|
||||
#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
|
||||
#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
|
||||
|
||||
#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
|
||||
#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */
|
||||
|
||||
/* SysTick Reload Register Definitions */
|
||||
#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
|
||||
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */
|
||||
|
||||
/* SysTick Current Register Definitions */
|
||||
#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
|
||||
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */
|
||||
|
||||
/* SysTick Calibration Register Definitions */
|
||||
#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
|
||||
#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
|
||||
|
||||
#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
|
||||
#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
|
||||
|
||||
#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
|
||||
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */
|
||||
|
||||
/*@} end of group CMSIS_SysTick */
|
||||
|
||||
#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */
|
||||
#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
|
||||
|
||||
#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */
|
||||
#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
|
||||
|
||||
#ifndef __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
|
||||
# define __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__ 0
|
||||
#endif
|
||||
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
/*============================ TYPES =========================================*/
|
||||
|
||||
/*!
|
||||
\brief Structure type to access the System Timer (SysTick).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
|
||||
__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
|
||||
__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
|
||||
__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
|
||||
} SysTick_Type;
|
||||
|
||||
/*!
|
||||
\brief Structure type to access the System Control Block (SCB).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
__IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
|
||||
__IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
|
||||
__IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
|
||||
__IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
|
||||
__IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
|
||||
__IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
|
||||
__IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */
|
||||
__IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
|
||||
__IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */
|
||||
__IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */
|
||||
__IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */
|
||||
__IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */
|
||||
__IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */
|
||||
__IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */
|
||||
__IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */
|
||||
__IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */
|
||||
__IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */
|
||||
__IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */
|
||||
__IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */
|
||||
uint32_t RESERVED0[5U];
|
||||
__IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */
|
||||
} SCB_Type;
|
||||
|
||||
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
#if !__PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
|
||||
__WEAK
|
||||
bool perfc_port_init_system_timer(bool bTimerOccupied)
|
||||
{
|
||||
do {
|
||||
if (bTimerOccupied) {
|
||||
break;
|
||||
}
|
||||
|
||||
__IRQ_SAFE {
|
||||
SysTick->CTRL = 0;
|
||||
|
||||
SysTick->LOAD = SysTick_LOAD_RELOAD_Msk; /* set reload register */
|
||||
//NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
|
||||
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
|
||||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
|
||||
SysTick_CTRL_TICKINT_Msk |
|
||||
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
|
||||
//SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
|
||||
}
|
||||
} while(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
__WEAK
|
||||
uint32_t perfc_port_get_system_timer_freq(void)
|
||||
{
|
||||
return SystemCoreClock;
|
||||
}
|
||||
|
||||
__WEAK
|
||||
bool perfc_port_is_system_timer_ovf_pending(void)
|
||||
{
|
||||
return SCB->ICSR & SCB_ICSR_PENDSTSET_Msk;
|
||||
}
|
||||
|
||||
__WEAK
|
||||
int64_t perfc_port_get_system_timer_top(void)
|
||||
{
|
||||
return SysTick->LOAD;
|
||||
}
|
||||
|
||||
__WEAK
|
||||
int64_t perfc_port_get_system_timer_elapsed(void)
|
||||
{
|
||||
return (int64_t)SysTick->LOAD - (uint32_t)SysTick->VAL;
|
||||
}
|
||||
|
||||
__WEAK
|
||||
void perfc_port_clear_system_timer_ovf_pending(void)
|
||||
{
|
||||
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
|
||||
}
|
||||
|
||||
__WEAK
|
||||
void perfc_port_stop_system_timer_counting(void)
|
||||
{
|
||||
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
|
||||
}
|
||||
|
||||
__WEAK
|
||||
void perfc_port_clear_system_timer_counter(void)
|
||||
{
|
||||
SysTick->VAL = 0UL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
53
perfc_port_default.h
Normal file
53
perfc_port_default.h
Normal file
@ -0,0 +1,53 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
#ifndef __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
|
||||
# define __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__ 0
|
||||
#endif
|
||||
|
||||
#if !__PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
|
||||
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
/*============================ TYPES =========================================*/
|
||||
typedef uint32_t perfc_global_interrupt_status_t;
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
|
||||
__STATIC_INLINE
|
||||
perfc_global_interrupt_status_t perfc_port_disable_global_interrupt(void)
|
||||
{
|
||||
perfc_global_interrupt_status_t tStatus = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
|
||||
return tStatus;
|
||||
}
|
||||
|
||||
__STATIC_INLINE
|
||||
void perfc_port_resume_global_interrupt(perfc_global_interrupt_status_t tStatus)
|
||||
{
|
||||
__set_PRIMASK(tStatus);
|
||||
}
|
||||
|
||||
#endif
|
1769
perfc_port_pmu.c
Normal file
1769
perfc_port_pmu.c
Normal file
File diff suppressed because it is too large
Load Diff
131
perfc_port_pmu.h
Normal file
131
perfc_port_pmu.h
Normal file
@ -0,0 +1,131 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
#if __PERFC_USE_PMU_PORTING__
|
||||
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
#define __cpu_perf__(__str, ...) \
|
||||
using( \
|
||||
struct { \
|
||||
uint64_t dwNoInstr; \
|
||||
uint64_t dwNoMemAccess; \
|
||||
uint64_t dwNoL1DCacheRefill; \
|
||||
int64_t lCycles; \
|
||||
uint32_t wInstrCalib; \
|
||||
uint32_t wMemAccessCalib; \
|
||||
float fCPI; \
|
||||
float fDCacheMissRate; \
|
||||
} __PERF_INFO__ = {0}, \
|
||||
({ \
|
||||
__PERF_INFO__.dwNoInstr = perfc_pmu_get_instruction_count(); \
|
||||
__PERF_INFO__.dwNoMemAccess = perfc_pmu_get_memory_access_count(); \
|
||||
__PERF_INFO__.wInstrCalib = perfc_pmu_get_instruction_count() \
|
||||
- __PERF_INFO__.dwNoInstr; \
|
||||
__PERF_INFO__.wMemAccessCalib = perfc_pmu_get_memory_access_count() \
|
||||
- __PERF_INFO__.dwNoMemAccess; \
|
||||
__PERF_INFO__.dwNoL1DCacheRefill \
|
||||
= perfc_pmu_get_L1_dcache_refill_count(); \
|
||||
__PERF_INFO__.dwNoInstr = perfc_pmu_get_instruction_count(); \
|
||||
__PERF_INFO__.dwNoMemAccess = perfc_pmu_get_memory_access_count(); \
|
||||
}), \
|
||||
({ \
|
||||
__PERF_INFO__.dwNoInstr = perfc_pmu_get_instruction_count() \
|
||||
- __PERF_INFO__.dwNoInstr \
|
||||
- __PERF_INFO__.wInstrCalib; \
|
||||
__PERF_INFO__.dwNoMemAccess = perfc_pmu_get_memory_access_count() \
|
||||
- __PERF_INFO__.dwNoMemAccess \
|
||||
- __PERF_INFO__.wMemAccessCalib; \
|
||||
__PERF_INFO__.dwNoL1DCacheRefill \
|
||||
= perfc_pmu_get_L1_dcache_refill_count() \
|
||||
- __PERF_INFO__.dwNoL1DCacheRefill; \
|
||||
\
|
||||
__PERF_INFO__.fDCacheMissRate \
|
||||
= (float)( (double)__PERF_INFO__.dwNoL1DCacheRefill \
|
||||
/ (double)__PERF_INFO__.dwNoMemAccess) \
|
||||
* 100.0f; \
|
||||
\
|
||||
__PERF_INFO__.fCPI = (float)( (double)__PERF_INFO__.lCycles \
|
||||
/ (double)__PERF_INFO__.dwNoInstr); \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
__perf_counter_printf__( "\r\n" \
|
||||
"[Report for " __str "]\r\n" \
|
||||
"-----------------------------------------\r\n" \
|
||||
"Instruction executed: %lld\r\n" \
|
||||
"Cycle Used: %lld\r\n" \
|
||||
"Cycles per Instructions: %3.3f \r\n\r\n" \
|
||||
"Memory Access Count: %lld\r\n" \
|
||||
"L1 DCache Refill Count: %lld\r\n" \
|
||||
"L1 DCache Miss Rate: %3.4f %% \r\n" \
|
||||
, \
|
||||
__PERF_INFO__.dwNoInstr, \
|
||||
__PERF_INFO__.lCycles, \
|
||||
(double)__PERF_INFO__.fCPI, \
|
||||
__PERF_INFO__.dwNoMemAccess, \
|
||||
__PERF_INFO__.dwNoL1DCacheRefill, \
|
||||
(double)__PERF_INFO__.fDCacheMissRate \
|
||||
); \
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
})) \
|
||||
__cycleof__("", { __PERF_INFO__.lCycles = __cycle_count__; })
|
||||
|
||||
|
||||
/*============================ TYPES =========================================*/
|
||||
typedef uint32_t perfc_global_interrupt_status_t;
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
extern
|
||||
void perfc_port_pmu_insert_to_debug_monitor_handler(void);
|
||||
|
||||
extern
|
||||
uint64_t perfc_pmu_get_instruction_count(void);
|
||||
|
||||
extern
|
||||
uint64_t perfc_pmu_get_memory_access_count(void);
|
||||
|
||||
extern
|
||||
uint64_t perfc_pmu_get_L1_dcache_refill_count(void);
|
||||
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
|
||||
__STATIC_INLINE
|
||||
perfc_global_interrupt_status_t perfc_port_disable_global_interrupt(void)
|
||||
{
|
||||
perfc_global_interrupt_status_t tStatus = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
|
||||
return tStatus;
|
||||
}
|
||||
|
||||
__STATIC_INLINE
|
||||
void perfc_port_resume_global_interrupt(perfc_global_interrupt_status_t tStatus)
|
||||
{
|
||||
__set_PRIMASK(tStatus);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -15,6 +15,7 @@
|
||||
;* *
|
||||
;****************************************************************************/
|
||||
|
||||
#if !__PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
|
||||
.syntax unified
|
||||
.arch armv6-m
|
||||
|
||||
@ -28,7 +29,7 @@
|
||||
__wrap_SysTick_Handler:
|
||||
push {r4, r5}
|
||||
push {r4, lr}
|
||||
ldr R0, =user_code_insert_to_systick_handler
|
||||
ldr R0, =perfc_port_insert_to_system_timer_insert_ovf_handler
|
||||
blx R0
|
||||
pop {r4, r5}
|
||||
mov lr, r5
|
||||
@ -42,3 +43,4 @@ __wrap_SysTick_Handler:
|
||||
|
||||
__ensure_systick_wrapper:
|
||||
bx lr
|
||||
#endif
|
@ -14,12 +14,16 @@
|
||||
;* limitations under the License. *
|
||||
;* *
|
||||
;****************************************************************************/
|
||||
#if defined(_RTE_)
|
||||
# include "RTE_Components.h"
|
||||
#endif
|
||||
|
||||
#if !defined(__RTE_PERFC_PORTING_USER_DEFINED__) && !defined(__PERFC_USE_PMU_PORTING__)
|
||||
|
||||
#if !__PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
|
||||
.syntax unified
|
||||
.arch armv6-m
|
||||
|
||||
|
||||
.eabi_attribute Tag_ABI_align_preserved, 1
|
||||
.text
|
||||
.thumb
|
||||
@ -31,7 +35,7 @@
|
||||
$Sub$$SysTick_Handler:
|
||||
push {r4, r5}
|
||||
push {r4, lr}
|
||||
ldr R0, =user_code_insert_to_systick_handler
|
||||
ldr R0, =perfc_port_insert_to_system_timer_insert_ovf_handler
|
||||
blx R0
|
||||
pop {r4, r5}
|
||||
mov lr, r5
|
||||
@ -39,9 +43,11 @@ $Sub$$SysTick_Handler:
|
||||
ldr R0, =$Super$$SysTick_Handler
|
||||
bx R0
|
||||
|
||||
|
||||
.globl __ensure_systick_wrapper
|
||||
.type __ensure_systick_wrapper, %function
|
||||
|
||||
__ensure_systick_wrapper:
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
#endif
|
@ -22,11 +22,11 @@
|
||||
|
||||
|$Sub$$SysTick_Handler| PROC
|
||||
EXPORT |$Sub$$SysTick_Handler|
|
||||
IMPORT user_code_insert_to_systick_handler
|
||||
IMPORT perfc_port_insert_to_system_timer_insert_ovf_handler
|
||||
IMPORT |$Super$$SysTick_Handler|
|
||||
push {r4, r5}
|
||||
push {r4, lr}
|
||||
LDR R0, =user_code_insert_to_systick_handler
|
||||
LDR R0, =perfc_port_insert_to_system_timer_insert_ovf_handler
|
||||
BLX R0
|
||||
pop {r4, r5}
|
||||
mov lr, r5
|
||||
|
132
template/perfc_port_user.c
Normal file
132
template/perfc_port_user.c
Normal file
@ -0,0 +1,132 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
#undef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __IMPLEMENT_PERF_COUNTER
|
||||
#include "perf_counter.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 ========================================*/
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
/*============================ TYPES =========================================*/
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
/* low level interface for porting */
|
||||
extern
|
||||
uint32_t perfc_port_get_system_timer_freq(void);
|
||||
extern
|
||||
int64_t perfc_port_get_system_timer_top(void);
|
||||
extern
|
||||
bool perfc_port_is_system_timer_ovf_pending(void);
|
||||
extern
|
||||
bool perfc_port_init_system_timer(bool bTimerOccupied);
|
||||
extern
|
||||
int64_t perfc_port_get_system_timer_elapsed(void);
|
||||
extern
|
||||
void perfc_port_clear_system_timer_ovf_pending(void);
|
||||
extern
|
||||
void perfc_port_stop_system_timer_counting(void);
|
||||
extern
|
||||
void perfc_port_clear_system_timer_counter(void);
|
||||
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
#if __PERFC_USE_USER_CUSTOM_PORTING__
|
||||
|
||||
bool perfc_port_init_system_timer(bool bIsTimeOccupied)
|
||||
{
|
||||
bool bResult = true;
|
||||
do {
|
||||
if (bIsTimeOccupied) {
|
||||
break;
|
||||
}
|
||||
|
||||
__IRQ_SAFE {
|
||||
/* Configure the system timer count with the longest possible period
|
||||
* clear counter
|
||||
* Clear overflow pending flag
|
||||
* Enable interrupt if required
|
||||
* start counting
|
||||
*/
|
||||
}
|
||||
} while(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t perfc_port_get_system_timer_freq(void)
|
||||
{
|
||||
/* return the system timer frequency */
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool perfc_port_is_system_timer_ovf_pending(void)
|
||||
{
|
||||
/* whether the system timer overflow is pending */
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t perfc_port_get_system_timer_top(void)
|
||||
{
|
||||
/* the top value of the counting */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t perfc_port_get_system_timer_elapsed(void)
|
||||
{
|
||||
/* the elapsed count number since last overflow */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void perfc_port_clear_system_timer_ovf_pending(void)
|
||||
{
|
||||
/* clear the overflow pending flag */
|
||||
}
|
||||
|
||||
void perfc_port_stop_system_timer_counting(void)
|
||||
{
|
||||
/* stop the system timer */
|
||||
}
|
||||
|
||||
void perfc_port_clear_system_timer_counter(void)
|
||||
{
|
||||
/* clear the system timer counter */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
53
template/perfc_port_user.h
Normal file
53
template/perfc_port_user.h
Normal file
@ -0,0 +1,53 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); *
|
||||
* you may not use this file except in compliance with the License. *
|
||||
* You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
#if __PERFC_USE_USER_CUSTOM_PORTING__
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
/*============================ TYPES =========================================*/
|
||||
typedef uint32_t perfc_global_interrupt_status_t;
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
/*============================ IMPLEMENTATION ================================*/
|
||||
|
||||
static
|
||||
inline
|
||||
perfc_global_interrupt_status_t perfc_port_disable_global_interrupt(void)
|
||||
{
|
||||
perfc_global_interrupt_status_t tStatus;
|
||||
|
||||
/* get global interrupt status */
|
||||
/* disable global interrupt */
|
||||
/* return the status */
|
||||
|
||||
return tStatus;
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
void perfc_port_resume_global_interrupt(perfc_global_interrupt_status_t tStatus)
|
||||
{
|
||||
/* resume the stored global interrupt status */
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user