I wanted a free running 32 bit (unsigned, of course) timer with greater 'granularity' than micros(); so I started looking and settled on FTM1 as being the thing to use.
First curiosity: If the FTM_SC_TOF bit is not reset very early in the interrupt handler routine the interrupt fires again for a reason I have not yet been able to become positive about - I think tho that it is more likely related to FTM_SC_TOF than anything else.
Second curiosity: This one is really curious to me; at first glance it seems that the inclusion of a line which, afaict, does not even get executed and simply reads FTM1_CNT into a variable (or would, if it were being executed ) also makes it stop re-firing the extra interrupt event regardless of where/when FTM_SC_TOF is reset in the handler routine.
Because the ftm1_isr is an all inclusive interrupt I made the (tester) handler check for other events firing it, in a very limited way at first (flagOdd on its own) and then decided to expand that to try to identify what the extraneous event(s) was(/were) - nothing became apparent, I think it must be the interrupt controller re-firing because of FTM_SC_TOF but it remains curious to me.
So, if you make JOHNNY_BE_STRANGE non zero flagOdd stops indicating any hits, let alone the same number of hits as flagEven. If instead MAKE_IT_GO_AWAY is made non zero it doesn't fire the unidentifiable interrupt either.
My final version of the interrupt handler is based on these findings
So, anybody willing to take a stab at curiosity #2?
I'm pretty sure about the first curiosity but anybody with a firmer idea of why resetting the overflow flag earliest in isr execution makes the extraneous event stop occuring would be very cool to hear from. Seems to have to be first (after checking it is set) thing done, I've seen { timer1.hi++; FTM1_SC&=~FTM_SC_TOF; } do the same re-fire as { timer1.hi++; FTM1_SC&=~FTM_SC_TOF; flagEven++; }
First curiosity: If the FTM_SC_TOF bit is not reset very early in the interrupt handler routine the interrupt fires again for a reason I have not yet been able to become positive about - I think tho that it is more likely related to FTM_SC_TOF than anything else.
Second curiosity: This one is really curious to me; at first glance it seems that the inclusion of a line which, afaict, does not even get executed and simply reads FTM1_CNT into a variable (or would, if it were being executed ) also makes it stop re-firing the extra interrupt event regardless of where/when FTM_SC_TOF is reset in the handler routine.
Because the ftm1_isr is an all inclusive interrupt I made the (tester) handler check for other events firing it, in a very limited way at first (flagOdd on its own) and then decided to expand that to try to identify what the extraneous event(s) was(/were) - nothing became apparent, I think it must be the interrupt controller re-firing because of FTM_SC_TOF but it remains curious to me.
Code:
#define JOHNNY_BE_STRANGE 0
#define MAKE_IT_GO_AWAY 0
typedef union {
uint32_t value;
struct {
uint16_t lo;
uint16_t hi;
};
} convert32to16;
volatile convert32to16 timer1;
volatile uint32_t flagOdd=0,flagEven=0;
volatile uint16_t flagVal=0;
void ftm1_isr(void)
{
if(FTM1_SC&FTM_SC_TOF)
{
#if MAKE_IT_GO_AWAY!=0
FTM1_SC&=~FTM_SC_TOF;
timer1.hi++;
// flagEven++; // the value of timer1.value being close to 12000000 indicates interrupt firing no probs.
#else
timer1.hi++;
flagEven++; // even with this line removed, under circumstances where flagOdd advances at all, flagOdd still advances.
FTM1_SC&=~FTM_SC_TOF;
#endif
} else if(FTM1_FMS&191) {
flagOdd|=((FTM1_FMS&255)<<8); // never seen this go off but leaving it here just in case.
} else {
flagOdd++;
#if JOHNNY_BE_STRANGE!=0 // really seems strange to me that the presence of the following line
flagVal=FTM1_CNT; // seems to make the second interrupt event fail to occur even though
#endif // I cannot see how this line executes in light of flagOdd never advancing when this line
} // is included in compilation.
}
elapsedMillis freddy;
void setup()
{
Serial.begin(Serial.baud());
delay(5000);
FTM1_MODE=FTM_MODE_WPDIS;
FTM1_MODE|=FTM_MODE_FTMEN;
FTM1_SC = 0; // disabled while I write some values to it.
FTM1_CNT=0;
FTM1_MOD=0xFFFF;
FTM1_C0SC=0; // these three lines are only here
FTM1_C1SC=0; // as part of my initial (vague-ish)
FTM1_QDCTRL=0; // attempt to kill the extra interrupt.
FTM1_SC = FTM_SC_TOIE|(1<<3)|2; // (use system clock, divide clock by 4, have an overflow interrupt)
FTM1_MODE&=~FTM_MODE_FTMEN;
// Higher priority for my purpose.
NVIC_SET_PRIORITY(IRQ_FTM1, 64);
NVIC_ENABLE_IRQ(IRQ_FTM1);
}
void loop()
{
if(Serial.available())
{
switch(Serial.read())
{
case 'a':
Serial.printf("FTM1_MODE: %u\n",FTM1_MODE);
Serial.printf("FTM1_C0SC: %u\n",FTM1_C0SC);
Serial.printf("FTM1_C1SC: %u\n",FTM1_C1SC);
Serial.printf("FTM1_STATUS: %u\n",FTM1_STATUS);
Serial.println();
break;
}
}
if(freddy>999)
{
timer1.lo=FTM1_CNT;
uint32_t jebus=freddy;
freddy=0;
FTM1_CNT=0;
Serial.printf("Millis: %u, FTM1_CNT: %u (%u,%u,%u)\n",jebus,timer1.value,flagEven,flagOdd,flagVal);
timer1.value=0;
flagEven=0;
flagOdd=0;
flagVal=0;
}
}
My final version of the interrupt handler is based on these findings
Code:
void ftm1_isr(void)
{
if(FTM1_SC&FTM_SC_TOF)
{
FTM1_SC&=~FTM_SC_TOF;
Timer.hi++;
}
}
I'm pretty sure about the first curiosity but anybody with a firmer idea of why resetting the overflow flag earliest in isr execution makes the extraneous event stop occuring would be very cool to hear from. Seems to have to be first (after checking it is set) thing done, I've seen { timer1.hi++; FTM1_SC&=~FTM_SC_TOF; } do the same re-fire as { timer1.hi++; FTM1_SC&=~FTM_SC_TOF; flagEven++; }
Last edited: