diff --git a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/gpio_timer.cpp b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/gpio_timer.cpp index fa4bcfe209124829fe3d3325596fe84c1a971c63..720c68ad2a2b1ffc03cfc17c143d09c56a470c3d 100644 --- a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/gpio_timer.cpp +++ b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/gpio_timer.cpp @@ -11,6 +11,7 @@ #include "miosix.h" #include <cstdlib> #include <cstdio> +#include "../../../../debugpin.h" using namespace miosix; GPIOtimer& GPIOtimer::instance(){ @@ -82,16 +83,41 @@ bool GPIOtimer::absoluteWaitTrigger(long long tick){ FastInterruptDisableLock dLock; b.setModeGPIOTimer(false); //output timer setPinMode(false); //output pin - if(b.IRQsetNextInterrupt2(tick)){ - return true; + if(!b.IRQsetNextInterrupt2(tick)){ + return false; } - return false; + return true; } bool GPIOtimer::waitTrigger(long long tick){ return absoluteWaitTrigger(b.getCurrentTick()+tick); } +bool GPIOtimer::absoluteSyncWaitTrigger(long long tick){ + { + FastInterruptDisableLock dLock; + b.setModeGPIOTimer(false); //output timer + setPinMode(false); //output pin + if(!b.IRQsetNextInterrupt2(tick)){ + return false; + } + + do { + tWaitingGPIO=Thread::IRQgetCurrentThread(); + Thread::IRQwait(); + { + FastInterruptEnableLock eLock(dLock); + Thread::yield(); + } + } while(tWaitingGPIO && tick>b.getCurrentTick()); + } + return true; +} + +bool GPIOtimer::syncWaitTrigger(long long tick){ + return absoluteSyncWaitTrigger(b.getCurrentTick()+tick); +} + long long GPIOtimer::aux1=0; GPIOtimer::~GPIOtimer() {} diff --git a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/gpio_timer.h b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/gpio_timer.h index 4aae9c831a8025c637f18269de92119307491bbc..32d859e36988a7e72d20cf0832004882afbeb9db 100644 --- a/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/gpio_timer.h +++ b/miosix/arch/cortexM3_efm32gg/efm32gg332f1024_wandstem/interfaces-impl/gpio_timer.h @@ -51,6 +51,8 @@ namespace miosix { */ bool absoluteWaitTrigger(long long tick); bool waitTrigger(long long tick); + bool absoluteSyncWaitTrigger(long long tick); + bool syncWaitTrigger(long long tick); 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 03ad111917ed35c592aa57d4113c73dfeb6db57f..933535092fbd84373dce2c20fee200738ebacb84 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 @@ -17,6 +17,7 @@ #include "high_resolution_timer_base.h" #include "kernel/timeconversion.h" #include "gpio_timer.h" +#include "../../../../debugpin.h" using namespace miosix; @@ -54,17 +55,21 @@ inline void interruptGPIOTimerRoutine(){ TIMER1->IFC = TIMER_IFC_CC2; TIMER3->IFC = TIMER_IFC_CC2; 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(GPIOtimer::tWaitingGPIO) - { - GPIOtimer::tWaitingGPIO->IRQwakeup(); - if(GPIOtimer::tWaitingGPIO->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) - Scheduler::IRQfindNextThread(); - GPIOtimer::tWaitingGPIO=nullptr; - } + //keep high for at least x Us + delayUs(1); + TIMER1->CC[2].CTRL = (TIMER1->CC[2].CTRL & ~_TIMER_CC_CTRL_CMOA_MASK) | TIMER_CC_CTRL_CMOA_CLEAR; + //I don't need to enable the interrupt because "output" is separated + //10 tick are enought to + TIMER1->CC[2].CCV = static_cast<unsigned int>(TIMER1->CNT+10);//static_cast<unsigned int>(tick & 0xFFFF); + } + //Reactivating the thread that is waiting for the event. + if(GPIOtimer::tWaitingGPIO){ + GPIOtimer::tWaitingGPIO->IRQwakeup(); + if(GPIOtimer::tWaitingGPIO->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) + Scheduler::IRQfindNextThread(); + GPIOtimer::tWaitingGPIO=nullptr; } + } static inline void callScheduler(){ @@ -98,25 +103,31 @@ static inline void setupTimers(){ // If the most significant 32bit aren't match wait for TIM3 to overflow! } -static inline void setupTimers2(){ +static inline bool setupTimers2(){ // We assume that this function is called only when the checkpoint is in future if (ms32chkp[2] == ms32time){ // If the most significant 32bit matches, enable TIM3 TIMER3->IFC = TIMER_IFC_CC2; TIMER3->IEN |= TIMER_IEN_CC2; - if (static_cast<unsigned short>(TIMER3->CNT) >= static_cast<unsigned short>(TIMER3->CC[2].CCV) + 1){ - // If TIM3 matches by the time it is being enabled, disable it right away + unsigned short temp=static_cast<unsigned short>(TIMER3->CC[2].CCV) + 1; + if (static_cast<unsigned short>(TIMER3->CNT) >= temp){ + TIMER1->CC[2].CTRL = (TIMER1->CC[2].CTRL & ~_TIMER_CC_CTRL_CMOA_MASK) | TIMER_CC_CTRL_CMOA_SET; + // If TIM3 matches by the time it is being enabled, disable it right away TIMER3->IFC = TIMER_IFC_CC2; TIMER3->IEN &= ~TIMER_IEN_CC2; // Enable TIM1 since TIM3 has been already matched TIMER1->IFC = TIMER_IFC_CC2; TIMER1->IEN |= TIMER_IEN_CC2; if (TIMER1->CNT >= TIMER1->CC[2].CCV){ - // If TIM1 matches by the time it is being enabled, call the scheduler right away + //This line introduce a delay of 10ticks... it should be revised + TIMER1->CC[2].CCV = static_cast<unsigned int>(10+TIMER1->CNT); + // If TIM1 matches by the time it is being enabled, call the scheduler right away interruptGPIOTimerRoutine(); + return false; } } } + return true; // If the most significant 32bit aren't match wait for TIM3 to overflow! } @@ -164,13 +175,18 @@ void __attribute__((used)) cstirqhnd3(){ //This if is to manage the GPIOtimer in OUTPUT Mode if ((TIMER3->IEN & TIMER_IEN_CC2) && (TIMER3->IF & TIMER_IF_CC2)){ TIMER3->IFC = TIMER_IFC_CC2; - if (static_cast<unsigned short>(TIMER3->CNT) >= static_cast<unsigned short>(TIMER3->CC[2].CCV) + 1){ - // Should happen if and only if most significant 32 bits have been matched + unsigned short temp=static_cast<unsigned short>(TIMER3->CC[2].CCV) + 1; + if (static_cast<unsigned short>(TIMER3->CNT) >= temp){ + //Set the mode to raise the pin + TIMER1->CC[2].CTRL = (TIMER1->CC[2].CTRL & ~_TIMER_CC_CTRL_CMOA_MASK) | TIMER_CC_CTRL_CMOA_SET; + // Should happen if and only if most significant 32 bits have been matched TIMER3->IEN &= ~ TIMER_IEN_CC2; // Enable TIM1 since TIM3 has been already matched TIMER1->IFC = TIMER_IFC_CC2; TIMER1->IEN |= TIMER_IEN_CC2; if (TIMER1->CNT >= TIMER1->CC[2].CCV){ + //This line introduce a delay of 10ticks... it should be revised + TIMER1->CC[2].CCV = static_cast<unsigned int>(10+TIMER1->CNT); // If TIM1 matches by the time it is being enabled, call the scheduler right away interruptGPIOTimerRoutine(); } @@ -298,36 +314,6 @@ void HighResolutionTimerBase::setCCInterrupt2Tim1(bool enable){ TIMER1->IEN&=~TIMER_IEN_CC2; } -// In this function I prepare the timer, but i don't enable the timer. -// Set true to get the input mode: wait for the raising of the pin and timestamp the time in which occurs -// Set false to get the output mode: When the time set is reached, raise the pin! -void HighResolutionTimerBase::setModeGPIOTimer(bool input){ - if(input){ - //Connect TIMER1->CC2 to PIN PE12, meaning GPIO10 on wandstem - TIMER1->ROUTE=TIMER_ROUTE_CC2PEN - | TIMER_ROUTE_LOCATION_LOC1; - //Configuro la modalità input - TIMER1->CC[2].CTRL=TIMER_CC_CTRL_MODE_INPUTCAPTURE | - TIMER_CC_CTRL_ICEDGE_RISING | - TIMER_CC_CTRL_INSEL_PIN; - - //Config PRS: Timer3 has to be a consumer, Timer1 a producer, TIMER3 keeps the most significative part - //TIMER1->CC2 as producer, i have to specify the event i'm interest in - PRS->CH[0].CTRL|=PRS_CH_CTRL_SOURCESEL_TIMER1 - |PRS_CH_CTRL_SIGSEL_TIMER1CC2; - - //TIMER3->CC2 as consumer - TIMER3->CC[2].CTRL=TIMER_CC_CTRL_PRSSEL_PRSCH0 - | TIMER_CC_CTRL_INSEL_PRS - | TIMER_CC_CTRL_ICEDGE_BOTH - | TIMER_CC_CTRL_MODE_INPUTCAPTURE; - - }else{ - TIMER1->CC[2].CTRL = TIMER_CC_CTRL_MODE_OUTPUTCOMPARE; - TIMER3->CC[2].CTRL = TIMER_CC_CTRL_MODE_OUTPUTCOMPARE; - } - -} long long HighResolutionTimerBase::getCurrentTick(){ bool interrupts=areInterruptsEnabled(); //TODO: optimization opportunity, if we can guarantee that no call to this @@ -341,46 +327,31 @@ long long HighResolutionTimerBase::getCurrentTick(){ } bool HighResolutionTimerBase::IRQsetNextInterrupt0(long long tick){ - ms32chkp[0] = tick & upperMask; - TIMER3->CC[0].CCV = static_cast<unsigned int>((tick & 0xFFFF0000)>>16); - TIMER1->CC[0].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() >= IRQgetSetTimeCCV0()) - { - //Now we should set TIMER3->IFS=TIMER_IFS_CC0 - NVIC_SetPendingIRQ(TIMER3_IRQn); - lateIrq=true; - return false; - } - return true; + return false; } -bool HighResolutionTimerBase::IRQsetNextInterrupt1(long long tick){ +void HighResolutionTimerBase::IRQsetNextInterrupt1(long long tick){ // First off, 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) - { + if(curTick >= tick){ // 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)-1; ms32chkp[1] = tick & upperMask; setupTimers(); - return true; } } +/* + Return true if the pin is going to raise, otherwise false, the pin remain low because the command arrived too late + */ bool HighResolutionTimerBase::IRQsetNextInterrupt2(long long tick){ TIMER1->IEN &= ~TIMER_IEN_CC2; TIMER3->IEN &= ~TIMER_IEN_CC2; @@ -394,9 +365,38 @@ bool HighResolutionTimerBase::IRQsetNextInterrupt2(long long tick){ ms32chkp[2] = tick & upperMask; TIMER3->CC[2].CCV = static_cast<unsigned int>((tick & 0xFFFF0000)>>16)-1; TIMER1->CC[2].CCV = static_cast<unsigned int>(tick & 0xFFFF); - setupTimers2(); - return true; + return setupTimers2(); } } +// In this function I prepare the timer, but i don't enable the timer. +// Set true to get the input mode: wait for the raising of the pin and timestamp the time in which occurs +// Set false to get the output mode: When the time set is reached, raise the pin! +void HighResolutionTimerBase::setModeGPIOTimer(bool input){ + //Connect TIMER1->CC2 to PIN PE12, meaning GPIO10 on wandstem + TIMER1->ROUTE=TIMER_ROUTE_CC2PEN + | TIMER_ROUTE_LOCATION_LOC1; + if(input){ + //Configuro la modalità input + TIMER1->CC[2].CTRL = TIMER_CC_CTRL_MODE_INPUTCAPTURE | + TIMER_CC_CTRL_ICEDGE_RISING | + TIMER_CC_CTRL_INSEL_PIN; + + //Config PRS: Timer3 has to be a consumer, Timer1 a producer, TIMER3 keeps the most significative part + //TIMER1->CC2 as producer, i have to specify the event i'm interest in + PRS->CH[0].CTRL|=PRS_CH_CTRL_SOURCESEL_TIMER1 + |PRS_CH_CTRL_SIGSEL_TIMER1CC2; + + //TIMER3->CC2 as consumer + TIMER3->CC[2].CTRL=TIMER_CC_CTRL_PRSSEL_PRSCH0 + | TIMER_CC_CTRL_INSEL_PRS + | TIMER_CC_CTRL_ICEDGE_BOTH + | TIMER_CC_CTRL_MODE_INPUTCAPTURE; + + }else{ + TIMER1->CC[2].CTRL = TIMER_CC_CTRL_MODE_OUTPUTCOMPARE; + TIMER3->CC[2].CTRL = TIMER_CC_CTRL_MODE_OUTPUTCOMPARE; + } +} + 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 aa9e7690f26391bdb5afdff9a6b57a38f7873f62..d0dbe197245412ddce2d63f5b8eaf0d21b5163cc 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 @@ -37,7 +37,7 @@ public: * \param tick the time when the interrupt will be fired, in timer ticks */ bool IRQsetNextInterrupt0(long long tick); - bool IRQsetNextInterrupt1(long long tick); + void IRQsetNextInterrupt1(long long tick); bool IRQsetNextInterrupt2(long long tick); /**