From 0c684419b5d31ba1e0a702a210e142dfd167e6b7 Mon Sep 17 00:00:00 2001 From: Sasan Golchin <ahmad.golchin@mail.polimi.it> Date: Mon, 26 Sep 2016 16:04:43 +0200 Subject: [PATCH] Aperiodic CSTimer support added for cortexM3_efm32gg/wandstem board --- .../interfaces-impl/cstimer.cpp | 193 ++++++++++++++++++ miosix/config/Makefile.inc | 3 +- .../efm32gg332f1024_wandstem/board_settings.h | 2 + 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer.cpp diff --git a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer.cpp b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer.cpp new file mode 100644 index 00000000..7ad008ad --- /dev/null +++ b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/cstimer.cpp @@ -0,0 +1,193 @@ +#include "interfaces/cstimer.h" +#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" + +using namespace miosix; + +const unsigned int timerBits=32; +const unsigned long long overflowIncrement=(1LL<<timerBits); +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 = 0; //most significant 32 bits of check point +static bool lateIrq=false; + +static inline long long nextInterrupt() +{ + return ms32chkp | TIMER3->CC[1].CCV<<16 | TIMER1->CC[1].CCV; +} + +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); +} + +void __attribute__((naked)) TIMER3_IRQHandler() +{ + saveContext(); + asm volatile("bl _Z10cstirqhnd3v"); + restoreContext(); +} + +void __attribute__((naked)) TIMER1_IRQHandler() +{ + saveContext(); + asm volatile("bl _Z10cstirqhnd1v"); + restoreContext(); +} +void __attribute__((naked)) TIMER2_IRQHandler() +{ + saveContext(); + asm volatile("bl _Z10cstirqhnd2v"); + restoreContext(); +} + +void __attribute__((used)) cstirqhnd3(){ + //Checkpoint + if (lateIrq){ + IRQtimerInterrupt(tc->tick2ns(IRQgetTick())); + lateIrq = false; + }else if (TIMER3->IF & TIMER_IF_CC1){ + TIMER3->IFC = TIMER_IFC_CC1; + if (ms32time == ms32chkp){ + TIMER1->IFC = TIMER_IFC_CC1; + NVIC_ClearPendingIRQ(TIMER1_IRQn); + NVIC_EnableIRQ(TIMER1_IRQn); + if (TIMER1->CNT >= TIMER1->CC[1].CCV){ + TIMER1->IFC = TIMER_IFC_CC1; + NVIC_DisableIRQ(TIMER1_IRQn); + IRQtimerInterrupt(tc->tick2ns(IRQgetTick())); + } + } + } + + //rollover + if (TIMER3->IF & TIMER_IF_OF){ + TIMER3->IFC = TIMER_IFC_OF; + ms32time += overflowIncrement; + } +} +void __attribute__((used)) cstirqhnd1(){ + //Checkpoint + if (TIMER1->IF & TIMER_IF_CC1){ + TIMER1->IFC = TIMER_IFC_CC1; + NVIC_ClearPendingIRQ(TIMER1_IRQn); + NVIC_DisableIRQ(TIMER1_IRQn); + IRQtimerInterrupt(tc->tick2ns(IRQgetTick())); + } +} + +void __attribute__((used)) cstirqhnd2(){ + +} + +// +// class ContextSwitchTimer +// + +namespace miosix { + + ContextSwitchTimer& ContextSwitchTimer::instance() + { + static ContextSwitchTimer instance; + return instance; + } + + void ContextSwitchTimer::IRQsetNextInterrupt(long long tick){ + ms32chkp = 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(IRQgetTick() >= nextInterrupt()) + { + NVIC_SetPendingIRQ(TIMER3_IRQn); + lateIrq=true; + } + } + + long long ContextSwitchTimer::getNextInterrupt() const + { + return nextInterrupt(); + } + + long long ContextSwitchTimer::getCurrentTick() const + { + bool interrupts=areInterruptsEnabled(); + //TODO: optimization opportunity, if we can guarantee that no call to this + //function occurs before kernel is started, then we can use + //fastInterruptDisable()) + if(interrupts) disableInterrupts(); + long long result=IRQgetTick(); + if(interrupts) enableInterrupts(); + return result; + } + + long long ContextSwitchTimer::IRQgetCurrentTick() const + { + return IRQgetTick(); + } + + ContextSwitchTimer::~ContextSwitchTimer(){} + + ContextSwitchTimer::ContextSwitchTimer() + { + //Power the timers up + { + InterruptDisableLock l; + CMU->HFPERCLKEN0 |= CMU_HFPERCLKEN0_TIMER1 | CMU_HFPERCLKEN0_TIMER2 + | CMU_HFPERCLKEN0_TIMER3; + } + //Configure Timers + TIMER1->CTRL = TIMER_CTRL_MODE_UP | TIMER_CTRL_CLKSEL_PRESCHFPERCLK + | TIMER_CTRL_PRESC_DIV1 | TIMER_CTRL_SYNC; + TIMER2->CTRL = TIMER_CTRL_MODE_UP | TIMER_CTRL_CLKSEL_PRESCHFPERCLK + | TIMER_CTRL_PRESC_DIV1 | TIMER_CTRL_SYNC; + TIMER3->CTRL = TIMER_CTRL_MODE_UP | TIMER_CTRL_CLKSEL_TIMEROUF + | TIMER_CTRL_SYNC; + + //Enable necessary interrupt lines + TIMER1->IEN = TIMER_IEN_CC1; + TIMER3->IEN = TIMER_IEN_OF | TIMER_IEN_CC1; + + TIMER1->CC[1].CTRL = TIMER_CC_CTRL_MODE_OUTPUTCOMPARE; + TIMER3->CC[1].CTRL = TIMER_CC_CTRL_MODE_OUTPUTCOMPARE; + + NVIC_SetPriority(TIMER1_IRQn,3); + NVIC_SetPriority(TIMER3_IRQn,3); + NVIC_ClearPendingIRQ(TIMER3_IRQn); + NVIC_ClearPendingIRQ(TIMER1_IRQn); + NVIC_EnableIRQ(TIMER3_IRQn); + NVIC_DisableIRQ(TIMER1_IRQn); + //Start timers + TIMER1->CMD = TIMER_CMD_START; + //Setup tick2ns conversion tool + timerFreq = 48000000; + tc=new TimeConversion(timerFreq); + } + +TimeConversion *tc; + +} \ No newline at end of file diff --git a/miosix/config/Makefile.inc b/miosix/config/Makefile.inc index f031af98..8a96f785 100644 --- a/miosix/config/Makefile.inc +++ b/miosix/config/Makefile.inc @@ -2111,7 +2111,8 @@ else ifeq ($(ARCH),cortexM3_efm32gg) $(BOARD_INC)/interfaces-impl/power_manager.cpp \ $(BOARD_INC)/interfaces-impl/gpioirq.cpp \ $(BOARD_INC)/interfaces-impl/hardware_timer.cpp \ - $(BOARD_INC)/interfaces-impl/transceiver.cpp + $(BOARD_INC)/interfaces-impl/transceiver.cpp \ + $(BOARD_INC)/interfaces-impl/cstimer.cpp ## Add a #define to allow querying board name CFLAGS_BASE += -DEFM32GG332F1024 -D_BOARD_WANDSTEM diff --git a/miosix/config/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/board_settings.h b/miosix/config/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/board_settings.h index 44ff1253..b40896c9 100644 --- a/miosix/config/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/board_settings.h +++ b/miosix/config/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/board_settings.h @@ -43,6 +43,8 @@ */ #define WANDSTEM_HW_REV 14 +#define USE_CSTIMER //FIXME: remove when cstimer becomes default + namespace miosix { /** -- GitLab