diff --git a/miosix/_tools/testsuite/testsuite.cpp b/miosix/_tools/testsuite/testsuite.cpp index 2060aa17d00f855798854c1ffba2242fc1aec77b..cbaba8afad373345a1e43276cf8fa36514964adb 100644 --- a/miosix/_tools/testsuite/testsuite.cpp +++ b/miosix/_tools/testsuite/testsuite.cpp @@ -803,14 +803,16 @@ also tests creation of multiple instances of the same thread static void t3_p1(void *argv) { - const int SLEEP_TIME=100; + const int SLEEP_TIME=100; // in ms for(;;) { if(Thread::testTerminate()) break; //Test that Thread::sleep sleeps the desired number of ticks - long long x=getTick(); + long long x1=getTick(); //getTick returns # passed quantums Thread::sleep(SLEEP_TIME); - if(llabs(((SLEEP_TIME*TICK_FREQ)/1000)-(getTick()-x))>5) + long long x2=getTick(); + //if(llabs(((SLEEP_TIME*TICK_FREQ)/1000)-(getTick()-x))>5) + if (llabs((x2-x1)*preemptionPeriodNs/1000000-SLEEP_TIME)>5) //Max tolerated error is 5ms fail("Thread::sleep() or getTick()"); } } @@ -880,16 +882,19 @@ static void test_3() if(t3_deleted==false) fail("multiple instances (4)"); //Testing Thread::sleepUntil() long long tick; - const int period=static_cast<int>(TICK_FREQ*0.01); //10ms + //const int period=static_cast<int>(TICK_FREQ*0.01); //10ms + const int period=10000000;//10ms { InterruptDisableLock lock; //Making these two operations atomic. - tick=getTick(); + tick=getTick()*preemptionPeriodNs; tick+=period; } for(int i=0;i<4;i++) { - Thread::sleepUntil(tick); - if(tick!=getTick()) fail("Thread::sleepUntil()"); + //tick is in number of quantums passed while sleepUntil requires ms + Thread::nanoSleepUntil(tick); + long long t2 = getTick(); + if(tick!=t2*preemptionPeriodNs) fail("Thread::sleepUntil()"); tick+=period; } pass(); diff --git a/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/cstimer.cpp b/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/cstimer.cpp index 0874558e4c89a4731b7ba85f85aae54a661efb4f..f56e6d526c36339b160e7ad5b0283de8f6bf1934 100644 --- a/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/cstimer.cpp +++ b/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/cstimer.cpp @@ -3,7 +3,7 @@ #include "interfaces/arch_registers.h" #include "kernel/kernel.h" #include "kernel/scheduler/timer_interrupt.h" -#include "../../../../../debugpin.h" +#include "kernel/timeconversion.h" using namespace miosix; @@ -61,15 +61,13 @@ void __attribute__((naked)) TIM2_IRQHandler() void __attribute__((used)) cstirqhnd() { - HighPin<debug1> h1; if(TIM2->SR & TIM_SR_CC1IF || lateIrq) { TIM2->SR = ~TIM_SR_CC1IF; if(ms32time==ms32chkp || lateIrq) { lateIrq=false; - HighPin<debug2> h2; - IRQtimerInterrupt(nextInterrupt()); + IRQtimerInterrupt(tc->tick2ns(nextInterrupt())); } } @@ -172,6 +170,9 @@ ContextSwitchTimer::ContextSwitchTimer() // interface. After this, the freq variable contains the frequency in Hz // at which the timer prescaler is clocked. if(RCC->CFGR & RCC_CFGR_PPRE1_2) timerFreq/=1<<((RCC->CFGR>>10) & 0x3); + tc=new TimeConversion(timerFreq); } +TimeConversion *tc; + } //namespace miosix diff --git a/miosix/config/arch/cortexM4_stm32f4/stm32f407vg_stm32f4discovery/board_settings.h b/miosix/config/arch/cortexM4_stm32f4/stm32f407vg_stm32f4discovery/board_settings.h index 5720a7dfb69ffad35e82a67b64b0431cd974ee26..324982dfe36f5907aa5b902011bb25ad079ab207 100644 --- a/miosix/config/arch/cortexM4_stm32f4/stm32f407vg_stm32f4discovery/board_settings.h +++ b/miosix/config/arch/cortexM4_stm32f4/stm32f407vg_stm32f4discovery/board_settings.h @@ -50,18 +50,21 @@ namespace miosix { /// STM32F407VG only has 192KB of RAM so there is room for a big 4K stack. const unsigned int MAIN_STACK_SIZE=4*1024; +/// Context Switch Quantum Size (measured in nanoseconds) +const unsigned int preemptionPeriodNs=1000000; + /// Frequency of tick (in Hz). The frequency of the STM32F100RB timer in the /// stm32vldiscovery board can be divided by 1000. This allows to use a 1KHz /// tick and the minimun Thread::sleep value is 1ms /// For the priority scheduler this is also the context switch frequency -const unsigned int TICK_FREQ=1000; +const unsigned int TICK_FREQ=1000; //FIX ME: Should be removed ///\internal Aux timer run @ 100KHz ///Note that since the timer is only 16 bits this imposes a limit on the ///burst measurement of 655ms. If due to a pause_kernel() or ///disable_interrupts() section a thread runs for more than that time, a wrong ///burst value will be measured -const unsigned int AUX_TIMER_CLOCK=100000; +const unsigned int AUX_TIMER_CLOCK=100000; //FIX ME: Should be removed const unsigned int AUX_TIMER_MAX=0xffff; ///<\internal Aux timer is 16 bits /// Serial port (USART3 PB10=TX, PB11=RX) diff --git a/miosix/interfaces/cstimer.h b/miosix/interfaces/cstimer.h index 6bb06eac4481dd6cacb27e7aa280294869c16caa..e9b1af524d92e8fb8bce9d2ebc9a9eb407950f58 100644 --- a/miosix/interfaces/cstimer.h +++ b/miosix/interfaces/cstimer.h @@ -1,6 +1,8 @@ #ifndef CSTIMER_H #define CSTIMER_H +#include "kernel/timeconversion.h" + namespace miosix { /** @@ -65,6 +67,8 @@ private: unsigned int timerFreq; }; +extern TimeConversion *tc; + } //namespace miosix #endif //TIMER_H diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp index 2b275ca2fbc514156c1b236b649709758004c43f..ce336f3dbb75b46b3670b86daf134abfd9e649bd 100644 --- a/miosix/kernel/kernel.cpp +++ b/miosix/kernel/kernel.cpp @@ -38,13 +38,12 @@ #include "kernel/scheduler/scheduler.h" #include "stdlib_integration/libc_integration.h" #include "interfaces/cstimer.h" +#include "timeconversion.h" #include <stdexcept> #include <algorithm> #include <string.h> #include <reent.h> -#define CSQUANTUM 84000 //FIXME: remove it please - /* Used by assembler context switch macros This variable is set by miosix::IRQfindNextThread in file kernel.cpp @@ -119,6 +118,8 @@ void *idleThread(void *argv) #ifndef JTAG_DISABLE_SLEEP //JTAG debuggers lose communication with the device if it enters sleep //mode, so to use debugging it is necessary to remove this instruction + +//FIX ME: deepsleep has not been integrated fully so the code is surrounded with ifdef #ifdef BOARD_efm32gg332f1024_wandstem bool sleep=false; { @@ -193,6 +194,7 @@ bool areInterruptsEnabled() return miosix_private::checkAreInterruptsEnabled(); } +//FIX ME: deepsleep has not been integrated fully so the code is surrounded with ifdef #ifdef BOARD_efm32gg332f1024_wandstem void deepSleepLock() { @@ -261,9 +263,9 @@ void startKernel() #ifdef USE_CSTIMER // Set the first checkpoint interrupt csRecord->p = nullptr; - csRecord->wakeup_time = CSQUANTUM; + csRecord->wakeup_time = preemptionPeriodNs; sleepingList->push_front(csRecord); - timer->IRQsetNextInterrupt(CSQUANTUM); + timer->IRQsetNextInterrupt(tc->ns2tick(preemptionPeriodNs)); #endif //USE_CSTIMER miosix_private::IRQportableStartKernel(); kernel_started=true; @@ -292,7 +294,7 @@ long long getTick() if(a==b) return a; } #else //USE_CSTIMER - return timer->getCurrentTick()/CSQUANTUM; + return tc->tick2ns(timer->getCurrentTick())/preemptionPeriodNs; #endif //USE_CSTIMER } @@ -320,7 +322,7 @@ void IRQaddToSleepingList(SleepData *x) //Upon any change to the sleepingList the ContextSwitchTimer should have //its interrupt set to the head of the list in order to keep it sync with //the list - timer->IRQsetNextInterrupt(sleepingList->front()->wakeup_time); + timer->IRQsetNextInterrupt(tc->ns2tick(sleepingList->front()->wakeup_time)); #endif } @@ -349,7 +351,7 @@ void IRQsetNextPreemption(long long preemptionTime) //Upon any change to the sleepingList the ContextSwitchTimer should have //its interrupt set to the head of the list in order to keep it sync with //the list - timer->IRQsetNextInterrupt(sleepingList->front()->wakeup_time); + timer->IRQsetNextInterrupt(tc->ns2tick(sleepingList->front()->wakeup_time)); #endif } /** @@ -466,10 +468,16 @@ bool Thread::testTerminate() } #ifdef USE_CSTIMER -inline void Thread::tickSleepUntil(long long absTicks) +void Thread::nanoSleep(unsigned int ns) +{ + if(ns==0) return; //TODO: should be (ns < resolution + epsilon) + //TODO: Mutual Exclusion issue + nanoSleepUntil(tc->tick2ns(ContextSwitchTimer::instance().getCurrentTick()) + ns); +} + +void Thread::nanoSleepUntil(long long absoluteTime) { - //absTicks: As it is in terms of real ticks of the kernel/timer, there's no - //resolution issues here. + //TODO: The absolute time should be rounded w.r.t. the timer resolution //This function does not care about setting the wakeup_time in the past //as it should be based on the policy taken into account by IRQwakeThreads @@ -482,25 +490,11 @@ inline void Thread::tickSleepUntil(long long absTicks) { FastInterruptDisableLock lock; d.p=const_cast<Thread*>(cur); - d.wakeup_time = absTicks; + d.wakeup_time = absoluteTime; IRQaddToSleepingList(&d);//Also sets SLEEP_FLAG } Thread::yield(); -} - -void Thread::nanoSleep(unsigned int ns) -{ - if(ns==0) return; //TODO: should be (ns < resolution + epsilon) - long long ticks = ns * 0.084;//TODO: ns2tick fast conversion needed - tickSleepUntil(ContextSwitchTimer::instance().getCurrentTick() + ticks); -} - -void Thread::nanoSleepUntil(long long absoluteTime) -{ - //TODO: The absolute time should be rounded w.r.t. the timer resolution - long long ticks = absoluteTime * 0.084;//TODO: ns2tick fast conversion needed - if (ticks <= ContextSwitchTimer::instance().getCurrentTick()) return; - tickSleepUntil(ticks); + } #endif diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h index 9712491b8bbfe69901719eeee3dcd8cd053659a6..125592e2292cb5e49df343badbd3af8b25831fff 100644 --- a/miosix/kernel/kernel.h +++ b/miosix/kernel/kernel.h @@ -964,17 +964,6 @@ private: * \param argv argument passed to the entry point */ static void threadLauncher(void *(*threadfunc)(void*), void *argv); - - /** - * Puts the thread to sleep until the given time. - * This is the base function for adding a thread to the sleeping list. - * Other functions such as nanoSleep, sleep and sleepUntil are base on - * appropriate calls to tickSleepUntil. - * \param absTicks: For a tickless kernel (i.e. it uses an external aperiodic - * timer) absTicks is in terms of aperiodic timer tick otherwise it is in - * terms of kernel's tick! - */ - static void tickSleepUntil(long long absTicks); /** * Allocates the idle thread and makes cur point to it diff --git a/miosix/kernel/scheduler/priority/priority_scheduler.cpp b/miosix/kernel/scheduler/priority/priority_scheduler.cpp index c294459c1d2a457226f4763920dcd3a539453f3a..231c79f7994c1fabe0e72e689ae60066a4b4f6f2 100644 --- a/miosix/kernel/scheduler/priority/priority_scheduler.cpp +++ b/miosix/kernel/scheduler/priority/priority_scheduler.cpp @@ -30,7 +30,6 @@ #include "kernel/process.h" #ifdef SCHED_TYPE_PRIORITY -#define CSQUANTUM 84000 //FIXME : Remove this namespace miosix { //These are defined in kernel.cpp @@ -199,7 +198,7 @@ void PriorityScheduler::IRQsetIdleThread(Thread *idleThread) unsigned int PriorityScheduler::IRQfindNextThread() { - if(kernel_running!=0) return CSQUANTUM;//If kernel is paused, do nothing + if(kernel_running!=0) return preemptionPeriodNs;//If kernel is paused, do nothing for(int i=PRIORITY_MAX-1;i>=0;i--) { if(thread_list[i]==NULL) continue; @@ -226,7 +225,7 @@ unsigned int PriorityScheduler::IRQfindNextThread() //Rotate to next thread so that next time the list is walked //a different thread, if available, will be chosen first thread_list[i]=temp; - return CSQUANTUM; + return preemptionPeriodNs; } else temp=temp->schedData.next; if(temp==thread_list[i]->schedData.next) break; } @@ -237,7 +236,7 @@ unsigned int PriorityScheduler::IRQfindNextThread() #ifdef WITH_PROCESSES MPUConfiguration::IRQdisable(); #endif //WITH_PROCESSES - return CSQUANTUM; + return preemptionPeriodNs; } Thread *PriorityScheduler::thread_list[PRIORITY_MAX]={0}; diff --git a/miosix/kernel/scheduler/timer_interrupt.h b/miosix/kernel/scheduler/timer_interrupt.h index 7ecdf70a46909431fd8ca630fcb73aefd9a801c8..6dd9b0cb2bc1d2ec14d18cf8fb87d7e5d4d73812 100644 --- a/miosix/kernel/scheduler/timer_interrupt.h +++ b/miosix/kernel/scheduler/timer_interrupt.h @@ -43,6 +43,9 @@ extern volatile Thread *cur;///\internal Do not use outside the kernel extern void IRQsetNextPreemption(long long preemptionTime); ///\internal Do not use outside the kernel extern bool IRQwakeThreads(long long currentTick);///\internal Do not use outside the kernel +/** + * @param currentTick: Should be in nanoseconds + */ inline void IRQtimerInterrupt(long long currentTick) { miosix_private::IRQstackOverflowCheck();