MLECO-3096: Removing "timer" from HAL profile.

Attempting to have timer functionality contained within
the platform drivers "package" as it should (in line with
the refactoring work done so far under HAL). This will
ensure that we don't need two timer implementations under
HAL "profiles" and therefore, this whole directory can be
removed.

This change also addressed issue with the applicatio level
Profiler code knowing about how the PMU has been set up by
the platform code. This link has been removed completely.
This will make it much easier to add/amend the Ethos-U PMU
event counters types and give each platform the capability
of populating their relvant counters. The application level
Profiler doesn't know which metrics it is displaying but
just calculates and maintains statistics for whatever PMU
counters it receives from the HAL level.

A fix for timing adapter issue introduced in the last CR
is also included.

Change-Id: Ia46e03a06e7b8e42b9ed2ba8f2af2dcd2229c110
Signed-off-by: Kshitij Sisodia <kshitij.sisodia@arm.com>
diff --git a/docs/sections/building.md b/docs/sections/building.md
index 699667b..5f8a3cb 100644
--- a/docs/sections/building.md
+++ b/docs/sections/building.md
@@ -206,7 +206,7 @@
   `ETHOS_U_NPU_ID` is `U65`. Default value is 393216 (see [default_vela.ini](../../scripts/vela/default_vela.ini) ).
 
 - `CPU_PROFILE_ENABLED`: Sets whether profiling information for the CPU core should be displayed. By default, this is
-  set to false, but can be turned on for FPGA targets. The the FVP and the CPU core cycle counts are not meaningful and
+  set to false, but can be turned on for FPGA targets. The FVP and the CPU core cycle counts are **not** meaningful and
   are not to be used.
 
 - `LOG_LEVEL`: Sets the verbosity level for the output of the application over `UART`, or `stdout`. Valid values are:
diff --git a/docs/sections/testing_benchmarking.md b/docs/sections/testing_benchmarking.md
index d1cd9df..2641049 100644
--- a/docs/sections/testing_benchmarking.md
+++ b/docs/sections/testing_benchmarking.md
@@ -101,11 +101,7 @@
 INFO - Profile for Inference:
 INFO - NPU AXI0_RD_DATA_BEAT_RECEIVED beats: 628122
 INFO - NPU AXI0_WR_DATA_BEAT_WRITTEN beats: 135087
-INFO - NPU AXI1_RD_DATA_BEAT_RECEIVED beats: 62870
-INFO - NPU ACTIVE cycles: 1081007
-INFO - NPU IDLE cycles: 626
-INFO - NPU TOTAL cycles: 1081634
-INFO - CPU ACTIVE cycles (approx): 993553
+...
 INFO - Time ms: 210
 ```
 
diff --git a/source/hal/CMakeLists.txt b/source/hal/CMakeLists.txt
index 19f152c..10016c2 100644
--- a/source/hal/CMakeLists.txt
+++ b/source/hal/CMakeLists.txt
@@ -30,20 +30,10 @@
 # Create static library
 add_library(${HAL_TARGET} STATIC)
 
-# Select which profile needs to be used:
-if (${CMAKE_CROSSCOMPILING})
-    set(PLATFORM_PROFILE bare-metal)
-else()
-    set(PLATFORM_PROFILE native)
-endif()
-
-set(PLATFORM_PROFILE_DIR    source/profiles/${PLATFORM_PROFILE})
-
 ## Common include directories - public
 target_include_directories(${HAL_TARGET}
     PUBLIC
-    include
-    ${PLATFORM_PROFILE_DIR}/timer/include)
+    include)
 
 ## Common sources for all profiles
 target_sources(${HAL_TARGET}
@@ -51,7 +41,7 @@
     source/hal.c
     source/data_psn.c
     source/data_acq.c
-    ${PLATFORM_PROFILE_DIR}/timer/platform_timer.c)
+    source/hal_timer.c)
 
 if (DEFINED VERIFY_TEST_OUTPUT)
     message(STATUS "Test output verification flag is: ${VERIFY_TEST_OUTPUT}")
diff --git a/source/hal/include/timer.h b/source/hal/include/timer.h
index 4429388..9910fcf 100644
--- a/source/hal/include/timer.h
+++ b/source/hal/include/timer.h
@@ -17,54 +17,20 @@
 #ifndef HAL_TIMER_H
 #define HAL_TIMER_H
 
-#include "platform_timer.h"
-
-/** Struct for describing the capabilities available for
- * the timer provided by HAL */
-typedef struct _platform_timer_capability {
-    uint32_t npu_cycles:    1;
-    uint32_t cpu_cycles:    1;
-    uint32_t duration_ms:   1;
-    uint32_t duration_us:   1;
-} timer_capability;
+#include "platform_drivers.h"  /* Platform package API */
+#include "user_input.h"        /* PMU structs and API */
 
 /* Structure to hold a platform specific timer implementation */
 typedef struct _platform_timer {
-    int inited;                 /**< initialised or not */
-    timer_capability cap;       /**< capability of this timer */
-
-    /* reset the timer */
-    void (* reset)(void);
-
-    /* Gets the current time counter. */
-    time_counter (* get_time_counter)(void);
-
-    /* Gets the duration in milliseconds. */
-    time_t (* get_duration_ms)(time_counter *start, time_counter *end);
-
-    /* Gets duration in microseconds. */
-    time_t (* get_duration_us)(time_counter *start, time_counter *end);
-
-    /* Gets difference in CPU cycle counts. */
-    uint64_t (* get_cpu_cycle_diff)(time_counter *start, time_counter *end);
-
-    /* Gets the difference in terms of cycle counts for collected pmu counters. */
-    int (* get_npu_cycles_diff)(time_counter *start, time_counter *end,
-                                uint64_t* pmu_counters_values, size_t size);
-
-    /* Wraps get_time_counter function with additional profiling
-     * initialisation, if required. */
-    time_counter (* start_profiling)(void);
-
-    /* Wraps get_time_counter function along with additional instructions when
-     * profiling ends, if required. */
-    time_counter (* stop_profiling)(void);
+    int inited;                           /**< Initialised or not. */
+    void (* reset)(void);                 /**< Reset the timer. */
+    pmu_counters (* get_counters)(void);  /**< Gets the current time counter. */
 
 } platform_timer;
 
 /**
  * @brief   Initialise the timer available for the platform.
  **/
-void init_timer(platform_timer *timer);
+void init_timer(platform_timer* timer);
 
 #endif /* HAL_TIMER_H */
diff --git a/source/hal/source/components/npu/CMakeLists.txt b/source/hal/source/components/npu/CMakeLists.txt
index c53dd02..9d0bf42 100644
--- a/source/hal/source/components/npu/CMakeLists.txt
+++ b/source/hal/source/components/npu/CMakeLists.txt
@@ -126,7 +126,8 @@
 target_sources(${ETHOS_U_NPU_COMPONENT}
     PRIVATE
     ethosu_npu_init.c
-    ethosu_cpu_cache.c)
+    ethosu_cpu_cache.c
+    ethosu_profiler.c)
 
 ## Add dependencies:
 target_link_libraries(${ETHOS_U_NPU_COMPONENT} PUBLIC
diff --git a/source/hal/source/components/npu/ethosu_profiler.c b/source/hal/source/components/npu/ethosu_profiler.c
new file mode 100644
index 0000000..3ac3497
--- /dev/null
+++ b/source/hal/source/components/npu/ethosu_profiler.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2022 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
+ *
+ *     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.
+ */
+
+#include "ethosu_profiler.h"
+#include "log_macros.h"
+
+#include <string.h>
+
+extern struct ethosu_driver ethosu_drv;     /* Default Arm Ethos-U NPU device driver object */
+static ethosu_pmu_counters npu_counters;    /* NPU counter local instance */
+
+/**
+ * @brief Gets the npu counter instance to be used.
+ * @return Pointer to the npu counter instance.
+ */
+static ethosu_pmu_counters* get_counter_instance(void)
+{
+    return &npu_counters;
+}
+
+/**
+ * @brief Checks if the counter has overflown.
+ * @param pmu_counter_mask  Mask for the event counter.
+ * @return  true if overflow is detected, false otherwise.
+ */
+static bool counter_overflow(uint32_t pmu_counter_mask)
+{
+    /* Check for overflow: The idle counter is 32 bit while the
+       total cycle count is 64 bit. */
+    const uint32_t overflow_status = ETHOSU_PMU_Get_CNTR_OVS(&ethosu_drv);
+    return pmu_counter_mask & overflow_status ? true : false;
+}
+
+void ethosu_pmu_init(void)
+{
+    uint32_t i = 0;
+    uint32_t evt_mask = ETHOSU_PMU_CCNT_Msk;
+    ethosu_pmu_counters* counters = get_counter_instance();
+    memset(counters, 0, sizeof(*counters));
+
+    /* Total counters = event counters + derived counters + total cycle count */
+    counters->num_total_counters = ETHOSU_PROFILER_NUM_COUNTERS;
+
+#if ETHOSU_PMU_NCOUNTERS >= 4
+    counters->npu_evt_counters[0].event_type = ETHOSU_PMU_NPU_IDLE;
+    counters->npu_evt_counters[0].event_mask = ETHOSU_PMU_CNT1_Msk;
+    counters->npu_evt_counters[0].name = "NPU IDLE";
+    counters->npu_evt_counters[0].unit = "cycles";
+
+    counters->npu_evt_counters[1].event_type = ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED;
+    counters->npu_evt_counters[1].event_mask = ETHOSU_PMU_CNT2_Msk;
+    counters->npu_evt_counters[1].name = "NPU AXI0_RD_DATA_BEAT_RECEIVED";
+    counters->npu_evt_counters[1].unit = "beats";
+
+    counters->npu_evt_counters[2].event_type = ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN;
+    counters->npu_evt_counters[2].event_mask = ETHOSU_PMU_CNT3_Msk;
+    counters->npu_evt_counters[2].name = "NPU AXI0_WR_DATA_BEAT_WRITTEN";
+    counters->npu_evt_counters[2].unit = "beats";
+
+    counters->npu_evt_counters[3].event_type = ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED;
+    counters->npu_evt_counters[3].event_mask = ETHOSU_PMU_CNT4_Msk;
+    counters->npu_evt_counters[3].name = "NPU AXI1_RD_DATA_BEAT_RECEIVED";
+    counters->npu_evt_counters[3].unit = "beats";
+#else /* ETHOSU_PMU_NCOUNTERS >= 4 */
+    #error "NPU PMU expects a minimum of 4 available event triggered counters!"
+#endif /* ETHOSU_PMU_NCOUNTERS >= 4 */
+
+#if ETHOSU_DERIVED_NCOUNTERS >= 1
+    counters->npu_derived_counters[0].name = "NPU ACTIVE";
+    counters->npu_derived_counters[0].unit = "cycles";
+#endif /* ETHOSU_DERIVED_NCOUNTERS >= 1 */
+
+    for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) {
+        ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, i, counters->npu_evt_counters[i].event_type);
+        evt_mask |= counters->npu_evt_counters[i].event_mask;
+    }
+
+    /* Reset overflow status. */
+    ETHOSU_PMU_Set_CNTR_OVS(&ethosu_drv, evt_mask);
+
+    /* Enable PMU. */
+    ETHOSU_PMU_Enable(&ethosu_drv);
+
+    /* Enable counters for cycle and event counters. */
+    ETHOSU_PMU_CNTR_Disable(&ethosu_drv, evt_mask);
+    ethosu_pmu_reset_counters();
+    ETHOSU_PMU_CNTR_Enable(&ethosu_drv, evt_mask);
+}
+
+/**
+ * @brief  Resets the Arm Ethos-U NPU PMU counters.
+ */
+void ethosu_pmu_reset_counters(void)
+{
+    /* Reset all cycle and event counters. */
+    ETHOSU_PMU_CYCCNT_Reset(&ethosu_drv);
+    ETHOSU_PMU_EVCNTR_ALL_Reset(&ethosu_drv);
+}
+
+/**
+ * @brief Get the Arm Ethos-U NPU PMU counters
+ * @return ethosu_pmu_counters
+ */
+ethosu_pmu_counters ethosu_get_pmu_counters(void)
+{
+    ethosu_pmu_counters* counters = get_counter_instance();
+    uint32_t i = 0;
+
+    /* Event counters */
+    for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) {
+        if (counter_overflow(counters->npu_evt_counters[i].event_mask)) {
+            warn("Counter overflow detected for %s.\n", counters->npu_evt_counters[i].name);
+        }
+        counters->npu_evt_counters[i].counter_value =
+            ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, i);
+    }
+
+    /* Total cycle count */
+    counters->npu_total_ccnt = ETHOSU_PMU_Get_CCNTR(&ethosu_drv);
+
+    /* Derived counters */
+#if ETHOSU_DERIVED_NCOUNTERS >= 1
+    if (counters->npu_evt_counters[0].event_type == ETHOSU_PMU_NPU_IDLE) {
+        counters->npu_derived_counters[0].counter_value =
+            counters->npu_total_ccnt - counters->npu_evt_counters[0].counter_value;
+    }
+#endif /* ETHOSU_DERIVED_NCOUNTERS >= 1 */
+
+    return *counters;
+}
diff --git a/source/hal/source/components/npu/include/ethosu_profiler.h b/source/hal/source/components/npu/include/ethosu_profiler.h
new file mode 100644
index 0000000..ca95b19
--- /dev/null
+++ b/source/hal/source/components/npu/include/ethosu_profiler.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2022 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
+ *
+ *     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 ETHOS_U_PROFILER_H
+#define ETHOS_U_PROFILER_H
+
+#include "pmu_ethosu.h"
+
+#define ETHOSU_DERIVED_NCOUNTERS     1      /**< Number of counters derived from event counters */
+#define ETHOSU_PROFILER_NUM_COUNTERS ( \
+            ETHOSU_DERIVED_NCOUNTERS + \
+            ETHOSU_PMU_NCOUNTERS +     \
+            1 /* total CCNT */)
+
+typedef struct npu_event_counter_ {
+    enum ethosu_pmu_event_type event_type;
+    uint32_t event_mask;
+    uint32_t counter_value;
+    char* unit;
+    char* name;
+} npu_evt_counter;
+
+typedef struct npu_derived_counter_ {
+    uint32_t counter_value;
+    char* unit;
+    char* name;
+} npu_derived_counter;
+
+typedef struct ethosu_pmu_counters_ {
+    uint64_t                npu_total_ccnt;     /**< Total NPU cycles */
+    npu_evt_counter         npu_evt_counters[ETHOSU_PMU_NCOUNTERS];
+    npu_derived_counter     npu_derived_counters[ETHOSU_DERIVED_NCOUNTERS];
+    uint32_t                num_total_counters; /**< Total number of counters */
+} ethosu_pmu_counters;
+
+/**
+ * @brief  Initialise the Arm Ethos-U NPU performance monitoring unit.
+ */
+void ethosu_pmu_init(void);
+
+/**
+ * @brief  Resets the Arm Ethos-U NPU PMU counters.
+ */
+void ethosu_pmu_reset_counters(void);
+
+/**
+ * @brief Get the Arm Ethos-U NPU PMU counters
+ * @return ethosu_pmu_counters
+ */
+ethosu_pmu_counters ethosu_get_pmu_counters(void);
+
+#endif /* ETHOS_U_PROFILER_H */
diff --git a/source/hal/source/components/npu_ta/CMakeLists.txt b/source/hal/source/components/npu_ta/CMakeLists.txt
index 6f7dac5..73bbef7 100644
--- a/source/hal/source/components/npu_ta/CMakeLists.txt
+++ b/source/hal/source/components/npu_ta/CMakeLists.txt
@@ -36,6 +36,10 @@
     set(SOURCE_GEN_DIR ${CMAKE_BINARY_DIR}/generated/ta)
 endif()
 
+# Base address definitions for the two timing adapters (platform should override these):
+set(TA0_BASE            "0x58103000"    CACHE STRING "Ethos-U NPU timing adapter 0")
+set(TA1_BASE            "0x58103200"    CACHE STRING "Ethos-U NPU timing adapter 1")
+
 ## If a TA config file is provided, we generate a settings file
 if (DEFINED TA_CONFIG_FILE)
     include(${TA_CONFIG_FILE})
diff --git a/source/hal/source/components/npu_ta/ethosu_ta_init.c b/source/hal/source/components/npu_ta/ethosu_ta_init.c
index 323ab73..f3c95b6 100644
--- a/source/hal/source/components/npu_ta/ethosu_ta_init.c
+++ b/source/hal/source/components/npu_ta/ethosu_ta_init.c
@@ -42,13 +42,13 @@
         .histbin = TA0_HISTBIN,
         .histcnt = TA0_HISTCNT};
 
-    if (0 != ta_init(&ta_0, TA0_BASE))
-    {
+    if (0 != ta_init(&ta_0, TA0_BASE)) {
         printf_err("TA0 initialisation failed\n");
         return 1;
     }
 
     ta_set_all(&ta_0, &ta_0_settings);
+    info("TA0 values set\n");
 #endif /* defined (TA0_BASE) */
 
 #if defined(TA1_BASE)
@@ -76,6 +76,7 @@
     }
 
     ta_set_all(&ta_1, &ta_1_settings);
+    info("TA1 values set\n");
 #endif /* defined (TA1_BASE) */
 
     return 0;
diff --git a/source/hal/source/components/platform_pmu/CMakeLists.txt b/source/hal/source/components/platform_pmu/CMakeLists.txt
new file mode 100644
index 0000000..3ef407d
--- /dev/null
+++ b/source/hal/source/components/platform_pmu/CMakeLists.txt
@@ -0,0 +1,30 @@
+#----------------------------------------------------------------------------
+#  Copyright (c) 2022 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
+#
+#      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.
+#----------------------------------------------------------------------------
+
+#####################################################################
+#  Interface library for platform performance monitoring unit       #
+#####################################################################
+cmake_minimum_required(VERSION 3.15.6)
+
+project(platform_pmu
+    DESCRIPTION     "Header/interface for platform PMU"
+    LANGUAGES       C)
+
+# Interface library:
+set(PLATFORM_PMU_TARGET platform_pmu)
+add_library(${PLATFORM_PMU_TARGET} INTERFACE)
+target_include_directories(${PLATFORM_PMU_TARGET} INTERFACE include)
diff --git a/source/hal/source/components/platform_pmu/include/platform_pmu.h b/source/hal/source/components/platform_pmu/include/platform_pmu.h
new file mode 100644
index 0000000..3724e57
--- /dev/null
+++ b/source/hal/source/components/platform_pmu/include/platform_pmu.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2022 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
+ *
+ *     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 PLATFORM_PMU_INTERFACE_H
+#define PLATFORM_PMU_INTERFACE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define NUM_PMU_COUNTERS     (10)     /**< Maximum number of available counters. */
+
+/**
+ * @brief   Container for a single unit for a PMU counter.
+ */
+typedef struct _pmu_counter_unit {
+    uint64_t value;     /**< Value of the counter expressed as 64 bits unsigned integer. */
+    const char* name;   /**< Name for the counter. */
+    const char* unit;   /**< Unit that the counter value represents (like cycles, beats, or milliseconds). */
+} pmu_counter_unit;
+
+/**
+ * @brief   Container for a an array of counters
+ */
+typedef struct _pmu_counters {
+    pmu_counter_unit counters[NUM_PMU_COUNTERS]; /**< Counter array. */
+    uint32_t num_counters;                       /**< Number of valid counters. */
+    bool initialised;                            /**< Initialised or not. */
+} pmu_counters;
+
+/**
+ * @brief   Resets the counters.
+ */
+void platform_reset_counters(void);
+
+/**
+ * @brief   Gets the current counter values.
+ * @returns A populated instance of pmu_counters struct.
+ **/
+pmu_counters platform_get_counters(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PLATFORM_PMU_INTERFACE_H */
diff --git a/source/hal/source/hal_timer.c b/source/hal/source/hal_timer.c
new file mode 100644
index 0000000..0488afa
--- /dev/null
+++ b/source/hal/source/hal_timer.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022 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
+ *
+ *     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.
+ */
+#include "timer.h"
+#include "log_macros.h"
+#include "platform_drivers.h"
+
+#include <assert.h>
+#include <string.h>
+#include <inttypes.h>
+
+/**
+ * @brief       Initialiser for HAL timer.
+ * @param[in]   timer  Platform timer to initialize.
+ **/
+void init_timer(platform_timer* timer)
+{
+    assert(timer);
+    memset(timer, 0, sizeof(*timer));
+
+    timer->reset = platform_reset_counters;
+    timer->get_counters = platform_get_counters;
+
+    timer->reset();
+    timer->inited = 1;
+}
diff --git a/source/hal/source/platform/mps3/CMakeLists.txt b/source/hal/source/platform/mps3/CMakeLists.txt
index 31cd004..2f0174b 100644
--- a/source/hal/source/platform/mps3/CMakeLists.txt
+++ b/source/hal/source/platform/mps3/CMakeLists.txt
@@ -32,14 +32,19 @@
 
 # Define target specific base addresses here (before adding the components)
 if (TARGET_SUBSYSTEM STREQUAL sse-300)
-    set(UART0_BASE          "0x49303000"    CACHE STRING "UART base address")
-    set(UART0_BAUDRATE      "115200"        CACHE STRING "UART baudrate")
-    set(SYSTEM_CORE_CLOCK   "25000000"      CACHE STRING "System peripheral clock (Hz)")
-    set(CLCD_CONFIG_BASE    "0x4930A000"    CACHE STRING "LCD configuration base address")
-    set(ETHOS_U_BASE_ADDR   "0x58102000"    CACHE STRING "Ethos-U NPU base address")
-    set(ETHOS_U_IRQN        "56"            CACHE STRING "Ethos-U55 Interrupt")
+    set(UART0_BASE           "0x49303000"   CACHE STRING "UART base address")
+    set(UART0_BAUDRATE       "115200"       CACHE STRING "UART baudrate")
+    set(SYSTEM_CORE_CLOCK    "25000000"     CACHE STRING "System peripheral clock (Hz)")
+    set(CLCD_CONFIG_BASE     "0x4930A000"   CACHE STRING "LCD configuration base address")
+    set(ETHOS_U_BASE_ADDR    "0x58102000"   CACHE STRING "Ethos-U NPU base address")
+    set(ETHOS_U_IRQN         "56"           CACHE STRING "Ethos-U55 Interrupt")
     set(ETHOS_U_SEC_ENABLED  "1"            CACHE STRING "Ethos-U NPU Security enable")
     set(ETHOS_U_PRIV_ENABLED "1"            CACHE STRING "Ethos-U NPU Privilege enable")
+
+    if (ETHOS_U_NPU_TIMING_ADAPTER_ENABLED)
+        set(TA0_BASE         "0x58103000"   CACHE STRING "Ethos-U NPU timing adapter 0")
+        set(TA1_BASE         "0x58103200"   CACHE STRING "Ethos-U NPU timing adapter 1")
+    endif()
 endif()
 
 # 2. Create static library
@@ -77,13 +82,22 @@
 ## Platform component: lcd
 add_subdirectory(${COMPONENTS_DIR}/lcd ${CMAKE_BINARY_DIR}/lcd)
 
+## Platform component: PMU
+add_subdirectory(${COMPONENTS_DIR}/platform_pmu ${CMAKE_BINARY_DIR}/platform_pmu)
+
 # Add dependencies:
 target_link_libraries(${PLATFORM_DRIVERS_TARGET} PUBLIC
     log
     cmsis_device
+    platform_pmu
     lcd_mps3
     $<IF:$<BOOL:STDOUT_RETARGET>,stdout_retarget_cmsdk,stdout>)
 
+# Set the CPU profiling definition
+if (CPU_PROFILE_ENABLED)
+    target_compile_definitions(${PLATFORM_DRIVERS_TARGET} PUBLIC CPU_PROFILE_ENABLED)
+endif()
+
 # If Ethos-U is enabled, we need the driver library too
 if (ETHOS_U_NPU_ENABLED)
 
diff --git a/source/hal/source/platform/mps3/include/timer_mps3.h b/source/hal/source/platform/mps3/include/timer_mps3.h
index e1faf69..b370e89 100644
--- a/source/hal/source/platform/mps3/include/timer_mps3.h
+++ b/source/hal/source/platform/mps3/include/timer_mps3.h
@@ -17,10 +17,17 @@
 #ifndef TIMER_MPS3_H
 #define TIMER_MPS3_H
 
+#include "platform_pmu.h"
+
 #include <stdint.h>
+#include <stdbool.h>
+
+#if defined (ARM_NPU)
+    #include "ethosu_profiler.h"    /* Arm Ethos-U NPU profiling functions. */
+#endif /* defined (ARM_NPU) */
 
 /* Container for timestamp up-counters. */
-typedef struct _mps3_time_counter {
+typedef struct mps3_pmu_counters_ {
     uint32_t    counter_1Hz;
     uint32_t    counter_100Hz;
 
@@ -29,8 +36,18 @@
 
     /* Running at processor core's internal clock rate, triggered by SysTick. */
     uint64_t    counter_systick;
-} base_time_counter;
+} mps3_pmu_counters;
 
+/**
+ * @brief   Resets the counters.
+ */
+void platform_reset_counters(void);
+
+/**
+ * @brief   Gets the current counter values.
+ * @returns A populated instance of pmu_counters struct.
+ **/
+pmu_counters platform_get_counters(void);
 
 /**
  * @brief  Gets the MPS3 core clock
@@ -39,57 +56,6 @@
 uint32_t get_mps3_core_clock(void);
 
 /**
- * @brief   Resets the counters.
- */
-void timer_reset(void);
-
-/**
- * @brief   Gets the current counter values.
- * @returns Mps3 timer counter.
- **/
-base_time_counter get_time_counter(void);
-
-/**
- * @brief       Gets the duration elapsed between two counters in milliseconds.
- * @param[in]   start   Pointer to base_time_counter value at start time.
- * @param[in]   end     Pointer to base_time_counter value at end.
- * @returns     Difference in milliseconds between the two give counters
- *              expressed as an unsigned integer.
- **/
-uint32_t get_duration_milliseconds(base_time_counter *start,
-                                   base_time_counter *end);
-
-/**
- * @brief       Gets the duration elapsed between two counters in microseconds.
- * @param[in]   start   Pointer to base_time_counter value at start time.
- * @param[in]   end     Pointer to base_time_counter value at end.
- * @returns     Difference in microseconds between the two give counters
- *              expressed as an unsigned integer.
- **/
-uint32_t get_duration_microseconds(base_time_counter *start,
-                                   base_time_counter *end);
-
-/**
- * @brief       Gets the cycle counts elapsed between start and end.
- * @param[in]   start   Pointer to base_time_counter value at start time.
- * @param[in]   end     Pointer to base_time_counter value at end.
- * @return      Difference in counter values as 32 bit unsigned integer.
- **/
-uint64_t get_cycle_count_diff(base_time_counter *start,
-                              base_time_counter *end);
-
-/**
- * @brief   Enables or triggers cycle counting mechanism, if required
- *          by the platform.
- **/
-void start_cycle_counter(void);
-
-/**
- * @brief   Stops cycle counting mechanism, if required by the platform.
- **/
-void stop_cycle_counter(void);
-
-/**
  * @brief   System tick interrupt handler.
  **/
 void SysTick_Handler(void);
diff --git a/source/hal/source/platform/mps3/source/timer_mps3.c b/source/hal/source/platform/mps3/source/timer_mps3.c
index 3511883..6330269 100644
--- a/source/hal/source/platform/mps3/source/timer_mps3.c
+++ b/source/hal/source/platform/mps3/source/timer_mps3.c
@@ -32,7 +32,28 @@
  */
 static int Init_SysTick(void);
 
-void timer_reset(void)
+/**
+ * @brief Adds one PMU counter to the counters' array
+ * @param value Value of the counter
+ * @param name  Name for the given counter
+ * @param unit  Unit for the "value"
+ * @param counters Pointer to the counter struct - the one to be populated.
+ * @return true if successfully added, false otherwise
+ */
+static bool add_pmu_counter(
+        uint64_t value,
+        const char* name,
+        const char* unit,
+        pmu_counters* counters);
+
+/**
+ * @brief Gets the evaluated millisecond timestamp from the given MPS3 counter struct.
+ * @param mps3_counters     Pointer to the MPS3 counters.
+ * @return microseconds timestamp as 32 bit unsigned integer.
+ */
+static uint32_t get_tstamp_milliseconds(mps3_pmu_counters* mps3_counters);
+
+void platform_reset_counters(void)
 {
     MPS3_FPGAIO->CLK1HZ   = 0;
     MPS3_FPGAIO->CLK100HZ = 0;
@@ -42,85 +63,93 @@
         printf_err("Failed to initialise system tick config\n");
     }
     debug("system tick config ready\n");
+
+#if defined (ARM_NPU)
+    ethosu_pmu_init();
+#endif /* defined (ARM_NPU) */
 }
 
-base_time_counter get_time_counter(void)
+pmu_counters platform_get_counters(void)
 {
-    base_time_counter t = {
-        .counter_1Hz        = MPS3_FPGAIO->CLK1HZ,
-        .counter_100Hz      = MPS3_FPGAIO->CLK100HZ,
-        .counter_fpga       = MPS3_FPGAIO->COUNTER,
-        .counter_systick    = Get_SysTick_Cycle_Count()
+    pmu_counters platform_counters = {
+        .num_counters = 0,
+        .initialised = true
     };
-    debug("Timestamp:\n");
-    debug("\tCounter 1 Hz:   %" PRIu32 "\n", t.counter_1Hz);
-    debug("\tCounter 100 Hz: %" PRIu32 "\n", t.counter_100Hz);
-    debug("\tCounter FPGA:   %" PRIu32 "\n", t.counter_fpga);
-    debug("\tCounter CPU:    %" PRIu64 "\n", t.counter_systick);
-    return t;
+    uint32_t i = 0;
+
+#if defined (ARM_NPU)
+    ethosu_pmu_counters npu_counters = ethosu_get_pmu_counters();
+    for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) {
+        add_pmu_counter(
+            npu_counters.npu_evt_counters[i].counter_value,
+            npu_counters.npu_evt_counters[i].name,
+            npu_counters.npu_evt_counters[i].unit,
+            &platform_counters);
+    }
+    for (i = 0; i < ETHOSU_DERIVED_NCOUNTERS; ++i) {
+        add_pmu_counter(
+            npu_counters.npu_derived_counters[i].counter_value,
+            npu_counters.npu_derived_counters[i].name,
+            npu_counters.npu_derived_counters[i].unit,
+            &platform_counters);
+    }
+    add_pmu_counter(
+        npu_counters.npu_total_ccnt,
+        "NPU TOTAL",
+        "cycles",
+        &platform_counters);
+#endif /* defined (ARM_NPU) */
+
+#if defined(CPU_PROFILE_ENABLED)
+    mps3_pmu_counters mps3_counters = {
+            .counter_1Hz        = MPS3_FPGAIO->CLK1HZ,
+            .counter_100Hz      = MPS3_FPGAIO->CLK100HZ,
+            .counter_fpga       = MPS3_FPGAIO->COUNTER,
+            .counter_systick    = Get_SysTick_Cycle_Count()
+    };
+
+    add_pmu_counter(
+            mps3_counters.counter_systick,
+            "CPU TOTAL",
+            "cycles",
+            &platform_counters);
+
+    add_pmu_counter(
+            get_tstamp_milliseconds(&mps3_counters),
+            "DURATION",
+            "milliseconds",
+            &platform_counters);
+#endif /* defined(CPU_PROFILE_ENABLED) */
+
+#if !defined(CPU_PROFILE_ENABLED)
+    UNUSED(get_tstamp_milliseconds);
+    UNUSED(Get_SysTick_Cycle_Count);
+#if !defined(ARM_NPU)
+    UNUSED(add_pmu_counter);
+    UNUSED(i);
+#endif /* !defined(ARM_NPU) */
+#endif /* !defined(CPU_PROFILE_ENABLED) */
+
+    return platform_counters;
 }
 
-/**
- * Please note, that there are no checks for overflow in this function => if
- * the time elapsed has been big (in days) this could happen and is currently
- * not handled.
- **/
-uint32_t get_duration_milliseconds(base_time_counter *start,
-                                   base_time_counter *end)
+uint32_t get_mps3_core_clock(void)
 {
-    uint32_t time_elapsed = 0;
-    if (end->counter_100Hz > start->counter_100Hz) {
-        time_elapsed = (end->counter_100Hz - start->counter_100Hz) * 10;
-    } else {
-        time_elapsed = (end->counter_1Hz - start->counter_1Hz) * 1000 +
-            ((0xFFFFFFFF - start->counter_100Hz) + end->counter_100Hz + 1) * 10;
+    const uint32_t default_clock = 32000000 /* 32 MHz clock */;
+    static int warned_once = 0;
+    if (0 != MPS3_SCC->CFG_ACLK) {
+        if (default_clock != MPS3_SCC->CFG_ACLK) {
+            warn("System clock is different to the MPS3 config set clock.\n");
+        }
+        return MPS3_SCC->CFG_ACLK;
     }
 
-    /* If the time elapsed is less than 100ms, use microseconds count to be
-     * more precise */
-    if (time_elapsed < 100) {
-        debug("Using the microsecond function instead..\n");
-        return get_duration_microseconds(start, end)/1000;
+    if (!warned_once) {
+        warn("MPS3_SCC->CFG_ACLK reads 0. Assuming default clock of %" PRIu32 "\n",
+             default_clock);
+        warned_once = 1;
     }
-
-    return time_elapsed;
-}
-
-/**
- * Like the microsecond counterpart, this function could return wrong results when
- * the counter (MAINCLK) overflows. There are no overflow counters available.
- **/
-uint32_t get_duration_microseconds(base_time_counter *start,
-                                   base_time_counter *end)
-{
-    const int divisor = get_mps3_core_clock()/1000000;
-    uint32_t time_elapsed = 0;
-    if (end->counter_fpga > start->counter_fpga) {
-        time_elapsed = (end->counter_fpga - start->counter_fpga)/divisor;
-    } else {
-        time_elapsed = ((0xFFFFFFFF - end->counter_fpga)
-            + start->counter_fpga + 1)/divisor;
-    }
-    return time_elapsed;
-}
-
-uint64_t get_cycle_count_diff(base_time_counter *start,
-                              base_time_counter *end)
-{
-    if (start->counter_systick > end->counter_systick) {
-        warn("start > end; counter might have overflown\n");
-    }
-    return end->counter_systick - start->counter_systick;
-}
-
-void start_cycle_counter(void)
-{
-    /* Nothing to do for FPGA */
-}
-
-void stop_cycle_counter(void)
-{
-    /* Nothing to do for FPGA */
+    return default_clock;
 }
 
 void SysTick_Handler(void)
@@ -173,21 +202,30 @@
     return err;
 }
 
-uint32_t get_mps3_core_clock(void)
+static bool add_pmu_counter(uint64_t value,
+                            const char* name,
+                            const char* unit,
+                            pmu_counters* counters)
 {
-    const uint32_t default_clock = 32000000 /* 32 MHz clock */;
-    static int warned_once = 0;
-    if (0 != MPS3_SCC->CFG_ACLK) {
-        if (default_clock != MPS3_SCC->CFG_ACLK) {
-            warn("System clock is different to the MPS3 config set clock.\n");
-        }
-        return MPS3_SCC->CFG_ACLK;
-    }
+    const uint32_t idx = counters->num_counters;
+    if (idx < NUM_PMU_COUNTERS) {
+        counters->counters[idx].value = value;
+        counters->counters[idx].name = name;
+        counters->counters[idx].unit = unit;
+        ++counters->num_counters;
 
-    if (!warned_once) {
-        warn("MPS3_SCC->CFG_ACLK reads 0. Assuming default clock of %" PRIu32 "\n",
-            default_clock);
-        warned_once = 1;
+        debug("%s: %" PRIu64 " %s\n", name, value, unit);
+        return true;
     }
-    return default_clock;
-}
\ No newline at end of file
+    printf_err("Failed to add PMU counter!\n");
+    return false;
+}
+
+static uint32_t get_tstamp_milliseconds(mps3_pmu_counters* mps3_counters)
+{
+    const uint32_t divisor = get_mps3_core_clock() / 1000;
+    if (mps3_counters->counter_100Hz > 100) {
+        return (mps3_counters->counter_100Hz * 10);
+    }
+    return (mps3_counters->counter_systick/divisor);
+}
diff --git a/source/hal/source/platform/native/CMakeLists.txt b/source/hal/source/platform/native/CMakeLists.txt
index 9673fef..e0cc711 100644
--- a/source/hal/source/platform/native/CMakeLists.txt
+++ b/source/hal/source/platform/native/CMakeLists.txt
@@ -43,7 +43,8 @@
 ## Platform sources
 target_sources(${PLATFORM_DRIVERS_TARGET}
     PRIVATE
-    source/platform_drivers.c)
+    source/platform_drivers.c
+    source/timer_native.c)
 
 ## Platform component directory
 if (NOT DEFINED COMPONENTS_DIR)
@@ -57,10 +58,14 @@
 ## Platform component: lcd
 add_subdirectory(${COMPONENTS_DIR}/lcd ${CMAKE_BINARY_DIR}/lcd)
 
+## Platform component: PMU
+add_subdirectory(${COMPONENTS_DIR}/platform_pmu ${CMAKE_BINARY_DIR}/platform_pmu)
+
 # Add dependencies:
 target_link_libraries(${PLATFORM_DRIVERS_TARGET}
     PUBLIC
     log
+    platform_pmu
     stdout
     lcd_stubs)
 
diff --git a/source/hal/source/platform/native/include/platform_drivers.h b/source/hal/source/platform/native/include/platform_drivers.h
index d93e31c..a203618 100644
--- a/source/hal/source/platform/native/include/platform_drivers.h
+++ b/source/hal/source/platform/native/include/platform_drivers.h
@@ -21,6 +21,7 @@
 #include "log_macros.h"     /* Logging related helpers. */
 #include "lcd_img.h"        /* LCD functions */
 #include "user_input.h"     /* User input function */
+#include "timer_native.h"   /* Native platform timer/profiler support */
 
 /**
  * @brief   Initialises the platform components.
diff --git a/source/hal/source/profiles/native/timer/include/platform_timer.h b/source/hal/source/platform/native/include/timer_native.h
similarity index 67%
rename from source/hal/source/profiles/native/timer/include/platform_timer.h
rename to source/hal/source/platform/native/include/timer_native.h
index df7b493..c8eeda2 100644
--- a/source/hal/source/profiles/native/timer/include/platform_timer.h
+++ b/source/hal/source/platform/native/include/timer_native.h
@@ -14,18 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef TIMER_H
-#define TIMER_H
+#ifndef NATIVE_TIMER_H
+#define NATIVE_TIMER_H
+
+#include "platform_pmu.h"
 
 #include <stdint.h>
 #include <time.h>
 
-/* Container for time struct */
-typedef struct _time_counter {
-    /* Current POSIX time in secs. */
-    time_t current_secs;
-    /* Nanoseconds expired in current second. */
-    time_t current_nsecs;
-} time_counter;
+/**
+ * @brief   Resets the counters.
+ */
+void platform_reset_counters(void);
 
-#endif /* TIMER_H */
\ No newline at end of file
+/**
+ * @brief   Gets the current counter values.
+ * @returns A populated instance of pmu_counters struct.
+ **/
+pmu_counters platform_get_counters(void);
+
+#endif /* NATIVE_TIMER_H */
diff --git a/source/hal/source/platform/native/source/timer_native.c b/source/hal/source/platform/native/source/timer_native.c
new file mode 100644
index 0000000..590975f
--- /dev/null
+++ b/source/hal/source/platform/native/source/timer_native.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 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
+ *
+ *     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.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "timer_native.h"
+
+#include "log_macros.h"
+
+#include <time.h>
+#include <string.h>
+
+#define MILLISECONDS_IN_SECOND      1000
+#define MICROSECONDS_IN_SECOND      1000000
+#define NANOSECONDS_IN_MILLISECOND  1000000
+#define NANOSECONDS_IN_MICROSECOND  1000
+
+void platform_reset_counters() { /* Nothing to do */ }
+
+pmu_counters platform_get_counters(void)
+{
+    struct timespec current_time;
+    pmu_counters platform_counters = {
+        .num_counters = 0,
+        .initialised = true
+    };
+    clock_gettime(1, &current_time);
+    uint64_t microseconds = (current_time.tv_sec * MICROSECONDS_IN_SECOND) +
+                            (current_time.tv_nsec / NANOSECONDS_IN_MICROSECOND);
+
+#if NUM_PMU_COUNTERS > 0
+    platform_counters.counters[0].value = microseconds;
+    platform_counters.counters[0].name = "Duration";
+    platform_counters.counters[0].unit = "microseconds";
+    ++platform_counters.num_counters;
+#endif /* NUM_PMU_COUNTERS > 0 */
+
+    return platform_counters;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/hal/source/platform/simple/CMakeLists.txt b/source/hal/source/platform/simple/CMakeLists.txt
index e11d9a9..119f711 100644
--- a/source/hal/source/platform/simple/CMakeLists.txt
+++ b/source/hal/source/platform/simple/CMakeLists.txt
@@ -31,14 +31,19 @@
 endif()
 
 # Define target specific values here (before adding the components)
-set(UART0_BASE          "0x49303000"    CACHE STRING "UART base address")
-set(UART0_BAUDRATE      "115200"        CACHE STRING "UART baudrate")
-set(SYSTEM_CORE_CLOCK   "25000000"      CACHE STRING "System peripheral clock (Hz)")
-set(ETHOS_U_BASE_ADDR   "0x58102000"    CACHE STRING "Ethos-U NPU base address")
-set(ETHOS_U_IRQN        "56"            CACHE STRING "Ethos-U55 Interrupt")
+set(UART0_BASE           "0x49303000"   CACHE STRING "UART base address")
+set(UART0_BAUDRATE       "115200"       CACHE STRING "UART baudrate")
+set(SYSTEM_CORE_CLOCK    "25000000"     CACHE STRING "System peripheral clock (Hz)")
+set(ETHOS_U_BASE_ADDR    "0x58102000"   CACHE STRING "Ethos-U NPU base address")
+set(ETHOS_U_IRQN         "56"           CACHE STRING "Ethos-U55 Interrupt")
 set(ETHOS_U_SEC_ENABLED  "1"            CACHE STRING "Ethos-U NPU Security enable")
 set(ETHOS_U_PRIV_ENABLED "1"            CACHE STRING "Ethos-U NPU Privilege enable")
 
+if (ETHOS_U_NPU_TIMING_ADAPTER_ENABLED)
+    set(TA0_BASE         "0x58103000"   CACHE STRING "Ethos-U NPU timing adapter 0")
+    set(TA1_BASE         "0x58103200"   CACHE STRING "Ethos-U NPU timing adapter 1")
+endif()
+
 # 2. Create static library
 add_library(${PLATFORM_DRIVERS_TARGET} STATIC)
 
@@ -69,13 +74,22 @@
 ## Platform component: lcd
 add_subdirectory(${COMPONENTS_DIR}/lcd ${CMAKE_BINARY_DIR}/lcd)
 
+## Platform component: PMU
+add_subdirectory(${COMPONENTS_DIR}/platform_pmu ${CMAKE_BINARY_DIR}/platform_pmu)
+
 # Add dependencies:
 target_link_libraries(${PLATFORM_DRIVERS_TARGET}  PUBLIC
         cmsis_device
         log
+        platform_pmu
         lcd_stubs
         $<IF:$<BOOL:STDOUT_RETARGET>,stdout_retarget_pl011,stdout>)
 
+# Set the CPU profiling definition
+if (CPU_PROFILE_ENABLED)
+    target_compile_definitions(${PLATFORM_DRIVERS_TARGET} PUBLIC CPU_PROFILE_ENABLED)
+endif()
+
 # If Ethos-U is enabled, we need the driver library too
 if (ETHOS_U_NPU_ENABLED)
 
diff --git a/source/hal/source/platform/simple/include/platform_drivers.h b/source/hal/source/platform/simple/include/platform_drivers.h
index 5f2ed33..31bb682 100644
--- a/source/hal/source/platform/simple/include/platform_drivers.h
+++ b/source/hal/source/platform/simple/include/platform_drivers.h
@@ -23,7 +23,8 @@
 /* Platform components */
 #include "RTE_Components.h"         /* For CPU related defintiions */
 #include "timer_simple_platform.h"  /* timer implementation */
-#include "user_input.h"             /* User input function */
+#include "platform_pmu.h"           /* PMU definitions and API */
+#include "user_input.h"             /* User input functions */
 #include "lcd_img.h"                /* LCD functions */
 
 /**
diff --git a/source/hal/source/platform/simple/include/timer_simple_platform.h b/source/hal/source/platform/simple/include/timer_simple_platform.h
index 683a207..40acd03 100644
--- a/source/hal/source/platform/simple/include/timer_simple_platform.h
+++ b/source/hal/source/platform/simple/include/timer_simple_platform.h
@@ -16,42 +16,25 @@
  */
 #ifndef TIMER_SIMPLE_PLATFORM_H
 #define TIMER_SIMPLE_PLATFORM_H
+
+#include "platform_pmu.h"
+
+#if defined (ARM_NPU)
+    #include "ethosu_profiler.h"    /* Arm Ethos-U NPU profiling functions. */
+#endif /* defined (ARM_NPU) */
+
 #include <stdint.h>
 
-#include "RTE_Components.h"
-
-/* Container for timestamp for simple platform. */
-typedef struct _generic_time_counter {
-    uint64_t    counter_systick;
-} base_time_counter;
-
 /**
  * @brief   Resets the counters.
  */
-void timer_reset(void);
+void platform_reset_counters(void);
 
 /**
  * @brief   Gets the current counter values.
- * @returns counter struct.
+ * @returns A populated instance of pmu_counters struct.
  **/
-base_time_counter get_time_counter(void);
-
-/**
- * @brief   Gets the cycle counts elapsed between start and end.
- * @return  difference in counter values as 32 bit unsigned integer.
- */
-uint64_t get_cycle_count_diff(base_time_counter *start, base_time_counter *end);
-
-/**
- * @brief   Enables or triggers cycle counting mechanism, if required
- *          by the platform.
- */
-void start_cycle_counter(void);
-
-/**
- * @brief   Stops cycle counting mechanism, if required by the platform.
- */
-void stop_cycle_counter(void);
+pmu_counters platform_get_counters(void);
 
 /**
  * @brief   System tick interrupt handler.
diff --git a/source/hal/source/platform/simple/source/timer_simple_platform.c b/source/hal/source/platform/simple/source/timer_simple_platform.c
index f7917b0..94af308 100644
--- a/source/hal/source/platform/simple/source/timer_simple_platform.c
+++ b/source/hal/source/platform/simple/source/timer_simple_platform.c
@@ -16,8 +16,8 @@
  */
 #include "timer_simple_platform.h"
 
-#include "log_macros.h"     /* Logging macros */
-#include "RTE_Components.h" /* For CPU related defintiions */
+#include "log_macros.h"     /* Logging macros. */
+#include "RTE_Components.h" /* CPU definitions and functions. */
 
 #include <inttypes.h>
 
@@ -35,43 +35,83 @@
  */
 static int Init_SysTick(void);
 
+/**
+ * @brief Adds one PMU counter to the counters' array
+ * @param value Value of the counter
+ * @param name  Name for the given counter
+ * @param unit  Unit for the "value"
+ * @param counters Pointer to the counter struct - the one to be populated.
+ * @return true if successfully added, false otherwise
+ */
+static bool add_pmu_counter(
+        uint64_t value,
+        const char* name,
+        const char* unit,
+        pmu_counters* counters);
 
-base_time_counter get_time_counter(void)
-{
-    base_time_counter t = {
-        .counter_systick = Get_SysTick_Cycle_Count()
-    };
-    debug("counter_systick: %" PRIu64 "\n", t.counter_systick);
-    return t;
-}
-
-void timer_reset(void)
+void platform_reset_counters(void)
 {
     if (0 != Init_SysTick()) {
         printf_err("Failed to initialise system tick config\n");
+        return;
     }
+
+#if defined(ARM_NPU)
+    ethosu_pmu_init();
+#endif /* defined (ARM_NPU) */
+
     debug("system tick config ready\n");
 }
 
-uint64_t get_cycle_count_diff(base_time_counter *start,
-                              base_time_counter *end)
+pmu_counters platform_get_counters(void)
 {
-    if (start->counter_systick > end->counter_systick) {
-        warn("start > end; counter might have overflown\n");
+    pmu_counters platform_counters = {
+        .num_counters = 0,
+        .initialised = true
+    };
+    uint32_t i = 0;
+
+#if defined (ARM_NPU)
+    ethosu_pmu_counters npu_counters = ethosu_get_pmu_counters();
+    for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) {
+        add_pmu_counter(
+                npu_counters.npu_evt_counters[i].counter_value,
+                npu_counters.npu_evt_counters[i].name,
+                npu_counters.npu_evt_counters[i].unit,
+                &platform_counters);
     }
-    return end->counter_systick - start->counter_systick;
-}
+    for (i = 0; i < ETHOSU_DERIVED_NCOUNTERS; ++i) {
+        add_pmu_counter(
+                npu_counters.npu_derived_counters[i].counter_value,
+                npu_counters.npu_derived_counters[i].name,
+                npu_counters.npu_derived_counters[i].unit,
+                &platform_counters);
+    }
+    add_pmu_counter(
+            npu_counters.npu_total_ccnt,
+            "NPU TOTAL",
+            "cycles",
+            &platform_counters);
+#endif /* defined (ARM_NPU) */
 
-void start_cycle_counter(void)
-{
-    /* Add any custom requirement for this platform here */
-}
+#if defined(CPU_PROFILE_ENABLED)
+    add_pmu_counter(
+            Get_SysTick_Cycle_Count(),
+            "CPU TOTAL",
+            "cycles",
+            &platform_counters);
+#endif /* defined(CPU_PROFILE_ENABLED) */
 
-void stop_cycle_counter(void)
-{
-    /* Add any custom requirement for this platform here */
-}
+#if !defined(CPU_PROFILE_ENABLED)
+    UNUSED(Get_SysTick_Cycle_Count);
+#if !defined(ARM_NPU)
+    UNUSED(add_pmu_counter);
+    UNUSED(i);
+#endif /* !defined(ARM_NPU) */
+#endif /* !defined(CPU_PROFILE_ENABLED) */
 
+    return platform_counters;
+}
 
 void SysTick_Handler(void)
 {
@@ -120,4 +160,21 @@
     }
 
     return err;
-}
\ No newline at end of file
+}
+
+static bool add_pmu_counter(uint64_t value,
+                            const char* name,
+                            const char* unit,
+                            pmu_counters* counters)
+{
+    const uint32_t idx = counters->num_counters;
+    if (idx < NUM_PMU_COUNTERS) {
+        counters->counters[idx].value = value;
+        counters->counters[idx].name = name;
+        counters->counters[idx].unit = unit;
+        ++counters->num_counters;
+        return true;
+    }
+    printf_err("Failed to add PMU counter!\n");
+    return false;
+}
diff --git a/source/hal/source/profiles/bare-metal/timer/include/platform_timer.h b/source/hal/source/profiles/bare-metal/timer/include/platform_timer.h
deleted file mode 100644
index dd3934e..0000000
--- a/source/hal/source/profiles/bare-metal/timer/include/platform_timer.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2022 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
- *
- *     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 BAREMETAL_TIMER_H
-#define BAREMETAL_TIMER_H
-
-#include "platform_drivers.h"
-
-#include <stdint.h>
-#include <time.h>
-
-typedef struct bm_time_counter {
-    base_time_counter       counter;
-
-#if defined (ARM_NPU)
-    uint64_t                npu_total_ccnt;
-    uint32_t                npu_idle_ccnt;
-    uint32_t                npu_axi0_read_beats;
-    uint32_t                npu_axi0_write_beats;
-    uint32_t                npu_axi1_read_beats;
-#endif /* ARM_NPU */
-
-} time_counter;
-
-#endif /* BAREMETAL_TIMER_H */
diff --git a/source/hal/source/profiles/bare-metal/timer/platform_timer.c b/source/hal/source/profiles/bare-metal/timer/platform_timer.c
deleted file mode 100644
index 0388198..0000000
--- a/source/hal/source/profiles/bare-metal/timer/platform_timer.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2022 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
- *
- *     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.
- */
-#include "timer.h"
-#include "log_macros.h"
-#include "platform_drivers.h"
-
-#include <assert.h>
-#include <string.h>
-#include <inttypes.h>
-
-#if defined (ARM_NPU)
-
-#include "pmu_ethosu.h"
-
-extern struct ethosu_driver ethosu_drv; /* Default Ethos-U55 device driver */
-
-/**
- * @brief Initialises the PMU and enables the cycle counter.
- **/
-static void _init_ethosu_cyclecounter(void);
-
-/**
- * @brief       Gets the difference of total NPU cycle counts.
- *              (includes active and idle)
- * @param[in]   st      Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      Total NPU cycle counts difference between the arguments expressed
- *              as unsigned 64 bit integer.
- **/
-static uint64_t bm_get_npu_total_cycle_diff(time_counter *st,
-                                            time_counter *end);
-
-/**
- * @brief       Gets the difference in active NPU cycle counts.
- * @param[in]   st      Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      Active NPU cycle counts difference between the arguments expressed
- *              as unsigned 64 bit integer.
- **/
-static uint64_t bm_get_npu_active_cycle_diff(time_counter *st,
-                                             time_counter *end);
-
-/** @brief  Gets the difference in idle NPU cycle counts
- * @param[in]   st      Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      Idle NPU cycle counts difference between the arguments expressed
- *              as unsigned 64 bit integer.
- **/
-static uint64_t bm_get_npu_idle_cycle_diff(time_counter *st,
-                                           time_counter *end);
-
-/** @brief  Gets the difference in axi0 bus reads cycle counts
- * @param[in]   st      Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      NPU AXI0 read cycle counts  difference between the arguments expressed
- *              as unsigned 64 bit integer.
- **/
-static uint64_t bm_get_npu_axi0_read_cycle_diff(time_counter *st,
-                                                time_counter *end);
-
-/** @brief  Gets the difference in axi0 bus writes cycle counts
- * @param[in]   st      Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      NPU AXI0 write cycle counts difference between the arguments expressed
- *              as unsigned 64 bit integer.
- **/
-static uint64_t bm_get_npu_axi0_write_cycle_diff(time_counter *st,
-                                                 time_counter *end);
-
-/** @brief  Gets the difference in axi1 bus reads cycle counts
- * @param[in]   st      Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      NPU AXI1 read cycle counts difference between the arguments expressed
- *              as unsigned 64 bit integer.
- **/
-static uint64_t bm_get_npu_axi1_read_cycle_diff(time_counter *st,
-                                                time_counter *end);
-
-/** @brief  Gets the difference for 6 collected cycle counts:
- * 1) total NPU
- * 2) active NPU
- * 3) idle NPU
- * 4) axi0 read
- * 5) axi0 write
- * 6) axi1 read
- * */
-static int bm_get_npu_cycle_diff(time_counter *st, time_counter *end,
-                                  uint64_t* pmu_counters_values, const size_t size);
-
-#endif /* defined (ARM_NPU) */
-
-#if defined(MPS3_PLATFORM)
-/**
- * @brief       Wrapper for getting milliseconds duration between time counters
- * @param[in]   st      Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      Difference in milliseconds between given time counters.
- **/
-static time_t bm_get_duration_ms(time_counter *st, time_counter *end);
-
-/**
- * @brief       Wrapper for getting microseconds duration between time counters
- * @param[in]   st      Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      Difference in microseconds between given time counters.
- **/
-static time_t bm_get_duration_us(time_counter *st, time_counter *end);
-#endif /* defined(MPS3_PLATFORM) */
-
-/**
- * @brief Wrapper for resetting timer.
- **/
-static void bm_timer_reset(void);
-
-/**
- * @brief   Wrapper for getting the current timer counter.
- * @return  Current time counter value.
- **/
-static time_counter bm_get_time_counter(void);
-
-/**
- * @brief   Wrapper for profiler start.
- * @return  Current profiler start timer counter.
- **/
-static time_counter bm_start_profiling(void);
-
-/**
- * @brief   Wrapper for profiler end.
- * @return  Current profiler end timer counter.
- **/
-static time_counter bm_stop_profiling(void);
-
-/**
- * @brief   Wrapper for getting CPU cycle difference between time counters.
- * @return  CPU cycle difference between given time counters expressed
- *          as unsigned 32 bit integer.
- **/
-static uint64_t bm_get_cpu_cycles_diff(time_counter *st, time_counter *end);
-
-/**
- * @brief       Initialiser for bare metal timer.
- * @param[in]   timer  Platform timer to initialize.
- **/
-void init_timer(platform_timer *timer)
-{
-    assert(timer);
-    memset(timer, 0, sizeof(*timer));
-
-    timer->reset            = bm_timer_reset;
-    timer->get_time_counter = bm_get_time_counter;
-    timer->start_profiling  = bm_start_profiling;
-    timer->stop_profiling   = bm_stop_profiling;
-    timer->get_cpu_cycle_diff = bm_get_cpu_cycles_diff;
-    timer->cap.cpu_cycles = 1;
-
-#if defined (MPS3_PLATFORM)
-    timer->cap.duration_ms  = 1;
-    timer->cap.duration_us  = 1;
-    timer->get_duration_ms  = bm_get_duration_ms;
-    timer->get_duration_us  = bm_get_duration_us;
-#endif  /* defined (MPS3_PLATFORM) */
-
-#if defined (ARM_NPU)
-    /* We are capable of reporting npu cycle counts. */
-    timer->cap.npu_cycles   = 1;
-    timer->get_npu_cycles_diff = bm_get_npu_cycle_diff;
-    _init_ethosu_cyclecounter();
-#endif /* defined (ARM_NPU) */
-
-    timer->reset();
-    timer->inited = 1;
-}
-
-#if defined (ARM_NPU)
-static void _reset_ethosu_counters()
-{
-    /* Reset all cycle and event counters. */
-    ETHOSU_PMU_CYCCNT_Reset(&ethosu_drv);
-    ETHOSU_PMU_EVCNTR_ALL_Reset(&ethosu_drv);
-}
-static void _init_ethosu_cyclecounter()
-{
-    /* Reset overflow status. */
-    ETHOSU_PMU_Set_CNTR_OVS(&ethosu_drv, ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CCNT_Msk);
-    /* We can retrieve only 4 PMU counters: */
-    ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, 0, ETHOSU_PMU_NPU_IDLE);
-    ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, 1, ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED);
-    ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, 2, ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN);
-    ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, 3, ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED);
-    /* Enable PMU. */
-    ETHOSU_PMU_Enable(&ethosu_drv);
-    /* Enable counters for cycle and counter# 0. */
-    ETHOSU_PMU_CNTR_Enable(&ethosu_drv, ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CNT2_Msk | ETHOSU_PMU_CNT3_Msk | ETHOSU_PMU_CNT4_Msk| ETHOSU_PMU_CCNT_Msk);
-    _reset_ethosu_counters();
-}
-
-static int bm_get_npu_cycle_diff(time_counter *st, time_counter *end,
-                                  uint64_t* pmu_counters_values, const size_t size)
-{
-    if (size == 6) {
-        pmu_counters_values[0] = bm_get_npu_total_cycle_diff(st, end);
-        pmu_counters_values[1] = bm_get_npu_active_cycle_diff(st, end);
-        pmu_counters_values[2] = bm_get_npu_idle_cycle_diff(st, end);
-        pmu_counters_values[3] = bm_get_npu_axi0_read_cycle_diff(st, end);
-        pmu_counters_values[4] = bm_get_npu_axi0_write_cycle_diff(st, end);
-        pmu_counters_values[5] = bm_get_npu_axi1_read_cycle_diff(st, end);
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-static uint64_t bm_get_npu_total_cycle_diff(time_counter *st, time_counter *end)
-{
-    return end->npu_total_ccnt - st->npu_total_ccnt;
-}
-
-static uint32_t counter_overflow(uint32_t pmu_counter_mask)
-{
-    /* Check for overflow: The idle counter is 32 bit while the
-       total cycle count is 64 bit. */
-    const uint32_t overflow_status = ETHOSU_PMU_Get_CNTR_OVS(&ethosu_drv);
-    return pmu_counter_mask & overflow_status;
-}
-
-static uint64_t bm_get_npu_idle_cycle_diff(time_counter *st, time_counter *end)
-{
-    if (counter_overflow(ETHOSU_PMU_CNT1_Msk)) {
-        printf_err("EthosU PMU idle counter overflow.\n");
-        return 0;
-    }
-    return (uint64_t)(end->npu_idle_ccnt - st->npu_idle_ccnt);
-}
-
-static uint64_t bm_get_npu_active_cycle_diff(time_counter *st, time_counter *end)
-{
-    /* Active NPU time = total time - idle time */
-    return bm_get_npu_total_cycle_diff(st, end) - bm_get_npu_idle_cycle_diff(st, end);
-}
-
-static uint64_t bm_get_npu_axi0_read_cycle_diff(time_counter *st, time_counter *end)
-{
-    if (counter_overflow(ETHOSU_PMU_CNT2_Msk)) {
-        printf_err("EthosU PMU axi0 read counter overflow.\n");
-        return 0;
-    }
-    return (uint64_t)(end->npu_axi0_read_beats - st->npu_axi0_read_beats);
-}
-
-static uint64_t bm_get_npu_axi0_write_cycle_diff(time_counter *st, time_counter *end)
-{
-    if (counter_overflow(ETHOSU_PMU_CNT3_Msk)) {
-        printf_err("EthosU PMU axi0 write counter overflow.\n");
-        return 0;
-    }
-    return (uint64_t)(end->npu_axi0_write_beats - st->npu_axi0_write_beats);
-}
-
-static uint64_t bm_get_npu_axi1_read_cycle_diff(time_counter *st, time_counter *end)
-{
-    if (counter_overflow(ETHOSU_PMU_CNT4_Msk)) {
-        printf_err("EthosU PMU axi1 read counter overflow.\n");
-        return 0;
-    }
-    return (uint64_t)(end->npu_axi1_read_beats - st->npu_axi1_read_beats);
-}
-
-#endif /* defined (ARM_NPU) */
-
-static void bm_timer_reset(void)
-{
-#if defined (ARM_NPU)
-    _init_ethosu_cyclecounter();
-#endif /* defined (ARM_NPU) */
-
-    timer_reset();
-}
-
-static time_counter bm_get_time_counter(void)
-{
-    time_counter t = {
-        .counter = get_time_counter(),
-
-#if defined (ARM_NPU)
-            .npu_total_ccnt = ETHOSU_PMU_Get_CCNTR(&ethosu_drv),
-            .npu_idle_ccnt = ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, 0),
-            .npu_axi0_read_beats = ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, 1),
-            .npu_axi0_write_beats = ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, 2),
-            .npu_axi1_read_beats = ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, 3)
-#endif /* defined (ARM_NPU) */
-
-    };
-
-#if defined (ARM_NPU)
-    debug("NPU total cc: %" PRIu64
-        "; NPU idle cc: %" PRIu32
-        "; NPU axi0 read beats: %" PRIu32
-        "; NPU axi0 write beats: %" PRIu32
-        "; NPU axi1 read beats: %" PRIu32 "\n",
-        t.npu_total_ccnt,
-        t.npu_idle_ccnt,
-        t.npu_axi0_read_beats,
-        t.npu_axi0_write_beats,
-        t.npu_axi1_read_beats);
-#endif /* defined (ARM_NPU) */
-
-    return t;
-}
-
-static time_counter bm_start_profiling(void)
-{
-    start_cycle_counter();
-    return bm_get_time_counter();
-}
-
-static time_counter bm_stop_profiling(void)
-{
-    stop_cycle_counter();
-    return bm_get_time_counter();
-}
-
-static uint64_t bm_get_cpu_cycles_diff(time_counter *st, time_counter *end)
-{
-    return get_cycle_count_diff(&(st->counter), &(end->counter));
-}
-
-#if defined(MPS3_PLATFORM)
-static time_t bm_get_duration_ms(time_counter *st, time_counter *end)
-{
-    return get_duration_milliseconds(&(st->counter), &(end->counter));
-}
-
-static time_t bm_get_duration_us(time_counter *st, time_counter *end)
-{
-    return get_duration_microseconds(&(st->counter), &(end->counter));
-}
-#endif /* defined(MPS3_PLATFORM) */
diff --git a/source/hal/source/profiles/native/timer/platform_timer.c b/source/hal/source/profiles/native/timer/platform_timer.c
deleted file mode 100644
index c311125..0000000
--- a/source/hal/source/profiles/native/timer/platform_timer.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2021 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
- *
- *     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.
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "timer.h"
-
-#include <assert.h>
-#include <time.h>
-#include <string.h>
-
-#define MILLISECONDS_IN_SECOND      1000
-#define MICROSECONDS_IN_SECOND      1000000
-#define NANOSECONDS_IN_MILLISECOND  1000000
-#define NANOSECONDS_IN_MICROSECOND  1000
-
-/**
- * @brief   Gets the current time counter value.
- * @return  Counter value expressed in terms of time_counter struct.
- **/
-static time_counter get_time_counter(void)
-{
-    struct timespec current_time;
-    clock_gettime(1, &current_time);
-    time_counter t = {
-        .current_secs = current_time.tv_sec,
-        .current_nsecs = current_time.tv_nsec
-    };
-
-    return t;
-}
-
-/**
- * @brief       Gets the time duration elapsed between start and end.
- * @param[in]   start   Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      Difference in milliseconds between the arguments expressed
- *              as unsigned 32 bit integer.
- **/
-static time_t get_duration_milliseconds(time_counter *start, time_counter *end)
-{
-    /* Convert both parts of time struct to ms then add for complete time. */
-    time_t seconds_part =
-        (end->current_secs - start->current_secs) * MILLISECONDS_IN_SECOND;
-    time_t nanoseconds_part =
-        (end->current_nsecs - start->current_nsecs) / NANOSECONDS_IN_MILLISECOND;
-
-    return seconds_part + nanoseconds_part;
-}
-
-/**
- * @brief       Gets the time duration elapsed between start and end.
- * @param[in]   start   Pointer to time_counter value at start time.
- * @param[in]   end     Pointer to time_counter value at end.
- * @return      Difference in microseconds between the arguments expressed
- *              as unsigned 32 bit integer.
- **/
-static time_t get_duration_microseconds(time_counter *start, time_counter *end)
-{
-    /* Convert both parts of time struct to us then add for complete time. */
-    time_t seconds_part =
-        (end->current_secs - start->current_secs) * MICROSECONDS_IN_SECOND;
-    time_t nanoseconds_part =
-        (end->current_nsecs - start->current_nsecs) / NANOSECONDS_IN_MICROSECOND;
-
-    return seconds_part + nanoseconds_part;
-}
-
-/**
- * @brief Stub for timer reset.
- **/
-void reset_timer() {}
-
-/**
- * @brief Initialise the timer for this platform.
- **/
-void init_timer(platform_timer *timer)
-{
-    assert(timer);
-    memset(timer, 0, sizeof(*timer));
-
-    timer->get_time_counter = get_time_counter;
-    timer->start_profiling = get_time_counter;
-    timer->stop_profiling = get_time_counter;
-    timer->get_duration_ms = get_duration_milliseconds;
-    timer->cap.duration_ms = 1;
-    timer->get_duration_us = get_duration_microseconds;
-    timer->cap.duration_us = 1;
-    timer->reset = reset_timer;
-    timer->inited = 1;
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/profiler/CMakeLists.txt b/source/profiler/CMakeLists.txt
index 8fcea1f..0a9c338 100644
--- a/source/profiler/CMakeLists.txt
+++ b/source/profiler/CMakeLists.txt
@@ -31,18 +31,9 @@
 
 target_include_directories(profiler PUBLIC include)
 
-# Set the CPU profiling defintiion
-if (CPU_PROFILE_ENABLED)
-    target_compile_definitions(profiler PRIVATE CPU_PROFILE_ENABLED)
-endif()
-
 # Profiling API depends on the logging interface and the HAL library.
 target_link_libraries(profiler PRIVATE log hal)
 
-# Set the CPU profiling defintiion
-target_compile_definitions(profiler PUBLIC
-        $<$<BOOL:${CPU_PROFILE_ENABLED}>:CPU_PROFILE_ENABLED>)
-
 # Display status
 message(STATUS "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR})
 message(STATUS "*******************************************************")
diff --git a/source/profiler/Profiler.cc b/source/profiler/Profiler.cc
index efbc64d..7e10097 100644
--- a/source/profiler/Profiler.cc
+++ b/source/profiler/Profiler.cc
@@ -40,7 +40,7 @@
         }
         if (this->m_pPlatform && !this->m_started) {
             this->m_pPlatform->timer->reset();
-            this->m_tstampSt = this->m_pPlatform->timer->start_profiling();
+            this->m_tstampSt = this->m_pPlatform->timer->get_counters();
             this->m_started = true;
             return true;
         }
@@ -51,7 +51,7 @@
     bool Profiler::StopProfiling()
     {
         if (this->m_pPlatform && this->m_started) {
-            this->m_tstampEnd = this->m_pPlatform->timer->stop_profiling();
+            this->m_tstampEnd = this->m_pPlatform->timer->get_counters();
             this->m_started = false;
 
             this->AddProfilingUnit(this->m_tstampSt, this->m_tstampEnd, this->m_name);
@@ -99,111 +99,28 @@
             result.name = item.first;
             result.samplesNum = series.size();
 
-            Statistics AXI0_RD {
-                .name = "NPU AXI0_RD_DATA_BEAT_RECEIVED",
-                .unit = "beats",
-                .total = 0,
-                .avrg = 0.0,
-                .min = series[0].axi0writes,
-                .max = 0
-            };
-            Statistics AXI0_WR {
-                    .name = "NPU AXI0_WR_DATA_BEAT_WRITTEN",
-                    .unit = "beats",
-                    .total = 0,
-                    .avrg = 0.0,
-                    .min = series[0].axi0reads,
-                    .max = 0
-            };
-            Statistics AXI1_RD {
-                    .name = "NPU AXI1_RD_DATA_BEAT_RECEIVED",
-                    .unit = "beats",
-                    .total = 0,
-                    .avrg = 0.0,
-                    .min = series[0].axi1reads,
-                    .max = 0
-            };
-            Statistics NPU_ACTIVE {
-                    .name = "NPU ACTIVE",
-                    .unit = "cycles",
-                    .total = 0,
-                    .avrg = 0.0,
-                    .min = series[0].activeNpuCycles,
-                    .max = 0
-            };
-            Statistics NPU_IDLE {
-                    .name = "NPU IDLE",
-                    .unit = "cycles",
-                    .total = 0,
-                    .avrg = 0.0,
-                    .min = series[0].idleNpuCycles,
-                    .max = 0
-            };
-            Statistics NPU_Total {
-                    .name = "NPU TOTAL",
-                    .unit = "cycles",
-                    .total = 0,
-                    .avrg = 0.0,
-                    .min = series[0].npuCycles,
-                    .max = 0,
-            };
-#if defined(CPU_PROFILE_ENABLED)
-            Statistics CPU_ACTIVE {
-                    .name = "CPU ACTIVE",
-                    .unit = "cycles (approx)",
-                    .total = 0,
-                    .avrg = 0.0,
-                    .min = series[0].cpuCycles - NPU_ACTIVE.min,
-                    .max = 0
-            };
-            Statistics TIME {
-                    .name = "Time",
-                    .unit = "ms",
-                    .total = 0,
-                    .avrg = 0.0,
-                    .min = static_cast<uint64_t>(series[0].time),
-                    .max = 0
-            };
-#endif
-            for(ProfilingUnit& unit: series){
-
-                calcProfilingStat(unit.npuCycles,
-                                  NPU_Total, result.samplesNum);
-
-                calcProfilingStat(unit.activeNpuCycles,
-                                  NPU_ACTIVE, result.samplesNum);
-
-                calcProfilingStat(unit.idleNpuCycles,
-                                  NPU_IDLE, result.samplesNum);
-
-                calcProfilingStat(unit.axi0writes,
-                                  AXI0_WR, result.samplesNum);
-
-                calcProfilingStat(unit.axi0reads,
-                                  AXI0_RD, result.samplesNum);
-
-                calcProfilingStat(unit.axi1reads,
-                                  AXI1_RD, result.samplesNum);
-#if defined(CPU_PROFILE_ENABLED)
-                calcProfilingStat(static_cast<uint64_t>(unit.time),
-                                  TIME, result.samplesNum);
-
-                calcProfilingStat(unit.cpuCycles - unit.activeNpuCycles,
-                                  CPU_ACTIVE, result.samplesNum);
-#endif
+            std::vector<Statistics> stats(series[0].counters.num_counters);
+            for (size_t i = 0; i < stats.size(); ++i) {
+                stats[i].name = series[0].counters.counters[i].name;
+                stats[i].unit = series[0].counters.counters[i].unit;
             }
-            result.data.emplace_back(AXI0_RD);
-            result.data.emplace_back(AXI0_WR);
-            result.data.emplace_back(AXI1_RD);
-            result.data.emplace_back(NPU_ACTIVE);
-            result.data.emplace_back(NPU_IDLE);
-            result.data.emplace_back(NPU_Total);
-#if defined(CPU_PROFILE_ENABLED)
-            result.data.emplace_back(CPU_ACTIVE);
-            result.data.emplace_back(TIME);
-#endif
-        results.emplace_back(result);
+
+            for(ProfilingUnit& unit: series) {
+                for (size_t i = 0; i < stats.size(); ++i) {
+                    calcProfilingStat(
+                        unit.counters.counters[i].value,
+                        stats[i],
+                        result.samplesNum);
+                }
+            }
+
+            for (Statistics& stat : stats) {
+                result.data.emplace_back(stat);
+            }
+
+            results.emplace_back(result);
         }
+
         this->Reset();
     }
 
@@ -216,10 +133,11 @@
         std::vector<ProfileResult> results{};
         GetAllResultsAndReset(results);
         for(ProfileResult& result: results) {
-            info("Profile for %s:\n", result.name.c_str());
-
-            if (printFullStat) {
-                printStatisticsHeader(result.samplesNum);
+            if (result.data.size()) {
+                info("Profile for %s:\n", result.name.c_str());
+                if (printFullStat) {
+                    printStatisticsHeader(result.samplesNum);
+                }
             }
 
             for (Statistics &stat: result.data) {
@@ -228,7 +146,7 @@
                          stat.name.c_str(), stat.unit.c_str(),
                          stat.total, stat.avrg, stat.min, stat.max);
                 } else {
-                    info("%s %s: %.0f\n", stat.name.c_str(), stat.unit.c_str(), stat.avrg);
+                    info("%s: %.0f %s\n", stat.name.c_str(), stat.avrg, stat.unit.c_str());
                 }
             }
         }
@@ -239,7 +157,7 @@
         this->m_name = std::string(str);
     }
 
-    void Profiler::AddProfilingUnit(time_counter start, time_counter end,
+    void Profiler::AddProfilingUnit(pmu_counters start, pmu_counters end,
                                     const std::string& name)
     {
         if (!this->m_pPlatform) {
@@ -247,33 +165,25 @@
             return;
         }
 
-        platform_timer * timer = this->m_pPlatform->timer;
+        struct ProfilingUnit unit = {
+            .counters = end
+        };
 
-        struct ProfilingUnit unit;
+        if (end.num_counters != start.num_counters ||
+                true != end.initialised || true != start.initialised) {
+            printf_err("Invalid start or end counters\n");
+            return;
+        }
 
-        if (timer->cap.npu_cycles && timer->get_npu_cycles_diff)
-        {
-            const size_t size = 6;
-            uint64_t pmuCounters[size] = {0};
-            /* 6 values: total cc, active cc, idle cc, axi0 read, axi0 write, axi1 read*/
-            if (0 == timer->get_npu_cycles_diff(&start, &end, pmuCounters, size)) {
-                unit.npuCycles = pmuCounters[0];
-                unit.activeNpuCycles = pmuCounters[1];
-                unit.idleNpuCycles = pmuCounters[2];
-                unit.axi0reads = pmuCounters[3];
-                unit.axi0writes = pmuCounters[4];
-                unit.axi1reads = pmuCounters[5];
+        for (size_t i = 0; i < unit.counters.num_counters; ++i) {
+            if (unit.counters.counters[i].value < start.counters[i].value) {
+                warn("Overflow detected for %s\n", unit.counters.counters[i].name);
+                unit.counters.counters[i].value = 0;
+            } else {
+                unit.counters.counters[i].value -= start.counters[i].value;
             }
         }
 
-        if (timer->cap.cpu_cycles && timer->get_cpu_cycle_diff) {
-            unit.cpuCycles = timer->get_cpu_cycle_diff(&start, &end);
-        }
-
-        if (timer->cap.duration_ms && timer->get_duration_ms) {
-            unit.time = timer->get_duration_ms(&start, &end);
-        }
-
         this->m_series[name].emplace_back(unit);
     }
 
diff --git a/source/profiler/include/Profiler.hpp b/source/profiler/include/Profiler.hpp
index 503d805..b8f9089 100644
--- a/source/profiler/include/Profiler.hpp
+++ b/source/profiler/include/Profiler.hpp
@@ -45,14 +45,7 @@
 
     /** A single profiling unit definition. */
     struct ProfilingUnit {
-        uint64_t npuCycles = 0;
-        uint64_t activeNpuCycles = 0;
-        uint64_t idleNpuCycles = 0;
-        uint64_t axi0writes = 0;
-        uint64_t axi0reads = 0;
-        uint64_t axi1reads = 0;
-        uint64_t cpuCycles = 0;
-        time_t time = 0;
+        pmu_counters counters;
     };
 
     /* A collection of profiling units. */
@@ -108,8 +101,8 @@
 
     private:
         ProfilingMap    m_series;                /* Profiling series map. */
-        time_counter    m_tstampSt{};            /* Container for a current starting timestamp. */
-        time_counter    m_tstampEnd{};           /* Container for a current ending timestamp. */
+        pmu_counters    m_tstampSt{};            /* Container for a current starting timestamp. */
+        pmu_counters    m_tstampEnd{};           /* Container for a current ending timestamp. */
         hal_platform *  m_pPlatform = nullptr;   /* Platform pointer - to get the timer. */
 
         bool            m_started = false;       /* Indicates profiler has been started. */
@@ -125,7 +118,7 @@
          * @param[in]   name    Name for the profiling unit series to be
          *                      appended to.
          **/
-        void AddProfilingUnit(time_counter start, time_counter end,
+        void AddProfilingUnit(pmu_counters start, pmu_counters end,
                               const std::string& name);
     };