diff --git a/DCCTimer.h b/DCCTimer.h
index 3b14fd6..ce4a618 100644
--- a/DCCTimer.h
+++ b/DCCTimer.h
@@ -3,6 +3,7 @@
* © 2021 Mike S
* © 2021-2023 Harald Barth
* © 2021 Fred Decker
+ * © 2023 Travis Farmer
* All rights reserved.
*
* This file is part of CommandStation-EX
@@ -90,6 +91,8 @@ private:
static const int DCC_SIGNAL_TIME=58; // this is the 58uS DCC 1-bit waveform half-cycle
#if defined(ARDUINO_ARCH_STM32) // TODO: PMA temporary hack - assumes 100Mhz F_CPU as STM32 can change frequency
static const long CLOCK_CYCLES=(100000000L / 1000000 * DCC_SIGNAL_TIME) >>1;
+#elif defined(ARDUINO_GIGA)
+ static const long CLOCK_CYCLES=(480000000L / 1000000 * DCC_SIGNAL_TIME) >>1;
#else
static const long CLOCK_CYCLES=(F_CPU / 1000000 * DCC_SIGNAL_TIME) >>1;
#endif
diff --git a/DCCTimerGiga.cpp b/DCCTimerGiga.cpp
new file mode 100644
index 0000000..6b1dd38
--- /dev/null
+++ b/DCCTimerGiga.cpp
@@ -0,0 +1,206 @@
+/*
+ * © 2023 Travis Farmer
+ * © 2023 Neil McKechnie
+ * © 2022-2023 Paul M. Antoine
+ * © 2021 Mike S
+ * © 2021, 2023 Harald Barth
+ * © 2021 Fred Decker
+ * © 2021 Chris Harlow
+ * © 2021 David Cutting
+ * All rights reserved.
+ *
+ * This file is part of Asbelos DCC API
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * It is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CommandStation. If not, see .
+ */
+
+// ATTENTION: this file only compiles on a STM32 based boards
+// Please refer to DCCTimer.h for general comments about how this class works
+// This is to avoid repetition and duplication.
+#if defined(ARDUINO_GIGA)
+
+#include "DCCTimer.h"
+#include "DIAG.h"
+#include "GigaHardwareTimer.h"
+#include
+//#include "config.h"
+///////////////////////////////////////////////////////////////////////////////////////////////
+// Experimental code for High Accuracy (HA) DCC Signal mode
+// Warning - use of TIM2 and TIM3 can affect the use of analogWrite() function on certain pins,
+// which is used by the DC motor types.
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+INTERRUPT_CALLBACK interruptHandler=0;
+
+//HardwareTimer* timer = NULL;
+//HardwareTimer* timerAux = NULL;
+HardwareTimer timer(TIM2);
+HardwareTimer timerAux(TIM3);
+
+static bool tim2ModeHA = false;
+static bool tim3ModeHA = false;
+
+void DCCTimer_Handler() __attribute__((interrupt));
+
+void DCCTimer_Handler() {
+ interruptHandler();
+}
+
+void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
+ interruptHandler=callback;
+ noInterrupts();
+
+ // adc_set_sample_rate(ADC_SAMPLETIME_480CYCLES);
+ timer.pause();
+ timerAux.pause();
+ timer.setPrescaleFactor(1);
+ timer.setOverflow(DCC_SIGNAL_TIME, MICROSEC_FORMAT);
+ timer.attachInterrupt(DCCTimer_Handler);
+ timer.refresh();
+ timerAux.setPrescaleFactor(1);
+ timerAux.setOverflow(DCC_SIGNAL_TIME, MICROSEC_FORMAT);
+ timerAux.refresh();
+
+ timer.resume();
+ timerAux.resume();
+
+ interrupts();
+}
+
+bool DCCTimer::isPWMPin(byte pin) {
+ switch (pin) {
+ case 12:
+ return true;
+ case 13:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void DCCTimer::setPWM(byte pin, bool high) {
+ switch (pin) {
+ case 12:
+ if (!tim3ModeHA) {
+ timerAux.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, 12);
+ tim3ModeHA = true;
+ }
+ if (high)
+ TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0;
+ else
+ TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1;
+ break;
+ case 13:
+ if (!tim2ModeHA) {
+ timer.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, 13);
+ tim2ModeHA = true;
+ }
+ if (high)
+ TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0;
+ else
+ TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1;
+ break;
+ }
+ }
+
+void DCCTimer::clearPWM() {
+ timer.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, NC);
+ tim2ModeHA = false;
+ timerAux.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, NC);
+ tim3ModeHA = false;
+}
+
+void DCCTimer::getSimulatedMacAddress(byte mac[6]) {
+ volatile uint32_t *serno1 = (volatile uint32_t *)UID_BASE;
+ volatile uint32_t *serno2 = (volatile uint32_t *)UID_BASE+4;
+ volatile uint32_t *serno3 = (volatile uint32_t *)UID_BASE+8;
+ volatile uint32_t m1 = *serno1;
+ volatile uint32_t m2 = *serno2;
+ volatile uint32_t m3 = *serno3;
+ mac[0] = 0xBE;
+ mac[1] = 0xEF;
+ mac[2] = m1 ^ m3 >> 24;
+ mac[3] = m1 ^ m3 >> 16;
+ mac[4] = m1 ^ m3 >> 8;
+ mac[5] = m1 ^ m3 >> 0;
+ //DIAG(F("MAC: %P:%P:%P:%P:%P:%P"),mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
+
+}
+volatile int DCCTimer::minimum_free_memory=__INT_MAX__;
+
+// Return low memory value...
+int DCCTimer::getMinimumFreeMemory() {
+ noInterrupts(); // Disable interrupts to get volatile value
+ int retval = freeMemory();
+ interrupts();
+ return retval;
+}
+extern "C" char* sbrk(int incr);
+
+int DCCTimer::freeMemory() {
+
+ char top;
+ unsigned int tmp = (unsigned int)(&top - reinterpret_cast(sbrk(0)));
+ return (int)(tmp / 1000);
+}
+
+void DCCTimer::reset() {
+ //Watchdog &watchdog = Watchdog::get_instance();
+ //Watchdog::stop();
+ //Watchdog::start(500);
+
+ //while(true) {};
+}
+
+int * ADCee::analogvals = NULL;
+
+int16_t ADCee::ADCmax()
+{
+ return 1023;
+}
+
+AdvancedADC adc(A0, A1);
+int ADCee::init(uint8_t pin) {
+ adc.begin(AN_RESOLUTION_10, 16000, 1, 512);
+ return 123;
+}
+
+/*
+ * Read function ADCee::read(pin) to get value instead of analogRead(pin)
+ */
+int ADCee::read(uint8_t pin, bool fromISR) {
+ static SampleBuffer buf = adc.read();
+ int retVal = -123;
+ if (adc.available()) {
+ buf.release();
+ buf = adc.read();
+ }
+ return (buf[pin - A0]);
+}
+
+/*
+ * Scan function that is called from interrupt
+ */
+#pragma GCC push_options
+#pragma GCC optimize ("-O3")
+void ADCee::scan() {
+}
+#pragma GCC pop_options
+
+void ADCee::begin() {
+ noInterrupts();
+
+ interrupts();
+}
+#endif
diff --git a/GigaHardwareTimer.cpp b/GigaHardwareTimer.cpp
new file mode 100644
index 0000000..3a699d5
--- /dev/null
+++ b/GigaHardwareTimer.cpp
@@ -0,0 +1,2003 @@
+/****************************************************************************************************************************
+ HardwareTimer.cpp
+
+ For Portenta_H7 boards
+ Written by Khoi Hoang
+
+ Built by Khoi Hoang https://github.com/khoih-prog/Portenta_H7_TimerInterrupt
+ Licensed under MIT license
+
+ 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 Portenta_H7 STM32 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.
+
+ Version: 1.4.0
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.1 K.Hoang 15/09/2021 Initial coding for Portenta_H7
+ 1.3.0 K.Hoang 17/09/2021 Add PWM features and examples
+ 1.3.1 K.Hoang 21/09/2021 Fix warnings in PWM examples
+ 1.4.0 K.Hoang 22/01/2022 Fix `multiple-definitions` linker error. Fix bug
+ *****************************************************************************************************************************/
+
+// Modified from stm32 core v2.0.0
+/*
+ Copyright (c) 2017 Daniel Fekete
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2019 STMicroelectronics
+ Modified to support Arduino_Core_STM32
+*/
+#if defined(ARDUINO_GIGA)
+#include "Arduino.h"
+#include "GigaHardwareTimer.h"
+
+#if defined(HAL_TIM_MODULE_ENABLED) && !defined(HAL_TIM_MODULE_ONLY)
+
+/* Private Defines */
+#define PIN_NOT_USED 0xFF
+#define MAX_RELOAD ((1 << 16) - 1) // Currently even 32b timers are used as 16b to have generic behavior
+
+
+/* Private Variables */
+timerObj_t *HardwareTimer_Handle[TIMER_NUM] = {NULL};
+
+/**
+ @brief HardwareTimer constructor: set default configuration values
+ @param Timer instance ex: TIM1, ...
+ @retval None
+*/
+HardwareTimer::HardwareTimer(TIM_TypeDef *instance)
+{
+ uint32_t index = get_timer_index(instance);
+
+ if (index == UNKNOWN_TIMER)
+ {
+ //Error_Handler();
+ }
+
+ HardwareTimer_Handle[index] = &_timerObj;
+
+ _timerObj.handle.Instance = instance;
+ _timerObj.handle.Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
+ _timerObj.handle.hdma[0] = NULL;
+ _timerObj.handle.hdma[1] = NULL;
+ _timerObj.handle.hdma[2] = NULL;
+ _timerObj.handle.hdma[3] = NULL;
+ _timerObj.handle.hdma[4] = NULL;
+ _timerObj.handle.hdma[5] = NULL;
+ _timerObj.handle.hdma[6] = NULL;
+ _timerObj.handle.Lock = HAL_UNLOCKED;
+ _timerObj.handle.State = HAL_TIM_STATE_RESET;
+
+ _timerObj.__this = (void *)this;
+ _timerObj.preemptPriority = TIM_IRQ_PRIO;
+ _timerObj.subPriority = TIM_IRQ_SUBPRIO;
+
+ /* Enable timer clock. Even if it is also done in HAL_TIM_Base_MspInit(),
+ it is done there so that it is possible to write registers right now */
+ enableTimerClock(&(_timerObj.handle));
+
+ // Initialize NULL callbacks
+ for (int i = 0; i < TIMER_CHANNELS + 1 ; i++)
+ {
+ callbacks[i] = NULL;
+ }
+
+ // Initialize channel mode and complementary
+ for (int i = 0; i < TIMER_CHANNELS; i++)
+ {
+#if defined(TIM_CCER_CC1NE)
+ isComplementaryChannel[i] = false;
+#endif
+ _ChannelMode[i] = TIMER_DISABLED;
+ }
+
+ /* Configure timer with some default values */
+ _timerObj.handle.Init.Prescaler = 0;
+ _timerObj.handle.Init.Period = MAX_RELOAD;
+ _timerObj.handle.Init.CounterMode = TIM_COUNTERMODE_UP;
+ _timerObj.handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+#if defined(TIM_RCR_REP)
+ _timerObj.handle.Init.RepetitionCounter = 0;
+#endif
+ _timerObj.handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
+ HAL_TIM_Base_Init(&(_timerObj.handle));
+}
+
+/**
+ @brief Pause HardwareTimer: stop timer
+ @param None
+ @retval None
+*/
+void HardwareTimer::pause()
+{
+ // Disable all IT
+ __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_UPDATE);
+ __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_CC1);
+ __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_CC2);
+ __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_CC3);
+ __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_CC4);
+
+ // Stop timer. Required to restore HAL State: HAL_TIM_STATE_READY
+ HAL_TIM_Base_Stop(&(_timerObj.handle));
+
+ /* Disable timer unconditionally. Required to guarantee timer is stopped,
+ even if some channels are still running */
+ LL_TIM_DisableCounter(_timerObj.handle.Instance);
+
+#if defined(TIM_CHANNEL_STATE_SET_ALL)
+ /* Starting from G4, new Channel state implementation prevents to restart a channel,
+ if the channel has not been explicitly be stopped with HAL interface */
+ TIM_CHANNEL_STATE_SET_ALL(&(_timerObj.handle), HAL_TIM_CHANNEL_STATE_READY);
+#endif
+#if defined(TIM_CHANNEL_N_STATE_SET_ALL)
+ TIM_CHANNEL_N_STATE_SET_ALL(&(_timerObj.handle), HAL_TIM_CHANNEL_STATE_READY);
+#endif
+}
+
+/**
+ @brief Pause only one channel.
+ Timer is still running but channel is disabled (output and interrupt)
+ @param Arduino channel [1..4]
+ @retval None
+*/
+void HardwareTimer::pauseChannel(uint32_t channel)
+{
+ int timAssociatedInputChannel;
+ int LLChannel = getLLChannel(channel);
+
+ if (LLChannel == -1)
+ {
+ //Error_Handler();
+ }
+
+ int interrupt = getIT(channel);
+
+ if (interrupt == -1)
+ {
+ //Error_Handler();
+ }
+
+ // Disable channel and corresponding interrupt
+ __HAL_TIM_DISABLE_IT(&(_timerObj.handle), interrupt);
+ LL_TIM_CC_DisableChannel(_timerObj.handle.Instance, LLChannel);
+#if defined(TIM_CHANNEL_STATE_SET)
+ /* Starting from G4, new Channel state implementation prevents to restart a channel,
+ if the channel has not been explicitly be stopped with HAL interface */
+#if defined(TIM_CHANNEL_N_STATE_SET)
+
+ if (isComplementaryChannel[channel - 1])
+ {
+ TIM_CHANNEL_N_STATE_SET(&(_timerObj.handle), getChannel(channel), HAL_TIM_CHANNEL_STATE_READY);
+ }
+ else
+#endif
+ {
+ TIM_CHANNEL_STATE_SET(&(_timerObj.handle), getChannel(channel), HAL_TIM_CHANNEL_STATE_READY);
+ }
+
+#endif
+
+ // In case 2 channels are used, disbale also the 2nd one
+ if (_ChannelMode[channel - 1] == TIMER_INPUT_FREQ_DUTY_MEASUREMENT)
+ {
+ // Identify and configure 2nd associated channel
+ timAssociatedInputChannel = getAssociatedChannel(channel);
+ __HAL_TIM_DISABLE_IT(&(_timerObj.handle), getIT(timAssociatedInputChannel));
+ LL_TIM_CC_DisableChannel(_timerObj.handle.Instance, getLLChannel(timAssociatedInputChannel));
+ }
+}
+
+/**
+ @brief Start or resume HardwareTimer: all channels are resumed, interrupts are enabled if necessary
+ @param None
+ @retval None
+*/
+void HardwareTimer::resume(void)
+{
+ // Clear flag and ennable IT
+ if (callbacks[0])
+ {
+ __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), TIM_FLAG_UPDATE);
+ __HAL_TIM_ENABLE_IT(&(_timerObj.handle), TIM_IT_UPDATE);
+
+ // Start timer in Time base mode. Required when there is no channel used but only update interrupt.
+ HAL_TIM_Base_Start(&(_timerObj.handle));
+ }
+
+ // Resume all channels
+ resumeChannel(1);
+ resumeChannel(2);
+ resumeChannel(3);
+ resumeChannel(4);
+}
+
+/**
+ @brief Convert arduino channel into HAL channel
+ @param Arduino channel [1..4]
+ @retval HAL channel. return -1 if arduino channel is invalid
+*/
+int HardwareTimer::getChannel(uint32_t channel)
+{
+ uint32_t return_value;
+
+ switch (channel)
+ {
+ case 1:
+ return_value = TIM_CHANNEL_1;
+ break;
+
+ case 2:
+ return_value = TIM_CHANNEL_2;
+ break;
+
+ case 3:
+ return_value = TIM_CHANNEL_3;
+ break;
+
+ case 4:
+ return_value = TIM_CHANNEL_4;
+ break;
+
+ default:
+ return_value = -1;
+ }
+
+ return return_value;
+}
+
+/**
+ @brief Convert arduino channel into LL channel
+ @param Arduino channel [1..4]
+ @retval LL channel. return -1 if arduino channel is invalid
+*/
+int HardwareTimer::getLLChannel(uint32_t channel)
+{
+ uint32_t return_value;
+#if defined(TIM_CCER_CC1NE)
+
+ if (isComplementaryChannel[channel - 1])
+ {
+ // Complementary channel
+ switch (channel)
+ {
+ case 1:
+ return_value = LL_TIM_CHANNEL_CH1N;
+ break;
+
+ case 2:
+ return_value = LL_TIM_CHANNEL_CH2N;
+ break;
+
+ case 3:
+ return_value = LL_TIM_CHANNEL_CH3N;
+ break;
+#if defined(LL_TIM_CHANNEL_CH4N)
+
+ case 4:
+ return_value = LL_TIM_CHANNEL_CH4N;
+ break;
+#endif
+
+ default:
+ return_value = -1;
+ }
+ }
+ else
+#endif
+ {
+ // Regular channel not complementary
+ switch (channel)
+ {
+ case 1:
+ return_value = LL_TIM_CHANNEL_CH1;
+ break;
+
+ case 2:
+ return_value = LL_TIM_CHANNEL_CH2;
+ break;
+
+ case 3:
+ return_value = LL_TIM_CHANNEL_CH3;
+ break;
+
+ case 4:
+ return_value = LL_TIM_CHANNEL_CH4;
+ break;
+
+ default:
+ return_value = -1;
+ }
+ }
+
+ return return_value;
+}
+
+/**
+ @brief Convert arduino channel into HAL Interrupt ID
+ @param Arduino channel [1..4]
+ @retval HAL channel. return -1 if arduino channel is invalid
+*/
+int HardwareTimer::getIT(uint32_t channel)
+{
+ uint32_t return_value;
+
+ switch (channel)
+ {
+ case 1:
+ return_value = TIM_IT_CC1;
+ break;
+
+ case 2:
+ return_value = TIM_IT_CC2;
+ break;
+
+ case 3:
+ return_value = TIM_IT_CC3;
+ break;
+
+ case 4:
+ return_value = TIM_IT_CC4;
+ break;
+
+ default:
+ return_value = -1;
+ }
+
+ return return_value;
+}
+
+/**
+ @brief Get input associated channel
+ Channel 1 and 2 are associated; channel 3 and 4 are associated
+ @param Arduino channel [1..4]
+ @retval HAL channel. return -1 if arduino channel is invalid
+*/
+int HardwareTimer::getAssociatedChannel(uint32_t channel)
+{
+ int timAssociatedInputChannel = -1;
+
+ switch (channel)
+ {
+ case 1:
+ timAssociatedInputChannel = 2;
+ break;
+
+ case 2:
+ timAssociatedInputChannel = 1;
+ break;
+
+ case 3:
+ timAssociatedInputChannel = 4;
+ break;
+
+ case 4:
+ timAssociatedInputChannel = 3;
+ break;
+
+ default:
+ break;
+ }
+
+ return timAssociatedInputChannel;
+}
+
+/**
+ @brief Configure specified channel and resume/start timer
+ @param Arduino channel [1..4]
+ @retval None
+*/
+void HardwareTimer::resumeChannel(uint32_t channel)
+{
+ int timChannel = getChannel(channel);
+ int timAssociatedInputChannel;
+
+ if (timChannel == -1)
+ {
+ //Error_Handler();
+ }
+
+ int interrupt = getIT(channel);
+
+ if (interrupt == -1)
+ {
+ //Error_Handler();
+ }
+
+ int LLChannel = getLLChannel(channel);
+
+ if (LLChannel == -1)
+ {
+ //Error_Handler();
+ }
+
+ // Clear flag and enable IT
+ if (callbacks[channel])
+ {
+ __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), interrupt);
+ __HAL_TIM_ENABLE_IT(&(_timerObj.handle), interrupt);
+ }
+
+ switch (_ChannelMode[channel - 1])
+ {
+ case TIMER_OUTPUT_COMPARE_PWM1:
+ case TIMER_OUTPUT_COMPARE_PWM2:
+ {
+#if defined(TIM_CCER_CC1NE)
+
+ if (isComplementaryChannel[channel - 1])
+ {
+ HAL_TIMEx_PWMN_Start(&(_timerObj.handle), timChannel);
+ }
+ else
+#endif
+ {
+ HAL_TIM_PWM_Start(&(_timerObj.handle), timChannel);
+ }
+ }
+ break;
+
+ case TIMER_OUTPUT_COMPARE_ACTIVE:
+ case TIMER_OUTPUT_COMPARE_INACTIVE:
+ case TIMER_OUTPUT_COMPARE_TOGGLE:
+ case TIMER_OUTPUT_COMPARE_FORCED_ACTIVE:
+ case TIMER_OUTPUT_COMPARE_FORCED_INACTIVE:
+ {
+#if defined(TIM_CCER_CC1NE)
+
+ if (isComplementaryChannel[channel - 1])
+ {
+ HAL_TIMEx_OCN_Start(&(_timerObj.handle), timChannel);
+ }
+ else
+#endif
+ {
+ HAL_TIM_OC_Start(&(_timerObj.handle), timChannel);
+ }
+ }
+ break;
+
+ case TIMER_INPUT_FREQ_DUTY_MEASUREMENT:
+ {
+ HAL_TIM_IC_Start(&(_timerObj.handle), timChannel);
+
+ // Enable 2nd associated channel
+ timAssociatedInputChannel = getAssociatedChannel(channel);
+ LL_TIM_CC_EnableChannel(_timerObj.handle.Instance, getLLChannel(timAssociatedInputChannel));
+
+ if (callbacks[channel])
+ {
+ __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), getIT(timAssociatedInputChannel));
+ __HAL_TIM_ENABLE_IT(&(_timerObj.handle), getIT(timAssociatedInputChannel));
+ }
+ }
+ break;
+
+ case TIMER_INPUT_CAPTURE_RISING:
+ case TIMER_INPUT_CAPTURE_FALLING:
+ case TIMER_INPUT_CAPTURE_BOTHEDGE:
+ {
+ HAL_TIM_IC_Start(&(_timerObj.handle), timChannel);
+ }
+ break;
+
+ case TIMER_NOT_USED:
+ case TIMER_OUTPUT_COMPARE:
+ default :
+ break;
+ }
+}
+
+/**
+ @brief Retrieve prescaler from hardware register
+ @param None
+ @retval prescaler factor
+*/
+uint32_t HardwareTimer::getPrescaleFactor()
+{
+ // Hardware register correspond to prescaler-1. Example PSC register value 0 means divided by 1
+ return (LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1);
+}
+
+/**
+ @brief Configure hardwareTimer prescaler
+ @param prescaler factor
+ @retval None
+*/
+void HardwareTimer::setPrescaleFactor(uint32_t prescaler)
+{
+ // Hardware register correspond to prescaler-1. Example PSC register value 0 means divided by 1
+ LL_TIM_SetPrescaler(_timerObj.handle.Instance, prescaler - 1);
+}
+
+/**
+ @brief Retrieve overflow (rollover) value from hardware register
+ @param format of returned value. If ommited default format is Tick
+ @retval overflow depending on format value:
+ TICK_FORMAT: return number of tick for overflow
+ MICROSEC_FORMAT: return number of microsecondes for overflow
+ HERTZ_FORMAT: return frequency in hertz for overflow
+*/
+uint32_t HardwareTimer::getOverflow(TimerFormat_t format)
+{
+ // Hardware register correspond to period count-1. Example ARR register value 9 means period of 10 timer cycle
+ uint32_t ARR_RegisterValue = LL_TIM_GetAutoReload(_timerObj.handle.Instance);
+ uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1;
+ uint32_t return_value;
+
+ switch (format)
+ {
+ case MICROSEC_FORMAT:
+ return_value = (uint32_t)(((ARR_RegisterValue + 1) * Prescalerfactor * 1000000.0) / getTimerClkFreq());
+ break;
+
+ case HERTZ_FORMAT:
+ return_value = (uint32_t)(getTimerClkFreq() / ((ARR_RegisterValue + 1) * Prescalerfactor));
+ break;
+
+ case TICK_FORMAT:
+ default :
+ return_value = ARR_RegisterValue + 1;
+ break;
+ }
+
+ return return_value;
+}
+
+/**
+ @brief Set overflow (rollover)
+
+ Note that by default, the new value will not be applied
+ immediately, but become effective at the next update event
+ (usually the next timer overflow). See setPreloadEnable()
+ for controlling this behaviour.
+ @param overflow: depend on format parameter
+ @param format of overflow parameter. If ommited default format is Tick
+ TICK_FORMAT: overflow is the number of tick for overflow
+ MICROSEC_FORMAT: overflow is the number of microsecondes for overflow
+ HERTZ_FORMAT: overflow is the frequency in hertz for overflow
+ @retval None
+*/
+void HardwareTimer::setOverflow(uint32_t overflow, TimerFormat_t format)
+{
+ uint32_t ARR_RegisterValue;
+ uint32_t PeriodTicks;
+ uint32_t Prescalerfactor;
+ uint32_t period_cyc;
+
+ // Remark: Hardware register correspond to period count-1. Example ARR register value 9 means period of 10 timer cycle
+ switch (format)
+ {
+ case MICROSEC_FORMAT:
+ period_cyc = overflow * (getTimerClkFreq() / 1000000);
+ Prescalerfactor = (period_cyc / 0x10000) + 1;
+ LL_TIM_SetPrescaler(_timerObj.handle.Instance, Prescalerfactor - 1);
+ PeriodTicks = period_cyc / Prescalerfactor;
+ break;
+
+ case HERTZ_FORMAT:
+ period_cyc = getTimerClkFreq() / overflow;
+ Prescalerfactor = (period_cyc / 0x10000) + 1;
+ LL_TIM_SetPrescaler(_timerObj.handle.Instance, Prescalerfactor - 1);
+ PeriodTicks = period_cyc / Prescalerfactor;
+ break;
+
+ case TICK_FORMAT:
+ default :
+ PeriodTicks = overflow;
+ break;
+ }
+
+ if (PeriodTicks > 0)
+ {
+ // The register specifies the maximum value, so the period is really one tick longer
+ ARR_RegisterValue = PeriodTicks - 1;
+ }
+ else
+ {
+ // But do not underflow in case a zero period was given somehow.
+ ARR_RegisterValue = 0;
+ }
+
+ __HAL_TIM_SET_AUTORELOAD(&_timerObj.handle, ARR_RegisterValue);
+}
+
+/**
+ @brief Retreive timer counter value
+ @param format of returned value. If ommited default format is Tick
+ @retval overflow depending on format value:
+ TICK_FORMAT: return number of tick for counter
+ MICROSEC_FORMAT: return number of microsecondes for counter
+ HERTZ_FORMAT: return frequency in hertz for counter
+*/
+uint32_t HardwareTimer::getCount(TimerFormat_t format)
+{
+ uint32_t CNT_RegisterValue = LL_TIM_GetCounter(_timerObj.handle.Instance);
+ uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1;
+ uint32_t return_value;
+
+ switch (format)
+ {
+ case MICROSEC_FORMAT:
+ return_value = (uint32_t)((CNT_RegisterValue * Prescalerfactor * 1000000.0) / getTimerClkFreq());
+ break;
+
+ case HERTZ_FORMAT:
+ return_value = (uint32_t)(getTimerClkFreq() / (CNT_RegisterValue * Prescalerfactor));
+ break;
+
+ case TICK_FORMAT:
+ default :
+ return_value = CNT_RegisterValue;
+ break;
+ }
+
+ return return_value;
+}
+
+/**
+ @brief Set timer counter value
+ @param counter: depend on format parameter
+ @param format of overflow parameter. If ommited default format is Tick
+ TICK_FORMAT: counter is the number of tick
+ MICROSEC_FORMAT: counter is the number of microsecondes
+ HERTZ_FORMAT: counter is the frequency in hertz
+ @retval None
+*/
+void HardwareTimer::setCount(uint32_t counter, TimerFormat_t format)
+{
+ uint32_t CNT_RegisterValue;
+ uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1;
+
+ switch (format)
+ {
+ case MICROSEC_FORMAT:
+ CNT_RegisterValue = ((counter * (getTimerClkFreq() / 1000000)) / Prescalerfactor);
+ break;
+
+ case HERTZ_FORMAT:
+ CNT_RegisterValue = (uint32_t)(getTimerClkFreq() / (counter * Prescalerfactor));
+ break;
+
+ case TICK_FORMAT:
+ default :
+ CNT_RegisterValue = counter;
+ break;
+ }
+
+ __HAL_TIM_SET_COUNTER(&(_timerObj.handle), CNT_RegisterValue);
+}
+
+/**
+ @brief Set channel mode
+ @param channel: Arduino channel [1..4]
+ @param mode: mode configuration for the channel (see TimerModes_t)
+ @param pin: Arduino pin number, ex: D1, 1 or PA1
+ @retval None
+*/
+void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, uint32_t pin)
+{
+ setMode(channel, mode, digitalPinToPinName(pin));
+}
+
+/**
+ @brief Set channel mode
+ @param channel: Arduino channel [1..4]
+ @param mode: mode configuration for the channel (see TimerModes_t)
+ @param pin: pin name, ex: PB_0
+ @retval None
+*/
+void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, PinName pin)
+{
+ int timChannel = getChannel(channel);
+ int timAssociatedInputChannel;
+ TIM_OC_InitTypeDef channelOC;
+ TIM_IC_InitTypeDef channelIC;
+
+ if (timChannel == -1)
+ {
+ //Error_Handler();
+ }
+
+ /* Configure some default values. Maybe overwritten later */
+ channelOC.OCMode = TIMER_NOT_USED;
+ channelOC.Pulse = __HAL_TIM_GET_COMPARE(&(_timerObj.handle),
+ timChannel); // keep same value already written in hardware (TIMER_CHANNELS + 1)))
+ {
+ //Error_Handler(); // only channel 1..4 have an interrupt
+ }
+
+ if (callbacks[channel])
+ {
+ // Callback previously configured : do not clear neither enable IT, it is just a change of callback
+ callbacks[channel] = callback;
+ }
+ else
+ {
+ callbacks[channel] = callback;
+
+ if (callback)
+ {
+ // Clear flag before enabling IT
+ __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), interrupt);
+ // Enable interrupt corresponding to channel, only if callback is valid
+ __HAL_TIM_ENABLE_IT(&(_timerObj.handle), interrupt);
+ }
+ }
+}
+
+/**
+ @brief Dettach interrupt callback on Capture/Compare event
+ @param channel: Arduino channel [1..4]
+ @retval None
+*/
+void HardwareTimer::detachInterrupt(uint32_t channel)
+{
+ int interrupt = getIT(channel);
+
+ if (interrupt == -1)
+ {
+ //Error_Handler();
+ }
+
+ if ((channel == 0) || (channel > (TIMER_CHANNELS + 1)))
+ {
+ //Error_Handler(); // only channel 1..4 have an interrupt
+ }
+
+ // Disable interrupt corresponding to channel and clear callback
+ __HAL_TIM_DISABLE_IT(&(_timerObj.handle), interrupt);
+ callbacks[channel] = NULL;
+}
+
+/**
+ @brief Checks if there's an interrupt callback attached on Rollover event
+ @retval returns true if a timer rollover interrupt has already been set
+*/
+bool HardwareTimer::hasInterrupt()
+{
+ return callbacks[0] != NULL;
+}
+
+/**
+ @brief Checks if there's an interrupt callback attached on Capture/Compare event
+ @param channel: Arduino channel [1..4]
+ @retval returns true if a channel compare match interrupt has already been set
+*/
+bool HardwareTimer::hasInterrupt(uint32_t channel)
+{
+ if ((channel == 0) || (channel > (TIMER_CHANNELS + 1)))
+ {
+ //Error_Handler(); // only channel 1..4 have an interrupt
+ }
+
+ return callbacks[channel] != NULL;
+}
+
+/**
+ @brief Generate an update event to force all registers (Autoreload, prescaler, compare) to be taken into account
+ @note Refresh() can only be called after a 1st call to resume() to be sure timer is initialised.
+ It is usefull while timer is running after some registers update
+ @retval None
+*/
+void HardwareTimer::refresh()
+{
+ HAL_TIM_GenerateEvent(&(_timerObj.handle), TIM_EVENTSOURCE_UPDATE);
+}
+
+/**
+ @brief Return the timer object handle object for more advanced setup
+ @note Using this function and editing the Timer handle is at own risk! No support will
+ be provided whatsoever if the HardwareTimer does not work as expected when editing
+ the handle using the HAL functionality or other custom coding.
+ @retval TIM_HandleTypeDef address
+*/
+TIM_HandleTypeDef *HardwareTimer::getHandle()
+{
+ return &_timerObj.handle;
+}
+
+/**
+ @brief Generic Update (rollover) callback which will call user callback
+ @param htim: HAL timer handle
+ @retval None
+*/
+void HardwareTimer::updateCallback(TIM_HandleTypeDef *htim)
+{
+ if (!htim)
+ {
+ //Error_Handler();
+ }
+
+ timerObj_t *obj = get_timer_obj(htim);
+ HardwareTimer *HT = (HardwareTimer *)(obj->__this);
+
+ if (HT->callbacks[0])
+ {
+ HT->callbacks[0]();
+ }
+}
+
+/**
+ @brief Generic Caputre and Compare callback which will call user callback
+ @param htim: HAL timer handle
+ @retval None
+*/
+void HardwareTimer::captureCompareCallback(TIM_HandleTypeDef *htim)
+{
+ if (!htim)
+ {
+ //Error_Handler();
+ }
+
+ uint32_t channel = htim->Channel;
+
+ switch (htim->Channel)
+ {
+ case HAL_TIM_ACTIVE_CHANNEL_1:
+ {
+ channel = 1;
+ break;
+ }
+
+ case HAL_TIM_ACTIVE_CHANNEL_2:
+ {
+ channel = 2;
+ break;
+ }
+
+ case HAL_TIM_ACTIVE_CHANNEL_3:
+ {
+ channel = 3;
+ break;
+ }
+
+ case HAL_TIM_ACTIVE_CHANNEL_4:
+ {
+ channel = 4;
+ break;
+ }
+
+ default:
+ return;
+ }
+
+ timerObj_t *obj = get_timer_obj(htim);
+ HardwareTimer *HT = (HardwareTimer *)(obj->__this);
+
+ if (HT->callbacks[channel])
+ {
+ HT->callbacks[channel]();
+ }
+}
+
+/**
+ @brief HardwareTimer destructor
+ @retval None
+*/
+HardwareTimer::~HardwareTimer()
+{
+ uint32_t index = get_timer_index(_timerObj.handle.Instance);
+ disableTimerClock(&(_timerObj.handle));
+ HardwareTimer_Handle[index] = NULL;
+ _timerObj.__this = NULL;
+}
+
+/**
+ @brief return timer index from timer handle
+ @param htim : one of the defined timer
+ @retval None
+*/
+timer_index_t get_timer_index(TIM_TypeDef *instance)
+{
+ timer_index_t index = UNKNOWN_TIMER;
+
+#if defined(TIM1_BASE)
+
+ if (instance == TIM1)
+ {
+ index = TIMER1_INDEX;
+ }
+
+#endif
+#if defined(TIM2_BASE)
+
+ if (instance == TIM2)
+ {
+ index = TIMER2_INDEX;
+ }
+
+#endif
+#if defined(TIM3_BASE)
+
+ if (instance == TIM3)
+ {
+ index = TIMER3_INDEX;
+ }
+
+#endif
+#if defined(TIM4_BASE)
+
+ if (instance == TIM4)
+ {
+ index = TIMER4_INDEX;
+ }
+
+#endif
+#if defined(TIM5_BASE)
+
+ if (instance == TIM5)
+ {
+ index = TIMER5_INDEX;
+ }
+
+#endif
+#if defined(TIM6_BASE)
+
+ if (instance == TIM6)
+ {
+ index = TIMER6_INDEX;
+ }
+
+#endif
+#if defined(TIM7_BASE)
+
+ if (instance == TIM7)
+ {
+ index = TIMER7_INDEX;
+ }
+
+#endif
+#if defined(TIM8_BASE)
+
+ if (instance == TIM8)
+ {
+ index = TIMER8_INDEX;
+ }
+
+#endif
+#if defined(TIM9_BASE)
+
+ if (instance == TIM9)
+ {
+ index = TIMER9_INDEX;
+ }
+
+#endif
+#if defined(TIM10_BASE)
+
+ if (instance == TIM10)
+ {
+ index = TIMER10_INDEX;
+ }
+
+#endif
+#if defined(TIM11_BASE)
+
+ if (instance == TIM11)
+ {
+ index = TIMER11_INDEX;
+ }
+
+#endif
+#if defined(TIM12_BASE)
+
+ if (instance == TIM12)
+ {
+ index = TIMER12_INDEX;
+ }
+
+#endif
+#if defined(TIM13_BASE)
+
+ if (instance == TIM13)
+ {
+ index = TIMER13_INDEX;
+ }
+
+#endif
+#if defined(TIM14_BASE)
+
+ if (instance == TIM14)
+ {
+ index = TIMER14_INDEX;
+ }
+
+#endif
+#if defined(TIM15_BASE)
+
+ if (instance == TIM15)
+ {
+ index = TIMER15_INDEX;
+ }
+
+#endif
+#if defined(TIM16_BASE)
+
+ if (instance == TIM16)
+ {
+ index = TIMER16_INDEX;
+ }
+
+#endif
+#if defined(TIM17_BASE)
+
+ if (instance == TIM17)
+ {
+ index = TIMER17_INDEX;
+ }
+
+#endif
+#if defined(TIM18_BASE)
+
+ if (instance == TIM18)
+ {
+ index = TIMER18_INDEX;
+ }
+
+#endif
+#if defined(TIM19_BASE)
+
+ if (instance == TIM19)
+ {
+ index = TIMER19_INDEX;
+ }
+
+#endif
+#if defined(TIM20_BASE)
+
+ if (instance == TIM20)
+ {
+ index = TIMER20_INDEX;
+ }
+
+#endif
+#if defined(TIM21_BASE)
+
+ if (instance == TIM21)
+ {
+ index = TIMER21_INDEX;
+ }
+
+#endif
+#if defined(TIM22_BASE)
+
+ if (instance == TIM22)
+ {
+ index = TIMER22_INDEX;
+ }
+
+#endif
+ return index;
+}
+
+/**
+ @brief This function return the timer clock frequency.
+ @param tim: timer instance
+ @retval frequency in Hz
+*/
+uint32_t HardwareTimer::getTimerClkFreq()
+{
+ RCC_ClkInitTypeDef clkconfig = {};
+ uint32_t pFLatency = 0U;
+ uint32_t uwTimclock = 0U, uwAPBxPrescaler = 0U;
+
+ /* Get clock configuration */
+ HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
+
+ switch (getTimerClkSrc(_timerObj.handle.Instance))
+ {
+ case 1:
+ uwAPBxPrescaler = clkconfig.APB1CLKDivider;
+ uwTimclock = HAL_RCC_GetPCLK1Freq();
+ break;
+
+ case 2:
+ uwAPBxPrescaler = clkconfig.APB2CLKDivider;
+ uwTimclock = HAL_RCC_GetPCLK2Freq();
+ break;
+
+ default:
+ case 0: // Unknown timer clock source
+ //Error_Handler();
+ break;
+ }
+
+ /* When TIMPRE bit of the RCC_CFGR register is reset,
+ if APBx prescaler is 1 or 2 then TIMxCLK = HCLK,
+ otherwise TIMxCLK = 2x PCLKx.
+ When TIMPRE bit in the RCC_CFGR register is set,
+ if APBx prescaler is 1,2 or 4, then TIMxCLK = HCLK,
+ otherwise TIMxCLK = 4x PCLKx
+ */
+ RCC_PeriphCLKInitTypeDef PeriphClkConfig = {};
+ HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkConfig);
+
+ if (PeriphClkConfig.TIMPresSelection == RCC_TIMPRES_ACTIVATED)
+ {
+ switch (uwAPBxPrescaler)
+ {
+ default:
+ case RCC_APB1_DIV1:
+ case RCC_APB1_DIV2:
+ case RCC_APB1_DIV4:
+
+ /* case RCC_APB2_DIV1: */
+ case RCC_APB2_DIV2:
+ case RCC_APB2_DIV4:
+ /* Note: in such cases, HCLK = (APBCLK * DIVx) */
+ uwTimclock = HAL_RCC_GetHCLKFreq();
+ break;
+
+ case RCC_APB1_DIV8:
+ case RCC_APB1_DIV16:
+ case RCC_APB2_DIV8:
+ case RCC_APB2_DIV16:
+ uwTimclock *= 4;
+ break;
+ }
+ }
+ else
+ {
+ switch (uwAPBxPrescaler)
+ {
+ default:
+ case RCC_APB1_DIV1:
+ case RCC_APB1_DIV2:
+
+ /* case RCC_APB2_DIV1: */
+ case RCC_APB2_DIV2:
+ /* Note: in such cases, HCLK = (APBCLK * DIVx) */
+ uwTimclock = HAL_RCC_GetHCLKFreq();
+ break;
+
+ case RCC_APB1_DIV4:
+ case RCC_APB1_DIV8:
+ case RCC_APB1_DIV16:
+ case RCC_APB2_DIV4:
+ case RCC_APB2_DIV8:
+ case RCC_APB2_DIV16:
+ uwTimclock *= 2;
+ break;
+ }
+ }
+
+ return uwTimclock;
+}
+
+/**
+ @brief This function will reset the timer
+ @param obj : Hardware timer instance ex: Timer6, ...
+ @retval None
+*/
+void HardwareTimer::timerHandleDeinit()
+{
+ HAL_TIM_Base_Stop_IT(&(_timerObj.handle));
+ HAL_TIM_Base_DeInit(&(_timerObj.handle));
+}
+
+/******************************************************************************/
+/* TIMx IRQ HANDLER */
+/******************************************************************************/
+extern "C" {
+
+ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
+ {
+ HardwareTimer::captureCompareCallback(htim);
+ }
+
+ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
+ {
+ HardwareTimer::captureCompareCallback(htim);
+ }
+
+ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
+ {
+ HardwareTimer::updateCallback(htim);
+ }
+
+#if defined(TIM1_BASE)
+ /**
+ @brief TIM1 IRQHandler common with TIM10 and TIM16 on some STM32F1xx
+ @param None
+ @retval None
+ */
+ void TIM1_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER1_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER1_INDEX]->handle);
+ }
+ }
+
+ void TIM1_CC_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER1_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER1_INDEX]->handle);
+ }
+ }
+#endif //TIM1_BASE
+
+#if defined(TIM2_BASE)
+ /**
+ @brief TIM2 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM2_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER2_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER2_INDEX]->handle);
+ }
+ }
+#endif //TIM2_BASE
+
+#if defined(TIM3_BASE)
+ /**
+ @brief TIM3 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM3_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER3_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER3_INDEX]->handle);
+ }
+ }
+#endif //TIM3_BASE
+
+#if defined(TIM4_BASE)
+ /**
+ @brief TIM4 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM4_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER4_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER4_INDEX]->handle);
+ }
+ }
+#endif //TIM4_BASE
+
+#if defined(TIM5_BASE)
+ /**
+ @brief TIM5 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM5_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER5_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER5_INDEX]->handle);
+ }
+ }
+#endif //TIM5_BASE
+
+#if defined(TIM6_BASE)
+ /**
+ @brief TIM6 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM6_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER6_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER6_INDEX]->handle);
+ }
+ }
+#endif //TIM6_BASE
+
+#if defined(TIM7_BASE)
+ /**
+ @brief TIM7 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM7_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER7_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER7_INDEX]->handle);
+ }
+ }
+#endif //TIM7_BASE
+
+#if defined(TIM8_BASE)
+ /**
+ @brief TIM8 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM8_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER8_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER8_INDEX]->handle);
+ }
+
+#if defined(TIM13_BASE)
+
+ if (HardwareTimer_Handle[TIMER13_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER13_INDEX]->handle);
+ }
+
+#endif // TIM13_BASE
+ }
+
+ void TIM8_CC_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER8_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER8_INDEX]->handle);
+ }
+ }
+#endif //TIM8_BASE
+
+#if defined(TIM9_BASE)
+ /**
+ @brief TIM9 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM9_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER9_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER9_INDEX]->handle);
+ }
+ }
+#endif //TIM9_BASE
+
+#if defined(TIM10_BASE)
+ /**
+ @brief TIM10 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM10_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER10_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER10_INDEX]->handle);
+ }
+ }
+#endif //TIM10_BASE
+
+#if defined(TIM11_BASE)
+ /**
+ @brief TIM11 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM11_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER11_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER11_INDEX]->handle);
+ }
+ }
+#endif //TIM11_BASE
+
+#if defined(TIM12_BASE)
+ /**
+ @brief TIM12 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM12_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER12_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER12_INDEX]->handle);
+ }
+ }
+#endif //TIM12_BASE
+
+#if defined(TIM13_BASE)
+ //#if !defined(STM32F1xx) && !defined(STM32F2xx) && !defined(STM32F4xx) && !defined(STM32F7xx) && !defined(STM32H7xx)
+ /**
+ @brief TIM13 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM13_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER13_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER13_INDEX]->handle);
+ }
+ }
+ //#endif
+#endif //TIM13_BASE
+
+#if defined(TIM14_BASE)
+ /**
+ @brief TIM14 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM14_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER14_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER14_INDEX]->handle);
+ }
+ }
+#endif //TIM14_BASE
+
+#if defined(TIM15_BASE)
+ /**
+ @brief TIM15 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM15_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER15_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER15_INDEX]->handle);
+ }
+ }
+#endif //TIM15_BASE
+
+#if defined(TIM16_BASE)
+ /**
+ @brief TIM16 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM16_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER16_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER16_INDEX]->handle);
+ }
+ }
+#endif //TIM16_BASE
+
+#if defined(TIM17_BASE)
+ /**
+ @brief TIM17 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM17_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER17_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER17_INDEX]->handle);
+ }
+ }
+#endif //TIM17_BASE
+
+#if defined(TIM18_BASE)
+ /**
+ @brief TIM18 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM18_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER18_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER18_INDEX]->handle);
+ }
+ }
+#endif //TIM18_BASE
+
+#if defined(TIM19_BASE)
+ /**
+ @brief TIM19 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM19_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER19_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER19_INDEX]->handle);
+ }
+ }
+#endif //TIM19_BASE
+
+#if defined(TIM20_BASE)
+ /**
+ @brief TIM20 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM20_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER20_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER20_INDEX]->handle);
+ }
+ }
+
+ void TIM20_CC_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER20_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER20_INDEX]->handle);
+ }
+ }
+#endif //TIM20_BASE
+
+#if defined(TIM21_BASE)
+ /**
+ @brief TIM21 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM21_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER21_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER21_INDEX]->handle);
+ }
+ }
+#endif //TIM21_BASE
+
+#if defined(TIM22_BASE)
+ /**
+ @brief TIM22 IRQHandler
+ @param None
+ @retval None
+ */
+ void TIM22_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER22_INDEX])
+ {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER22_INDEX]->handle);
+ }
+ }
+#endif //TIM22_BASE
+}
+
+#endif // HAL_TIM_MODULE_ENABLED && !HAL_TIM_MODULE_ONLY
+#endif
\ No newline at end of file
diff --git a/GigaHardwareTimer.h b/GigaHardwareTimer.h
new file mode 100644
index 0000000..11ca5aa
--- /dev/null
+++ b/GigaHardwareTimer.h
@@ -0,0 +1,220 @@
+/****************************************************************************************************************************
+ HardwareTimer.h
+
+ For Portenta_H7 boards
+ Written by Khoi Hoang
+
+ Built by Khoi Hoang https://github.com/khoih-prog/Portenta_H7_TimerInterrupt
+ Licensed under MIT license
+
+ 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 Portenta_H7 STM32 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.
+
+ Version: 1.4.0
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.1 K.Hoang 15/09/2021 Initial coding for Portenta_H7
+ 1.3.0 K.Hoang 17/09/2021 Add PWM features and examples
+ 1.3.1 K.Hoang 21/09/2021 Fix warnings in PWM examples
+ 1.4.0 K.Hoang 22/01/2022 Fix `multiple-definitions` linker error. Fix bug
+ *****************************************************************************************************************************/
+
+// Modified from stm32 core v2.0.0
+
+/*
+ Copyright (c) 2017 Daniel Fekete
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2019 STMicroelectronics
+ Modified to support Arduino_Core_STM32
+*/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef GIGAHARDWARETIMER_H_
+#define GIGAHARDWARETIMER_H_
+#if defined(ARDUINO_GIGA)
+/* Includes ------------------------------------------------------------------*/
+#include "Gigatimer.h"
+
+#if defined(HAL_TIM_MODULE_ENABLED) && !defined(HAL_TIM_MODULE_ONLY)
+
+#define TIMER_CHANNELS 4 // channel5 and channel 6 are not considered here has they don't have gpio output and they don't have interrupt
+
+typedef enum
+{
+ TIMER_DISABLED, // == TIM_OCMODE_TIMING no output, useful for only-interrupt
+ // Output Compare
+ TIMER_OUTPUT_COMPARE, // == Obsolete, use TIMER_DISABLED instead. Kept for compatibility reason
+ TIMER_OUTPUT_COMPARE_ACTIVE, // == TIM_OCMODE_ACTIVE pin is set high when counter == channel compare
+ TIMER_OUTPUT_COMPARE_INACTIVE, // == TIM_OCMODE_INACTIVE pin is set low when counter == channel compare
+ TIMER_OUTPUT_COMPARE_TOGGLE, // == TIM_OCMODE_TOGGLE pin toggles when counter == channel compare
+ TIMER_OUTPUT_COMPARE_PWM1, // == TIM_OCMODE_PWM1 pin high when counter < channel compare, low otherwise
+ TIMER_OUTPUT_COMPARE_PWM2, // == TIM_OCMODE_PWM2 pin low when counter < channel compare, high otherwise
+ TIMER_OUTPUT_COMPARE_FORCED_ACTIVE, // == TIM_OCMODE_FORCED_ACTIVE pin always high
+ TIMER_OUTPUT_COMPARE_FORCED_INACTIVE, // == TIM_OCMODE_FORCED_INACTIVE pin always low
+
+ //Input capture
+ TIMER_INPUT_CAPTURE_RISING, // == TIM_INPUTCHANNELPOLARITY_RISING
+ TIMER_INPUT_CAPTURE_FALLING, // == TIM_INPUTCHANNELPOLARITY_FALLING
+ TIMER_INPUT_CAPTURE_BOTHEDGE, // == TIM_INPUTCHANNELPOLARITY_BOTHEDGE
+
+ // Used 2 channels for a single pin. One channel in TIM_INPUTCHANNELPOLARITY_RISING another channel in TIM_INPUTCHANNELPOLARITY_FALLING.
+ // Channels must be used by pair: CH1 with CH2, or CH3 with CH4
+ // This mode is very useful for Frequency and Dutycycle measurement
+ TIMER_INPUT_FREQ_DUTY_MEASUREMENT,
+
+ TIMER_NOT_USED = 0xFFFF // This must be the last item of this enum
+} TimerModes_t;
+
+typedef enum
+{
+ TICK_FORMAT, // default
+ MICROSEC_FORMAT,
+ HERTZ_FORMAT,
+} TimerFormat_t;
+
+typedef enum
+{
+ RESOLUTION_1B_COMPARE_FORMAT = 1, // used for Dutycycle: [0 .. 1]
+ RESOLUTION_2B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 3]
+ RESOLUTION_3B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 7]
+ RESOLUTION_4B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 15]
+ RESOLUTION_5B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 31]
+ RESOLUTION_6B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 63]
+ RESOLUTION_7B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 127]
+ RESOLUTION_8B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 255]
+ RESOLUTION_9B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 511]
+ RESOLUTION_10B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 1023]
+ RESOLUTION_11B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 2047]
+ RESOLUTION_12B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 4095]
+ RESOLUTION_13B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 8191]
+ RESOLUTION_14B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 16383]
+ RESOLUTION_15B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 32767]
+ RESOLUTION_16B_COMPARE_FORMAT, // used for Dutycycle: [0 .. 65535]
+
+ TICK_COMPARE_FORMAT = 0x80, // default
+ MICROSEC_COMPARE_FORMAT,
+ HERTZ_COMPARE_FORMAT,
+ PERCENT_COMPARE_FORMAT, // used for Dutycycle
+} TimerCompareFormat_t;
+
+#ifdef __cplusplus
+
+#include
+using callback_function_t = std::function;
+
+/* Class --------------------------------------------------------*/
+class HardwareTimer
+{
+ public:
+ HardwareTimer(TIM_TypeDef *instance);
+ ~HardwareTimer(); // destructor
+
+ void pause(void); // Pause counter and all output channels
+ void pauseChannel(uint32_t channel); // Timer is still running but channel (output and interrupt) is disabled
+ void resume(void); // Resume counter and all output channels
+ void resumeChannel(uint32_t channel); // Resume only one channel
+
+ void setPrescaleFactor(uint32_t prescaler); // set prescaler register (which is factor value - 1)
+ uint32_t getPrescaleFactor();
+
+ void setOverflow(uint32_t val, TimerFormat_t format =
+ TICK_FORMAT); // set AutoReload register depending on format provided
+ uint32_t getOverflow(TimerFormat_t format = TICK_FORMAT); // return overflow depending on format provided
+
+ void setPWM(uint32_t channel, PinName pin, uint32_t frequency, uint32_t dutycycle,
+ callback_function_t PeriodCallback = nullptr,
+ callback_function_t CompareCallback = nullptr); // Set all in one command freq in HZ, Duty in percentage. Including both interrup.
+ void setPWM(uint32_t channel, uint32_t pin, uint32_t frequency, uint32_t dutycycle,
+ callback_function_t PeriodCallback = nullptr, callback_function_t CompareCallback = nullptr);
+
+ void setCount(uint32_t val, TimerFormat_t format =
+ TICK_FORMAT); // set timer counter to value 'val' depending on format provided
+ uint32_t getCount(TimerFormat_t format =
+ TICK_FORMAT); // return current counter value of timer depending on format provided
+
+ void setMode(uint32_t channel, TimerModes_t mode,
+ PinName pin = NC); // Configure timer channel with specified mode on specified pin if available
+ void setMode(uint32_t channel, TimerModes_t mode, uint32_t pin);
+
+ TimerModes_t getMode(uint32_t channel); // Retrieve configured mode
+
+ void setPreloadEnable(bool value); // Configure overflow preload enable setting
+
+ uint32_t getCaptureCompare(uint32_t channel,
+ TimerCompareFormat_t format = TICK_COMPARE_FORMAT); // return Capture/Compare register value of specified channel depending on format provided
+ void setCaptureCompare(uint32_t channel, uint32_t compare,
+ TimerCompareFormat_t format = TICK_COMPARE_FORMAT); // set Compare register value of specified channel depending on format provided
+
+ void setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority); // set interrupt priority
+
+ //Add interrupt to period update
+ void attachInterrupt(callback_function_t
+ callback); // Attach interrupt callback which will be called upon update event (timer rollover)
+ void detachInterrupt(); // remove interrupt callback which was attached to update event
+ bool hasInterrupt(); //returns true if a timer rollover interrupt has already been set
+ //Add interrupt to capture/compare channel
+ void attachInterrupt(uint32_t channel,
+ callback_function_t callback); // Attach interrupt callback which will be called upon compare match event of specified channel
+ void detachInterrupt(uint32_t
+ channel); // remove interrupt callback which was attached to compare match event of specified channel
+ bool hasInterrupt(uint32_t channel); //returns true if an interrupt has already been set on the channel compare match
+ void timerHandleDeinit(); // Timer deinitialization
+
+ // Refresh() is usefull while timer is running after some registers update
+ void refresh(
+ void); // Generate update event to force all registers (Autoreload, prescaler, compare) to be taken into account
+
+ uint32_t getTimerClkFreq(); // return timer clock frequency in Hz.
+
+ static void captureCompareCallback(TIM_HandleTypeDef
+ *htim); // Generic Caputre and Compare callback which will call user callback
+ static void updateCallback(TIM_HandleTypeDef
+ *htim); // Generic Update (rollover) callback which will call user callback
+
+ // The following function(s) are available for more advanced timer options
+ TIM_HandleTypeDef *getHandle(); // return the handle address for HAL related configuration
+ int getChannel(uint32_t channel);
+ int getLLChannel(uint32_t channel);
+ int getIT(uint32_t channel);
+ int getAssociatedChannel(uint32_t channel);
+#if defined(TIM_CCER_CC1NE)
+ bool isComplementaryChannel[TIMER_CHANNELS];
+#endif
+ private:
+ TimerModes_t _ChannelMode[TIMER_CHANNELS];
+ timerObj_t _timerObj;
+ callback_function_t callbacks[1 +
+ TIMER_CHANNELS]; //Callbacks: 0 for update, 1-4 for channels. (channel5/channel6, if any, doesn't have interrupt)
+};
+
+extern timerObj_t *HardwareTimer_Handle[TIMER_NUM];
+
+extern timer_index_t get_timer_index(TIM_TypeDef *htim);
+
+#endif /* __cplusplus */
+
+#endif // HAL_TIM_MODULE_ENABLED && !HAL_TIM_MODULE_ONLY
+#endif
+#endif // GIGAHARDWARETIMER_H_
diff --git a/Gigatimer.c b/Gigatimer.c
new file mode 100644
index 0000000..d3e2b0a
--- /dev/null
+++ b/Gigatimer.c
@@ -0,0 +1,950 @@
+/****************************************************************************************************************************
+ timer.c
+
+ For Portenta_H7 boards
+ Written by Khoi Hoang
+
+ Built by Khoi Hoang https://github.com/khoih-prog/Portenta_H7_TimerInterrupt
+ Licensed under MIT license
+
+ 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 Portenta_H7 STM32 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.
+
+ Version: 1.4.0
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.1 K.Hoang 15/09/2021 Initial coding for Portenta_H7
+ 1.3.0 K.Hoang 17/09/2021 Add PWM features and examples
+ 1.3.1 K.Hoang 21/09/2021 Fix warnings in PWM examples
+ 1.4.0 K.Hoang 22/01/2022 Fix `multiple-definitions` linker error. Fix bug
+ *****************************************************************************************************************************/
+
+// Modified from stm32 core v2.0.0
+/*
+ *******************************************************************************
+ Copyright (c) 2019, STMicroelectronics
+ All rights reserved.
+
+ This software component is licensed by ST under BSD 3-Clause license,
+ the "License"; You may not use this file except in compliance with the
+ License. You may obtain a copy of the License at:
+ opensource.org/licenses/BSD-3-Clause
+
+ *******************************************************************************
+*/
+#if defined(ARDUINO_GIGA)
+#include "Gigatimer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if defined(HAL_TIM_MODULE_ENABLED) && !defined(HAL_TIM_MODULE_ONLY)
+
+/* Private Functions */
+/* Aim of the function is to get _timerObj pointer using htim pointer */
+/* Highly inspired from magical linux kernel's "container_of" */
+/* (which was not directly used since not compatible with IAR toolchain) */
+timerObj_t *get_timer_obj(TIM_HandleTypeDef *htim)
+{
+ timerObj_t *obj;
+ obj = (timerObj_t *)((char *)htim - offsetof(timerObj_t, handle));
+ return (obj);
+}
+
+/**
+ @brief TIMER Initialization - clock init and nvic init
+ @param htim_base: TIM handle
+ @retval None
+*/
+void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim_base)
+{
+ timerObj_t *obj = get_timer_obj(htim_base);
+ enableTimerClock(htim_base);
+
+ // configure Update interrupt
+ HAL_NVIC_SetPriority(getTimerUpIrq(htim_base->Instance), obj->preemptPriority, obj->subPriority);
+ HAL_NVIC_EnableIRQ(getTimerUpIrq(htim_base->Instance));
+
+ if (getTimerCCIrq(htim_base->Instance) != getTimerUpIrq(htim_base->Instance))
+ {
+ // configure Capture Compare interrupt
+ HAL_NVIC_SetPriority(getTimerCCIrq(htim_base->Instance), obj->preemptPriority, obj->subPriority);
+ HAL_NVIC_EnableIRQ(getTimerCCIrq(htim_base->Instance));
+ }
+}
+
+/**
+ @brief TIMER Deinitialization - clock and nvic
+ @param htim_base: TIM handle
+ @retval None
+*/
+void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim_base)
+{
+ disableTimerClock(htim_base);
+ HAL_NVIC_DisableIRQ(getTimerUpIrq(htim_base->Instance));
+ HAL_NVIC_DisableIRQ(getTimerCCIrq(htim_base->Instance));
+}
+
+/**
+ @brief Initializes the TIM Output Compare MSP.
+ @param htim: TIM handle
+ @retval None
+*/
+void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
+{
+ timerObj_t *obj = get_timer_obj(htim);
+ enableTimerClock(htim);
+
+ // configure Update interrupt
+ HAL_NVIC_SetPriority(getTimerUpIrq(htim->Instance), obj->preemptPriority, obj->subPriority);
+ HAL_NVIC_EnableIRQ(getTimerUpIrq(htim->Instance));
+
+ if (getTimerCCIrq(htim->Instance) != getTimerUpIrq(htim->Instance))
+ {
+ // configure Capture Compare interrupt
+ HAL_NVIC_SetPriority(getTimerCCIrq(htim->Instance), obj->preemptPriority, obj->subPriority);
+ HAL_NVIC_EnableIRQ(getTimerCCIrq(htim->Instance));
+ }
+}
+
+/**
+ @brief DeInitialize TIM Output Compare MSP.
+ @param htim: TIM handle
+ @retval None
+*/
+void HAL_TIM_OC_MspDeInit(TIM_HandleTypeDef *htim)
+{
+ disableTimerClock(htim);
+ HAL_NVIC_DisableIRQ(getTimerUpIrq(htim->Instance));
+ HAL_NVIC_DisableIRQ(getTimerCCIrq(htim->Instance));
+}
+
+/**
+ @brief Initializes the TIM Input Capture MSP.
+ @param htim: TIM handle
+ @retval None
+*/
+void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
+{
+ enableTimerClock(htim);
+}
+
+/**
+ @brief DeInitialize TIM Input Capture MSP.
+ @param htim: TIM handle
+ @retval None
+*/
+void HAL_TIM_IC_MspDeInit(TIM_HandleTypeDef *htim)
+{
+ disableTimerClock(htim);
+}
+
+/* Exported functions */
+/**
+ @brief Enable the timer clock
+ @param htim: TIM handle
+ @retval None
+*/
+void enableTimerClock(TIM_HandleTypeDef *htim)
+{
+ // Enable TIM clock
+#if defined(TIM1_BASE)
+ if (htim->Instance == TIM1)
+ {
+ __HAL_RCC_TIM1_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM2_BASE)
+
+ if (htim->Instance == TIM2)
+ {
+ __HAL_RCC_TIM2_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM3_BASE)
+
+ if (htim->Instance == TIM3)
+ {
+ __HAL_RCC_TIM3_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM4_BASE)
+
+ if (htim->Instance == TIM4)
+ {
+ __HAL_RCC_TIM4_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM5_BASE)
+
+ if (htim->Instance == TIM5)
+ {
+ __HAL_RCC_TIM5_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM6_BASE)
+
+ if (htim->Instance == TIM6)
+ {
+ __HAL_RCC_TIM6_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM7_BASE)
+
+ if (htim->Instance == TIM7)
+ {
+ __HAL_RCC_TIM7_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM8_BASE)
+
+ if (htim->Instance == TIM8)
+ {
+ __HAL_RCC_TIM8_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM9_BASE)
+
+ if (htim->Instance == TIM9)
+ {
+ __HAL_RCC_TIM9_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM10_BASE)
+
+ if (htim->Instance == TIM10)
+ {
+ __HAL_RCC_TIM10_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM11_BASE)
+
+ if (htim->Instance == TIM11)
+ {
+ __HAL_RCC_TIM11_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM12_BASE)
+
+ if (htim->Instance == TIM12)
+ {
+ __HAL_RCC_TIM12_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM13_BASE)
+
+ if (htim->Instance == TIM13)
+ {
+ __HAL_RCC_TIM13_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM14_BASE)
+
+ if (htim->Instance == TIM14)
+ {
+ __HAL_RCC_TIM14_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM15_BASE)
+
+ if (htim->Instance == TIM15)
+ {
+ __HAL_RCC_TIM15_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM16_BASE)
+
+ if (htim->Instance == TIM16)
+ {
+ __HAL_RCC_TIM16_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM17_BASE)
+
+ if (htim->Instance == TIM17)
+ {
+ __HAL_RCC_TIM17_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM18_BASE)
+
+ if (htim->Instance == TIM18)
+ {
+ __HAL_RCC_TIM18_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM19_BASE)
+
+ if (htim->Instance == TIM19)
+ {
+ __HAL_RCC_TIM19_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM20_BASE)
+
+ if (htim->Instance == TIM20)
+ {
+ __HAL_RCC_TIM20_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM21_BASE)
+
+ if (htim->Instance == TIM21)
+ {
+ __HAL_RCC_TIM21_CLK_ENABLE();
+ }
+
+#endif
+#if defined(TIM22_BASE)
+
+ if (htim->Instance == TIM22)
+ {
+ __HAL_RCC_TIM22_CLK_ENABLE();
+ }
+
+#endif
+}
+
+/**
+ @brief Disable the timer clock
+ @param htim: TIM handle
+ @retval None
+*/
+void disableTimerClock(TIM_HandleTypeDef *htim)
+{
+ // Enable TIM clock
+#if defined(TIM1_BASE)
+ if (htim->Instance == TIM1)
+ {
+ __HAL_RCC_TIM1_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM2_BASE)
+
+ if (htim->Instance == TIM2)
+ {
+ __HAL_RCC_TIM2_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM3_BASE)
+
+ if (htim->Instance == TIM3)
+ {
+ __HAL_RCC_TIM3_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM4_BASE)
+
+ if (htim->Instance == TIM4)
+ {
+ __HAL_RCC_TIM4_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM5_BASE)
+
+ if (htim->Instance == TIM5)
+ {
+ __HAL_RCC_TIM5_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM6_BASE)
+
+ if (htim->Instance == TIM6)
+ {
+ __HAL_RCC_TIM6_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM7_BASE)
+
+ if (htim->Instance == TIM7)
+ {
+ __HAL_RCC_TIM7_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM8_BASE)
+
+ if (htim->Instance == TIM8)
+ {
+ __HAL_RCC_TIM8_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM9_BASE)
+
+ if (htim->Instance == TIM9)
+ {
+ __HAL_RCC_TIM9_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM10_BASE)
+
+ if (htim->Instance == TIM10)
+ {
+ __HAL_RCC_TIM10_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM11_BASE)
+
+ if (htim->Instance == TIM11)
+ {
+ __HAL_RCC_TIM11_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM12_BASE)
+
+ if (htim->Instance == TIM12)
+ {
+ __HAL_RCC_TIM12_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM13_BASE)
+
+ if (htim->Instance == TIM13)
+ {
+ __HAL_RCC_TIM13_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM14_BASE)
+
+ if (htim->Instance == TIM14)
+ {
+ __HAL_RCC_TIM14_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM15_BASE)
+
+ if (htim->Instance == TIM15)
+ {
+ __HAL_RCC_TIM15_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM16_BASE)
+
+ if (htim->Instance == TIM16)
+ {
+ __HAL_RCC_TIM16_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM17_BASE)
+
+ if (htim->Instance == TIM17)
+ {
+ __HAL_RCC_TIM17_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM18_BASE)
+
+ if (htim->Instance == TIM18)
+ {
+ __HAL_RCC_TIM18_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM19_BASE)
+
+ if (htim->Instance == TIM19)
+ {
+ __HAL_RCC_TIM19_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM20_BASE)
+
+ if (htim->Instance == TIM20)
+ {
+ __HAL_RCC_TIM20_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM21_BASE)
+
+ if (htim->Instance == TIM21)
+ {
+ __HAL_RCC_TIM21_CLK_DISABLE();
+ }
+
+#endif
+#if defined(TIM22_BASE)
+
+ if (htim->Instance == TIM22)
+ {
+ __HAL_RCC_TIM22_CLK_DISABLE();
+ }
+
+#endif
+}
+
+/**
+ @brief This function return IRQ number corresponding to update interrupt event of timer instance.
+ @param tim: timer instance
+ @retval IRQ number
+*/
+IRQn_Type getTimerUpIrq(TIM_TypeDef *tim)
+{
+ IRQn_Type IRQn = NonMaskableInt_IRQn;
+
+ if (tim != (TIM_TypeDef *)NC)
+ {
+ /* Get IRQn depending on TIM instance */
+ switch ((uint32_t)tim)
+ {
+#if defined(TIM1_BASE)
+
+ case (uint32_t)TIM1_BASE:
+ IRQn = TIM1_IRQn;
+ break;
+#endif
+#if defined(TIM2_BASE)
+
+ case (uint32_t)TIM2_BASE:
+ IRQn = TIM2_IRQn;
+ break;
+#endif
+#if defined(TIM3_BASE)
+
+ case (uint32_t)TIM3_BASE:
+ IRQn = TIM3_IRQn;
+ break;
+#endif
+#if defined(TIM4_BASE)
+
+ case (uint32_t)TIM4_BASE:
+ IRQn = TIM4_IRQn;
+ break;
+#endif
+#if defined(TIM5_BASE)
+
+ case (uint32_t)TIM5_BASE:
+ IRQn = TIM5_IRQn;
+ break;
+#endif
+
+ // KH
+#if 0
+#if defined(TIM6_BASE)
+
+ case (uint32_t)TIM6_BASE:
+ IRQn = TIM6_IRQn;
+ break;
+#endif
+#endif
+ //////
+
+#if defined(TIM7_BASE)
+
+ case (uint32_t)TIM7_BASE:
+ IRQn = TIM7_IRQn;
+ break;
+#endif
+#if defined(TIM8_BASE)
+
+ case (uint32_t)TIM8_BASE:
+ IRQn = TIM8_IRQn;
+ break;
+#endif
+#if defined(TIM9_BASE)
+
+ case (uint32_t)TIM9_BASE:
+ IRQn = TIM9_IRQn;
+ break;
+#endif
+#if defined(TIM10_BASE)
+
+ case (uint32_t)TIM10_BASE:
+ IRQn = TIM10_IRQn;
+ break;
+#endif
+#if defined(TIM11_BASE)
+
+ case (uint32_t)TIM11_BASE:
+ IRQn = TIM11_IRQn;
+ break;
+#endif
+#if defined(TIM12_BASE)
+
+ case (uint32_t)TIM12_BASE:
+ IRQn = TIM12_IRQn;
+ break;
+#endif
+#if defined(TIM13_BASE)
+
+ case (uint32_t)TIM13_BASE:
+ IRQn = TIM13_IRQn;
+ break;
+#endif
+#if defined(TIM14_BASE)
+
+ case (uint32_t)TIM14_BASE:
+ IRQn = TIM14_IRQn;
+ break;
+#endif
+#if defined(TIM15_BASE)
+
+ case (uint32_t)TIM15_BASE:
+ IRQn = TIM15_IRQn;
+ break;
+#endif
+#if defined(TIM16_BASE)
+
+ case (uint32_t)TIM16_BASE:
+ IRQn = TIM16_IRQn;
+ break;
+#endif
+#if defined(TIM17_BASE)
+
+ case (uint32_t)TIM17_BASE:
+ IRQn = TIM17_IRQn;
+ break;
+#endif
+#if defined(TIM18_BASE)
+
+ case (uint32_t)TIM18_BASE:
+ IRQn = TIM18_IRQn;
+ break;
+#endif
+#if defined(TIM19_BASE)
+
+ case (uint32_t)TIM19_BASE:
+ IRQn = TIM19_IRQn;
+ break;
+#endif
+#if defined(TIM20_BASE)
+
+ case (uint32_t)TIM20_BASE:
+ IRQn = TIM20_IRQn;
+ break;
+#endif
+#if defined(TIM21_BASE)
+
+ case (uint32_t)TIM21_BASE:
+ IRQn = TIM21_IRQn;
+ break;
+#endif
+#if defined(TIM22_BASE)
+
+ case (uint32_t)TIM22_BASE:
+ IRQn = TIM22_IRQn;
+ break;
+#endif
+
+ default:
+ //_Error_Handler("TIM: Unknown timer IRQn", (int)tim);
+ break;
+ }
+ }
+
+ return IRQn;
+}
+
+/**
+ @brief This function return IRQ number corresponding to Capture or Compare interrupt event of timer instance.
+ @param tim: timer instance
+ @retval IRQ number
+*/
+IRQn_Type getTimerCCIrq(TIM_TypeDef *tim)
+{
+ IRQn_Type IRQn = NonMaskableInt_IRQn;
+
+ if (tim != (TIM_TypeDef *)NC)
+ {
+ /* Get IRQn depending on TIM instance */
+ switch ((uint32_t)tim)
+ {
+#if defined(TIM1_BASE)
+
+ case (uint32_t)TIM1_BASE:
+ IRQn = TIM1_CC_IRQn;
+ break;
+#endif
+#if defined(TIM2_BASE)
+
+ case (uint32_t)TIM2_BASE:
+ IRQn = TIM2_IRQn;
+ break;
+#endif
+#if defined(TIM3_BASE)
+
+ case (uint32_t)TIM3_BASE:
+ IRQn = TIM3_IRQn;
+ break;
+#endif
+#if defined(TIM4_BASE)
+
+ case (uint32_t)TIM4_BASE:
+ IRQn = TIM4_IRQn;
+ break;
+#endif
+#if defined(TIM5_BASE)
+
+ case (uint32_t)TIM5_BASE:
+ IRQn = TIM5_IRQn;
+ break;
+#endif
+
+#if 0
+ // KH
+#if defined(TIM6_BASE)
+
+ case (uint32_t)TIM6_BASE:
+ IRQn = TIM6_IRQn;
+ break;
+#endif
+#endif
+ //////
+
+#if defined(TIM7_BASE)
+
+ case (uint32_t)TIM7_BASE:
+ IRQn = TIM7_IRQn;
+ break;
+#endif
+#if defined(TIM8_BASE)
+
+ case (uint32_t)TIM8_BASE:
+ IRQn = TIM8_CC_IRQn;
+ break;
+#endif
+#if defined(TIM9_BASE)
+
+ case (uint32_t)TIM9_BASE:
+ IRQn = TIM9_IRQn;
+ break;
+#endif
+#if defined(TIM10_BASE)
+
+ case (uint32_t)TIM10_BASE:
+ IRQn = TIM10_IRQn;
+ break;
+#endif
+#if defined(TIM11_BASE)
+
+ case (uint32_t)TIM11_BASE:
+ IRQn = TIM11_IRQn;
+ break;
+#endif
+#if defined(TIM12_BASE)
+
+ case (uint32_t)TIM12_BASE:
+ IRQn = TIM12_IRQn;
+ break;
+#endif
+#if defined(TIM13_BASE)
+
+ case (uint32_t)TIM13_BASE:
+ IRQn = TIM13_IRQn;
+ break;
+#endif
+#if defined(TIM14_BASE)
+
+ case (uint32_t)TIM14_BASE:
+ IRQn = TIM14_IRQn;
+ break;
+#endif
+#if defined(TIM15_BASE)
+
+ case (uint32_t)TIM15_BASE:
+ IRQn = TIM15_IRQn;
+ break;
+#endif
+#if defined(TIM16_BASE)
+
+ case (uint32_t)TIM16_BASE:
+ IRQn = TIM16_IRQn;
+ break;
+#endif
+#if defined(TIM17_BASE)
+
+ case (uint32_t)TIM17_BASE:
+ IRQn = TIM17_IRQn;
+ break;
+#endif
+#if defined(TIM18_BASE)
+
+ case (uint32_t)TIM18_BASE:
+ IRQn = TIM18_IRQn;
+ break;
+#endif
+#if defined(TIM19_BASE)
+
+ case (uint32_t)TIM19_BASE:
+ IRQn = TIM19_IRQn;
+ break;
+#endif
+#if defined(TIM20_BASE)
+
+ case (uint32_t)TIM20_BASE:
+ IRQn = TIM20_CC_IRQn;
+ break;
+#endif
+#if defined(TIM21_BASE)
+
+ case (uint32_t)TIM21_BASE:
+ IRQn = TIM21_IRQn;
+ break;
+#endif
+#if defined(TIM22_BASE)
+
+ case (uint32_t)TIM22_BASE:
+ IRQn = TIM22_IRQn;
+ break;
+#endif
+ break;
+
+ default:
+ //_Error_Handler("TIM: Unknown timer IRQn", (int)tim);
+ break;
+ }
+ }
+
+ return IRQn;
+}
+
+/**
+ @brief This function return the timer clock source.
+ @param tim: timer instance
+ @retval 1 = PCLK1 or 2 = PCLK2
+*/
+uint8_t getTimerClkSrc(TIM_TypeDef *tim)
+{
+ uint8_t clkSrc = 0;
+
+ if (tim != (TIM_TypeDef *)NC)
+#if defined(STM32F0xx) || defined(STM32G0xx)
+ /* TIMx source CLK is PCKL1 */
+ clkSrc = 1;
+
+#else
+ {
+ /* Get source clock depending on TIM instance */
+ switch ((uint32_t)tim)
+ {
+#if defined(TIM2_BASE)
+
+ case (uint32_t)TIM2:
+#endif
+#if defined(TIM3_BASE)
+ case (uint32_t)TIM3:
+#endif
+#if defined(TIM4_BASE)
+ case (uint32_t)TIM4:
+#endif
+#if defined(TIM5_BASE)
+ case (uint32_t)TIM5:
+#endif
+#if defined(TIM6_BASE)
+ case (uint32_t)TIM6:
+#endif
+#if defined(TIM7_BASE)
+ case (uint32_t)TIM7:
+#endif
+#if defined(TIM12_BASE)
+ case (uint32_t)TIM12:
+#endif
+#if defined(TIM13_BASE)
+ case (uint32_t)TIM13:
+#endif
+#if defined(TIM14_BASE)
+ case (uint32_t)TIM14:
+#endif
+#if defined(TIM18_BASE)
+ case (uint32_t)TIM18:
+#endif
+ clkSrc = 1;
+ break;
+#if defined(TIM1_BASE)
+
+ case (uint32_t)TIM1:
+#endif
+#if defined(TIM8_BASE)
+ case (uint32_t)TIM8:
+#endif
+#if defined(TIM9_BASE)
+ case (uint32_t)TIM9:
+#endif
+#if defined(TIM10_BASE)
+ case (uint32_t)TIM10:
+#endif
+#if defined(TIM11_BASE)
+ case (uint32_t)TIM11:
+#endif
+#if defined(TIM15_BASE)
+ case (uint32_t)TIM15:
+#endif
+#if defined(TIM16_BASE)
+ case (uint32_t)TIM16:
+#endif
+#if defined(TIM17_BASE)
+ case (uint32_t)TIM17:
+#endif
+#if defined(TIM19_BASE)
+ case (uint32_t)TIM19:
+#endif
+#if defined(TIM20_BASE)
+ case (uint32_t)TIM20:
+#endif
+#if defined(TIM21_BASE)
+ case (uint32_t)TIM21:
+#endif
+#if defined(TIM22_BASE)
+ case (uint32_t)TIM22:
+#endif
+ clkSrc = 2;
+ break;
+
+ default:
+ ////_Error_Handler("TIM: Unknown timer instance", (int)tim);
+ break;
+ }
+ }
+#endif
+ return clkSrc;
+}
+
+
+#endif /* HAL_TIM_MODULE_ENABLED && !HAL_TIM_MODULE_ONLY */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Gigatimer.h b/Gigatimer.h
new file mode 100644
index 0000000..6788b27
--- /dev/null
+++ b/Gigatimer.h
@@ -0,0 +1,198 @@
+/****************************************************************************************************************************
+ timer.h
+
+ For Portenta_H7 boards
+ Written by Khoi Hoang
+
+ Built by Khoi Hoang https://github.com/khoih-prog/Portenta_H7_TimerInterrupt
+ Licensed under MIT license
+
+ 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 Portenta_H7 STM32 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.
+
+ Version: 1.4.0
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.1 K.Hoang 15/09/2021 Initial coding for Portenta_H7
+ 1.3.0 K.Hoang 17/09/2021 Add PWM features and examples
+ 1.3.1 K.Hoang 21/09/2021 Fix warnings in PWM examples
+ 1.4.0 K.Hoang 22/01/2022 Fix `multiple-definitions` linker error. Fix bug
+ *****************************************************************************************************************************/
+
+// Modified from stm32 core v2.0.0
+
+/*
+ *******************************************************************************
+ Copyright (c) 2019, STMicroelectronics
+ All rights reserved.
+
+ This software component is licensed by ST under BSD 3-Clause license,
+ the "License"; You may not use this file except in compliance with the
+ License. You may obtain a copy of the License at:
+ opensource.org/licenses/BSD-3-Clause
+
+ *******************************************************************************
+*/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __GIGATIMER_H
+#define __GIGATIMER_H
+#if defined(ARDUINO_GIGA)
+/* Includes ------------------------------------------------------------------*/
+#include "PinNames.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(HAL_TIM_MODULE_ENABLED) && !defined(HAL_TIM_MODULE_ONLY)
+
+/* Exported constants --------------------------------------------------------*/
+#ifndef TIM_IRQ_PRIO
+#if (__CORTEX_M == 0x00U)
+#define TIM_IRQ_PRIO 3
+#else
+#define TIM_IRQ_PRIO 14
+#endif /* __CORTEX_M */
+
+#endif /* TIM_IRQ_PRIO */
+
+#ifndef TIM_IRQ_SUBPRIO
+#define TIM_IRQ_SUBPRIO 0
+#endif
+
+#if defined(TIM1_BASE) && !defined(TIM1_IRQn)
+#define TIM1_IRQn TIM1_UP_IRQn
+#define TIM1_IRQHandler TIM1_UP_IRQHandler
+#endif
+
+#if defined(TIM8_BASE) && !defined(TIM8_IRQn)
+#define TIM8_IRQn TIM8_UP_TIM13_IRQn
+#define TIM8_IRQHandler TIM8_UP_TIM13_IRQHandler
+#endif
+
+#if defined(TIM12_BASE) && !defined(TIM12_IRQn)
+#define TIM12_IRQn TIM8_BRK_TIM12_IRQn
+#define TIM12_IRQHandler TIM8_BRK_TIM12_IRQHandler
+#endif
+
+#if defined(TIM13_BASE) && !defined(TIM13_IRQn)
+#define TIM13_IRQn TIM8_UP_TIM13_IRQn
+#endif
+
+#if defined(TIM14_BASE) && !defined(TIM14_IRQn)
+#define TIM14_IRQn TIM8_TRG_COM_TIM14_IRQn
+#define TIM14_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler
+#endif
+
+
+typedef enum
+{
+#if defined(TIM1_BASE)
+ TIMER1_INDEX,
+#endif
+#if defined(TIM2_BASE)
+ TIMER2_INDEX,
+#endif
+#if defined(TIM3_BASE)
+ TIMER3_INDEX,
+#endif
+#if defined(TIM4_BASE)
+ TIMER4_INDEX,
+#endif
+#if defined(TIM5_BASE)
+ TIMER5_INDEX,
+#endif
+#if defined(TIM6_BASE)
+ TIMER6_INDEX,
+#endif
+#if defined(TIM7_BASE)
+ TIMER7_INDEX,
+#endif
+#if defined(TIM8_BASE)
+ TIMER8_INDEX,
+#endif
+#if defined(TIM9_BASE)
+ TIMER9_INDEX,
+#endif
+#if defined(TIM10_BASE)
+ TIMER10_INDEX,
+#endif
+#if defined(TIM11_BASE)
+ TIMER11_INDEX,
+#endif
+#if defined(TIM12_BASE)
+ TIMER12_INDEX,
+#endif
+#if defined(TIM13_BASE)
+ TIMER13_INDEX,
+#endif
+#if defined(TIM14_BASE)
+ TIMER14_INDEX,
+#endif
+#if defined(TIM15_BASE)
+ TIMER15_INDEX,
+#endif
+#if defined(TIM16_BASE)
+ TIMER16_INDEX,
+#endif
+#if defined(TIM17_BASE)
+ TIMER17_INDEX,
+#endif
+#if defined(TIM18_BASE)
+ TIMER18_INDEX,
+#endif
+#if defined(TIM19_BASE)
+ TIMER19_INDEX,
+#endif
+#if defined(TIM20_BASE)
+ TIMER20_INDEX,
+#endif
+#if defined(TIM21_BASE)
+ TIMER21_INDEX,
+#endif
+#if defined(TIM22_BASE)
+ TIMER22_INDEX,
+#endif
+
+ TIMER_NUM,
+ UNKNOWN_TIMER = 0XFFFF
+} timer_index_t;
+
+
+// This structure is used to be able to get HardwareTimer instance (C++ class)
+// from handler (C structure) specially for interrupt management
+typedef struct
+{
+ // Those 2 first fields must remain in this order at the beginning of the structure
+ void *__this;
+ TIM_HandleTypeDef handle;
+ uint32_t preemptPriority;
+ uint32_t subPriority;
+} timerObj_t;
+
+/* Exported functions ------------------------------------------------------- */
+timerObj_t *get_timer_obj(TIM_HandleTypeDef *htim);
+
+void enableTimerClock(TIM_HandleTypeDef *htim);
+void disableTimerClock(TIM_HandleTypeDef *htim);
+
+uint32_t getTimerIrq(TIM_TypeDef *tim);
+uint8_t getTimerClkSrc(TIM_TypeDef *tim);
+
+IRQn_Type getTimerUpIrq(TIM_TypeDef *tim);
+IRQn_Type getTimerCCIrq(TIM_TypeDef *tim);
+
+#endif /* HAL_TIM_MODULE_ENABLED && !HAL_TIM_MODULE_ONLY */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif /* __GIGATIMER_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/MotorDriver.cpp b/MotorDriver.cpp
index 61e229f..419798f 100644
--- a/MotorDriver.cpp
+++ b/MotorDriver.cpp
@@ -5,6 +5,7 @@
* © 2020-2023 Harald Barth
* © 2020-2021 Chris Harlow
* © 2023 Colin Murdoch
+ * © 2023 Travis Farmer
* All rights reserved.
*
* This file is part of CommandStation-EX
@@ -57,6 +58,7 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i
getFastPin(F("SIG"),signalPin,fastSignalPin);
pinMode(signalPin, OUTPUT);
+ #ifndef ARDUINO_GIGA // no giga
fastSignalPin.shadowinout = NULL;
if (HAVE_PORTA(fastSignalPin.inout == &PORTA)) {
DIAG(F("Found PORTA pin %d"),signalPin);
@@ -88,13 +90,14 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i
fastSignalPin.shadowinout = fastSignalPin.inout;
fastSignalPin.inout = &shadowPORTF;
}
-
+ #endif // giga
signalPin2=signal_pin2;
if (signalPin2!=UNUSED_PIN) {
dualSignal=true;
getFastPin(F("SIG2"),signalPin2,fastSignalPin2);
pinMode(signalPin2, OUTPUT);
+ #ifndef ARDUINO_GIGA // no giga
fastSignalPin2.shadowinout = NULL;
if (HAVE_PORTA(fastSignalPin2.inout == &PORTA)) {
DIAG(F("Found PORTA pin %d"),signalPin2);
@@ -126,6 +129,7 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i
fastSignalPin2.shadowinout = fastSignalPin2.inout;
fastSignalPin2.inout = &shadowPORTF;
}
+ #endif // giga
}
else dualSignal=false;
@@ -501,8 +505,16 @@ unsigned int MotorDriver::mA2raw( unsigned int mA) {
return (int32_t)mA * senseScale / senseFactorInternal;
}
+
void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & result) {
// DIAG(F("MotorDriver %S Pin=%d,"),type,pin);
+#if defined(ARDUINO_GIGA) // yes giga
+ (void)type;
+ (void)input; // no warnings please
+
+ result = pin;
+
+#else // no giga
(void) type; // avoid compiler warning if diag not used above.
#if defined(ARDUINO_ARCH_SAMD)
PortGroup *port = digitalPinToPort(pin);
@@ -517,6 +529,7 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res
result.inout = portOutputRegister(port);
result.maskHIGH = digitalPinToBitMask(pin);
result.maskLOW = ~result.maskHIGH;
+#endif // giga
// DIAG(F(" port=0x%x, inoutpin=0x%x, isinput=%d, mask=0x%x"),port, result.inout,input,result.maskHIGH);
}
diff --git a/MotorDriver.h b/MotorDriver.h
index 20a91d3..ecc0ae0 100644
--- a/MotorDriver.h
+++ b/MotorDriver.h
@@ -4,6 +4,7 @@
* © 2021 Fred Decker
* © 2020 Chris Harlow
* © 2022 Harald Barth
+ * © 2023 Travis Farmer
* All rights reserved.
*
* This file is part of CommandStation-EX
@@ -30,12 +31,21 @@
// use powers of two so we can do logical and/or on the track modes in if clauses.
enum TRACK_MODE : byte {TRACK_MODE_NONE = 1, TRACK_MODE_MAIN = 2, TRACK_MODE_PROG = 4,
TRACK_MODE_DC = 8, TRACK_MODE_DCX = 16, TRACK_MODE_EXT = 32};
+#if defined(ARDUINO_GIGA) // yes giga
+#define setHIGH(fastpin) digitalWrite(fastpin,1)
+#define setLOW(fastpin) digitalWrite(fastpin,0)
+#else // no giga
#define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH
#define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW
+#endif // giga
+#if defined(ARDUINO_GIGA) // yes giga
+#define isHIGH(fastpin) ((PinStatus)digitalRead(fastpin)==1)
+#define isLOW(fastpin) ((PinStatus)digitalRead(fastpin)==0)
+#else // no giga
#define isHIGH(fastpin) (*fastpin.inout & fastpin.maskHIGH)
#define isLOW(fastpin) (!isHIGH(fastpin))
-
+#endif // giga
#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
@@ -117,12 +127,19 @@ typedef uint32_t portreg_t;
typedef uint8_t portreg_t;
#endif
+#if defined(ARDUINO_GIGA) // yes giga
+typedef int FASTPIN;
+
+
+#else // no giga
struct FASTPIN {
volatile portreg_t *inout;
portreg_t maskHIGH;
portreg_t maskLOW;
volatile portreg_t *shadowinout;
};
+#endif // giga
+
// The port registers that are shadowing
// the real port registers. These are
// defined in Motordriver.cpp
@@ -148,6 +165,12 @@ class MotorDriver {
// otherwise the call from interrupt context can undo whatever we do
// from outside interrupt
void setBrake( bool on, bool interruptContext=false);
+ #if defined(ARDUINO_GIGA) // yes giga
+ __attribute__((always_inline)) inline void setSignal( bool high) {
+ digitalWrite(signalPin, high);
+ if (dualSignal) digitalWrite(signalPin2, !high);
+ };
+ #else // no giga
__attribute__((always_inline)) inline void setSignal( bool high) {
if (trackPWM) {
DCCTimer::setPWM(signalPin,high);
@@ -163,6 +186,7 @@ class MotorDriver {
}
}
};
+ #endif // giga
inline void enableSignal(bool on) {
if (on)
pinMode(signalPin, OUTPUT);
@@ -184,6 +208,12 @@ class MotorDriver {
int getCurrentRaw(bool fromISR=false);
unsigned int raw2mA( int raw);
unsigned int mA2raw( unsigned int mA);
+#if defined(ARDUINO_GIGA) // yes giga
+ inline bool digitalPinHasPWM(int pin) {
+ if (pin!=UNUSED_PIN && pin>=2 && pin<=13) return true;
+ else return false;
+ }
+#endif // giga
inline bool brakeCanPWM() {
#if defined(ARDUINO_ARCH_ESP32)
return (brakePin != UNUSED_PIN); // This was just (true) but we probably do need to check for UNUSED_PIN!
diff --git a/WifiInterface.cpp b/WifiInterface.cpp
index 27830bb..a1a6787 100644
--- a/WifiInterface.cpp
+++ b/WifiInterface.cpp
@@ -3,6 +3,7 @@
* © 2020-2022 Harald Barth
* © 2020-2022 Chris Harlow
* © 2023 Nathan Kellenicki
+ * © 2023 Travis Farmer
* All rights reserved.
*
* This file is part of CommandStation-EX
@@ -57,6 +58,14 @@ Stream * WifiInterface::wifiStream;
#define SERIAL3 Serial3
#endif
+#if defined(ARDUINO_GIGA) // yes giga
+#define NUM_SERIAL 5
+#define SERIAL1 Serial1
+#define SERIAL2 Serial2
+#define SERIAL3 Serial3
+#define SERIAL4 Serial4
+#endif // giga
+
#if defined(ARDUINO_ARCH_STM32)
// Handle serial ports availability on STM32 for variants!
// #undef NUM_SERIAL
diff --git a/defines.h b/defines.h
index e90d7f4..e530b03 100644
--- a/defines.h
+++ b/defines.h
@@ -5,6 +5,7 @@
* © 2021 Fred Decker
* © 2020-2022 Harald Barth
* © 2020-2021 Chris Harlow
+ * © 2023 Travis Farmer
*
* This file is part of CommandStation-EX
*
@@ -147,7 +148,25 @@
// #ifndef I2C_USE_WIRE
// #define I2C_USE_WIRE
// #endif
-
+#elif defined(ARDUINO_GIGA)
+ #define ARDUINO_TYPE "Giga"
+ #ifndef DISABLE_EEPROM
+ #define DISABLE_EEPROM
+ #endif
+ //#if !defined(I2C_USE_WIRE)
+ //#define I2C_USE_WIRE
+ //#endif
+ #define SDA I2C_SDA
+ #define SCL I2C_SCL
+ #define DCC_EX_TIMER
+ // these don't work...
+ //extern const uint16_t PROGMEM port_to_input_PGM[];
+ //extern const uint16_t PROGMEM port_to_output_PGM[];
+ //extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
+ //#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
+ //#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
+ //#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
+
/* TODO when ready
#elif defined(ARDUINO_ARCH_RP2040)
#define ARDUINO_TYPE "RP2040"