From 50669f941ddc00e7f8ee9b4f4276ba0af43a71ef Mon Sep 17 00:00:00 2001 From: Fabiano Riccardi <fabiuz4@hotmail.it> Date: Mon, 10 Oct 2016 07:16:35 -0700 Subject: [PATCH] Refactoring of cstimer in high_resolution_timer_base, base class for the future timers Signed-off-by: Fabiano Riccardi <fabiuz4@hotmail.it> --- .../interfaces-impl/cstimer.cpp | 25 +- .../interfaces-impl/cstimer_impl.h | 29 ++ .../high_resolution_timer_base.cpp | 277 +++++++++++++++--- .../high_resolution_timer_base.h | 4 +- miosix/config/Makefile.inc | 3 +- miosix/interfaces/cstimer.h | 3 + 6 files changed, 286 insertions(+), 55 deletions(-) create mode 100644 miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer_impl.h diff --git a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer.cpp b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer.cpp index c89b72dd..21b77240 100644 --- a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer.cpp +++ b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer.cpp @@ -3,6 +3,7 @@ #include "kernel/kernel.h" #include "kernel/scheduler/timer_interrupt.h" #include "kernel/timeconversion.h" +#include "cstimer_impl.h" #include "high_resolution_timer_base.h" using namespace miosix; @@ -21,28 +22,26 @@ namespace miosix { } void ContextSwitchTimer::IRQsetNextInterrupt(long long ns){ - b.IRQsetNextInterrupt1(tc->ns2tick(ns)); + pImpl->b.IRQsetNextInterrupt1(tc->ns2tick(ns)); } - long long ContextSwitchTimer::getNextInterrupt() const - { - return tc->tick2ns(b.IRQgetSetTimeCCV1()); + long long ContextSwitchTimer::getNextInterrupt() const{ + return tc->tick2ns(pImpl->b.IRQgetSetTimeCCV1()); } - long long ContextSwitchTimer::getCurrentTick() const - { - return tc->tick2ns(b.getCurrentTick()); + long long ContextSwitchTimer::getCurrentTick() const{ + return tc->tick2ns(pImpl->b.getCurrentTick()); } - long long ContextSwitchTimer::IRQgetCurrentTick() const - { - return tc->tick2ns(b.IRQgetCurrentTick()); + long long ContextSwitchTimer::IRQgetCurrentTick() const{ + return tc->tick2ns(pImpl->b.IRQgetCurrentTick()); } ContextSwitchTimer::~ContextSwitchTimer(){} - ContextSwitchTimer::ContextSwitchTimer(): b(HighResolutionTimerBase::instance()) - { - tc = new TimeConversion(b.getTimerFrequency()); + ContextSwitchTimer::ContextSwitchTimer(){ + pImpl=new ContextSwitchTimerImpl(); + timerFreq=pImpl->b.getTimerFrequency(); + tc = new TimeConversion(timerFreq); } } \ No newline at end of file diff --git a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer_impl.h b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer_impl.h new file mode 100644 index 00000000..2088b115 --- /dev/null +++ b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer_impl.h @@ -0,0 +1,29 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/* + * File: cstimer_impl.h + * Author: fabiuz + * + * Created on October 3, 2016, 2:36 AM + */ +#include "high_resolution_timer_base.h" + +#ifndef CSTIMER_IMPL_H +#define CSTIMER_IMPL_H +namespace miosix{ + +class ContextSwitchTimerImpl{ + public: + HighResolutionTimerBase& b; + ContextSwitchTimerImpl(): + b(HighResolutionTimerBase::instance()){}; +}; + +} + +#endif /* CSTIMER_IMPL_H */ + diff --git a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/high_resolution_timer_base.cpp b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/high_resolution_timer_base.cpp index bad6a546..349c7723 100644 --- a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/high_resolution_timer_base.cpp +++ b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/high_resolution_timer_base.cpp @@ -14,12 +14,8 @@ #include "interfaces/arch_registers.h" #include "kernel/kernel.h" #include "kernel/scheduler/timer_interrupt.h" -#include "kernel/timeconversion.h" -#include "../../../../../debugpin.h" -#include "CMSIS/Include/core_cm3.h" -#include "bsp_impl.h" #include "high_resolution_timer_base.h" - +#include "kernel/timeconversion.h" using namespace miosix; const unsigned int timerBits=32; @@ -28,8 +24,159 @@ const unsigned long long lowerMask=overflowIncrement-1; const unsigned long long upperMask=0xFFFFFFFFFFFFFFFFLL-lowerMask; static long long ms32time = 0; //most significant 32 bits of counter -static long long ms32chkp[3] = {0}; //most significant 32 bits of check point +static long long ms32chkp[3] = {0,0,0}; //most significant 32 bits of check point static bool lateIrq=false; +static TimeConversion* tc; + +static inline unsigned int IRQread32Timer(){ + unsigned int high=TIMER3->CNT; + unsigned int low=TIMER1->CNT; + unsigned int high2=TIMER3->CNT; + if(high==high2){ + return (high<<16)|low; + } + return high2<<16|TIMER1->CNT; +} + +static inline long long IRQgetTick(){ + //PENDING BIT TRICK + unsigned int counter=IRQread32Timer(); + if((TIMER3->IF & _TIMER_IFC_OF_MASK) && IRQread32Timer()>=counter) + return (ms32time | static_cast<long long>(counter)) + overflowIncrement; + return ms32time | static_cast<long long>(counter); +} + +inline void interruptGPIOTimerRoutine(){ + if(TIMER1->CC[2].CTRL & TIMER_CC_CTRL_MODE_OUTPUTCOMPARE){ + expansion::gpio10::high(); + }else if(TIMER1->CC[2].CTRL & TIMER_CC_CTRL_MODE_INPUTCAPTURE){ + //Reactivating the thread that is waiting for the event. + if(HighResolutionTimerBase::tWaitingGPIO) + { + HighResolutionTimerBase::tWaitingGPIO->IRQwakeup(); + if(HighResolutionTimerBase::tWaitingGPIO->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) + Scheduler::IRQfindNextThread(); + HighResolutionTimerBase::tWaitingGPIO=nullptr; + } + } +} + +static inline void callScheduler(){ + TIMER1->IEN &= ~TIMER_IEN_CC1; + TIMER3->IEN &= ~TIMER_IEN_CC1; + long long tick = tc->tick2ns(IRQgetTick()); + IRQtimerInterrupt(tick); +} + +static inline void setupTimers(long long curTick,long long nextIntTick){ + long long diffs = ms32chkp[1] - ms32time; + long int diff = TIMER3->CC[1].CCV - TIMER3->CNT; + if (diffs == 0 || (diffs==1 && (TIMER3->IF & TIMER_IF_OF)) ){ + if (diff==0 || diff==-1){ + if (diff==-1){ //if TIM1 overflows before calculating diff + callScheduler(); + }else{ + TIMER1->IFC = TIMER_IFC_CC1; + TIMER1->IEN |= TIMER_IEN_CC1; + if (TIMER1->CNT > TIMER1->CC[1].CCV || /* TIM1 overflows after calculating diff */ + (TIMER3->CC[1].CCV - static_cast<unsigned int>((IRQgetTick() & 0xFFFF0000)>>16)==-1 && + TIMER1->CNT < TIMER1->CC[1].CCV)){ + + callScheduler(); + } + } + }else{ + TIMER3->CC[1].CCV--; + TIMER3->IFC = TIMER_IFC_CC1; + TIMER3->IEN |= TIMER_IEN_CC1; + if (TIMER3->CNT == TIMER3->CC[1].CCV){ + TIMER1->IFC = TIMER_IFC_CC1; + TIMER1->IEN |= TIMER_IEN_CC1; + TIMER3->IEN &= ~TIMER_IEN_CC1; + }else if (TIMER3->CNT > TIMER3->CC[1].CCV){ + callScheduler(); + } + } + }else{ + TIMER3->IFC = TIMER_IFC_CC1; + TIMER3->IEN |= TIMER_IEN_CC1; + } +} +/* +void __attribute__((naked)) TIMER3_IRQHandler() +{ + saveContext(); + asm volatile("bl _Z10cstirqhnd3v"); + restoreContext(); +} + + + //This routine has to manage the timer1 interrupt disable/enable to guarantee efficiency + +void __attribute__((used)) cstirqhnd3(){ + //Context Switch - Checkpoint + if (lateIrq){ + IRQtimerInterrupt(tc->tick2ns(IRQgetTick())); + lateIrq = false; + }else if (TIMER3->IF & TIMER_IF_CC1){ + TIMER3->IFC = TIMER_IFC_CC1; + if (ms32time == ms32chkp[1]){ + TIMER1->IFC = TIMER_IFC_CC1; + NVIC_ClearPendingIRQ(TIMER1_IRQn); + NVIC_EnableIRQ(TIMER1_IRQn); + //TIMER1->IEN |= TIMER_IEN_CC1; + if (TIMER1->CNT >= TIMER1->CC[1].CCV){ + TIMER1->IFC = TIMER_IFC_CC1; + NVIC_DisableIRQ(TIMER1_IRQn); + //TIMER1->IEN &= ~TIMER_IEN_CC1; + IRQtimerInterrupt(tc->tick2ns(IRQgetTick())); + } + } + } + +// if(TIMER3->IF & TIMER_IF_CC0){ +// TIMER3->IFC = TIMER_IFC_CC0; +// if (ms32time == ms32chkp[0]){ +// //global++; +// TIMER1->IFC = TIMER_IFC_CC0; +// TIMER1->IEN |= TIMER_IEN_CC0; +// NVIC_ClearPendingIRQ(TIMER1_IRQn); +// NVIC_EnableIRQ(TIMER1_IRQn); +// if (TIMER1->CNT >= TIMER1->CC[0].CCV){ +// TIMER1->IEN &= ~TIMER_IEN_CC0; +// TIMER1->IFC = TIMER_IFC_CC0; +// interruptGPIOTimerRoutine(); +// //global+=10; +// } +// } +// } + + //Rollover + if (TIMER3->IF & TIMER_IF_OF){ + TIMER3->IFC = TIMER_IFC_OF; + ms32time += overflowIncrement; + } +} + +void __attribute__((used)) cstirqhnd1(){ + //Context Switch - Checkpoint + if (TIMER1->IF & TIMER_IF_CC1){ + TIMER1->IFC = TIMER_IFC_CC1; + //TIMER1->IEN &= ~TIMER_IEN_CC1; + NVIC_ClearPendingIRQ(TIMER1_IRQn); + NVIC_DisableIRQ(TIMER1_IRQn); + IRQtimerInterrupt(tc->tick2ns(IRQgetTick())); + } + +// if (TIMER1->IF & TIMER_IF_CC2){ +// //global+=100; +// TIMER1->IEN &= ~TIMER_IEN_CC2; +// TIMER1->IFC = TIMER_IFC_CC2; +// NVIC_ClearPendingIRQ(TIMER1_IRQn); +// interruptGPIOTimerRoutine(); +// } + +} void __attribute__((naked)) TIMER1_IRQHandler() { @@ -45,17 +192,47 @@ void __attribute__((naked)) TIMER2_IRQHandler() } void __attribute__((used)) cstirqhnd2(){} +*/ +void __attribute__((naked)) TIMER3_IRQHandler() +{ + saveContext(); + asm volatile("bl _Z10cstirqhnd3v"); + restoreContext(); +} +void __attribute__((naked)) TIMER1_IRQHandler() +{ + saveContext(); + asm volatile("bl _Z10cstirqhnd1v"); + restoreContext(); +} - -static inline unsigned int IRQread32Timer(){ - unsigned int high=TIMER3->CNT; - unsigned int low=TIMER1->CNT; - unsigned int high2=TIMER3->CNT; - if(high==high2){ - return (high<<16)|low; +void __attribute__((used)) cstirqhnd3(){ + + //Checkpoint + if (TIMER3->IF & TIMER_IF_CC1){ + + TIMER3->IFC = TIMER_IFC_CC1; + long long diffs = ms32chkp[1] - ms32time; + if (diffs == 0|| (diffs==1 && (TIMER3->IF & TIMER_IF_OF)) ){ + TIMER3->IEN &= ~TIMER_IEN_CC1; + TIMER1->IFC = TIMER_IFC_CC1; + TIMER1->IEN |= TIMER_IEN_CC1; + if (TIMER1->CNT >= TIMER1->CC[1].CCV){ + callScheduler(); //WHat if CCV=0xFFFF + } + } + } + //rollover + if (TIMER3->IF & TIMER_IF_OF){ + TIMER3->IFC = TIMER_IFC_OF; + ms32time += overflowIncrement; + } +} +void __attribute__((used)) cstirqhnd1(){ + if (TIMER1->IF & TIMER_IF_CC1){ + callScheduler(); } - return high2<<16|TIMER1->CNT; } HighResolutionTimerBase& HighResolutionTimerBase::instance(){ @@ -88,9 +265,26 @@ HighResolutionTimerBase::HighResolutionTimerBase() { TIMER3->CTRL = TIMER_CTRL_MODE_UP | TIMER_CTRL_CLKSEL_TIMEROUF | TIMER_CTRL_SYNC; + //Code to entirely reset TIMER1, needed if you want run after the flash + TIMER1->CMD=TIMER_CMD_STOP; + TIMER1->CTRL=0; + TIMER1->ROUTE=0; + TIMER1->IEN=0; + TIMER1->IFC=~0; + TIMER1->TOP=0xFFFF; + TIMER1->CNT=0; + TIMER1->CC[0].CTRL=0; + TIMER1->CC[0].CCV=0; + TIMER1->CC[1].CTRL=0; + TIMER1->CC[1].CCV=0; + TIMER1->CC[2].CTRL=0; + TIMER1->CC[2].CCV=0; + + + //Enable necessary interrupt lines - TIMER1->IEN = TIMER_IEN_CC1; - TIMER3->IEN = /*TIMER_IEN_OF |*/ TIMER_IEN_CC1; + TIMER1->IEN = 0; + TIMER3->IEN = TIMER_IEN_OF; //OF needed to increment the software counter (32-bit) TIMER1->CC[1].CTRL = TIMER_CC_CTRL_MODE_OUTPUTCOMPARE; TIMER3->CC[1].CTRL = TIMER_CC_CTRL_MODE_OUTPUTCOMPARE; @@ -100,24 +294,26 @@ HighResolutionTimerBase::HighResolutionTimerBase() { NVIC_ClearPendingIRQ(TIMER3_IRQn); NVIC_ClearPendingIRQ(TIMER1_IRQn); NVIC_EnableIRQ(TIMER3_IRQn); - NVIC_DisableIRQ(TIMER1_IRQn); + NVIC_EnableIRQ(TIMER1_IRQn); + timerFreq=48000000; + tc=new TimeConversion(timerFreq); //Start timers TIMER1->CMD = TIMER_CMD_START; - //Setup tick2ns conversion tool - timerFreq = 48000000; + //Synchronization is required only when timers are to start. + //If the sync is not disabled after start, start/stop on another timer + //(e.g. TIMER0) will affect the behavior of context switch timer! + TIMER1->CTRL &= ~TIMER_CTRL_SYNC; + TIMER2->CTRL &= ~TIMER_CTRL_SYNC; + TIMER3->CTRL &= ~TIMER_CTRL_SYNC; } -Thread* HighResolutionTimerBase::tWaiting=nullptr; +Thread* HighResolutionTimerBase::tWaitingGPIO=nullptr; HighResolutionTimerBase::~HighResolutionTimerBase() {} long long HighResolutionTimerBase::IRQgetCurrentTick(){ - //PENDING BIT TRICK - unsigned int counter=IRQread32Timer(); - if((TIMER3->IF & _TIMER_IFC_OF_MASK) && IRQread32Timer()>=counter) - return (ms32time | static_cast<long long>(counter)) + overflowIncrement; - return ms32time | static_cast<long long>(counter); + return IRQgetTick(); } void HighResolutionTimerBase::setCCInterrupt0(bool enable){ @@ -203,25 +399,28 @@ bool HighResolutionTimerBase::IRQsetNextInterrupt0(long long tick){ return false; } return true; -} +} bool HighResolutionTimerBase::IRQsetNextInterrupt1(long long tick){ - ms32chkp[1] = tick & upperMask; - TIMER3->CC[1].CCV = static_cast<unsigned int>((tick & 0xFFFF0000)>>16); - TIMER1->CC[1].CCV = static_cast<unsigned int>(tick & 0xFFFF); - /* - In order to prevent back to back interrupts due to a checkpoint - set in the past, raise lateIrq flag to indicate this IRQ should - be processed only once - */ - if(IRQgetCurrentTick() >= IRQgetSetTimeCCV1()) + // First off, clear and disable timers to prevent unnecessary IRQ + // when IRQsetNextInterrupt is called multiple times consecutively. + TIMER1->IEN &= ~TIMER_IEN_CC1; + TIMER3->IEN &= ~TIMER_IEN_CC1; + + long long curTick = IRQgetTick(); + if(curTick >= tick) { - NVIC_SetPendingIRQ(TIMER3_IRQn); - // TIMER3->IFS=TIMER_IFS_CC1; ???? - lateIrq=true; + // The interrupt is in the past => call timerInt immediately + callScheduler(); //TODO: It could cause multiple invocations of sched. return false; + }else{ + // Apply the new interrupt on to the timer channels + TIMER1->CC[1].CCV = static_cast<unsigned int>(tick & 0xFFFF); + TIMER3->CC[1].CCV = static_cast<unsigned int>((tick & 0xFFFF0000)>>16); + ms32chkp[1] = tick & upperMask; + setupTimers(curTick, tick); + return true; } - return true; } bool HighResolutionTimerBase::IRQsetNextInterrupt2(long long tick){ diff --git a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/high_resolution_timer_base.h b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/high_resolution_timer_base.h index 9f14e315..d5522920 100644 --- a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/high_resolution_timer_base.h +++ b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/high_resolution_timer_base.h @@ -11,7 +11,7 @@ * Created on September 27, 2016, 2:20 AM */ -#include "../../../../miosix.h" +#include "miosix.h" #ifndef HIGH_RESOLUTION_TIMER_BASE_H #define HIGH_RESOLUTION_TIMER_BASE_H @@ -20,7 +20,7 @@ namespace miosix { class HighResolutionTimerBase { public: - static Thread *tWaiting; + static Thread *tWaitingGPIO; static HighResolutionTimerBase& instance(); diff --git a/miosix/config/Makefile.inc b/miosix/config/Makefile.inc index 8a96f785..7197f628 100644 --- a/miosix/config/Makefile.inc +++ b/miosix/config/Makefile.inc @@ -2112,7 +2112,8 @@ else ifeq ($(ARCH),cortexM3_efm32gg) $(BOARD_INC)/interfaces-impl/gpioirq.cpp \ $(BOARD_INC)/interfaces-impl/hardware_timer.cpp \ $(BOARD_INC)/interfaces-impl/transceiver.cpp \ - $(BOARD_INC)/interfaces-impl/cstimer.cpp + $(BOARD_INC)/interfaces-impl/cstimer.cpp \ + $(BOARD_INC)/interfaces-impl/high_resolution_timer_base.cpp ## Add a #define to allow querying board name CFLAGS_BASE += -DEFM32GG332F1024 -D_BOARD_WANDSTEM diff --git a/miosix/interfaces/cstimer.h b/miosix/interfaces/cstimer.h index 92d32400..1befa418 100644 --- a/miosix/interfaces/cstimer.h +++ b/miosix/interfaces/cstimer.h @@ -3,6 +3,8 @@ namespace miosix { +class ContextSwitchTimerImpl; + /** * This class is a low level interface to a hardware timer, that is used as * the basis for the Miosix timing infrastructure. In detail, it allows to @@ -66,6 +68,7 @@ private: */ ContextSwitchTimer(); unsigned int timerFreq; + ContextSwitchTimerImpl* pImpl; }; } //namespace miosix -- GitLab