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`.
- 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{...}`
- Helper macros for C language extension:
- VB like `with()`
-`foreach()`, dimof(), `CONNECT()`
- C# like `using()`
- simple overload feature of OOPC made out of ANSI-C99, `__PLOOC_VA_NUM_ARGS()`
- ...
## 1. How To Use
### 1.1 Measure CPU cycles for specified code segment
You can measure specified code segment with a macro helper `__cycleof__()`, it is a wrapper of `get_system_ticks()`.
**Syntax:**
```c
__cycleof__(<DescriptionStringforthetarget>, [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 `__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()`.
#### **Example 1:** Simple measurement with printf
```c
__cycleof__() {
foreach(example_lv0_t, s_tItem, ptItem) {
printf("Processing item with ID = %d\r\n", _->chID);
This example shows how to use the delta value of `get_system_ticks()` to measure the CPU cycles used by specified code segment. In fact, the `__cycleof__()` is implemented in the same way:
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()`.
If you have not modify anything in `EventRecorderConf.h`, **you don't have to**, and please keep the default configuration. If you see warnings like this:
**By using perf_counter as the reference clock, EventRecorder can have the highest clock resolution on the target system without worring about the presence of DWT or any conflicting usage of SysTick.**
1. The `SystemCoreClock` has been updated with the new system frequency. Usually, the HAL will update the `SystemCoreClock` automatically, but in some rare cases where `SystemCoreClock` is updated accordingly, you should do it yourself.
> **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`.
7. Make sure the `SystemCoreClock` is updated with the same value as CPU frequency.
8.**IMPORTANT**: Make sure the `SysTick_CTRL_CLKSOURCE_Msk` bit ( bit 2) of `SysTick->CTRL` register is `1` that means SysTick runs with the same clock source as the target Cortex-M processor.
9. Initialize the perf_counter with boolean value that indicates whether the user applications and/or RTOS have already occupied the SysTick.
```c
void main(void)
{
//! setup system clock
/*! \brief Update SystemCoreClock with the latest CPU frequency
*! If the function doesn't exist or doesn't work correctly,
*! Please update SystemCoreClock directly with the correct
*! system frequency in Hz.
*!
*! extern volatile uint32_t SystemCoreClock;
*/
SystemCoreClockUpdate();
/*! \brief initialize perf_counter() and pass true if SysTick is
*! occupied by user applications or RTOS, otherwise pass
*! false.
*/
init_cycle_counter(true);
...
while(1) {
...
}
}
```
10.**IMPORTANT**: Please enable GNU extension in your compiler. For **GCC** and **CLANG**, it is `--std=gnu99` or `--std=gnu11`, and for other compilers, please check the user manual first. Failed to do so, you will not only trigger the warning in `perf_counter.h`, but also lose the function correctness of `__cycleof__()` and `__super_loop_monitor__()`, because `__PLOOC_VA_NUM_ARGS()` isn't report `0` when passed with no argument.
```c
#if __PLOOC_VA_NUM_ARGS() != 0
#warning Please enable GNC extensions, it is required by __cycleof__() and \
__super_loop_monitor__()
#endif
```
11. It is nice to add macro definition `__PERF_COUNTER__` to your project GLOBALLY. It helps other module to detect the existence of perf_counter. For Example, LVGL [`lv_conf_cmsis.h`](https://github.com/lvgl/lvgl/blob/d367bb7cf17dc34863f4439bba9b66a820088951/env_support/cmsis-pack/lv_conf_cmsis.h#L81-L99) use this macro to detect perf_counter and uses `get_system_ms()` to implement `lv_tick_get()`.
1. Download the cmsis-pack from the`cmsis-pack` folder. It is a file with name `GorgonMeducer.perf_counter.<version>.pack`, for example `GorgonMeducer.perf_counter.2.2.0.pack`
5. Make sure your system contains the CMSIS (with a version 5.7.0 or above) as `perf_counter.h` includes `cmsis_compiler.h`. Usually, you should do this with RTE as shown below:
6. Make sure the `SystemCoreClock` is updated with the same value as CPU frequency.
7.**IMPORTANT**: Make sure the `SysTick_CTRL_CLKSOURCE_Msk` bit ( bit 2) of `SysTick->CTRL` register is `1` that means SysTick runs with the same clock source as the target Cortex-M processor.
8. Initialize the perf_counter with boolean value that indicates whether the user applications and/or RTOS have already occupied the SysTick.
```c
void main(void)
{
//! setup system clock
/*! \brief Update SystemCoreClock with the latest CPU frequency
*! If the function doesn't exist or doesn't work correctly,
*! Please update SystemCoreClock directly with the correct
*! system frequency in Hz.
*!
*! extern volatile uint32_t SystemCoreClock;
*/
SystemCoreClockUpdate();
/*! \brief initialize perf_counter() and pass true if SysTick is
*! occupied by user applications or RTOS, otherwise pass
*! false.
*/
init_cycle_counter(true);
...
while(1) {
...
}
}
```
9.**IMPORTANT**: Please enable GNU extension in your compiler.
For Arm Compiler 5, please select both **C99 mode** and GNU extensions in the **Option for target dialog** as shown below:
Failed to do so, you will not only trigger the warning in `perf_counter.h`, but also lose the function correctness of `__cycleof__()` and `__super_loop_monitor__()`, because `__PLOOC_VA_NUM_ARGS()` isn't report `0` when passed with no argument.
```c
#if __PLOOC_VA_NUM_ARGS() != 0
#warning Please enable GNC extensions, it is required by __cycleof__() and \
perf_counter has registered as one of the [RT-Thread software packages](https://packages.rt-thread.org/en/detail.html?package=perf_counter), which locats in `system` category. In [ENV](https://www.rt-thread.io/download.html?download=Env) or [RT-Thread Studio](https://www.rt-thread.io/download.html?download=Studio), you just need to simply enable cputime framework. RT-Thread will automatically enable perf_counter if you are using Cortex-M architecture.
This error usually pops up in **Arm Compiler 5** and **Arm Compiler 6**. It is because you haven't implemented any non-weak `SysTick_Handler()`. Please provide an EMPTY one in any c source file to solve this problem:
**NOTE**: If you deploy perf_counter using cmsis-pack and encounter this issue, please **DO NOT** call function `user_code_insert_to_systick_handler()` in this **should-be-empty**`SysTick_Handler()`.
Since version v2.1.0 I removed the unnecessary bundle feature from the cmsis-pack. If you have used the older version, you will encounter this issue. To solve this problem: