diff --git a/miosix/_tools/testsuite/testsuite.cpp b/miosix/_tools/testsuite/testsuite.cpp index cbaba8afad373345a1e43276cf8fa36514964adb..baff1d61148351132b41513f3a9c82b74aa38608 100644 --- a/miosix/_tools/testsuite/testsuite.cpp +++ b/miosix/_tools/testsuite/testsuite.cpp @@ -797,7 +797,7 @@ static void test_2() tests: Thread::sleep() Thread::sleepUntil() -getTick() +getTime() also tests creation of multiple instances of the same thread */ @@ -808,12 +808,11 @@ static void t3_p1(void *argv) { if(Thread::testTerminate()) break; //Test that Thread::sleep sleeps the desired number of ticks - long long x1=getTick(); //getTick returns # passed quantums + long long x1=getTime(); //getTime returns passed time in ns Thread::sleep(SLEEP_TIME); - 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()"); + long long x2=getTime(); + if(llabs((x2-x1)/1000000-SLEEP_TIME)>5) //Max tolerated error is 5ms + fail("Thread::sleep() or getTime()"); } } @@ -882,19 +881,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=10000000;//10ms { InterruptDisableLock lock; //Making these two operations atomic. - tick=getTick()*preemptionPeriodNs; + tick=getTime(); tick+=period; } for(int i=0;i<4;i++) { - //tick is in number of quantums passed while sleepUntil requires ms + //tick is in number of ns passed, wakeup time should not differ by > 1ms Thread::nanoSleepUntil(tick); - long long t2 = getTick(); - if(tick!=t2*preemptionPeriodNs) fail("Thread::sleepUntil()"); + long long t2 = getTime(); + if((t2-tick)/1000000>0) fail("Thread::sleepUntil()"); tick+=period; } pass(); @@ -934,7 +933,7 @@ static void t4_p1(void *argv) static void t4_p2(void *argv) { const int period=static_cast<int>(TICK_FREQ*0.03); - long long tick=getTick(); + long long tick=getTime(); for(int i=0;i<10;i++) { long long prevTick=tick; @@ -942,7 +941,7 @@ static void t4_p2(void *argv) Thread::setPriority(Priority(tick)); //Change deadline Thread::sleepUntil(prevTick); //Make sure the task is run periodically delayMs(14); - if(getTick()>tick) fail("Deadline missed (A)\n"); + if(getTime()>tick) fail("Deadline missed (A)\n"); } } #endif //SCHED_TYPE_EDF @@ -961,7 +960,7 @@ static void test_4() //Check IRQgetPriority if(p->IRQgetPriority()!=0) fail("IRQgetPriority"); //Check that tick is not incremented and t4_v1 is not updated - long long tick=getTick(); + long long tick=getTime(); t4_v1=false; for(int i=0;i<4;i++) { @@ -983,7 +982,7 @@ static void test_4() fastDisableInterrupts();// //Check that tick is not incremented and t4_v1 is not updated - tick=getTick(); + tick=getTime(); t4_v1=false; for(int i=0;i<4;i++) { @@ -3064,11 +3063,11 @@ void t20_t2(void* arg) t20_v1=0; eq->post(t20_f1); eq->post(t20_f1); - unsigned long long t1=getTick(); + unsigned long long t1=getTime(); eq->post(bind(t20_f2,10,4)); //This should block - unsigned long long t2=getTick(); + unsigned long long t2=getTime(); //The other thread sleep for 50ms before calling run() - if((t2-t1)<static_cast<unsigned long long>(TICK_FREQ*0.04)) + if((t2-t1)/1000000 < 40) fail("Not blocked"); Thread::sleep(10); if(t20_v1!=14) fail("Not called"); diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp index e1b0e5dc31e05ea2bfed6daf8f4eea4c61c9d438..8b88bfc93b0381232977b3eafacd4aec1e926ece 100644 --- a/miosix/kernel/kernel.cpp +++ b/miosix/kernel/kernel.cpp @@ -247,7 +247,7 @@ bool isKernelRunning() return (kernel_running==0) && kernel_started; } -long long getTick() +long long getTime() { return ContextSwitchTimer::instance().getCurrentTick(); } diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h index da9d602f93570231eb790b7c4beec5010048bdd8..c19440be86ccbe24918caaa68f1e6a689983b6f6 100644 --- a/miosix/kernel/kernel.h +++ b/miosix/kernel/kernel.h @@ -404,11 +404,11 @@ void startKernel(); bool isKernelRunning(); /** - * Returns the current kernel tick.<br>Can be called also with interrupts - * disabled and/or kernel paused. - * \return current kernel tick + * Returns the time passed in nanoseconds since the context switch started.<br> + * Can be called also with interrupts disabled and/or kernel paused. + * \return current time in nanoseconds */ -long long getTick(); +long long getTime(); //Forwrd declaration struct SleepData; @@ -527,9 +527,8 @@ public: * \code * void periodicThread() * { - * //Run every 90 milliseconds - * const int period=static_cast<int>(TICK_FREQ*0.09); - * long long tick=getTick(); + * const int period=90; //Run every 90 milliseconds + * long long tick=getTime()/1000000; //convert ns to ms * for(;;) * { * //Do work diff --git a/miosix/kernel/sync.cpp b/miosix/kernel/sync.cpp index 4f076a741b3d5be416fdb704fac8c25480effbca..733e7202a884ef4151db9501689f2b9182e8b1ce 100644 --- a/miosix/kernel/sync.cpp +++ b/miosix/kernel/sync.cpp @@ -478,14 +478,14 @@ void Timer::start() { first=false; running=true; - start_tick=getTick(); + start_tick=getTime(); } void Timer::stop() { if(running==false) return; running=false; - tick_count+=getTick()-start_tick; + tick_count+=getTime()-start_tick; start_tick=0; } diff --git a/miosix/stdlib_integration/libc_integration.cpp b/miosix/stdlib_integration/libc_integration.cpp index 7a99231aba8526676adfe6c366e8573b8a48cea9..200042386d0853e1e46500354311edb24515bf84 100644 --- a/miosix/stdlib_integration/libc_integration.cpp +++ b/miosix/stdlib_integration/libc_integration.cpp @@ -904,55 +904,38 @@ int getdents(unsigned int fd, struct dirent *dirp, unsigned int count) #define CLOCK_MONOTONIC 4 #endif -/// Conversion factor from ticks to nanoseconds -/// TICK_FREQ in Miosix is either 1000 or (on older chips) 200, so a simple -/// multiplication/division factor does not cause rounding errors -static constexpr long tickNsFactor=1000000000/miosix::TICK_FREQ; +static constexpr int nsPerSec = 1000000000; /** * Convert from timespec to the Miosix representation of time * \param tp input timespec, must not be nullptr and be a valid pointer - * \return Miosix ticks + * \return Miosix nanoseconds */ inline long long timespec2ll(const struct timespec *tp) { //NOTE: the cast is required to prevent overflow with older versions //of the Miosix compiler where tv_sec is int and not long long - return static_cast<long long>(tp->tv_sec)*miosix::TICK_FREQ - + tp->tv_nsec/tickNsFactor; + //TODO: optimize + return static_cast<long long>(tp->tv_sec) * nsPerSec + tp->tv_nsec; } /** - * Convert from he Miosix representation of time to a timespec - * \param tick input Miosix ticks + * Convert from the Miosix representation of time to a timespec + * \param ns input Miosix nanoseconds * \param tp output timespec, must not be nullptr and be a valid pointer */ -inline void ll2timespec(long long tick, struct timespec *tp) +inline void ll2timespec(long long ns, struct timespec *tp) { - #ifdef __ARM_EABI__ - // Despite there being a single intrinsic, __aeabi_ldivmod, that computes - // both the result of the / and % operator, GCC 9.2.0 isn't smart enough and - // calls the intrinsic twice. This asm implementation saves ~115 cycles - // by calling it once. Sadly, I had to use asm as the calling conventions - // of the intrinsic appear to be nonstandard. - // NOTE: actually a and b, by being 64 bit numbers, occupy register pairs - register long long a asm("r0") = tick; - register long long b asm("r2") = miosix::TICK_FREQ; - // NOTE: clobbering lr to mark function not leaf due to the bl - asm volatile("bl __aeabi_ldivmod" : "+r"(a), "+r"(b) :: "lr"); - tp->tv_sec = a; - tp->tv_nsec = static_cast<long>(b) * tickNsFactor; - #else //__ARM_EABI__ - tp->tv_sec = tick / miosix::TICK_FREQ; - tp->tv_nsec = static_cast<long>(tick % miosix::TICK_FREQ) * tickNsFactor; - #endif //__ARM_EABI__ + //TODO: optimize + tp->tv_sec = ns / nsPerSec; + tp->tv_nsec = static_cast<long>(ns % nsPerSec); } int clock_gettime(clockid_t clock_id, struct timespec *tp) { if(tp==nullptr) return -1; //TODO: support CLOCK_REALTIME - ll2timespec(miosix::getTick(),tp); + ll2timespec(miosix::getTime(),tp); return 0; } @@ -966,7 +949,7 @@ int clock_getres(clockid_t clock_id, struct timespec *res) { if(res==nullptr) return -1; res->tv_sec=0; - res->tv_nsec=tickNsFactor; + res->tv_nsec=1; //TODO: get resolution from hardware timer return 0; } @@ -975,9 +958,9 @@ int clock_nanosleep(clockid_t clock_id, int flags, { if(req==nullptr) return -1; //TODO: support CLOCK_REALTIME - long long timeTick=timespec2ll(req); - if(flags!=TIMER_ABSTIME) timeTick+=miosix::getTick(); - miosix::Thread::sleepUntil(timeTick); + long long timeNs=timespec2ll(req); + if(flags!=TIMER_ABSTIME) timeNs+=miosix::getTime(); + miosix::Thread::nanoSleepUntil(timeNs); return 0; }