From 42480b63be8416785771f0b68aa5d2abf4e87b54 Mon Sep 17 00:00:00 2001
From: Sasan Golchin <ahmad.golchin@mail.polimi.it>
Date: Thu, 13 Oct 2016 14:49:13 +0200
Subject: [PATCH] Control Scheduler modified to work with CSTimer instead of
 AuxTimer

---
 .../common/interfaces-impl/portability.cpp    | 85 -------------------
 .../scheduler/control/control_scheduler.cpp   | 47 ++++++++--
 .../scheduler/control/control_scheduler.h     |  2 +-
 miosix/kernel/scheduler/control/parameters.h  |  8 +-
 4 files changed, 44 insertions(+), 98 deletions(-)

diff --git a/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/portability.cpp b/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/portability.cpp
index 9b27e6ce..4776adab 100644
--- a/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/portability.cpp
+++ b/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/portability.cpp
@@ -56,25 +56,6 @@ void SVC_Handler()
     restoreContext();
 }
 
-#ifdef SCHED_TYPE_CONTROL_BASED
-/**
- * \internal
- * Auxiliary timer interupt routine.
- * Used for variable lenght bursts in control based scheduler.
- * Since inside naked functions only assembler code is allowed, this function
- * only calls the ctxsave/ctxrestore macros (which are in assembler), and calls
- * the implementation code in ISR_yield()
- */
-void TIM3_IRQHandler() __attribute__((naked));
-void TIM3_IRQHandler()
-{
-    saveContext();
-    //Call ISR_auxTimer(). Name is a C++ mangled name.
-    asm volatile("bl _ZN14miosix_private12ISR_auxTimerEv");
-    restoreContext();
-}
-#endif //SCHED_TYPE_CONTROL_BASED
-
 namespace miosix_private {
 
 /**
@@ -132,22 +113,6 @@ void ISR_yield()
     #endif //WITH_PROCESSES
 }
 
-#ifdef SCHED_TYPE_CONTROL_BASED
-/**
- * \internal
- * Auxiliary timer interupt routine.
- * Used for variable lenght bursts in control based scheduler.
- */
-void ISR_auxTimer() __attribute__((noinline));
-void ISR_auxTimer()
-{
-    IRQstackOverflowCheck();
-    miosix::Scheduler::IRQfindNextThread();//If the kernel is running, preempt
-    if(miosix::kernel_running!=0) miosix::tick_skew=true;
-    TIM3->SR=0;
-}
-#endif //SCHED_TYPE_CONTROL_BASED
-
 void IRQstackOverflowCheck()
 {
     const unsigned int watermarkSize=miosix::WATERMARK_LEN/sizeof(unsigned int);
@@ -278,9 +243,6 @@ void IRQportableStartKernel()
     #ifdef WITH_PROCESSES
     miosix::IRQenableMPUatBoot();
     #endif //WITH_PROCESSES
-    #ifdef SCHED_TYPE_CONTROL_BASED
-    AuxiliaryTimer::IRQinit();
-    #endif //SCHED_TYPE_CONTROL_BASED
 
     //create a temporary space to save current registers. This data is useless
     //since there's no way to stop the sheduler, but we need to save it anyway.
@@ -303,51 +265,4 @@ void sleepCpu()
     __WFI();
 }
 
-#ifdef SCHED_TYPE_CONTROL_BASED
-void AuxiliaryTimer::IRQinit()
-{
-    RCC->APB1ENR|=RCC_APB1ENR_TIM3EN;
-    RCC_SYNC();
-    DBGMCU->APB1FZ|=DBGMCU_APB1_FZ_DBG_TIM3_STOP; //Tim3 stops while debugging
-    TIM3->CR1=0; //Upcounter, not started, no special options
-    TIM3->CR2=0; //No special options
-    TIM3->SMCR=0; //No external trigger
-    TIM3->CNT=0; //Clear timer
-    //get timer frequency considering APB1 prescaler
-    //consider that timer clock is twice APB1 clock when the APB1 prescaler has
-    //a division factor greater than 2
-    int timerClock=SystemCoreClock;
-    int apb1prescaler=(RCC->CFGR>>10) & 7;
-    if(apb1prescaler>4) timerClock>>=(apb1prescaler-4);
-    TIM3->PSC=(timerClock/miosix::AUX_TIMER_CLOCK)-1;
-    TIM3->ARR=0xffff; //Count from zero to 0xffff
-    TIM3->DIER=TIM_DIER_CC1IE; //Enable interrupt on compare
-    TIM3->CCR1=0xffff; //This will be initialized later with setValue
-    NVIC_SetPriority(TIM3_IRQn,3);//High priority for TIM3 (Max=0, min=15)
-    NVIC_EnableIRQ(TIM3_IRQn);
-    TIM3->CR1=TIM_CR1_CEN; //Start timer
-    //This is very important: without this the prescaler shadow register may
-    //not be updated
-    TIM3->EGR=TIM_EGR_UG;
-}
-
-int AuxiliaryTimer::IRQgetValue()
-{
-    return static_cast<int>(TIM3->CNT);
-}
-
-void AuxiliaryTimer::IRQsetValue(int x)
-{
-    TIM3->CR1=0; //Stop timer since changing CNT or CCR1 while running fails
-    TIM3->CNT=0;
-    TIM3->CCR1=static_cast<unsigned short>(std::min(x,0xffff));
-    TIM3->CR1=TIM_CR1_CEN; //Start timer again
-    //The above instructions cause a spurious if not called within the
-    //timer 2 IRQ (This happens if called from an SVC).
-    //Clearing the pending bit prevents this spurious interrupt
-    TIM3->SR=0;
-    NVIC_ClearPendingIRQ(TIM3_IRQn);
-}
-#endif //SCHED_TYPE_CONTROL_BASED
-
 } //namespace miosix_private
diff --git a/miosix/kernel/scheduler/control/control_scheduler.cpp b/miosix/kernel/scheduler/control/control_scheduler.cpp
index 09a1ea38..b131273d 100644
--- a/miosix/kernel/scheduler/control/control_scheduler.cpp
+++ b/miosix/kernel/scheduler/control/control_scheduler.cpp
@@ -29,6 +29,7 @@
 #include "kernel/error.h"
 #include "kernel/process.h"
 #include <limits>
+#include "interfaces/cstimer.h"
 
 using namespace std;
 
@@ -39,6 +40,9 @@ namespace miosix {
 //These are defined in kernel.cpp
 extern volatile Thread *cur;
 extern volatile int kernel_running;
+static ContextSwitchTimer& timer = ContextSwitchTimer::instance();
+extern IntrusiveList<SleepData> *sleepingList;
+static long long burstStart = 0;
 
 //
 // class ControlScheduler
@@ -145,20 +149,45 @@ Thread *ControlScheduler::IRQgetIdleThread()
     return idle;
 }
 
-void ControlScheduler::IRQfindNextThread()
+// Should be called when the current thread is the idle thread
+static inline void IRQsetNextPreemptionForIdle(){
+    if (sleepingList->empty())
+        timer.IRQsetNextInterrupt(numeric_limits<long long>::max());
+    else
+        timer.IRQsetNextInterrupt(sleepingList->front()->wakeup_time);
+}
+
+// Should be called for threads other than idle thread
+static inline void IRQsetNextPreemption(long long burst){
+    long long firstWakeupInList;
+    long long nextPreemption;
+    if (sleepingList->empty())
+        firstWakeupInList = numeric_limits<long long>::max();
+    else
+        firstWakeupInList = sleepingList->front()->wakeup_time;
+    burstStart = timer.IRQgetCurrentTick();
+    nextPreemption = burstStart + burst;
+    if (firstWakeupInList < nextPreemption)
+        timer.IRQsetNextInterrupt(firstWakeupInList);
+    else
+        timer.IRQsetNextInterrupt(nextPreemption);
+}
+
+unsigned int ControlScheduler::IRQfindNextThread()
 {
     // Warning: since this function is called within interrupt routines, it
     //is not possible to add/remove elements to threadList, since that would
     //require dynamic memory allocation/deallocation which is forbidden within
     //interrupts. Iterating the list is safe, though
 
-    if(kernel_running!=0) return;//If kernel is paused, do nothing
+    if(kernel_running!=0) return 0;//If kernel is paused, do nothing
 
     if(cur!=idle)
     {
         //Not preempting from the idle thread, store actual burst time of
         //the preempted thread
-        int Tp=miosix_private::AuxiliaryTimer::IRQgetValue();
+        //int Tp=miosix_private::AuxiliaryTimer::IRQgetValue(); //CurTime - LastTime = real burst
+        int Tp = static_cast<int>(timer.IRQgetCurrentTick() - burstStart);
         cur->schedData.Tp=Tp;
         Tr+=Tp;
     }
@@ -204,8 +233,9 @@ void ControlScheduler::IRQfindNextThread()
                 #ifdef WITH_PROCESSES
                 MPUConfiguration::IRQdisable();
                 #endif
-                miosix_private::AuxiliaryTimer::IRQsetValue(bIdle);
-                return;
+                //miosix_private::AuxiliaryTimer::IRQsetValue(bIdle); //curTime + burst
+                IRQsetNextPreemptionForIdle();
+                return 0;
             }
 
             //End of round reached, run scheduling algorithm
@@ -230,9 +260,10 @@ void ControlScheduler::IRQfindNextThread()
             #else //WITH_PROCESSES
             ctxsave=cur->ctxsave;
             #endif //WITH_PROCESSES
-            miosix_private::AuxiliaryTimer::IRQsetValue(
-                    curInRound->schedData.bo/multFactor);
-            return;
+            //miosix_private::AuxiliaryTimer::IRQsetValue(
+            //        curInRound->schedData.bo/multFactor);
+            IRQsetNextPreemption(curInRound->schedData.bo/multFactor);
+            return 0;
         } else {
             //If we get here we have a non ready thread that cannot run,
             //so regardless of the burst calculated by the scheduler
diff --git a/miosix/kernel/scheduler/control/control_scheduler.h b/miosix/kernel/scheduler/control/control_scheduler.h
index a52db3bd..851ccd87 100644
--- a/miosix/kernel/scheduler/control/control_scheduler.h
+++ b/miosix/kernel/scheduler/control/control_scheduler.h
@@ -150,7 +150,7 @@ public:
      * It's behaviour is to modify the global variable miosix::cur which always
      * points to the currently running thread.
      */
-    static void IRQfindNextThread();
+    static unsigned int IRQfindNextThread();
 
 private:
 
diff --git a/miosix/kernel/scheduler/control/parameters.h b/miosix/kernel/scheduler/control/parameters.h
index c6586139..db1f144d 100644
--- a/miosix/kernel/scheduler/control/parameters.h
+++ b/miosix/kernel/scheduler/control/parameters.h
@@ -76,19 +76,19 @@ const int multFactor=static_cast<int>(1.0f/kpi);
 
 ///Instead of fixing a round time the current policy is to have
 ///roundTime=bNominal * numThreads, where bNominal is the nominal thread burst
-static const int bNominal=static_cast<int>(AUX_TIMER_CLOCK*0.004);// 4ms
+static const int bNominal=static_cast<int>(4000000);// 4ms
 
 ///minimum burst time (to avoid inefficiency caused by context switch
 ///time longer than burst time)
-static const int bMin=static_cast<int>(AUX_TIMER_CLOCK*0.0002);// 200us
+static const int bMin=static_cast<int>(200000);// 200us
 
 ///maximum burst time (to avoid losing responsiveness/timer overflow)
-static const int bMax=static_cast<int>(AUX_TIMER_CLOCK*0.02);// 20ms
+static const int bMax=static_cast<int>(20000000);// 20ms
 
 ///idle thread has a fixed burst length that can be modified here
 ///it is recomended to leave it to a high value, but that does not cause
 ///overflow of the auxiliary timer
-static const int bIdle=static_cast<int>(AUX_TIMER_CLOCK*0.5);// 500ms
+static const int bIdle=static_cast<int>(500000000);// 500ms
 
 }
 
-- 
GitLab