|
6 | 6 | [](#Contributing) |
7 | 7 | [](http://github.com/khoih-prog/SAMD_TimerInterrupt/issues) |
8 | 8 |
|
9 | | -<a href="https://www.buymeacoffee.com/khoihprog6" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 50px !important;width: 181px !important;" ></a> |
| 9 | +<a href="https://www.buymeacoffee.com/khoihprog6" title="Donate to my libraries using BuyMeACoffee"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Donate to my libraries using BuyMeACoffee" style="height: 50px !important;width: 181px !important;" ></a> |
| 10 | +<a href="https://www.buymeacoffee.com/khoihprog6" title="Donate to my libraries using BuyMeACoffee"><img src="https://img.shields.io/badge/buy%20me%20a%20coffee-donate-orange.svg?logo=buy-me-a-coffee&logoColor=FFDD00" style="height: 20px !important;width: 200px !important;" ></a> |
10 | 11 |
|
11 | 12 | --- |
12 | 13 | --- |
@@ -153,7 +154,7 @@ The catch is **your function is now part of an ISR (Interrupt Service Routine), |
153 | 154 | ## Prerequisites |
154 | 155 |
|
155 | 156 | 1. [`Arduino IDE 1.8.19+` for Arduino](https://github.com/arduino/Arduino). [](https://github.com/arduino/Arduino/releases/latest) |
156 | | - 2. [`Arduino SAMD core 1.8.12+`](https://github.com/arduino/ArduinoCore-samd) for SAMD ARM Cortex-M0+ boards. [](https://github.com/arduino/ArduinoCore-samd/releases/latest) |
| 157 | + 2. [`Arduino SAMD core 1.8.13+`](https://github.com/arduino/ArduinoCore-samd) for SAMD ARM Cortex-M0+ boards. [](https://github.com/arduino/ArduinoCore-samd/releases/latest) |
157 | 158 | 3. [`Adafruit SAMD core 1.7.9+`](https://github.com/adafruit/ArduinoCore-samd) for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). [](https://github.com/adafruit/ArduinoCore-samd/releases/latest) |
158 | 159 | 4. [`Seeeduino SAMD core 1.8.2+`](https://github.com/Seeed-Studio/ArduinoCore-samd) for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.). [](https://github.com/Seeed-Studio/ArduinoCore-samd/releases/latest/) |
159 | 160 | 5. [`Sparkfun SAMD core 1.8.1+`](https://github.com/sparkfun/Arduino_Boards) for SAMD21/SAMD51 boards (SparkFun_RedBoard_Turbo, SparkFun_SAMD51_Thing_Plus, etc.). |
@@ -523,354 +524,9 @@ void setup() |
523 | 524 |
|
524 | 525 | ### Example [ISR_16_Timers_Array_Complex](examples/ISR_16_Timers_Array_Complex) |
525 | 526 |
|
526 | | -``` |
527 | | -#if !( defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \ |
528 | | - || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \ |
529 | | - || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) \ |
530 | | - || defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD51__) || defined(__SAMD51J20A__) \ |
531 | | - || defined(__SAMD51J19A__) || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) \ |
532 | | - || defined(__SAMD21E15A__) || defined(__SAMD21E16A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__) \ |
533 | | - || defined(__SAMD21G15A__) || defined(__SAMD21G16A__) || defined(__SAMD21G17A__) || defined(__SAMD21G18A__) \ |
534 | | - || defined(__SAMD21J15A__) || defined(__SAMD21J16A__) || defined(__SAMD21J17A__) || defined(__SAMD21J18A__) ) |
535 | | - #error This code is designed to run on SAMD21/SAMD51 platform! Please check your Tools->Board setting. |
536 | | -#endif |
537 | | -
|
538 | | -// These define's must be placed at the beginning before #include "SAMDTimerInterrupt.h" |
539 | | -// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4 |
540 | | -// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. |
541 | | -// Don't define TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system. |
542 | | -#define TIMER_INTERRUPT_DEBUG 0 |
543 | | -#define _TIMERINTERRUPT_LOGLEVEL_ 0 |
544 | | -
|
545 | | -// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error |
546 | | -#include "SAMDTimerInterrupt.h" |
547 | | -
|
548 | | -// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error |
549 | | -#include "SAMD_ISR_Timer.h" |
550 | | -
|
551 | | -#include <SimpleTimer.h> // https://github.com/jfturcot/SimpleTimer |
552 | | -
|
553 | | -#ifndef LED_BUILTIN |
554 | | -#define LED_BUILTIN 13 |
555 | | -#endif |
556 | | -
|
557 | | -#ifndef LED_BLUE |
558 | | -#define LED_BLUE 2 |
559 | | -#endif |
560 | | -
|
561 | | -#ifndef LED_RED |
562 | | -#define LED_RED 3 |
563 | | -#endif |
564 | | -
|
565 | | -#define HW_TIMER_INTERVAL_US 10000L |
566 | | -
|
567 | | -volatile uint32_t startMillis = 0; |
568 | | -
|
569 | | -// You can select SAMD Hardware Timer from SAMD_TIMER_1 or SAMD_TIMER_3 |
570 | | -
|
571 | | -// Depending on the board, you can select SAMD21 Hardware Timer from TC3-TCC |
572 | | -// SAMD21 Hardware Timer from TC3 or TCC |
573 | | -// SAMD51 Hardware Timer only TC3 |
574 | | -
|
575 | | -// Init SAMD timer TIMER_TC3 |
576 | | -SAMDTimer ITimer(TIMER_TC3); |
577 | | -
|
578 | | -#if (TIMER_INTERRUPT_USING_SAMD21) |
579 | | -// Init SAMD timer TIMER_TCC |
580 | | -//SAMDTimer ITimer(TIMER_TCC); |
581 | | -#endif |
582 | | -
|
583 | | -// Init SAMD_ISR_Timer |
584 | | -// Each SAMD_ISR_Timer can service 16 different ISR-based timers |
585 | | -SAMD_ISR_Timer ISR_Timer; |
586 | | -
|
587 | | -#define LED_TOGGLE_INTERVAL_MS 2000L |
588 | | -
|
589 | | -void TimerHandler() |
590 | | -{ |
591 | | - static bool toggle = false; |
592 | | - static int timeRun = 0; |
593 | | -
|
594 | | - ISR_Timer.run(); |
595 | | -
|
596 | | - // Toggle LED every LED_TOGGLE_INTERVAL_MS = 2000ms = 2s |
597 | | - if (++timeRun == ((LED_TOGGLE_INTERVAL_MS * 1000) / HW_TIMER_INTERVAL_US) ) |
598 | | - { |
599 | | - timeRun = 0; |
600 | | -
|
601 | | - //timer interrupt toggles pin LED_BUILTIN |
602 | | - digitalWrite(LED_BUILTIN, toggle); |
603 | | - toggle = !toggle; |
604 | | - } |
605 | | -} |
606 | | -
|
607 | | -///////////////////////////////////////////////// |
608 | | -
|
609 | | -#define NUMBER_ISR_TIMERS 16 |
| 527 | +https://github.com/khoih-prog/SAMD_TimerInterrupt/blob/329513558a9d43b15533a469ceabc30b5896fd80/examples/ISR_16_Timers_Array_Complex/ISR_16_Timers_Array_Complex.ino#L35-L380 |
610 | 528 |
|
611 | | -typedef void (*irqCallback) (); |
612 | | -
|
613 | | -///////////////////////////////////////////////// |
614 | | -
|
615 | | -#define USE_COMPLEX_STRUCT true |
616 | | -
|
617 | | -#if USE_COMPLEX_STRUCT |
618 | | -
|
619 | | -typedef struct |
620 | | -{ |
621 | | - irqCallback irqCallbackFunc; |
622 | | - uint32_t TimerInterval; |
623 | | - unsigned long deltaMillis; |
624 | | - unsigned long previousMillis; |
625 | | -} ISRTimerData; |
626 | | -
|
627 | | -// In NRF52, avoid doing something fancy in ISR, for example Serial.print() |
628 | | -// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment |
629 | | -// Or you can get this run-time error / crash |
630 | | -
|
631 | | -void doingSomething(int index); |
632 | | -
|
633 | | -#else |
634 | | -
|
635 | | -volatile unsigned long deltaMillis [NUMBER_ISR_TIMERS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
636 | | -volatile unsigned long previousMillis [NUMBER_ISR_TIMERS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
637 | | -
|
638 | | -// You can assign any interval for any timer here, in milliseconds |
639 | | -uint32_t TimerInterval[NUMBER_ISR_TIMERS] = |
640 | | -{ |
641 | | - 5000L, 10000L, 15000L, 20000L, 25000L, 30000L, 35000L, 40000L, |
642 | | - 45000L, 50000L, 55000L, 60000L, 65000L, 70000L, 75000L, 80000L |
643 | | -}; |
644 | | -
|
645 | | -void doingSomething(int index) |
646 | | -{ |
647 | | - unsigned long currentMillis = millis(); |
648 | | -
|
649 | | - deltaMillis[index] = currentMillis - previousMillis[index]; |
650 | | - previousMillis[index] = currentMillis; |
651 | | -} |
652 | | -
|
653 | | -#endif |
654 | | -
|
655 | | -//////////////////////////////////// |
656 | | -// Shared |
657 | | -//////////////////////////////////// |
658 | | -
|
659 | | -void doingSomething0() |
660 | | -{ |
661 | | - doingSomething(0); |
662 | | -} |
663 | | -
|
664 | | -void doingSomething1() |
665 | | -{ |
666 | | - doingSomething(1); |
667 | | -} |
668 | | -
|
669 | | -void doingSomething2() |
670 | | -{ |
671 | | - doingSomething(2); |
672 | | -} |
673 | | -
|
674 | | -void doingSomething3() |
675 | | -{ |
676 | | - doingSomething(3); |
677 | | -} |
678 | | -
|
679 | | -void doingSomething4() |
680 | | -{ |
681 | | - doingSomething(4); |
682 | | -} |
683 | | -
|
684 | | -void doingSomething5() |
685 | | -{ |
686 | | - doingSomething(5); |
687 | | -} |
688 | 529 |
|
689 | | -void doingSomething6() |
690 | | -{ |
691 | | - doingSomething(6); |
692 | | -} |
693 | | -
|
694 | | -void doingSomething7() |
695 | | -{ |
696 | | - doingSomething(7); |
697 | | -} |
698 | | -
|
699 | | -void doingSomething8() |
700 | | -{ |
701 | | - doingSomething(8); |
702 | | -} |
703 | | -
|
704 | | -void doingSomething9() |
705 | | -{ |
706 | | - doingSomething(9); |
707 | | -} |
708 | | -
|
709 | | -void doingSomething10() |
710 | | -{ |
711 | | - doingSomething(10); |
712 | | -} |
713 | | -
|
714 | | -void doingSomething11() |
715 | | -{ |
716 | | - doingSomething(11); |
717 | | -} |
718 | | -
|
719 | | -void doingSomething12() |
720 | | -{ |
721 | | - doingSomething(12); |
722 | | -} |
723 | | -
|
724 | | -void doingSomething13() |
725 | | -{ |
726 | | - doingSomething(13); |
727 | | -} |
728 | | -
|
729 | | -void doingSomething14() |
730 | | -{ |
731 | | - doingSomething(14); |
732 | | -} |
733 | | -
|
734 | | -void doingSomething15() |
735 | | -{ |
736 | | - doingSomething(15); |
737 | | -} |
738 | | -
|
739 | | -#if USE_COMPLEX_STRUCT |
740 | | -
|
741 | | -ISRTimerData curISRTimerData[NUMBER_ISR_TIMERS] = |
742 | | -{ |
743 | | - //irqCallbackFunc, TimerInterval, deltaMillis, previousMillis |
744 | | - { doingSomething0, 5000L, 0, 0 }, |
745 | | - { doingSomething1, 10000L, 0, 0 }, |
746 | | - { doingSomething2, 15000L, 0, 0 }, |
747 | | - { doingSomething3, 20000L, 0, 0 }, |
748 | | - { doingSomething4, 25000L, 0, 0 }, |
749 | | - { doingSomething5, 30000L, 0, 0 }, |
750 | | - { doingSomething6, 35000L, 0, 0 }, |
751 | | - { doingSomething7, 40000L, 0, 0 }, |
752 | | - { doingSomething8, 45000L, 0, 0 }, |
753 | | - { doingSomething9, 50000L, 0, 0 }, |
754 | | - { doingSomething10, 55000L, 0, 0 }, |
755 | | - { doingSomething11, 60000L, 0, 0 }, |
756 | | - { doingSomething12, 65000L, 0, 0 }, |
757 | | - { doingSomething13, 70000L, 0, 0 }, |
758 | | - { doingSomething14, 75000L, 0, 0 }, |
759 | | - { doingSomething15, 80000L, 0, 0 } |
760 | | -}; |
761 | | -
|
762 | | -void doingSomething(int index) |
763 | | -{ |
764 | | - unsigned long currentMillis = millis(); |
765 | | -
|
766 | | - curISRTimerData[index].deltaMillis = currentMillis - curISRTimerData[index].previousMillis; |
767 | | - curISRTimerData[index].previousMillis = currentMillis; |
768 | | -} |
769 | | -
|
770 | | -#else |
771 | | -
|
772 | | -irqCallback irqCallbackFunc[NUMBER_ISR_TIMERS] = |
773 | | -{ |
774 | | - doingSomething0, doingSomething1, doingSomething2, doingSomething3, |
775 | | - doingSomething4, doingSomething5, doingSomething6, doingSomething7, |
776 | | - doingSomething8, doingSomething9, doingSomething10, doingSomething11, |
777 | | - doingSomething12, doingSomething13, doingSomething14, doingSomething15 |
778 | | -}; |
779 | | -
|
780 | | -#endif |
781 | | -/////////////////////////////////////////// |
782 | | -
|
783 | | -#define SIMPLE_TIMER_MS 2000L |
784 | | -
|
785 | | -// Init SimpleTimer |
786 | | -SimpleTimer simpleTimer; |
787 | | -
|
788 | | -// Here is software Timer, you can do somewhat fancy stuffs without many issues. |
789 | | -// But always avoid |
790 | | -// 1. Long delay() it just doing nothing and pain-without-gain wasting CPU power.Plan and design your code / strategy ahead |
791 | | -// 2. Very long "do", "while", "for" loops without predetermined exit time. |
792 | | -void simpleTimerDoingSomething2s() |
793 | | -{ |
794 | | - static unsigned long previousMillis = startMillis; |
795 | | -
|
796 | | - unsigned long currMillis = millis(); |
797 | | -
|
798 | | - Serial.print(F("SimpleTimer : ")); Serial.print(SIMPLE_TIMER_MS / 1000); |
799 | | - Serial.print(F(", ms : ")); Serial.print(currMillis); |
800 | | - Serial.print(F(", Dms : ")); Serial.println(currMillis - previousMillis); |
801 | | -
|
802 | | - for (uint16_t i = 0; i < NUMBER_ISR_TIMERS; i++) |
803 | | - { |
804 | | -#if USE_COMPLEX_STRUCT |
805 | | - Serial.print(F("Timer : ")); Serial.print(i); |
806 | | - Serial.print(F(", programmed : ")); Serial.print(curISRTimerData[i].TimerInterval); |
807 | | - Serial.print(F(", actual : ")); Serial.println(curISRTimerData[i].deltaMillis); |
808 | | -#else |
809 | | - Serial.print(F("Timer : ")); Serial.print(i); |
810 | | - Serial.print(F(", programmed : ")); Serial.print(TimerInterval[i]); |
811 | | - Serial.print(F(", actual : ")); Serial.println(deltaMillis[i]); |
812 | | -#endif |
813 | | - } |
814 | | -
|
815 | | - previousMillis = currMillis; |
816 | | -} |
817 | | -
|
818 | | -void setup() |
819 | | -{ |
820 | | - pinMode(LED_BUILTIN, OUTPUT); |
821 | | -
|
822 | | - Serial.begin(115200); |
823 | | - while (!Serial); |
824 | | -
|
825 | | - delay(100); |
826 | | -
|
827 | | - Serial.print(F("\nStarting ISR_16_Timers_Array_Complex on ")); Serial.println(BOARD_NAME); |
828 | | - Serial.println(SAMD_TIMER_INTERRUPT_VERSION); |
829 | | - Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz")); |
830 | | -
|
831 | | - // Interval in microsecs |
832 | | - if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_US, TimerHandler)) |
833 | | - { |
834 | | - startMillis = millis(); |
835 | | - Serial.print(F("Starting ITimer OK, millis() = ")); Serial.println(startMillis); |
836 | | - } |
837 | | - else |
838 | | - Serial.println(F("Can't set ITimer. Select another freq. or timer")); |
839 | | -
|
840 | | - startMillis = millis(); |
841 | | -
|
842 | | - // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary |
843 | | - // You can use up to 16 timer for each ISR_Timer |
844 | | - for (uint16_t i = 0; i < NUMBER_ISR_TIMERS; i++) |
845 | | - { |
846 | | -#if USE_COMPLEX_STRUCT |
847 | | - curISRTimerData[i].previousMillis = startMillis; |
848 | | - ISR_Timer.setInterval(curISRTimerData[i].TimerInterval, curISRTimerData[i].irqCallbackFunc); |
849 | | -#else |
850 | | - previousMillis[i] = millis(); |
851 | | - ISR_Timer.setInterval(TimerInterval[i], irqCallbackFunc[i]); |
852 | | -#endif |
853 | | - } |
854 | | -
|
855 | | - // You need this timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary. |
856 | | - simpleTimer.setInterval(SIMPLE_TIMER_MS, simpleTimerDoingSomething2s); |
857 | | -} |
858 | | -
|
859 | | -#define BLOCKING_TIME_MS 10000L |
860 | | -
|
861 | | -void loop() |
862 | | -{ |
863 | | - // This unadvised blocking task is used to demonstrate the blocking effects onto the execution and accuracy to Software timer |
864 | | - // You see the time elapse of ISR_Timer still accurate, whereas very unaccurate for Software Timer |
865 | | - // The time elapse for 2000ms software timer now becomes 3000ms (BLOCKING_TIME_MS) |
866 | | - // While that of ISR_Timer is still prefect. |
867 | | - delay(BLOCKING_TIME_MS); |
868 | | -
|
869 | | - // You need this Software timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary |
870 | | - // You don't need to and never call ISR_Timer.run() here in the loop(). It's already handled by ISR timer. |
871 | | - simpleTimer.run(); |
872 | | -} |
873 | | -``` |
874 | 530 | --- |
875 | 531 | --- |
876 | 532 |
|
|
0 commit comments