diff --git a/miosix/kernel/cpu_time_counter.cpp b/miosix/kernel/cpu_time_counter.cpp
index 3788053a18ab7135c16814d083c04a5dc4db9192..441d92382c002c2d1d5073ba2c6888c3b0b70051 100644
--- a/miosix/kernel/cpu_time_counter.cpp
+++ b/miosix/kernel/cpu_time_counter.cpp
@@ -26,7 +26,6 @@
  ***************************************************************************/
 
 #include "cpu_time_counter.h"
-#include "cpu_time_counter_private.h"
 #include "kernel/kernel.h"
 
 #ifdef WITH_CPU_TIME_COUNTER
@@ -43,8 +42,9 @@ long long CPUTimeCounter::getActiveThreadTime()
     {
         PauseKernelLock pk;
         curTime = IRQgetTime();
-        usedTime = runningThread->timeCounterData.usedCpuTime;
-        lastAct = runningThread->timeCounterData.lastActivation;
+        auto cur = Thread::PKgetCurrentThread();
+        usedTime = cur->timeCounterData.usedCpuTime;
+        lastAct = cur->timeCounterData.lastActivation;
     }
     return usedTime + (curTime - lastAct);
 }
diff --git a/miosix/kernel/cpu_time_counter.h b/miosix/kernel/cpu_time_counter.h
index b28ea5a7681b72b75718c1f75cdf0a17dd578340..ba3125790329f5db4060e3292127c4a023697d78 100644
--- a/miosix/kernel/cpu_time_counter.h
+++ b/miosix/kernel/cpu_time_counter.h
@@ -193,26 +193,26 @@ private:
      * threads.
      */
     static void PKremoveDeadThreads();
-
-    /**
-     * \internal
-     * Notify that a context switch is about to happen.
-     * \returns The current time.
-     */
-    static inline long long IRQwillSwitchContext();
-
-    /**
-     * \internal
-     * Notify that a context switch has just happened.
-     * \param t The time of the context switch.
-     */
-    static inline void IRQdidSwitchContext(long long t);
     
     static Thread *head; ///< Head of the thread list
     static Thread *tail; ///< Tail of the thread list
     static volatile unsigned int nThreads; ///< Number of threads in the list
 };
 
+/**
+ * Function to be called in the context switch code to profile threads
+ * \param prev time count struct of previously running thread
+ * \param prev time count struct of thread to be scheduled next
+ * \param t (approximate) current time, a time point taken somewhere during
+ * the context switch code
+ */
+static inline void IRQprofileContextSwitch(CPUTimeCounterPrivateThreadData& prev,
+    CPUTimeCounterPrivateThreadData& next, long long t)
+{
+    prev.usedCpuTime += t - prev.lastActivation;
+    next.lastActivation = t;
+}
+
 /**
  * \}
  */
diff --git a/miosix/kernel/cpu_time_counter_private.h b/miosix/kernel/cpu_time_counter_private.h
deleted file mode 100644
index 62d24a7256a0e70ed6755fb8a9c29303b9e3b7e4..0000000000000000000000000000000000000000
--- a/miosix/kernel/cpu_time_counter_private.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2023 by Daniele Cattaneo                                *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   As a special exception, if other files instantiate templates or use   *
- *   macros or inline functions from this file, or you compile this file   *
- *   and link it with other works to produce a work based on this file,    *
- *   this file does not by itself cause the resulting work to be covered   *
- *   by the GNU General Public License. However the source code for this   *
- *   file must still be made available in accordance with the GNU General  *
- *   Public License. This exception does not invalidate any other reasons  *
- *   why a work based on this file might be covered by the GNU General     *
- *   Public License.                                                       *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
- ***************************************************************************/
-
-#pragma once
-
-#include "cpu_time_counter.h"
-
-#ifdef WITH_CPU_TIME_COUNTER
-
-namespace miosix {
-
-// Declared in kernel.cpp
-extern volatile Thread *runningThread;
-
-long long CPUTimeCounter::IRQwillSwitchContext()
-{
-    long long t=IRQgetTime();
-    runningThread->timeCounterData.usedCpuTime+=t-runningThread->timeCounterData.lastActivation;
-    return t;
-}
-
-void CPUTimeCounter::IRQdidSwitchContext(long long t)
-{
-    runningThread->timeCounterData.lastActivation=t;
-}
-
-} //namespace miosix
-
-#endif //WITH_CPU_TIME_COUNTER
diff --git a/miosix/kernel/scheduler/control/control_scheduler.cpp b/miosix/kernel/scheduler/control/control_scheduler.cpp
index 68630cfbea603375722610f664ecd4b76a1b3132..5a6b73944f68e9741584ad555d6e81b33d9705a3 100644
--- a/miosix/kernel/scheduler/control/control_scheduler.cpp
+++ b/miosix/kernel/scheduler/control/control_scheduler.cpp
@@ -51,7 +51,9 @@ static inline void IRQsetNextPreemptionForIdle()
 {
     if(sleepingList.empty()) nextPreemption=numeric_limits<long long>::max();
     else nextPreemption=sleepingList.front()->wakeupTime;
-
+    #ifdef WITH_CPU_TIME_COUNTER
+    burstStart=IRQgetTime();
+    #endif // WITH_CPU_TIME_COUNTER
     //We could not set an interrupt if the sleeping list is empty but there's
     //no such hurry to run idle anyway, so why bother?
     internal::IRQosTimerSetInterrupt(nextPreemption);
@@ -183,6 +185,9 @@ long long ControlScheduler::IRQgetNextPreemption()
 void ControlScheduler::IRQfindNextThread()
 {
     if(kernelRunning!=0) return;//If kernel is paused, do nothing
+    #ifdef WITH_CPU_TIME_COUNTER
+    Thread *prev=const_cast<Thread*>(runningThread);
+    #endif // WITH_CPU_TIME_COUNTER
 
     if(runningThread!=idle)
     {
@@ -235,6 +240,10 @@ void ControlScheduler::IRQfindNextThread()
                 miosix_private::MPUConfiguration::IRQdisable();
                 #endif
                 IRQsetNextPreemptionForIdle();
+                #ifdef WITH_CPU_TIME_COUNTER
+                IRQprofileContextSwitch(prev->timeCounterData,
+                                        idle->timeCounterData,burstStart);
+                #endif //WITH_CPU_TIME_COUNTER
                 return;
             }
 
@@ -261,6 +270,10 @@ void ControlScheduler::IRQfindNextThread()
             ctxsave=runningThread->ctxsave;
             #endif //WITH_PROCESSES
             IRQsetNextPreemption(curInRound->schedData.bo/multFactor);
+            #ifdef WITH_CPU_TIME_COUNTER
+            IRQprofileContextSwitch(prev->timeCounterData,
+                                    curInRound->timeCounterData,burstStart);
+            #endif //WITH_CPU_TIME_COUNTER
             return;
         } else {
             //If we get here we have a non ready thread that cannot run,
@@ -585,6 +598,9 @@ long long ControlScheduler::IRQgetNextPreemption()
 void ControlScheduler::IRQfindNextThread()
 {
     if(kernelRunning!=0) return;//If kernel is paused, do nothing
+    #ifdef WITH_CPU_TIME_COUNTER
+    Thread *prev=const_cast<Thread*>(runningThread);
+    #endif // WITH_CPU_TIME_COUNTER
 
     if(runningThread!=idle)
     {
@@ -632,6 +648,10 @@ void ControlScheduler::IRQfindNextThread()
                 MPUConfiguration::IRQdisable();
                 #endif
                 IRQsetNextPreemptionForIdle();
+                #ifdef WITH_CPU_TIME_COUNTER
+                IRQprofileContextSwitch(prev->timeCounterData,
+                                        idle->timeCounterData,burstStart);
+                #endif //WITH_CPU_TIME_COUNTER
                 return;
             }
 
@@ -658,6 +678,10 @@ void ControlScheduler::IRQfindNextThread()
             ctxsave=runningThread->ctxsave;
             #endif //WITH_PROCESSES
             IRQsetNextPreemption(runningThread->schedData.bo/multFactor);
+            #ifdef WITH_CPU_TIME_COUNTER
+            IRQprofileContextSwitch(prev->timeCounterData,
+                                    (*curInRound)->t->timeCounterData,burstStart);
+            #endif //WITH_CPU_TIME_COUNTER
             return;
         } else {
             //Error: a not ready thread end up in the ready list
diff --git a/miosix/kernel/scheduler/edf/edf_scheduler.cpp b/miosix/kernel/scheduler/edf/edf_scheduler.cpp
index dc21918f6caf699dea0300a6b5234f8caeec31ba..9f7bdd7be6b85a931a328872f61b4947f3a27639 100644
--- a/miosix/kernel/scheduler/edf/edf_scheduler.cpp
+++ b/miosix/kernel/scheduler/edf/edf_scheduler.cpp
@@ -129,6 +129,9 @@ static void IRQsetNextPreemption()
 void EDFScheduler::IRQfindNextThread()
 {
     if(kernelRunning!=0) return;//If kernel is paused, do nothing
+    #ifdef WITH_CPU_TIME_COUNTER
+    Thread *prev=const_cast<Thread*>(runningThread);
+    #endif // WITH_CPU_TIME_COUNTER
     Thread *walk=head;
     for(;;)
     {
@@ -150,6 +153,10 @@ void EDFScheduler::IRQfindNextThread()
             ctxsave=runningThread->ctxsave;
             #endif //WITH_PROCESSES
             IRQsetNextPreemption();
+            #ifdef WITH_CPU_TIME_COUNTER
+            IRQprofileContextSwitch(prev->timeCounterData,walk->timeCounterData,
+                                    IRQgetTime());
+            #endif //WITH_CPU_TIME_COUNTER
             return;
         }
         walk=walk->schedData.next;
diff --git a/miosix/kernel/scheduler/priority/priority_scheduler.cpp b/miosix/kernel/scheduler/priority/priority_scheduler.cpp
index ee1425c2d99c88342e4454520c7967839ddf45ef..2d6f9780175591e81b9e6354fd56bfc07783a415 100644
--- a/miosix/kernel/scheduler/priority/priority_scheduler.cpp
+++ b/miosix/kernel/scheduler/priority/priority_scheduler.cpp
@@ -203,23 +203,28 @@ long long PriorityScheduler::IRQgetNextPreemption()
     return nextPeriodicPreemption;
 }
 
-static void IRQsetNextPreemption(bool runningIdleThread)
+static long long IRQsetNextPreemption(bool runningIdleThread)
 {
     long long first;
     if(sleepingList.empty()) first=std::numeric_limits<long long>::max();
     else first=sleepingList.front()->wakeupTime;
 
+    long long t=IRQgetTime();
     if(runningIdleThread) nextPeriodicPreemption=first;
-    else nextPeriodicPreemption=std::min(first,IRQgetTime()+MAX_TIME_SLICE);
+    else nextPeriodicPreemption=std::min(first,t+MAX_TIME_SLICE);
 
     //We could not set an interrupt if the sleeping list is empty and runningThread
     //is idle but there's no such hurry to run idle anyway, so why bother?
     internal::IRQosTimerSetInterrupt(nextPeriodicPreemption);
+    return t;
 }
 
 void PriorityScheduler::IRQfindNextThread()
 {
     if(kernelRunning!=0) return;//If kernel is paused, do nothing
+    #ifdef WITH_CPU_TIME_COUNTER
+    Thread *prev=const_cast<Thread*>(runningThread);
+    #endif // WITH_CPU_TIME_COUNTER
     for(int i=PRIORITY_MAX-1;i>=0;i--)
     {
         if(threadList[i]==nullptr) continue;
@@ -246,7 +251,12 @@ void PriorityScheduler::IRQfindNextThread()
                 //Rotate to next thread so that next time the list is walked
                 //a different thread, if available, will be chosen first
                 threadList[i]=temp;
+                #ifndef WITH_CPU_TIME_COUNTER
                 IRQsetNextPreemption(false);
+                #else //WITH_CPU_TIME_COUNTER
+                auto t=IRQsetNextPreemption(false);
+                IRQprofileContextSwitch(prev->timeCounterData,temp->timeCounterData,t);
+                #endif //WITH_CPU_TIME_COUNTER
                 return;
             } else temp=temp->schedData.next;
             if(temp==threadList[i]->schedData.next) break;
@@ -258,7 +268,12 @@ void PriorityScheduler::IRQfindNextThread()
     #ifdef WITH_PROCESSES
     MPUConfiguration::IRQdisable();
     #endif //WITH_PROCESSES
+    #ifndef WITH_CPU_TIME_COUNTER
     IRQsetNextPreemption(true);
+    #else //WITH_CPU_TIME_COUNTER
+    auto t=IRQsetNextPreemption(true);
+    IRQprofileContextSwitch(prev->timeCounterData,idle->timeCounterData,t);
+    #endif //WITH_CPU_TIME_COUNTER
 }
 
 Thread *PriorityScheduler::threadList[PRIORITY_MAX]={nullptr};
diff --git a/miosix/kernel/scheduler/scheduler.h b/miosix/kernel/scheduler/scheduler.h
index 85888f4f48af0f9c198646479019d68e9d69577f..f11e678cd970725f929d5dad11978106667cb917 100755
--- a/miosix/kernel/scheduler/scheduler.h
+++ b/miosix/kernel/scheduler/scheduler.h
@@ -31,7 +31,7 @@
 #include "kernel/scheduler/priority/priority_scheduler.h"
 #include "kernel/scheduler/control/control_scheduler.h"
 #include "kernel/scheduler/edf/edf_scheduler.h"
-#include "kernel/cpu_time_counter_private.h"
+#include "kernel/cpu_time_counter.h"
 
 namespace miosix {
 
@@ -165,13 +165,7 @@ public:
      */
     static void IRQfindNextThread()
     {
-        #ifdef WITH_CPU_TIME_COUNTER
-        long long t=CPUTimeCounter::IRQwillSwitchContext();
-        #endif
         T::IRQfindNextThread();
-        #ifdef WITH_CPU_TIME_COUNTER
-        CPUTimeCounter::IRQdidSwitchContext(t);
-        #endif
     }
     
     /**