khoih-prog/SAMD_TimerInterrupt

Bug when going from a >20000us period to a <20000us period. The timer period become 4 times greater.

thiagothimotti opened this issue · 9 comments

Describe the bug

If I set a interval greater than 20000us and then set a smaller than 20000us, I'll have my period 4 times bigger than expected.

Steps to Reproduce

SAMDTimer ITimer(TIMER_TC3);

uint32_t myClockTimer=0,lastMicros=0;

void clock(void)
{	
	myClockTimer=micros()-lastMicros;    //2us come from here
	lastMicros=micros();
}

void setup() {

}

void loop(){
		ITimer.attachInterruptInterval(20005, clock);  //myClockTimer=20003 (20005 minus 2us, it's correct) 
		delay(5000);
		ITimer.attachInterruptInterval(19995, clock);  //myClockTimer=79978(4 times bigger than expected, minus 2us) 
		delay(5000);
}

Expected behavior

The expected behavior was a timer period of 19995us.

Actual behavior

The actual behavior was a timer period 4 times bigger.

Information

Arduino Core v1.8.9
Atmel Studio

Some observations

If I start with 19000us, works fine. Then I go to 21000us, works fine. When I go back to 19000us, the bug happen.
Only noticed when going from a bigger(>20000) to smaller(<20000). And since this happen the smaller won't work anymore.
I'm suspecting some bug with the preScaler.

Hi @thiagothimotti

I'm amazed that you found out an interesting hard-to-find bug. I'm able to duplicate it and will investigate and fix.

This is the sketch to duplicate

#if !( defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \
    || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \
    || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(__SAMD21G18A__) \
    || defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD21E18A__) || defined(__SAMD51__) || defined(__SAMD51J20A__) || defined(__SAMD51J19A__) \
    || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) || defined(__SAMD21G18A__) )
#error This code is designed to run on SAMD21/SAMD51 platform! Please check your Tools->Board setting.
#endif

// These define's must be placed at the beginning before #include "SAMDTimerInterrupt.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
// Don't define TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG         4
#define _TIMERINTERRUPT_LOGLEVEL_     4

#include "SAMDTimerInterrupt.h"

SAMDTimer ITimer(TIMER_TC3);

uint32_t myClockTimer = 0, lastMicros = 0;

void clock(void)
{
  myClockTimer = micros() - lastMicros; //2us come from here
  lastMicros = micros();
}
void setup()
{
  Serial.begin(115200);
  while (!Serial);

  delay(100);

  Serial.print(F("\nStarting Argument_None_uS on ")); Serial.println(BOARD_NAME);
  Serial.println(SAMD_TIMER_INTERRUPT_VERSION);
  Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
}

void loop()
{
  ITimer.attachInterruptInterval(19995, clock);  //myClockTimer=79978(4 times bigger than expected, minus 2us)
  delay(5000);
  Serial.print(F("myClockTimer (19995) = ")); Serial.println(myClockTimer);
  ITimer.attachInterruptInterval(19995, clock);  //myClockTimer=79978(4 times bigger than expected, minus 2us)
  delay(5000);
  Serial.print(F("myClockTimer (19995) = ")); Serial.println(myClockTimer);
  ITimer.attachInterruptInterval(19995, clock);  //myClockTimer=79978(4 times bigger than expected, minus 2us)
  delay(5000);
  Serial.print(F("myClockTimer (19995) = ")); Serial.println(myClockTimer);
  ITimer.attachInterruptInterval(19000, clock);  //myClockTimer=79978(4 times bigger than expected, minus 2us)
  delay(5000);
  Serial.print(F("myClockTimer (19000) = ")); Serial.println(myClockTimer);
  ITimer.attachInterruptInterval(20005, clock);  //myClockTimer=20003 (20005 minus 2us, it's correct)
  delay(5000);
  Serial.print(F("myClockTimer (20005) = ")); Serial.println(myClockTimer);
  ITimer.attachInterruptInterval(30000, clock);  //myClockTimer=79978(4 times bigger than expected, minus 2us)
  delay(5000);
  Serial.print(F("myClockTimer (30000) = ")); Serial.println(myClockTimer);
  ITimer.attachInterruptInterval(19995, clock);  //myClockTimer=79978(4 times bigger than expected, minus 2us)
  delay(5000);
  Serial.print(F("myClockTimer (19995) = ")); Serial.println(myClockTimer);
  ITimer.attachInterruptInterval(30000, clock);  //myClockTimer=79978(4 times bigger than expected, minus 2us)
  delay(5000);
  Serial.print(F("myClockTimer (30000) = ")); Serial.println(myClockTimer);
  
}

and the Terminal output

Starting Argument_None_uS on SEEED_XIAO_M0
SAMDTimerInterrupt v1.3.1
CPU Frequency = 48 MHz
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19995) = 19993           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19995) = 19993           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19995) = 19993           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19000) = 18998           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (20005) = 20002           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (30000) = 29997           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19995) = 79978           <========== ERROR ===========================<======ERROR
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (30000) = 29996           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19995) = 79978           <========== ERROR ===========================<======ERROR
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19995) = 79978           <========== ERROR ===========================<======ERROR
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19995) = 79978           <========== ERROR ===========================<======ERROR
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (19000) = 75998           <========== ERROR ===========================<======ERROR
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (20005) = 20002           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
myClockTimer (30000) = 29997           <========== OK
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00

Already found out and fixed the bug. Will publish the new release within today.

Test result for TC3 OK

Starting Argument_None_uS on SEEED_XIAO_M0
SAMDTimerInterrupt v1.4.0
CPU Frequency = 48 MHz
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19000 , frequency = 52.63
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19000 , _prescaler = 16
[TISR] _compareValue = 56999
myClockTimer (19000) = 18998
[TISR] _period = 20005 , frequency = 49.99
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 20005 , _prescaler = 64
[TISR] _compareValue = 15002
myClockTimer (20005) = 20002
[TISR] _period = 30000 , frequency = 33.33
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 30000 , _prescaler = 64
[TISR] _compareValue = 22498
myClockTimer (30000) = 29997
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 30000 , frequency = 33.33
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 30000 , _prescaler = 64
[TISR] _compareValue = 22498
myClockTimer (30000) = 29997
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19000 , frequency = 52.63
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 19000 , _prescaler = 16
[TISR] _compareValue = 56999
myClockTimer (19000) = 18998
[TISR] _period = 20005 , frequency = 49.99
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 20005 , _prescaler = 64
[TISR] _compareValue = 15002
myClockTimer (20005) = 20004
[TISR] _period = 30000 , frequency = 33.33
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00
[TISR] SAMD21 TC3 period = 30000 , _prescaler = 64
[TISR] _compareValue = 22498

Amazing ! Incredibly fast ! What was?

Test for TCC also OK

Starting Argument_None_uS on SEEED_XIAO_M0
SAMDTimerInterrupt v1.4.0
CPU Frequency = 48 MHz
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 19000 , frequency = 52.63
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 19000 , _prescaler = 16
[TISR] _compareValue = 56999
myClockTimer (19000) = 18998
[TISR] _period = 20005 , frequency = 49.99
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 20005 , _prescaler = 64
[TISR] _compareValue = 15002
myClockTimer (20005) = 20002
[TISR] _period = 30000 , frequency = 33.33
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 30000 , _prescaler = 64
[TISR] _compareValue = 22498
myClockTimer (30000) = 29996
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984
myClockTimer (19995) = 19993           <========== OK===============================<=======OK
[TISR] _period = 30000 , frequency = 33.33
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 30000 , _prescaler = 64
[TISR] _compareValue = 22498
myClockTimer (30000) = 29997
[TISR] _period = 19995 , frequency = 50.01
[TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48
[TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000
[TISR] SAMD21 TCC period = 19995 , _prescaler = 16
[TISR] _compareValue = 59984

What was?

I didn't expect the attachInterruptInterval() to be called repeatedly, and didn't fully reinit the PreScaler register.
Now, I have to reinit every time we have a change in the Timer.
You'll see in the code

Great ! 👍 Thank you.

I have to thank you 👍 for finding the interesting bug. Your contribution will be noted in new release.

Hi @thiagothimotti

Already published the new SAMD_TimerInterrupt Releases v1.4.0 with your contribution noted in Contributions and Thanks.

You can also see a new RepeatedAttachInterrupt_uS example, based on yours, has also been added to the new Release.

Please test and see if everything is working OK on your side.

I'm looking forward to receiving your next Contributions.

Regards,


Releases v1.4.0

  1. Fix SAMD21 rare bug caused by not fully init Prescaler. Check Bug when going from a >20000us period to a <20000us period. The timer period become 4 times greater. #3

Hi @khoih-prog,
Tested and stable.
I'm new to gitHub, learning how to contribute here. I'll be following this repository.
Your library really helped my application, thank you 👍