Skip to content
Snippets Groups Projects
Commit 7d622095 authored by Fabiano Riccardi's avatar Fabiano Riccardi Committed by Federico
Browse files

Improvement in GPIOTimer output mode, now it is working even there are few details to fix

parent 42480b63
Branches
No related tags found
2 merge requests!40Update to Miosix 2.7,!17Draft: Improved miosix build system and fixed cmake scripts
......@@ -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 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() {}
......@@ -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);
......
......@@ -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){
//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)
{
if(GPIOtimer::tWaitingGPIO){
GPIOtimer::tWaitingGPIO->IRQwakeup();
if(GPIOtimer::tWaitingGPIO->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
Scheduler::IRQfindNextThread();
GPIOtimer::tWaitingGPIO=nullptr;
}
}
}
static inline void callScheduler(){
......@@ -98,13 +103,15 @@ 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){
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;
......@@ -112,11 +119,15 @@ static inline void setupTimers2(){
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();
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){
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;
}
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,8 +365,37 @@ 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;
}
}
......
......@@ -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);
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment