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