Releases v1.0.0 to support RP2040-based boards

### Initial Releases v1.0.0

1. Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc. using [Earle Philhower's arduino-pico core](https://github.com/earlephilhower/arduino-pico)
This commit is contained in:
Khoi Hoang
2021-05-11 20:58:08 -04:00
committed by GitHub
commit 5e6d0251b3
28 changed files with 5027 additions and 0 deletions
@@ -0,0 +1,117 @@
/****************************************************************************************************************************
Argument_Complex.ino
RPi_Pico_ISR_Timer-Impl.h
For RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
Licensed under MIT license
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
• This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.
• Four alarms: match on the lower 32 bits of counter, IRQ on match: TIMER_IRQ_0-TIMER_IRQ_3
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one RPI_PICO timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani@ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 11/05/2021 Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc.
*****************************************************************************************************************************/
#if !( defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) )
#error This code is intended to run on the RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 1
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "RPi_Pico_TimerInterrupt.h"
#if !defined(LED_BUILTIN)
#define LED_BUILTIN 25
#endif
// Init RPI_PICO_Timer
RPI_PICO_Timer ITimer1(1);
struct pinStruct
{
unsigned int Pin1;
unsigned int Pin2;
unsigned int Pin3;
};
volatile pinStruct myOutputPins = { LED_BUILTIN, 0, 1 };
bool TimerHandler(struct repeating_timer *t)
{
static bool toggle = false;
//timer interrupt toggles pins
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("Toggle pin1 = "); Serial.println( myOutputPins.Pin1 );
#endif
digitalWrite(myOutputPins.Pin1, toggle);
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("Read pin2 ("); Serial.print( myOutputPins.Pin2 );
Serial.print(") = ");
Serial.println(digitalRead(myOutputPins.Pin2) ? "HIGH" : "LOW" );
Serial.print("Read pin3 ("); Serial.print( myOutputPins.Pin1 );
Serial.print(") = ");
Serial.println(digitalRead(myOutputPins.Pin3) ? "HIGH" : "LOW" );
#endif
toggle = !toggle;
return true;
}
#define TIMER_INTERVAL_MS 1000
void setup()
{
pinMode(myOutputPins.Pin1, OUTPUT);
pinMode(myOutputPins.Pin2, OUTPUT);
pinMode(myOutputPins.Pin3, OUTPUT);
Serial.begin(115200);
while (!Serial);
Serial.print(F("\nStarting Argument_Complex on "));
Serial.println(BOARD_NAME);
Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
// Interval in microsecs
if (ITimer1.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler))
{
Serial.print(F("Starting ITimer1 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
}
void loop()
{
}
+139
View File
@@ -0,0 +1,139 @@
/****************************************************************************************************************************
Argument_None.ino
RPi_Pico_ISR_Timer-Impl.h
For RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
Licensed under MIT license
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
• This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.
• Four alarms: match on the lower 32 bits of counter, IRQ on match: TIMER_IRQ_0-TIMER_IRQ_3
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one RPI_PICO timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani@ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 11/05/2021 Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc.
*****************************************************************************************************************************/
/*
Notes:
Special design is necessary to share data between interrupt code and the rest of your program.
Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
variable can not spontaneously change. Because your function may change variables while your program is using them,
the compiler needs this hint. But volatile alone is often not enough.
When accessing shared variables, usually interrupts must be disabled. Even with volatile,
if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
or the entire sequence of your code which accesses the data.
*/
#if !( defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) )
#error This code is intended to run on the RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 1
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "RPi_Pico_TimerInterrupt.h"
#ifndef LED_BUILTIN
#define LED_BUILTIN 25 // Pin LED_BUILTIN mapped to pin GPIO25 of RPI_PICO, control on-board LED
#endif
#define PIN_D1 1 // Pin D1 mapped to pin GPIO1 of RPI_PICO
bool TimerHandler0(struct repeating_timer *t)
{
static bool toggle0 = false;
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("ITimer0: millis() = "); Serial.println(millis());
#endif
//timer interrupt toggles pin LED_BUILTIN
digitalWrite(LED_BUILTIN, toggle0);
toggle0 = !toggle0;
return true;
}
bool TimerHandler1(struct repeating_timer *t)
{
static bool toggle1 = false;
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("ITimer1: millis() = "); Serial.println(millis());
#endif
//timer interrupt toggles outputPin
digitalWrite(PIN_D1, toggle1);
toggle1 = !toggle1;
return true;
}
#define TIMER0_INTERVAL_MS 1000
#define TIMER1_INTERVAL_MS 5000
// Init RPI_PICO_Timer
RPI_PICO_Timer ITimer0(0);
RPI_PICO_Timer ITimer1(1);
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PIN_D1, OUTPUT);
Serial.begin(115200);
while (!Serial);
delay(100);
Serial.print(F("\nStarting Argument_None on ")); Serial.println(BOARD_NAME);
Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
// Interval in microsecs
if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
{
Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer0. Select another Timer, freq. or timer"));
// Interval in microsecs
if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
{
Serial.print(F("Starting ITimer1 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer1. Select another Timer, freq. or timer"));
}
void loop()
{
}
@@ -0,0 +1,133 @@
/****************************************************************************************************************************
Argument_Simple.ino
RPi_Pico_ISR_Timer-Impl.h
For RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
Licensed under MIT license
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
• This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.
• Four alarms: match on the lower 32 bits of counter, IRQ on match: TIMER_IRQ_0-TIMER_IRQ_3
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one RPI_PICO timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani@ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 11/05/2021 Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc.
*****************************************************************************************************************************/
#if !( defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) )
#error This code is intended to run on the RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 1
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "RPi_Pico_TimerInterrupt.h"
#if !defined(LED_BUILTIN)
#define LED_BUILTIN 25
#endif
unsigned int outputPin1 = LED_BUILTIN;
unsigned int outputPin2 = 1;
// Init RPI_PICO_Timer
RPI_PICO_Timer ITimer1(1);
RPI_PICO_Timer ITimer2(2);
#define TIMER1_INTERVAL_MS 1000
bool TimerHandler1(struct repeating_timer *t)
{
static bool toggle1 = false;
#if (TIMER_INTERRUPT_DEBUG > 0)
//timer interrupt toggles pin outputPin1
Serial.print("Pin"); Serial.print(outputPin1); Serial.println(toggle1 ? F(" ON") : F(" OFF"));
#endif
digitalWrite(outputPin1, toggle1);
toggle1 = !toggle1;
return true;
}
#define TIMER2_INTERVAL_MS 2000
bool TimerHandler2(struct repeating_timer *t)
{
static bool toggle2 = false;
#if (TIMER_INTERRUPT_DEBUG > 0)
//timer interrupt toggles pin outputPin2
Serial.print("Pin"); Serial.print(outputPin2); Serial.println(toggle2 ? F(" ON") : F(" OFF"));
#endif
//timer interrupt toggles pin outputPin2
digitalWrite(outputPin2, toggle2);
toggle2 = !toggle2;
return true;
}
void setup()
{
pinMode(outputPin1, OUTPUT);
pinMode(outputPin2, OUTPUT);
Serial.begin(115200);
while (!Serial);
Serial.print(F("\nStarting Argument_Simple on "));
Serial.println(BOARD_NAME);
Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
{
Serial.print(F("Starting ITimer1 OK, millis() = ")); Serial.println(millis());
#if (TIMER_INTERRUPT_DEBUG > 1)
Serial.print(F("OutputPin1 = ")); Serial.print(outputPin1);
#endif
}
else
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
if (ITimer2.attachInterruptInterval(TIMER2_INTERVAL_MS * 1000, TimerHandler2))
{
Serial.print(F("Starting ITimer2 OK, millis() = ")); Serial.println(millis());
#if (TIMER_INTERRUPT_DEBUG > 1)
Serial.print(F("OutputPin2 = ")); Serial.print(outputPin2);
#endif
}
else
Serial.println(F("Can't set ITimer2. Select another freq. or timer"));
}
void loop()
{
}
@@ -0,0 +1,182 @@
/****************************************************************************************************************************
Change_Interval.ino
RPi_Pico_ISR_Timer-Impl.h
For RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
Licensed under MIT license
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
• This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.
• Four alarms: match on the lower 32 bits of counter, IRQ on match: TIMER_IRQ_0-TIMER_IRQ_3
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one RPI_PICO timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani@ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 11/05/2021 Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc.
*****************************************************************************************************************************/
/*
Notes:
Special design is necessary to share data between interrupt code and the rest of your program.
Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
variable can not spontaneously change. Because your function may change variables while your program is using them,
the compiler needs this hint. But volatile alone is often not enough.
When accessing shared variables, usually interrupts must be disabled. Even with volatile,
if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
or the entire sequence of your code which accesses the data.
*/
#if !( defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) )
#error This code is intended to run on the RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 1
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "RPi_Pico_TimerInterrupt.h"
#ifndef LED_BUILTIN
#define LED_BUILTIN 25 // Pin D2 mapped to pin GPIO2/ADC12 of ESP32, control on-board LED
#endif
#define PIN_D1 1 // Pin D1 mapped to pin GPIO1 of RPI_PICO
volatile uint32_t Timer0Count = 0;
volatile uint32_t Timer1Count = 0;
bool TimerHandler0(struct repeating_timer *t)
{
static bool toggle0 = false;
// Flag for checking to be sure ISR is working as Serial.print is not OK here in ISR
Timer0Count++;
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("ITimer0: millis() = "); Serial.println(millis());
#endif
//timer interrupt toggles pin LED_BUILTIN
digitalWrite(LED_BUILTIN, toggle0);
toggle0 = !toggle0;
return true;
}
bool TimerHandler1(struct repeating_timer *t)
{
static bool toggle1 = false;
// Flag for checking to be sure ISR is working as Serial.print is not OK here in ISR
Timer1Count++;
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("ITimer1: millis() = "); Serial.println(millis());
#endif
//timer interrupt toggles PIN_D1
digitalWrite(PIN_D1, toggle1);
toggle1 = !toggle1;
return true;
}
void printResult(uint32_t currTime)
{
Serial.print(F("Time = ")); Serial.print(currTime);
Serial.print(F(", Timer0Count = ")); Serial.print(Timer0Count);
Serial.print(F(", Timer1Count = ")); Serial.println(Timer1Count);
}
#define TIMER0_INTERVAL_MS 2000
#define TIMER1_INTERVAL_MS 5000
// Init ESP32 timer 0
RPI_PICO_Timer ITimer0(0);
RPI_PICO_Timer ITimer1(1);
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PIN_D1, OUTPUT);
Serial.begin(115200);
while (!Serial);
delay(100);
Serial.print(F("\nStarting Change_Interval on ")); Serial.println(BOARD_NAME);
Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
// Interval in microsecs
if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
{
Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
// Interval in microsecs
if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
{
Serial.print(F("Starting ITimer1 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
}
#define CHECK_INTERVAL_MS 10000L
#define CHANGE_INTERVAL_MS 20000L
void loop()
{
static uint32_t lastTime = 0;
static uint32_t lastChangeTime = 0;
static uint32_t currTime;
static uint32_t multFactor = 0;
currTime = millis();
if (currTime - lastTime > CHECK_INTERVAL_MS)
{
printResult(currTime);
lastTime = currTime;
if (currTime - lastChangeTime > CHANGE_INTERVAL_MS)
{
//setInterval(unsigned long interval, timerCallback callback)
multFactor = (multFactor + 1) % 2;
ITimer0.setInterval(TIMER0_INTERVAL_MS * 1000 * (multFactor + 1), TimerHandler0);
ITimer1.setInterval(TIMER1_INTERVAL_MS * 1000 * (multFactor + 1), TimerHandler1);
Serial.print(F("Changing Interval, Timer0 = ")); Serial.print(TIMER0_INTERVAL_MS * (multFactor + 1));
Serial.print(F(", Timer1 = ")); Serial.println(TIMER1_INTERVAL_MS * (multFactor + 1));
lastChangeTime = currTime;
}
}
}
@@ -0,0 +1,179 @@
/****************************************************************************************************************************
ISR_Timers_Array_Simple.ino
RPi_Pico_ISR_Timer-Impl.h
For RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
Licensed under MIT license
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
• This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.
• Four alarms: match on the lower 32 bits of counter, IRQ on match: TIMER_IRQ_0-TIMER_IRQ_3
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one RPI_PICO timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani@ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 11/05/2021 Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc.
*****************************************************************************************************************************/
#if !( defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) )
#error This code is intended to run on the RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 1
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "RPi_Pico_TimerInterrupt.h"
#include "RPi_Pico_ISR_Timer.h"
#include <SimpleTimer.h> // https://github.com/schinken/SimpleTimer
// Init RPI_PICO_Timer
RPI_PICO_Timer ITimer1(1);
RPI_PICO_ISR_Timer ISR_timer;
#ifndef LED_BUILTIN
#define LED_BUILTIN 25
#endif
#define LED_TOGGLE_INTERVAL_MS 1000L
// You have to use longer time here if having problem because Arduino AVR clock is low, 16MHz => lower accuracy.
// Tested OK with 1ms when not much load => higher accuracy.
#define TIMER_INTERVAL_MS 1L
volatile uint32_t startMillis = 0;
volatile uint32_t deltaMillis2s = 0;
volatile uint32_t deltaMillis5s = 0;
volatile uint32_t previousMillis2s = 0;
volatile uint32_t previousMillis5s = 0;
bool TimerHandler(struct repeating_timer *t)
{
static bool toggle = false;
static int timeRun = 0;
ISR_timer.run();
// Toggle LED every LED_TOGGLE_INTERVAL_MS = 2000ms = 2s
if (++timeRun == ((LED_TOGGLE_INTERVAL_MS) / TIMER_INTERVAL_MS) )
{
timeRun = 0;
//timer interrupt toggles pin LED_BUILTIN
digitalWrite(LED_BUILTIN, toggle);
toggle = !toggle;
}
return true;
}
void doingSomething2s()
{
unsigned long currentMillis = millis();
deltaMillis2s = currentMillis - previousMillis2s;
previousMillis2s = currentMillis;
}
void doingSomething5s()
{
unsigned long currentMillis = millis();
deltaMillis5s = currentMillis - previousMillis5s;
previousMillis5s = currentMillis;
}
/////////////////////////////////////////////////
#define SIMPLE_TIMER_MS 2000L
// Init SimpleTimer
SimpleTimer simpleTimer;
// Here is software Timer, you can do somewhat fancy stuffs without many issues.
// But always avoid
// 1. Long delay() it just doing nothing and pain-without-gain wasting CPU power.Plan and design your code / strategy ahead
// 2. Very long "do", "while", "for" loops without predetermined exit time.
void simpleTimerDoingSomething2s()
{
static unsigned long previousMillis = startMillis;
unsigned long currMillis = millis();
Serial.print(F("SimpleTimer : programmed ")); Serial.print(SIMPLE_TIMER_MS);
Serial.print(F("ms, current time ms : ")); Serial.print(currMillis);
Serial.print(F(", Delta ms : ")); Serial.println(currMillis - previousMillis);
Serial.print(F("Timer2s actual : ")); Serial.println(deltaMillis2s);
Serial.print(F("Timer5s actual : ")); Serial.println(deltaMillis5s);
previousMillis = currMillis;
}
////////////////////////////////////////////////
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
while (!Serial);
Serial.print(F("\nStarting ISR_Timers_Array_Simple on "));
Serial.println(BOARD_NAME);
Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
if (ITimer1.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler))
{
Serial.print(F("Starting ITimer1 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
ISR_timer.setInterval(2000L, doingSomething2s);
ISR_timer.setInterval(5000L, doingSomething5s);
// You need this timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary.
simpleTimer.setInterval(SIMPLE_TIMER_MS, simpleTimerDoingSomething2s);
}
#define BLOCKING_TIME_MS 10000L
void loop()
{
// This unadvised blocking task is used to demonstrate the blocking effects onto the execution and accuracy to Software timer
// You see the time elapse of ISR_Timer still accurate, whereas very unaccurate for Software Timer
// The time elapse for 2000ms software timer now becomes 3000ms (BLOCKING_TIME_MS)
// While that of ISR_Timer is still prefect.
delay(BLOCKING_TIME_MS);
// You need this Software timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary
// You don't need to and never call ISR_Timer.run() here in the loop(). It's already handled by ISR timer.
simpleTimer.run();
}
+158
View File
@@ -0,0 +1,158 @@
/****************************************************************************************************************************
RPM_Measure.ino
RPi_Pico_ISR_Timer-Impl.h
For RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
Licensed under MIT license
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
• This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.
• Four alarms: match on the lower 32 bits of counter, IRQ on match: TIMER_IRQ_0-TIMER_IRQ_3
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one RPI_PICO timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani@ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 11/05/2021 Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc.
*****************************************************************************************************************************/
/*
Notes:
Special design is necessary to share data between interrupt code and the rest of your program.
Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
variable can not spontaneously change. Because your function may change variables while your program is using them,
the compiler needs this hint. But volatile alone is often not enough.
When accessing shared variables, usually interrupts must be disabled. Even with volatile,
if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
or the entire sequence of your code which accesses the data.
RPM Measuring uses high frequency hardware timer 1Hz == 1ms) to measure the time from of one rotation, in ms
then convert to RPM. One rotation is detected by reading the state of a magnetic REED SW or IR LED Sensor
Asssuming LOW is active.
For example: Max speed is 600RPM => 10 RPS => minimum 100ms a rotation. We'll use 80ms for debouncing
If the time between active state is less than 8ms => consider noise.
RPM = 60000 / (rotation time in ms)
You can also use interrupt to detect whenever the SW is active, set a flag then use timer to count the time between active state
*/
#if !( defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) )
#error This code is intended to run on the RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 1
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "RPi_Pico_TimerInterrupt.h"
#define PIN_D1 1 // Pin D1 mapped to pin GPIO1 of RPI_PICO
unsigned int SWPin = PIN_D1;
#define TIMER0_INTERVAL_MS 1
#define DEBOUNCING_INTERVAL_MS 80
#define LOCAL_DEBUG 1
// Init RPI_PICO_Timer, can use any from 0-15 pseudo-hardware timers
RPI_PICO_Timer ITimer0(0);
volatile unsigned long rotationTime = 0;
float RPM = 0.00;
float avgRPM = 0.00;
volatile int debounceCounter;
bool TimerHandler0(struct repeating_timer *t)
{
if ( !digitalRead(SWPin) && (debounceCounter >= DEBOUNCING_INTERVAL_MS / TIMER0_INTERVAL_MS ) )
{
//min time between pulses has passed
RPM = (float) ( 60000.0f / ( rotationTime * TIMER0_INTERVAL_MS ) );
avgRPM = ( 2 * avgRPM + RPM) / 3,
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("RPM = "); Serial.print(avgRPM);
Serial.print(", rotationTime ms = "); Serial.println(rotationTime * TIMER0_INTERVAL_MS);
#endif
rotationTime = 0;
debounceCounter = 0;
}
else
{
debounceCounter++;
}
if (rotationTime >= 5000)
{
// If idle, set RPM to 0, don't increase rotationTime
RPM = 0;
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("RPM = "); Serial.print(RPM); Serial.print(", rotationTime = "); Serial.println(rotationTime);
#endif
rotationTime = 0;
}
else
{
rotationTime++;
}
return true;
}
void setup()
{
pinMode(SWPin, INPUT_PULLUP);
Serial.begin(115200);
while (!Serial);
delay(100);
Serial.print(F("\nStarting RPM_Measure on ")); Serial.println(BOARD_NAME);
Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
// Using ESP32 => 80 / 160 / 240MHz CPU clock ,
// For 64-bit timer counter
// For 16-bit timer prescaler up to 1024
// Interval in microsecs
if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
{
Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
Serial.flush();
}
void loop()
{
}
+191
View File
@@ -0,0 +1,191 @@
/****************************************************************************************************************************
SwitchDebounce.ino
RPi_Pico_ISR_Timer-Impl.h
For RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
Licensed under MIT license
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
• This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.
• Four alarms: match on the lower 32 bits of counter, IRQ on match: TIMER_IRQ_0-TIMER_IRQ_3
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one RPI_PICO timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani@ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 11/05/2021 Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc.
*****************************************************************************************************************************/
/*
Notes:
Special design is necessary to share data between interrupt code and the rest of your program.
Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
variable can not spontaneously change. Because your function may change variables while your program is using them,
the compiler needs this hint. But volatile alone is often not enough.
When accessing shared variables, usually interrupts must be disabled. Even with volatile,
if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
or the entire sequence of your code which accesses the data.
Switch Debouncing uses high frequency hardware timer 50Hz == 20ms) to measure the time from the SW is pressed,
debouncing time is 100ms => SW is considered pressed if timer count is > 5, then call / flag SW is pressed
When the SW is released, timer will count (debounce) until more than 50ms until consider SW is released.
We can set to flag or call a function whenever SW is pressed more than certain predetermined time, even before
SW is released.
*/
#if !( defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) )
#error This code is intended to run on the RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 1
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "RPi_Pico_TimerInterrupt.h"
#define PIN_D1 1 // Pin D1 mapped to pin GPIO1 of RPI_PICO
unsigned int SWPin = PIN_D1;
#define TIMER1_INTERVAL_MS 20
#define DEBOUNCING_INTERVAL_MS 100
#define LONG_PRESS_INTERVAL_MS 5000
#define LOCAL_DEBUG 2
// Init RPI_PICO_Timer, can use any from 0-15 pseudo-hardware timers
RPI_PICO_Timer ITimer1(1);
volatile bool SWPressed = false;
volatile bool SWLongPressed = false;
bool TimerHandler1(struct repeating_timer *t)
{
static unsigned int debounceCountSWPressed = 0;
static unsigned int debounceCountSWReleased = 0;
#if (LOCAL_DEBUG > 1)
static unsigned long SWPressedTime;
static unsigned long SWReleasedTime;
unsigned long currentMillis = millis();
#endif
if ( (!digitalRead(SWPin)) )
{
// Start debouncing counting debounceCountSWPressed and clear debounceCountSWReleased
debounceCountSWReleased = 0;
if (++debounceCountSWPressed >= DEBOUNCING_INTERVAL_MS / TIMER1_INTERVAL_MS)
{
// Call and flag SWPressed
if (!SWPressed)
{
#if (LOCAL_DEBUG > 1)
SWPressedTime = currentMillis;
Serial.print("SW Press, from millis() = "); Serial.println(SWPressedTime);
#endif
SWPressed = true;
// Do something for SWPressed here in ISR
// But it's better to use outside software timer to do your job instead of inside ISR
//Your_Response_To_Press();
}
if (debounceCountSWPressed >= LONG_PRESS_INTERVAL_MS / TIMER1_INTERVAL_MS)
{
// Call and flag SWLongPressed
if (!SWLongPressed)
{
#if (LOCAL_DEBUG > 1)
Serial.print("SW Long Pressed, total time ms = "); Serial.print(currentMillis);
Serial.print(" - "); Serial.print(SWPressedTime);
Serial.print(" = "); Serial.println(currentMillis - SWPressedTime);
#endif
SWLongPressed = true;
// Do something for SWLongPressed here in ISR
// But it's better to use outside software timer to do your job instead of inside ISR
//Your_Response_To_Long_Press();
}
}
}
}
else
{
// Start debouncing counting debounceCountSWReleased and clear debounceCountSWPressed
if ( SWPressed && (++debounceCountSWReleased >= DEBOUNCING_INTERVAL_MS / TIMER1_INTERVAL_MS))
{
#if (LOCAL_DEBUG > 1)
SWReleasedTime = currentMillis;
// Call and flag SWPressed
Serial.print("SW Released, from millis() = "); Serial.println(SWReleasedTime);
#endif
SWPressed = false;
SWLongPressed = false;
// Do something for !SWPressed here in ISR
// But it's better to use outside software timer to do your job instead of inside ISR
//Your_Response_To_Release();
// Call and flag SWPressed
#if (LOCAL_DEBUG > 1)
Serial.print("SW Pressed total time ms = ");
Serial.println(SWReleasedTime - SWPressedTime);
#endif
debounceCountSWPressed = 0;
}
}
return true;
}
void setup()
{
pinMode(SWPin, INPUT_PULLUP);
Serial.begin(115200);
while (!Serial);
delay(100);
Serial.print(F("\nStarting SwitchDebounce on ")); Serial.println(BOARD_NAME);
Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
// Interval in microsecs
if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
{
Serial.print(F("Starting ITimer1 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
}
void loop()
{
}
@@ -0,0 +1,191 @@
/****************************************************************************************************************************
TimerInterruptTest.ino
RPi_Pico_ISR_Timer-Impl.h
For RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
Licensed under MIT license
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
• This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.
• Four alarms: match on the lower 32 bits of counter, IRQ on match: TIMER_IRQ_0-TIMER_IRQ_3
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one RPI_PICO timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani@ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 11/05/2021 Initial coding to support RP2040-based boards such as RASPBERRY_PI_PICO. etc.
*****************************************************************************************************************************/
/*
Notes:
Special design is necessary to share data between interrupt code and the rest of your program.
Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
variable can not spontaneously change. Because your function may change variables while your program is using them,
the compiler needs this hint. But volatile alone is often not enough.
When accessing shared variables, usually interrupts must be disabled. Even with volatile,
if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
or the entire sequence of your code which accesses the data.
*/
#if !( defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) )
#error This code is intended to run on the RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 1
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "RPi_Pico_TimerInterrupt.h"
#ifndef LED_BUILTIN
#define LED_BUILTIN 25 // Pin D2 mapped to pin GPIO2/ADC12 of ESP32, control on-board LED
#endif
#define PIN_D1 1 // Pin D1 mapped to pin GPIO1 of RPI_PICO
bool TimerHandler0(struct repeating_timer *t)
{
static bool toggle0 = false;
static bool started = false;
if (!started)
{
started = true;
pinMode(LED_BUILTIN, OUTPUT);
}
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("ITimer0 called, millis() = "); Serial.println(millis());
#endif
//timer interrupt toggles pin LED_BUILTIN
digitalWrite(LED_BUILTIN, toggle0);
toggle0 = !toggle0;
return true;
}
bool TimerHandler1(struct repeating_timer *t)
{
static bool toggle1 = false;
static bool started = false;
if (!started)
{
started = true;
pinMode(PIN_D1, OUTPUT);
}
#if (TIMER_INTERRUPT_DEBUG > 0)
Serial.print("ITimer1 called, millis() = "); Serial.println(millis());
#endif
//timer interrupt toggles outputPin
digitalWrite(PIN_D1, toggle1);
toggle1 = !toggle1;
return true;
}
#define TIMER0_INTERVAL_MS 1000
#define TIMER0_DURATION_MS 5000
#define TIMER1_INTERVAL_MS 3000
#define TIMER1_DURATION_MS 15000
// Init RPI_PICO_Timer, can use any from 0-15 pseudo-hardware timers
RPI_PICO_Timer ITimer0(0);
RPI_PICO_Timer ITimer1(1);
void setup()
{
Serial.begin(115200);
while (!Serial);
delay(100);
Serial.print(F("\nStarting TimerInterruptTest on ")); Serial.println(BOARD_NAME);
Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
// Interval in microsecs
if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
{
Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
// Interval in microsecs
if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
{
Serial.print(F("Starting ITimer1 OK, millis() = ")); Serial.println(millis());
}
else
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
Serial.flush();
}
void loop()
{
static unsigned long lastTimer0 = 0;
static unsigned long lastTimer1 = 0;
static bool timer0Stopped = false;
static bool timer1Stopped = false;
if (millis() - lastTimer0 > TIMER0_DURATION_MS)
{
lastTimer0 = millis();
if (timer0Stopped)
{
Serial.print(F("Start ITimer0, millis() = ")); Serial.println(millis());
ITimer0.restartTimer();
}
else
{
Serial.print(F("Stop ITimer0, millis() = ")); Serial.println(millis());
ITimer0.stopTimer();
}
timer0Stopped = !timer0Stopped;
}
if (millis() - lastTimer1 > TIMER1_DURATION_MS)
{
lastTimer1 = millis();
if (timer1Stopped)
{
Serial.print(F("Start ITimer1, millis() = ")); Serial.println(millis());
ITimer1.restartTimer();
}
else
{
Serial.print(F("Stop ITimer1, millis() = ")); Serial.println(millis());
ITimer1.stopTimer();
}
timer1Stopped = !timer1Stopped;
}
}