diff --git a/cores/arduino/HardwareTimer.cpp b/cores/arduino/HardwareTimer.cpp
new file mode 100644
index 0000000000..86d279591c
--- /dev/null
+++ b/cores/arduino/HardwareTimer.cpp
@@ -0,0 +1,1429 @@
+/*
+ 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
+*/
+
+#include "Arduino.h"
+#include "HardwareTimer.h"
+
+#ifdef HAL_TIM_MODULE_ENABLED
+
+/* 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 */
+HardwareTimerObj_t *HardwareTimer_Handle[TIMER_NUM] = {NULL};
+
+IRQn_Type getTimerUpIrq(TIM_TypeDef *tim);
+IRQn_Type getTimerCCIrq(TIM_TypeDef *tim);
+
+/**
+ * @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] = &_HardwareTimerObj;
+
+ _HardwareTimerObj.handle.Instance = instance;
+ _HardwareTimerObj.handle.Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
+ _HardwareTimerObj.handle.hdma[0] = NULL;
+ _HardwareTimerObj.handle.hdma[1] = NULL;
+ _HardwareTimerObj.handle.hdma[2] = NULL;
+ _HardwareTimerObj.handle.hdma[3] = NULL;
+ _HardwareTimerObj.handle.hdma[4] = NULL;
+ _HardwareTimerObj.handle.hdma[5] = NULL;
+ _HardwareTimerObj.handle.hdma[6] = NULL;
+ _HardwareTimerObj.handle.Lock = HAL_UNLOCKED;
+ _HardwareTimerObj.handle.State = HAL_TIM_STATE_RESET;
+
+ _HardwareTimerObj.handle.Instance = instance;
+ _HardwareTimerObj.__this = (void *)this;
+
+ // Enable Timer clock
+ enableTimerClock(&(_HardwareTimerObj.handle));
+
+ // Configure HAL structure for all channels
+ for (int i = 0; i < TIMER_CHANNELS; i++) {
+ _channelOC[i].OCMode = TIMER_NOT_USED;
+ _channelOC[i].OCPolarity = TIM_OCPOLARITY_HIGH;
+ _channelOC[i].OCFastMode = TIM_OCFAST_DISABLE;
+
+#if defined(TIM_CR2_OIS1)
+ _channelOC[i].OCIdleState = TIM_OCIDLESTATE_RESET;
+#endif
+#if defined(TIM_CCER_CC1NE)
+ _channelOC[i].OCNPolarity = TIM_OCNPOLARITY_HIGH;
+#if defined(TIM_CR2_OIS1)
+ _channelOC[i].OCNIdleState = TIM_OCNIDLESTATE_RESET;
+#endif
+#endif
+ _channelIC[i].ICPolarity = TIMER_NOT_USED;
+ _channelIC[i].ICSelection = TIM_ICSELECTION_DIRECTTI;
+ _channelIC[i].ICPrescaler = TIM_ICPSC_DIV1;
+ _channelIC[i].ICFilter = 0;
+
+ for (int i = 0; i < TIMER_CHANNELS ; i++) {
+ callbacks[i] = NULL;
+ }
+ }
+}
+
+/**
+ * @brief Pause HardwareTimer: stop timer
+ * @param None
+ * @retval None
+ */
+void HardwareTimer::pause()
+{
+ HAL_TIM_Base_Stop_IT(&(_HardwareTimerObj.handle));
+}
+
+/**
+ * @brief Start or resume HardwareTimer: all channels are resumed, interrupts are enabled if necessary
+ * @param None
+ * @retval None
+ */
+void HardwareTimer::resume(void)
+{
+ _HardwareTimerObj.handle.Init.CounterMode = TIM_COUNTERMODE_UP;
+ _HardwareTimerObj.handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+#if defined(TIM_RCR_REP)
+ _HardwareTimerObj.handle.Init.RepetitionCounter = 0;
+#endif
+ _HardwareTimerObj.handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
+ HAL_TIM_Base_Init(&(_HardwareTimerObj.handle));
+
+ // Start timer with IT if required
+ if (callbacks[0] != NULL) {
+ HAL_TIM_Base_Start_IT(&(_HardwareTimerObj.handle));
+ } else {
+ HAL_TIM_Base_Start(&(_HardwareTimerObj.handle));
+ }
+
+ resumeChannel(1);
+ resumeChannel(2);
+ resumeChannel(3);
+ resumeChannel(4);
+}
+
+/**
+ * @brief Convert arduino 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 Configure specified channel and resume/start timer
+ * @param Arduino channel [1..4]
+ * @retval None
+ */
+void HardwareTimer::resumeChannel(uint32_t channel)
+{
+ int timChannel = getChannel(channel);
+ if (timChannel == -1) {
+ Error_Handler();
+ }
+
+ if (IS_TIM_PWM_MODE(_channelOC[channel - 1].OCMode)) {
+ HAL_TIM_PWM_ConfigChannel(&(_HardwareTimerObj.handle), &_channelOC[channel - 1], timChannel);
+
+ if ((channel < (TIMER_CHANNELS + 1)) && (callbacks[channel] != NULL)) {
+ // Only channel 1..4 can have interruption
+#if defined(TIM_CCER_CC1NE)
+ if (isComplementaryChannel[channel]) {
+ HAL_TIMEx_PWMN_Start_IT(&(_HardwareTimerObj.handle), timChannel);
+ } else
+#endif
+ {
+ HAL_TIM_PWM_Start_IT(&(_HardwareTimerObj.handle), timChannel);
+ }
+ } else {
+#if defined(TIM_CCER_CC1NE)
+ if (isComplementaryChannel[channel]) {
+ HAL_TIMEx_PWMN_Start(&(_HardwareTimerObj.handle), timChannel);
+ } else
+#endif
+ {
+ HAL_TIM_PWM_Start(&(_HardwareTimerObj.handle), timChannel);
+ }
+ }
+ } else if (IS_TIM_OC_MODE(_channelOC[channel - 1].OCMode)) {
+ HAL_TIM_OC_ConfigChannel(&(_HardwareTimerObj.handle), &_channelOC[channel - 1], timChannel);
+
+ if ((channel < (TIMER_CHANNELS + 1)) && (callbacks[channel] != NULL)) {
+ // Only channel 1..4 can have interruption
+#if defined(TIM_CCER_CC1NE)
+ if (isComplementaryChannel[channel]) {
+ HAL_TIMEx_OCN_Start_IT(&(_HardwareTimerObj.handle), timChannel);
+ } else
+#endif
+ {
+ HAL_TIM_OC_Start_IT(&(_HardwareTimerObj.handle), timChannel);
+ }
+ } else {
+#if defined(TIM_CCER_CC1NE)
+ if (isComplementaryChannel[channel]) {
+ HAL_TIMEx_OCN_Start(&(_HardwareTimerObj.handle), timChannel);
+ } else
+#endif
+ {
+ HAL_TIM_OC_Start(&(_HardwareTimerObj.handle), timChannel);
+ }
+ }
+ } else if (_channelIC[channel - 1].ICPolarity != TIMER_NOT_USED) {
+ HAL_TIM_IC_ConfigChannel(&(_HardwareTimerObj.handle), &_channelIC[channel - 1], timChannel);
+
+ if (callbacks[channel] != NULL) {
+ HAL_TIM_IC_Start_IT(&(_HardwareTimerObj.handle), timChannel);
+ } else {
+ HAL_TIM_IC_Start(&(_HardwareTimerObj.handle), timChannel);
+ }
+ }
+}
+
+/**
+ * @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 (_HardwareTimerObj.handle.Init.Prescaler + 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
+ __HAL_TIM_SET_PRESCALER(&_HardwareTimerObj.handle, prescaler - 1);
+ _HardwareTimerObj.handle.Init.Prescaler = 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 = __HAL_TIM_GET_AUTORELOAD(&(_HardwareTimerObj.handle));
+ uint32_t Prescalerfactor = _HardwareTimerObj.handle.Instance->PSC + 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)
+ * @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 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;
+ __HAL_TIM_SET_PRESCALER(&_HardwareTimerObj.handle, Prescalerfactor - 1);
+ _HardwareTimerObj.handle.Init.Prescaler = Prescalerfactor - 1;
+ ARR_RegisterValue = (period_cyc / Prescalerfactor) - 1;
+ break;
+ case HERTZ_FORMAT:
+ period_cyc = getTimerClkFreq() / overflow;
+ Prescalerfactor = (period_cyc / 0x10000) + 1;
+ __HAL_TIM_SET_PRESCALER(&_HardwareTimerObj.handle, Prescalerfactor - 1);
+ _HardwareTimerObj.handle.Init.Prescaler = Prescalerfactor - 1;
+ ARR_RegisterValue = (period_cyc / Prescalerfactor) - 1;
+ break;
+ case TICK_FORMAT:
+ default :
+ ARR_RegisterValue = overflow - 1;
+ break;
+ }
+
+ __HAL_TIM_SET_AUTORELOAD(&_HardwareTimerObj.handle, ARR_RegisterValue);
+ _HardwareTimerObj.handle.Init.Period = 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 = __HAL_TIM_GET_COUNTER(&(_HardwareTimerObj.handle));
+ uint32_t Prescalerfactor = _HardwareTimerObj.handle.Instance->PSC + 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 = _HardwareTimerObj.handle.Instance->PSC + 1;
+ switch (format) {
+ case MICROSEC_FORMAT:
+ CNT_RegisterValue = ((counter * (getTimerClkFreq() / 1000000)) / Prescalerfactor) - 1 ;
+ break;
+ case HERTZ_FORMAT:
+ CNT_RegisterValue = (uint32_t)((getTimerClkFreq() / (counter * Prescalerfactor)) - 1);
+ break;
+ case TICK_FORMAT:
+ default :
+ CNT_RegisterValue = counter - 1;
+ break;
+ }
+ __HAL_TIM_SET_COUNTER(&(_HardwareTimerObj.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)
+{
+ if (getChannel(channel) == -1) {
+ Error_Handler();
+ }
+
+ switch (mode) {
+ case TIMER_OUTPUT_COMPARE:
+ _channelOC[channel - 1].OCMode = TIM_OCMODE_TIMING;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ case TIMER_OUTPUT_COMPARE_ACTIVE:
+ _channelOC[channel - 1].OCMode = TIM_OCMODE_ACTIVE;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ case TIMER_OUTPUT_COMPARE_INACTIVE:
+ _channelOC[channel - 1].OCMode = TIM_OCMODE_ACTIVE;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ case TIMER_OUTPUT_COMPARE_TOGGLE:
+ _channelOC[channel - 1].OCMode = TIM_OCMODE_TOGGLE;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ case TIMER_OUTPUT_COMPARE_PWM1:
+ _channelOC[channel - 1].OCMode = TIM_OCMODE_PWM1;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ case TIMER_OUTPUT_COMPARE_PWM2:
+ _channelOC[channel - 1].OCMode = TIM_OCMODE_PWM2;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ case TIMER_OUTPUT_COMPARE_FORCED_ACTIVE:
+ _channelOC[channel - 1].OCMode = TIM_OCMODE_FORCED_ACTIVE;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ case TIMER_OUTPUT_COMPARE_FORCED_INACTIVE:
+ _channelOC[channel - 1].OCMode = TIM_OCMODE_FORCED_INACTIVE;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ case TIMER_INPUT_CAPTURE_RISING:
+ _channelIC[channel - 1].ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
+ _channelIC[0].ICSelection = TIM_ICSELECTION_DIRECTTI;
+ _channelOC[channel - 1].OCMode = TIMER_NOT_USED;
+ break;
+ case TIMER_INPUT_CAPTURE_FALLING:
+ _channelIC[channel - 1].ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
+ _channelIC[0].ICSelection = TIM_ICSELECTION_DIRECTTI;
+ _channelOC[channel - 1].OCMode = TIMER_NOT_USED;
+ break;
+ case TIMER_INPUT_CAPTURE_BOTHEDGE:
+ _channelIC[channel - 1].ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
+ _channelOC[channel - 1].OCMode = TIMER_NOT_USED;
+ break;
+ case TIMER_INPUT_FREQ_DUTY_MEASUREMENT:
+ switch (channel) {
+ case 1:
+ _channelIC[0].ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
+ _channelIC[0].ICSelection = TIM_ICSELECTION_DIRECTTI;
+ _channelIC[1].ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
+ _channelIC[1].ICSelection = TIM_ICSELECTION_INDIRECTTI;
+ break;
+ case 2:
+ _channelIC[1].ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
+ _channelIC[1].ICSelection = TIM_ICSELECTION_DIRECTTI;
+ _channelIC[0].ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
+ _channelIC[0].ICSelection = TIM_ICSELECTION_INDIRECTTI;
+ break;
+ case 3:
+ _channelIC[2].ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
+ _channelIC[2].ICSelection = TIM_ICSELECTION_DIRECTTI;
+ _channelIC[3].ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
+ _channelIC[3].ICSelection = TIM_ICSELECTION_INDIRECTTI;
+ break;
+ case 4:
+ _channelIC[3].ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
+ _channelIC[3].ICSelection = TIM_ICSELECTION_DIRECTTI;
+ _channelIC[2].ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
+ _channelIC[2].ICSelection = TIM_ICSELECTION_INDIRECTTI;
+ break;
+ default:
+ break;
+ }
+ _channelOC[channel - 1].OCMode = TIMER_NOT_USED;
+ break;
+ case TIMER_DISABLED:
+ _channelOC[channel - 1].OCMode = TIMER_NOT_USED;
+ _channelIC[channel - 1].ICSelection = TIM_ICSELECTION_DIRECTTI;
+ _channelIC[channel - 1].ICPolarity = TIMER_NOT_USED;
+ break;
+ default:
+ break;
+ }
+
+ if (pin != NC) {
+ if ((int)get_pwm_channel(pin) == getChannel(channel)) {
+ /* Configure PWM GPIO pins */
+ pinmap_pinout(pin, PinMap_PWM);
+ } else {
+ // Pin doesn't match with timer output channels
+ Error_Handler();
+ }
+
+#if defined(TIM_CCER_CC1NE)
+ isComplementaryChannel[channel] = STM_PIN_INVERTED(pinmap_function(pin, PinMap_PWM));
+#endif
+ }
+}
+
+/**
+ * @brief Set channel Capture/Compare register
+ * @param channel: Arduino channel [1..4]
+ * @param compare: compare value depending on format
+ * @param format of compare parameter. If ommited default format is Tick
+ * TICK_FORMAT: compare is the number of tick
+ * MICROSEC_FORMAT: compare is the number of microsecondes
+ * HERTZ_FORMAT: compare is the frequency in hertz
+ * @retval None
+ */
+void HardwareTimer::setCaptureCompare(uint32_t channel, uint32_t compare, TimerCompareFormat_t format)
+{
+ int timChannel = getChannel(channel);
+ uint32_t Prescalerfactor = _HardwareTimerObj.handle.Instance->PSC + 1;
+ uint32_t CCR_RegisterValue;
+
+ if (timChannel == -1) {
+ Error_Handler();
+ }
+
+ switch (format) {
+ case MICROSEC_COMPARE_FORMAT:
+ CCR_RegisterValue = ((compare * (getTimerClkFreq() / 1000000)) / Prescalerfactor) - 1 ;
+ break;
+ case HERTZ_COMPARE_FORMAT:
+ CCR_RegisterValue = (getTimerClkFreq() / (compare * Prescalerfactor)) - 1;
+ break;
+ case PERCENT_COMPARE_FORMAT:
+ CCR_RegisterValue = ((__HAL_TIM_GET_AUTORELOAD(&(_HardwareTimerObj.handle)) + 1) * compare) / 100;
+ break;
+ case RESOLUTION_8B_COMPARE_FORMAT:
+ CCR_RegisterValue = ((__HAL_TIM_GET_AUTORELOAD(&(_HardwareTimerObj.handle)) + 1) * compare) / 255 ;
+ break;
+ case RESOLUTION_12B_COMPARE_FORMAT:
+ CCR_RegisterValue = ((__HAL_TIM_GET_AUTORELOAD(&(_HardwareTimerObj.handle)) + 1) * compare) / 4095 ;
+ break;
+ case TICK_COMPARE_FORMAT:
+ default :
+ CCR_RegisterValue = compare - 1;
+ break;
+ }
+
+ __HAL_TIM_SET_COMPARE(&(_HardwareTimerObj.handle), timChannel, CCR_RegisterValue);
+ _channelOC[channel - 1].Pulse = CCR_RegisterValue;
+}
+
+/**
+ * @brief Retrieve Capture/Compare value
+ * @param channel: Arduino channel [1..4]
+ * @param format of return value. If ommited default format is Tick
+ * TICK_FORMAT: return value is the number of tick for Capture/Compare value
+ * MICROSEC_FORMAT: return value is the number of microsecondes for Capture/Compare value
+ * HERTZ_FORMAT: return value is the frequency in hertz for Capture/Compare value
+ * @retval None
+ */
+uint32_t HardwareTimer::getCaptureCompare(uint32_t channel, TimerCompareFormat_t format)
+{
+ int timChannel = getChannel(channel);
+ uint32_t CCR_RegisterValue = __HAL_TIM_GET_COMPARE(&(_HardwareTimerObj.handle), timChannel);
+ uint32_t Prescalerfactor = _HardwareTimerObj.handle.Instance->PSC + 1;
+ uint32_t return_value;
+
+ if (timChannel == -1) {
+ Error_Handler();
+ }
+
+ switch (format) {
+ case MICROSEC_COMPARE_FORMAT:
+ return_value = (uint32_t)((CCR_RegisterValue * Prescalerfactor * 1000000.0) / getTimerClkFreq());
+ break;
+ case HERTZ_COMPARE_FORMAT:
+ return_value = (uint32_t)(getTimerClkFreq() / (CCR_RegisterValue * Prescalerfactor));
+ break;
+ case PERCENT_COMPARE_FORMAT:
+ return_value = (CCR_RegisterValue * 100) / __HAL_TIM_GET_AUTORELOAD(&(_HardwareTimerObj.handle));
+ break;
+ case RESOLUTION_8B_COMPARE_FORMAT:
+ return_value = (CCR_RegisterValue * 255) / __HAL_TIM_GET_AUTORELOAD(&(_HardwareTimerObj.handle));
+ break;
+ case RESOLUTION_12B_COMPARE_FORMAT:
+ return_value = (CCR_RegisterValue * 4095) / __HAL_TIM_GET_AUTORELOAD(&(_HardwareTimerObj.handle));
+ break;
+ case TICK_COMPARE_FORMAT:
+ default :
+ return_value = CCR_RegisterValue;
+ break;
+ }
+ return return_value;
+}
+
+/**
+ * @param channel: Arduino channel [1..4]
+ * @param pin: Arduino pin number, ex D1, 1 or PA1
+ * @param frequency: PWM frequency expessed in hertz
+ * @param dutycycle: PWM dutycycle expressed in percentage
+ * @param format of return value. If ommited default format is Tick
+ * TICK_FORMAT: return value is the number of tick for Capture/Compare value
+ * MICROSEC_FORMAT: return value is the number of microsecondes for Capture/Compare value
+ * HERTZ_FORMAT: return value is the frequency in hertz for Capture/Compare value
+ * @retval None
+ */
+void HardwareTimer::setPWM(uint32_t channel, uint32_t pin, uint32_t frequency, uint32_t dutycycle, void (*PeriodCallback)(HardwareTimer *), void (*CompareCallback)(HardwareTimer *))
+{
+ setPWM(channel, digitalPinToPinName(pin), frequency, dutycycle, PeriodCallback, CompareCallback);
+}
+
+/**
+ * @brief All in one function to configure PWM
+ * @param channel: Arduino channel [1..4]
+ * @param pin: pin name, ex PB_0
+ * @param frequency: PWM frequency expessed in hertz
+ * @param dutycycle: PWM dutycycle expressed in percentage
+ * @param format of return value. If ommited default format is Tick
+ * TICK_FORMAT: return value is the number of tick for Capture/Compare value
+ * MICROSEC_FORMAT: return value is the number of microsecondes for Capture/Compare value
+ * HERTZ_FORMAT: return value is the frequency in hertz for Capture/Compare value
+ * @retval None
+ */
+void HardwareTimer::setPWM(uint32_t channel, PinName pin, uint32_t frequency, uint32_t dutycycle, void (*PeriodCallback)(HardwareTimer *), void (*CompareCallback)(HardwareTimer *))
+{
+ setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
+ setOverflow(frequency, HERTZ_FORMAT);
+ setCaptureCompare(channel, dutycycle, PERCENT_COMPARE_FORMAT);
+ if (PeriodCallback != NULL) {
+ attachInterrupt(PeriodCallback);
+ }
+ if (CompareCallback != NULL) {
+ attachInterrupt(channel, CompareCallback);
+ }
+ resume();
+}
+
+/**
+ * @brief Attach interrupt callback on update (rollover) event
+ * @param callback: interrupt callback
+ * @retval None
+ */
+void HardwareTimer::attachInterrupt(void (*callback)(HardwareTimer *))
+{
+ callbacks[0] = callback;
+}
+
+/**
+ * @brief Dettach interrupt callback on update (rollover) event
+ * @retval None
+ */
+void HardwareTimer::detachInterrupt()
+{
+ callbacks[0] = NULL;
+}
+
+/**
+ * @brief Attach interrupt callback on Capture/Compare event
+ * @param channel: Arduino channel [1..4]
+ * @param callback: interrupt callback
+ * @retval None
+ */
+void HardwareTimer::attachInterrupt(uint32_t channel, void (*callback)(HardwareTimer *))
+{
+ if ((channel == 0) || (channel > (TIMER_CHANNELS + 1))) {
+ Error_Handler(); // only channel 1..4 have an interrupt
+ }
+
+ callbacks[channel] = callback;
+}
+
+/**
+ * @brief Dettach interrupt callback on Capture/Compare event
+ * @param channel: Arduino channel [1..4]
+ * @retval None
+ */
+void HardwareTimer::detachInterrupt(uint32_t channel)
+{
+ if ((channel == 0) || (channel > (TIMER_CHANNELS + 1))) {
+ Error_Handler(); // only channel 1..4 have an interrupt
+ }
+
+ callbacks[channel] = NULL;
+}
+
+/**
+ * @brief Generate an update event to force all registers (Autoreload, prescaler, compare) to be taken into account
+ * @retval None
+ */
+void HardwareTimer::refresh()
+{
+ HAL_TIM_GenerateEvent(&(_HardwareTimerObj.handle), TIM_EVENTSOURCE_UPDATE);
+}
+
+/**
+ * @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 == NULL) {
+ Error_Handler();
+ }
+
+ HardwareTimerObj_t *obj = get_timer_obj(htim);
+ HardwareTimer *HT = (HardwareTimer *)(obj->__this);
+
+ if (HT->callbacks[0] != NULL) {
+ HT->callbacks[0](HT);
+ }
+}
+
+/**
+ * @brief Generic Caputre and Compare callback which will call user callback
+ * @param htim: HAL timer handle
+ * @retval None
+ */
+void HardwareTimer::captureCompareCallback(TIM_HandleTypeDef *htim)
+{
+ 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;
+ }
+
+ if (htim == NULL) {
+ Error_Handler();
+ }
+
+ HardwareTimerObj_t *obj = get_timer_obj(htim);
+ HardwareTimer *HT = (HardwareTimer *)(obj->__this);
+
+ if (HT->callbacks[channel] != NULL) {
+ HT->callbacks[channel](HT);
+ }
+}
+
+/**
+ * @brief HardwareTimer destructor
+ * @retval None
+ */
+HardwareTimer::~HardwareTimer()
+{
+ uint32_t index = get_timer_index(_HardwareTimerObj.handle.Instance);
+ HardwareTimer_Handle[index] = NULL;
+ _HardwareTimerObj.__this = NULL;
+ enableTimerClock(&(_HardwareTimerObj.handle));
+}
+
+/**
+ * @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 = TIMER2_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(_HardwareTimerObj.handle.Instance)) {
+ case 1:
+ uwAPBxPrescaler = clkconfig.APB1CLKDivider;
+ uwTimclock = HAL_RCC_GetPCLK1Freq();
+ break;
+#if !defined(STM32F0xx) && !defined(STM32G0xx)
+ case 2:
+ uwAPBxPrescaler = clkconfig.APB2CLKDivider;
+ uwTimclock = HAL_RCC_GetPCLK2Freq();
+ break;
+#endif
+ default:
+ case 0: // Unknown timer clock source
+ Error_Handler();
+ break;
+ }
+
+#if defined(STM32H7xx)
+ /* 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:
+ 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:
+ // uwTimclock*=1;
+ 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;
+ }
+ }
+#else
+ /* When TIMPRE bit of the RCC_DCKCFGR register is reset,
+ * if APBx prescaler is 1, then TIMxCLK = PCLKx,
+ * otherwise TIMxCLK = 2x PCLKx.
+ * When TIMPRE bit in the RCC_DCKCFGR register is set,
+ * if APBx prescaler is 1,2 or 4, then TIMxCLK = HCLK,
+ * otherwise TIMxCLK = 4x PCLKx
+ */
+#if defined(STM32F4xx) || defined(STM32F7xx)
+#if !defined(STM32F405xx) && !defined(STM32F415xx) &&\
+ !defined(STM32F407xx) && !defined(STM32F417xx)
+ RCC_PeriphCLKInitTypeDef PeriphClkConfig = {};
+ HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkConfig);
+
+ if (PeriphClkConfig.TIMPresSelection == RCC_TIMPRES_ACTIVATED)
+ switch (uwAPBxPrescaler) {
+ default:
+ case RCC_HCLK_DIV1:
+ case RCC_HCLK_DIV2:
+ case RCC_HCLK_DIV4:
+ uwTimclock = HAL_RCC_GetHCLKFreq();
+ break;
+ case RCC_HCLK_DIV8:
+ case RCC_HCLK_DIV16:
+ uwTimclock *= 4;
+ break;
+ } else
+#endif
+#endif
+ switch (uwAPBxPrescaler) {
+ default:
+ case RCC_HCLK_DIV1:
+ // uwTimclock*=1;
+ break;
+ case RCC_HCLK_DIV2:
+ case RCC_HCLK_DIV4:
+ case RCC_HCLK_DIV8:
+ case RCC_HCLK_DIV16:
+ uwTimclock *= 2;
+ break;
+ }
+#endif /* STM32H7xx */
+ return uwTimclock;
+}
+
+/* Aim of the function is to get _HardwareTimerObj_s pointer using htim pointer */
+/* Highly inspired from magical linux kernel's "container_of" */
+/* (which was not directly used since not compatible with IAR toolchain) */
+HardwareTimerObj_t *get_timer_obj(TIM_HandleTypeDef *htim)
+{
+ HardwareTimerObj_t *obj;
+ obj = (HardwareTimerObj_t *)((char *)htim - offsetof(HardwareTimerObj_t, handle));
+ return (obj);
+}
+
+/**
+ * @brief This function will reset the timer
+ * @param obj : Hardware timer instance ex: Timer6, ...
+ * @retval None
+ */
+void HardwareTimer::timerHandleDeinit()
+{
+ HAL_TIM_Base_Stop_IT(&(_HardwareTimerObj.handle));
+ HAL_TIM_Base_DeInit(&(_HardwareTimerObj.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] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER1_INDEX]->handle);
+ }
+
+#if defined(STM32F1xx) || defined(STM32F2xx) || defined(STM32F4xx) || defined(STM32F7xx)
+#if defined (TIM10_BASE)
+ if (HardwareTimer_Handle[TIMER10_INDEX] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER10_INDEX]->handle);
+ }
+#endif
+#endif
+
+#if defined(STM32F1xx) || defined(STM32F3xx) || defined(STM32G4xx) || defined(STM32L4xx) || \
+ defined(STM32WBxx)
+#if defined (TIM16_BASE)
+ if (HardwareTimer_Handle[TIMER16_INDEX] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER16_INDEX]->handle);
+ }
+#endif
+#endif
+ }
+
+#if !defined(STM32F3xx)
+ void TIM1_CC_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER1_INDEX] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER1_INDEX]->handle);
+ }
+ }
+#endif // !STM32F3xx
+#endif //TIM1_BASE
+
+#if defined(TIM2_BASE)
+ /**
+ * @brief TIM2 IRQHandler
+ * @param None
+ * @retval None
+ */
+ void TIM2_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER2_INDEX] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER8_INDEX]->handle);
+ }
+
+#if defined(STM32F1xx) || defined(STM32F2xx) ||defined(STM32F4xx) || defined(STM32F7xx) || defined(STM32H7xx)
+#if defined(TIMER13_BASE)
+ if (HardwareTimer_Handle[TIMER13_INDEX] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER13_INDEX]->handle);
+ }
+#endif // TIMER13_BASE
+#endif
+ }
+
+ void TIM8_CC_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER8_INDEX] != NULL) {
+ 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] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER9_INDEX]->handle);
+ }
+ }
+#endif //TIM9_BASE
+
+#if defined(TIM10_BASE)
+#if !defined(STM32F1xx) && !defined(STM32F2xx) && !defined(STM32F4xx) && !defined(STM32F7xx)
+ /**
+ * @brief TIM10 IRQHandler
+ * @param None
+ * @retval None
+ */
+ void TIM10_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER10_INDEX] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER10_INDEX]->handle);
+ }
+ }
+#endif
+#endif //TIM10_BASE
+
+#if defined(TIM11_BASE)
+ /**
+ * @brief TIM11 IRQHandler
+ * @param None
+ * @retval None
+ */
+ void TIM11_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER11_INDEX] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER15_INDEX]->handle);
+ }
+ }
+#endif //TIM15_BASE
+
+#if defined(TIM16_BASE)
+#if !defined(STM32F1xx) && !defined(STM32F3xx) && !defined(STM32G4xx) && !defined(STM32L4xx)
+ /**
+ * @brief TIM16 IRQHandler
+ * @param None
+ * @retval None
+ */
+ void TIM16_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER16_INDEX] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER16_INDEX]->handle);
+ }
+ }
+#endif
+#endif //TIM16_BASE
+
+#if defined(TIM17_BASE)
+ /**
+ * @brief TIM17 IRQHandler
+ * @param None
+ * @retval None
+ */
+ void TIM17_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER17_INDEX] != NULL) {
+ 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] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER18_INDEX]->handle);
+ }
+
+#if defined(STM32F3xx)
+#if defined (TIM1_BASE)
+ if (HardwareTimer_Handle[TIMER1_INDEX] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER1_INDEX]->handle);
+ }
+#endif
+#endif
+ }
+#endif //TIM18_BASE
+
+#if defined(TIM19_BASE)
+ /**
+ * @brief TIM19 IRQHandler
+ * @param None
+ * @retval None
+ */
+ void TIM19_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER19_INDEX] != NULL) {
+ 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] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER20_INDEX]->handle);
+ }
+ }
+
+ void TIM20_CC_IRQHandler(void)
+ {
+ if (HardwareTimer_Handle[TIMER20_INDEX] != NULL) {
+ 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] != NULL) {
+ 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] != NULL) {
+ HAL_TIM_IRQHandler(&HardwareTimer_Handle[TIMER22_INDEX]->handle);
+ }
+ }
+#endif //TIM22_BASE
+}
+
+#endif // HAL_TIM_MODULE_ENABLED
\ No newline at end of file
diff --git a/cores/arduino/HardwareTimer.h b/cores/arduino/HardwareTimer.h
new file mode 100644
index 0000000000..7ad5c62448
--- /dev/null
+++ b/cores/arduino/HardwareTimer.h
@@ -0,0 +1,154 @@
+/*
+ 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 HARDWARETIMER_H_
+#define HARDWARETIMER_H_
+
+/* Includes ------------------------------------------------------------------*/
+#include "timer.h"
+
+#ifdef HAL_TIM_MODULE_ENABLED
+
+#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,
+ // Output Compare
+ TIMER_OUTPUT_COMPARE, // == TIM_OCMODE_TIMING no output, useful for only-interrupt
+ 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 {
+ TICK_COMPARE_FORMAT, // default
+ MICROSEC_COMPARE_FORMAT,
+ HERTZ_COMPARE_FORMAT,
+ PERCENT_COMPARE_FORMAT, // used for Dutycycle
+ RESOLUTION_8B_COMPARE_FORMAT, // used for Dutycycle: [0.. 255]
+ RESOLUTION_12B_COMPARE_FORMAT // used for Dutycycle: [0.. 4095]
+} TimerCompareFormat_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;
+} HardwareTimerObj_t;
+
+#ifdef __cplusplus
+
+/* Class --------------------------------------------------------*/
+class HardwareTimer {
+ public:
+ HardwareTimer(TIM_TypeDef *instance);
+ ~HardwareTimer(); // destructor
+
+ void pause(void); // Pause counter and all output channels
+ void resume(void); // Resume counter and all output channels
+
+ void setPrescaleFactor(uint32_t format = TICK_FORMAT); // 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, void (*PeriodCallback)(HardwareTimer *) = NULL, void (*CompareCallback)(HardwareTimer *) = NULL); // 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, void (*PeriodCallback)(HardwareTimer *) = NULL, void (*CompareCallback)(HardwareTimer *) = NULL);
+
+
+ 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);
+
+ 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
+
+ //Add interrupt to period update
+ void attachInterrupt(void (*handler)(HardwareTimer *)); // Attach interrupt callback which will be called upon update event (timer rollover)
+ void detachInterrupt(); // remove interrupt callback which was attached to update event
+ //Add interrupt to capture/compare channel
+ void attachInterrupt(uint32_t channel, void (*handler)(HardwareTimer *)); // 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
+
+ void timerHandleDeinit(); // Timer deinitialization
+
+ 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
+
+ private:
+ TIM_OC_InitTypeDef _channelOC[TIMER_CHANNELS];
+ TIM_IC_InitTypeDef _channelIC[TIMER_CHANNELS];
+ HardwareTimerObj_t _HardwareTimerObj;
+ void (*callbacks[1 + TIMER_CHANNELS])(HardwareTimer *); //Callbacks: 0 for update, 1-4 for channels. (channel5/channel6, if any, doesn't have interrupt)
+
+ int getChannel(uint32_t channel);
+ void resumeChannel(uint32_t channel);
+#if defined(TIM_CCER_CC1NE)
+ bool isComplementaryChannel[TIMER_CHANNELS];
+#endif
+};
+
+HardwareTimerObj_t *get_timer_obj(TIM_HandleTypeDef *htim);
+
+extern HardwareTimerObj_t *HardwareTimer_Handle[TIMER_NUM];
+
+extern timer_index_t get_timer_index(TIM_TypeDef *htim);
+
+#endif /* __cplusplus */
+
+#endif // HAL_TIM_MODULE_ENABLED
+#endif // HARDWARETIMER_H_
\ No newline at end of file
diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp
index 6037e026d1..89dfc646c9 100644
--- a/cores/arduino/Tone.cpp
+++ b/cores/arduino/Tone.cpp
@@ -20,36 +20,118 @@
*/
#include "Arduino.h"
+#include "HardwareTimer.h"
-PinName g_lastPin = NC;
+#if defined(HAL_TIM_MODULE_ENABLED) && defined(TIMER_TONE)
-#ifdef HAL_TIM_MODULE_ENABLED
-static stimer_t _timer;
+#define MAX_FREQ 65535
-// frequency (in hertz) and duration (in milliseconds).
+typedef struct {
+ PinName pin;
+ int32_t count;
+} timerPinInfo_t;
+
+static void timerTonePinInit(PinName p, uint32_t frequency, uint32_t duration);
+static void tonePeriodElapsedCallback(HardwareTimer *HT);
+static timerPinInfo_t TimerTone_pinInfo = {NC, 0};
+static HardwareTimer *TimerTone = NULL;
+
+/**
+ * @brief Tone Period elapsed callback in non-blocking mode
+ * @param htim : timer handle
+ * @retval None
+ */
+static void tonePeriodElapsedCallback(HardwareTimer *HT)
+{
+ UNUSED(HT);
+ GPIO_TypeDef *port = get_GPIO_Port(STM_PORT(TimerTone_pinInfo.pin));
+
+ if (port != NULL) {
+ if (TimerTone_pinInfo.count != 0) {
+ if (TimerTone_pinInfo.count > 0) {
+ TimerTone_pinInfo.count--;
+ }
+ digital_io_toggle(port, STM_LL_GPIO_PIN(TimerTone_pinInfo.pin));
+ } else {
+ digital_io_write(port, STM_LL_GPIO_PIN(TimerTone_pinInfo.pin), 0);
+ }
+ }
+}
+
+/**
+ * @brief This function will reset the tone timer
+ * @param port : pointer to port
+ * @param pin : pin number to toggle
+ * @retval None
+ */
+static void timerTonePinDeinit()
+{
+ if (TimerTone != NULL) {
+ TimerTone->timerHandleDeinit();
+ }
+ if (TimerTone_pinInfo.pin != NC) {
+ pin_function(TimerTone_pinInfo.pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
+ TimerTone_pinInfo.pin = NC;
+ }
+}
+
+static void timerTonePinInit(PinName p, uint32_t frequency, uint32_t duration)
+{
+ uint32_t timFreq = 2 * frequency;
+
+ if (frequency <= MAX_FREQ) {
+ if (frequency == 0) {
+ timerTonePinDeinit();
+ } else {
+ TimerTone_pinInfo.pin = p;
+ //Calculate the toggle count
+ if (duration > 0) {
+ TimerTone_pinInfo.count = ((timFreq * duration) / 1000);
+ } else {
+ TimerTone_pinInfo.count = -1;
+ }
+
+ pin_function(TimerTone_pinInfo.pin, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0));
+
+ TimerTone->setMode(1, TIMER_OUTPUT_COMPARE, NC);
+ TimerTone->setOverflow(timFreq, HERTZ_FORMAT);
+ TimerTone->attachInterrupt(tonePeriodElapsedCallback);
+ TimerTone->resume();
+ }
+ }
+}
+
+// frequency (in hertz) and duration (in milliseconds).
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
{
PinName p = digitalPinToPinName(_pin);
+
+ if (TimerTone == NULL) {
+ TimerTone = new HardwareTimer(TIMER_TONE);
+ }
+
if (p != NC) {
- if ((g_lastPin == NC) || (g_lastPin == p)) {
- _timer.pin = p;
- TimerPinInit(&_timer, frequency, duration);
- g_lastPin = p;
+ if ((TimerTone_pinInfo.pin == NC) || (TimerTone_pinInfo.pin == p)) {
+ timerTonePinInit(p, frequency, duration);
}
}
}
-
-void noTone(uint8_t _pin)
+void noTone(uint8_t _pin, bool destruct)
{
PinName p = digitalPinToPinName(_pin);
- if (p != NC) {
- TimerPinDeinit(&_timer);
- g_lastPin = NC;
+ if ((p != NC) && (TimerTone_pinInfo.pin == p)) {
+ timerTonePinDeinit();
+
+ if ((destruct) && (TimerTone != NULL)) {
+ delete (TimerTone);
+ TimerTone = NULL;
+ }
}
}
#else
+#warning "TIMER_TONE or HAL_TIM_MODULE_ENABLED not defined"
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
{
UNUSED(_pin);
@@ -61,4 +143,4 @@ void noTone(uint8_t _pin)
{
UNUSED(_pin);
}
-#endif /* HAL_TIM_MODULE_ENABLED */
+#endif /* HAL_TIM_MODULE_ENABLED && TIMER_TONE */
diff --git a/cores/arduino/Tone.h b/cores/arduino/Tone.h
index 6b7b304070..2c14839816 100644
--- a/cores/arduino/Tone.h
+++ b/cores/arduino/Tone.h
@@ -34,7 +34,7 @@ extern void tone(uint8_t _pin, unsigned int frequency, unsigned long duration =
*
* \param _pin
*/
-extern void noTone(uint8_t _pin);
+extern void noTone(uint8_t _pin, bool destruct = false);
#endif
diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h
index 50ad4dc63a..23c953a2ba 100644
--- a/cores/arduino/pins_arduino.h
+++ b/cores/arduino/pins_arduino.h
@@ -302,13 +302,13 @@ PinName analogInputToPinName(uint32_t pin);
#define DACC_RESOLUTION 12
#endif
#ifndef PWM_RESOLUTION
-#define PWM_RESOLUTION 8
+#define PWM_RESOLUTION 12
#endif
#ifndef PWM_FREQUENCY
#define PWM_FREQUENCY 1000
#endif
#ifndef PWM_MAX_DUTY_CYCLE
-#define PWM_MAX_DUTY_CYCLE 255
+#define PWM_MAX_DUTY_CYCLE 4095
#endif
#endif /*_PINS_ARDUINO_H_*/
diff --git a/cores/arduino/stm32/analog.c b/cores/arduino/stm32/analog.cpp
similarity index 89%
rename from cores/arduino/stm32/analog.c
rename to cores/arduino/stm32/analog.cpp
index 16e36cb95b..c406157f6f 100644
--- a/cores/arduino/stm32/analog.c
+++ b/cores/arduino/stm32/analog.cpp
@@ -37,7 +37,7 @@
*/
#include "stm32_def.h"
#include "analog.h"
-#include "timer.h"
+#include "HardwareTimer.h"
#include "PinAF_STM32F1.h"
#include "stm32yyxx_ll_adc.h"
@@ -273,7 +273,7 @@ static uint32_t get_adc_internal_channel(PinName pin)
#endif /* HAL_ADC_MODULE_ENABLED */
#ifdef HAL_TIM_MODULE_ENABLED
-static uint32_t get_pwm_channel(PinName pin)
+uint32_t get_pwm_channel(PinName pin)
{
uint32_t function = pinmap_function(pin, PinMap_PWM);
uint32_t channel = 0;
@@ -392,7 +392,7 @@ void dac_write_value(PinName pin, uint32_t value, uint8_t do_init)
DAC_ChannelConfTypeDef dacChannelConf = {};
uint32_t dacChannel;
- DacHandle.Instance = pinmap_peripheral(pin, PinMap_DAC);
+ DacHandle.Instance = (DAC_TypeDef *)pinmap_peripheral(pin, PinMap_DAC);
if (DacHandle.Instance == NP) {
return;
}
@@ -536,7 +536,7 @@ void dac_stop(PinName pin)
DAC_HandleTypeDef DacHandle;
uint32_t dacChannel;
- DacHandle.Instance = pinmap_peripheral(pin, PinMap_DAC);
+ DacHandle.Instance = (DAC_TypeDef *)pinmap_peripheral(pin, PinMap_DAC);
if (DacHandle.Instance == NP) {
return;
}
@@ -781,7 +781,7 @@ uint16_t adc_read_value(PinName pin)
channel = get_adc_internal_channel(pin);
samplingTime = ADC_SAMPLINGTIME_INTERNAL;
} else {
- AdcHandle.Instance = pinmap_peripheral(pin, PinMap_ADC);
+ AdcHandle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC);
channel = get_adc_channel(pin);
}
@@ -976,106 +976,32 @@ uint16_t adc_read_value(PinName pin)
#ifdef HAL_TIM_MODULE_ENABLED
////////////////////////// PWM INTERFACE FUNCTIONS /////////////////////////////
-
-/**
- * @brief TIM MSP Initialization
- * This function configures the hardware resources used in this example:
- * - Peripheral's clock enable
- * - Peripheral's GPIO Configuration
- * @param htim: TIM handle pointer
- * @retval None
- */
-void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
-{
- /*##-1- Enable peripherals and GPIO Clocks #################################*/
- /* TIMx Peripheral clock enable */
- timer_enable_clock(htim);
-
- /* Configure PWM GPIO pins */
- pinmap_pinout(g_current_pin, PinMap_PWM);
-}
-
-/**
- * @brief DeInitializes TIM PWM MSP.
- * @param htim : TIM handle
- * @retval None
- */
-void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef *htim)
-{
- timer_disable_clock(htim);
-}
-
/**
* @brief This function will set the PWM to the required value
* @param port : the gpio port to use
* @param pin : the gpio pin to use
* @param clock_freq : frequency of the tim clock
- * @param period : period of the tim counter
* @param value : the value to push on the PWM output
- * @param do_init : if set to 1 the initialization of the PWM is done
* @retval None
*/
-void pwm_start(PinName pin, uint32_t clock_freq,
- uint32_t period, uint32_t value, uint8_t do_init)
+void pwm_start(PinName pin, uint32_t PWM_freq, uint32_t value)
{
- TIM_HandleTypeDef timHandle = {};
- TIM_OC_InitTypeDef timConfig = {};
- uint32_t timChannel;
-
- /* Compute the prescaler value to have TIM counter clock equal to clock_freq Hz */
- timHandle.Instance = pinmap_peripheral(pin, PinMap_PWM);
- if (timHandle.Instance == NP) {
- return;
+ TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin, PinMap_PWM);
+ HardwareTimer *HT;
+ uint32_t index = get_timer_index(Instance);
+ if (HardwareTimer_Handle[index] == NULL) {
+ HardwareTimer_Handle[index]->__this = new HardwareTimer((TIM_TypeDef *)pinmap_peripheral(pin, PinMap_PWM));
}
- timHandle.Init.Prescaler = (uint32_t)(getTimerClkFreq(timHandle.Instance) / clock_freq) - 1;
- timHandle.Init.Period = period - 1;
- timHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- timHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
-#if !defined(STM32L0xx) && !defined(STM32L1xx)
- timHandle.Init.RepetitionCounter = 0;
-#endif
- timHandle.State = HAL_TIM_STATE_RESET;
- // TBC: is timHandle.State field should be saved ?
- if (do_init == 1) {
- g_current_pin = pin;
- if (HAL_TIM_PWM_Init(&timHandle) != HAL_OK) {
- return;
- }
- }
- timChannel = get_pwm_channel(pin);
- if (!IS_TIM_CHANNELS(timChannel)) {
- return;
- }
- //HAL_TIM_PWM_Stop(&timHandle, timChannel);
+ HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this);
- /*##-2- Configure the PWM channels #########################################*/
- /* Common configuration for all channels */
- timConfig.OCMode = TIM_OCMODE_PWM1;
- timConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
- timConfig.OCFastMode = TIM_OCFAST_DISABLE;
-#if !defined(STM32L0xx) && !defined(STM32L1xx)
- timConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
- timConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
- timConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
-#endif
- timConfig.Pulse = value;
+ uint32_t channel = STM_PIN_CHANNEL(pinmap_function(pin, PinMap_PWM));
- if (HAL_TIM_PWM_ConfigChannel(&timHandle, &timConfig, timChannel) != HAL_OK) {
- /*##-2- Configure the PWM channels #########################################*/
- return;
- }
-
-#if !defined(STM32L0xx) && !defined(STM32L1xx)
- if (STM_PIN_INVERTED(pinmap_function(pin, PinMap_PWM))) {
- HAL_TIMEx_PWMN_Start(&timHandle, timChannel);
- } else
-#endif
- {
- HAL_TIM_PWM_Start(&timHandle, timChannel);
- }
+ HT->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
+ HT->setOverflow(PWM_freq, HERTZ_FORMAT);
+ HT->setCaptureCompare(channel, value, RESOLUTION_12B_COMPARE_FORMAT);
+ HT->resume();
}
-
/**
* @brief This function will disable the PWM
* @param port : the gpio port to use
@@ -1084,28 +1010,18 @@ void pwm_start(PinName pin, uint32_t clock_freq,
*/
void pwm_stop(PinName pin)
{
- TIM_HandleTypeDef timHandle;
- uint32_t timChannel;
-
- timHandle.Instance = pinmap_peripheral(pin, PinMap_PWM);
- if (timHandle.Instance == NP) {
- return;
- }
- timChannel = get_pwm_channel(pin);
- if (!IS_TIM_CHANNELS(timChannel)) {
- return;
+ TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin, PinMap_PWM);
+ HardwareTimer *HT;
+ uint32_t index = get_timer_index(Instance);
+ if (HardwareTimer_Handle[index] == NULL) {
+ HardwareTimer_Handle[index]->__this = new HardwareTimer((TIM_TypeDef *)pinmap_peripheral(pin, PinMap_PWM));
}
-#if !defined(STM32L0xx) && !defined(STM32L1xx)
- if (STM_PIN_INVERTED(pinmap_function(pin, PinMap_PWM))) {
- HAL_TIMEx_PWMN_Stop(&timHandle, timChannel);
- } else
-#endif
- {
- HAL_TIM_PWM_Stop(&timHandle, timChannel);
+ HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this);
+ if (HT != NULL) {
+ delete (HT);
+ HT = NULL;
}
-
- HAL_TIM_PWM_DeInit(&timHandle);
}
#endif /* HAL_TIM_MODULE_ENABLED */
diff --git a/cores/arduino/stm32/analog.h b/cores/arduino/stm32/analog.h
index 8a49f42048..4e1a660501 100644
--- a/cores/arduino/stm32/analog.h
+++ b/cores/arduino/stm32/analog.h
@@ -51,8 +51,9 @@ extern "C" {
void dac_write_value(PinName pin, uint32_t value, uint8_t do_init);
void dac_stop(PinName pin);
uint16_t adc_read_value(PinName pin);
-void pwm_start(PinName pin, uint32_t clock_freq, uint32_t period, uint32_t value, uint8_t do_init);
+void pwm_start(PinName pin, uint32_t clock_freq, uint32_t value);
void pwm_stop(PinName pin);
+uint32_t get_pwm_channel(PinName pin);
#ifdef __cplusplus
}
diff --git a/cores/arduino/stm32/timer.c b/cores/arduino/stm32/timer.c
index 54d0a352c2..b79c6ec9cb 100644
--- a/cores/arduino/stm32/timer.c
+++ b/cores/arduino/stm32/timer.c
@@ -1,40 +1,15 @@
-/**
- ******************************************************************************
- * @file timer.c
- * @author WI6LABS
- * @version V1.0.0
- * @date 01-August-2016
- * @brief provide timer services
- *
- ******************************************************************************
- * @attention
- *
- *
© COPYRIGHT(c) 2016 STMicroelectronics
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- ******************************************************************************
- */
+/*
+ *******************************************************************************
+ * 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
+ *
+ *******************************************************************************
+ */
#include "core_debug.h"
#include "timer.h"
#include "board.h"
@@ -44,118 +19,38 @@ extern "C" {
#endif
#ifdef HAL_TIM_MODULE_ENABLED
-/* Private Variables */
-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
-} timer_index_t;
-
-static TIM_HandleTypeDef *timer_handles[TIMER_NUM] = {NULL};
-
/* Private Functions */
-static void HAL_TIMx_PeriodElapsedCallback(stimer_t *obj);
-
-/* Aim of the function is to get timer_s pointer using htim pointer */
-/* Highly inspired from magical linux kernel's "container_of" */
-/* (which was not directly used since not compatible with IAR toolchain) */
-stimer_t *get_timer_obj(TIM_HandleTypeDef *htim)
-{
- struct timer_s *obj_s;
- stimer_t *obj;
-
- obj_s = (struct timer_s *)((char *)htim - offsetof(struct timer_s, handle));
- obj = (stimer_t *)((char *)obj_s - offsetof(stimer_t, timer));
-
- return (obj);
-}
/**
* @brief TIMER Initialization - clock init and nvic init
- * @param htim_base : one of the defined timer
+ * @param htim_base: TIM handle
* @retval None
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim_base)
{
- timer_enable_clock(htim_base);
+ enableTimerClock(htim_base);
+
+ // configure Update interrupt
+ HAL_NVIC_SetPriority(getTimerUpIrq(htim_base->Instance), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
+ HAL_NVIC_EnableIRQ(getTimerUpIrq(htim_base->Instance));
- HAL_NVIC_SetPriority(getTimerIrq(htim_base->Instance), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
- HAL_NVIC_EnableIRQ(getTimerIrq(htim_base->Instance));
+ if (getTimerCCIrq(htim_base->Instance) != getTimerUpIrq(htim_base->Instance)) {
+ // configure Capture Compare interrupt
+ HAL_NVIC_SetPriority(getTimerCCIrq(htim_base->Instance), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
+ HAL_NVIC_EnableIRQ(getTimerCCIrq(htim_base->Instance));
+ }
}
/**
* @brief TIMER Deinitialization - clock and nvic
- * @param htim_base : one of the defined timer
+ * @param htim_base: TIM handle
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim_base)
{
- timer_disable_clock(htim_base);
- HAL_NVIC_DisableIRQ(getTimerIrq(htim_base->Instance));
+ disableTimerClock(htim_base);
+ HAL_NVIC_DisableIRQ(getTimerUpIrq(htim_base->Instance));
+ HAL_NVIC_DisableIRQ(getTimerCCIrq(htim_base->Instance));
}
/**
@@ -165,7 +60,17 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim_base)
*/
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{
- timer_enable_clock(htim);
+ enableTimerClock(htim);
+
+ // configure Update interrupt
+ HAL_NVIC_SetPriority(getTimerUpIrq(htim->Instance), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
+ HAL_NVIC_EnableIRQ(getTimerUpIrq(htim->Instance));
+
+ if (getTimerCCIrq(htim->Instance) != getTimerUpIrq(htim->Instance)) {
+ // configure Capture Compare interrupt
+ HAL_NVIC_SetPriority(getTimerCCIrq(htim->Instance), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
+ HAL_NVIC_EnableIRQ(getTimerCCIrq(htim->Instance));
+ }
}
/**
@@ -175,231 +80,158 @@ void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
*/
void HAL_TIM_OC_MspDeInit(TIM_HandleTypeDef *htim)
{
- timer_disable_clock(htim);
-}
-
-/**
- * @brief Output Compare callback in non-blocking mode
- * @param htim : TIM OC handle
- * @retval None
- */
-void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
-{
- stimer_t *obj = get_timer_obj(htim);
- switch (htim->Channel) {
- case HAL_TIM_ACTIVE_CHANNEL_1:
- if (obj->irqHandleOC_CH1 != NULL) {
- obj->irqHandleOC_CH1();
- }
- if (obj->irqHandleOC != NULL) {
- obj->irqHandleOC(obj, TIM_CHANNEL_1);
- }
- break;
- case HAL_TIM_ACTIVE_CHANNEL_2:
- if (obj->irqHandleOC_CH2 != NULL) {
- obj->irqHandleOC_CH2();
- }
- break;
- case HAL_TIM_ACTIVE_CHANNEL_3:
- if (obj->irqHandleOC_CH3 != NULL) {
- obj->irqHandleOC_CH3();
- }
- break;
- case HAL_TIM_ACTIVE_CHANNEL_4:
- if (obj->irqHandleOC_CH4 != NULL) {
- obj->irqHandleOC_CH4();
- }
- break;
- default:
- break;
- }
+ disableTimerClock(htim);
+ HAL_NVIC_DisableIRQ(getTimerUpIrq(htim->Instance));
+ HAL_NVIC_DisableIRQ(getTimerCCIrq(htim->Instance));
}
/**
- * @brief Period elapsed callback in non-blocking mode
- * @param timer_id : id of the timer
+ * @brief Initializes the TIM Input Capture MSP.
+ * @param htim: TIM handle
* @retval None
*/
-void HAL_TIMx_PeriodElapsedCallback(stimer_t *obj)
+void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
- GPIO_TypeDef *port = get_GPIO_Port(STM_PORT(obj->pin));
-
- if (port != NULL) {
- if (obj->pinInfo.count != 0) {
- if (obj->pinInfo.count > 0) {
- obj->pinInfo.count--;
- }
- obj->pinInfo.state = (obj->pinInfo.state == 0) ? 1 : 0;
- digital_io_write(port, STM_LL_GPIO_PIN(obj->pin), obj->pinInfo.state);
- } else {
- digital_io_write(port, STM_LL_GPIO_PIN(obj->pin), 0);
- }
- }
+ enableTimerClock(htim);
}
/**
- * @brief Period elapsed callback in non-blocking mode
- * @param htim : TIM handle
+ * @brief DeInitialize TIM Input Capture MSP.
+ * @param htim: TIM handle
* @retval None
*/
-void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
+void HAL_TIM_IC_MspDeInit(TIM_HandleTypeDef *htim)
{
- stimer_t *obj = get_timer_obj(htim);
-
- if (obj->irqHandle != NULL) {
- obj->irqHandle(obj);
- }
+ disableTimerClock(htim);
}
/* Exported functions */
/**
* @brief Enable the timer clock
- * @param htim : one of the defined timer
+ * @param htim: TIM handle
* @retval None
*/
-void timer_enable_clock(TIM_HandleTypeDef *htim)
+void enableTimerClock(TIM_HandleTypeDef *htim)
{
// Enable TIM clock
#if defined(TIM1_BASE)
if (htim->Instance == TIM1) {
__HAL_RCC_TIM1_CLK_ENABLE();
- timer_handles[TIMER1_INDEX] = htim;
}
#endif
#if defined(TIM2_BASE)
if (htim->Instance == TIM2) {
__HAL_RCC_TIM2_CLK_ENABLE();
- timer_handles[TIMER2_INDEX] = htim;
}
#endif
#if defined(TIM3_BASE)
if (htim->Instance == TIM3) {
__HAL_RCC_TIM3_CLK_ENABLE();
- timer_handles[TIMER3_INDEX] = htim;
}
#endif
#if defined(TIM4_BASE)
if (htim->Instance == TIM4) {
__HAL_RCC_TIM4_CLK_ENABLE();
- timer_handles[TIMER4_INDEX] = htim;
}
#endif
#if defined(TIM5_BASE)
if (htim->Instance == TIM5) {
__HAL_RCC_TIM5_CLK_ENABLE();
- timer_handles[TIMER5_INDEX] = htim;
}
#endif
#if defined(TIM6_BASE)
if (htim->Instance == TIM6) {
__HAL_RCC_TIM6_CLK_ENABLE();
- timer_handles[TIMER6_INDEX] = htim;
}
#endif
#if defined(TIM7_BASE)
if (htim->Instance == TIM7) {
__HAL_RCC_TIM7_CLK_ENABLE();
- timer_handles[TIMER7_INDEX] = htim;
}
#endif
#if defined(TIM8_BASE)
if (htim->Instance == TIM8) {
__HAL_RCC_TIM8_CLK_ENABLE();
- timer_handles[TIMER8_INDEX] = htim;
}
#endif
#if defined(TIM9_BASE)
if (htim->Instance == TIM9) {
__HAL_RCC_TIM9_CLK_ENABLE();
- timer_handles[TIMER9_INDEX] = htim;
}
#endif
#if defined(TIM10_BASE)
if (htim->Instance == TIM10) {
__HAL_RCC_TIM10_CLK_ENABLE();
- timer_handles[TIMER10_INDEX] = htim;
}
#endif
#if defined(TIM11_BASE)
if (htim->Instance == TIM11) {
__HAL_RCC_TIM11_CLK_ENABLE();
- timer_handles[TIMER11_INDEX] = htim;
}
#endif
#if defined(TIM12_BASE)
if (htim->Instance == TIM12) {
__HAL_RCC_TIM12_CLK_ENABLE();
- timer_handles[TIMER12_INDEX] = htim;
}
#endif
#if defined(TIM13_BASE)
if (htim->Instance == TIM13) {
__HAL_RCC_TIM13_CLK_ENABLE();
- timer_handles[TIMER13_INDEX] = htim;
}
#endif
#if defined(TIM14_BASE)
if (htim->Instance == TIM14) {
__HAL_RCC_TIM14_CLK_ENABLE();
- timer_handles[TIMER14_INDEX] = htim;
}
#endif
#if defined(TIM15_BASE)
if (htim->Instance == TIM15) {
__HAL_RCC_TIM15_CLK_ENABLE();
- timer_handles[TIMER15_INDEX] = htim;
}
#endif
#if defined(TIM16_BASE)
if (htim->Instance == TIM16) {
__HAL_RCC_TIM16_CLK_ENABLE();
- timer_handles[TIMER16_INDEX] = htim;
}
#endif
#if defined(TIM17_BASE)
if (htim->Instance == TIM17) {
__HAL_RCC_TIM17_CLK_ENABLE();
- timer_handles[TIMER17_INDEX] = htim;
}
#endif
#if defined(TIM18_BASE)
if (htim->Instance == TIM18) {
__HAL_RCC_TIM18_CLK_ENABLE();
- timer_handles[TIMER18_INDEX] = htim;
}
#endif
#if defined(TIM19_BASE)
if (htim->Instance == TIM19) {
__HAL_RCC_TIM19_CLK_ENABLE();
- timer_handles[TIMER19_INDEX] = htim;
}
#endif
#if defined(TIM20_BASE)
if (htim->Instance == TIM20) {
__HAL_RCC_TIM20_CLK_ENABLE();
- timer_handles[TIMER20_INDEX] = htim;
}
#endif
#if defined(TIM21_BASE)
if (htim->Instance == TIM21) {
__HAL_RCC_TIM21_CLK_ENABLE();
- timer_handles[TIMER21_INDEX] = htim;
}
#endif
#if defined(TIM22_BASE)
if (htim->Instance == TIM22) {
__HAL_RCC_TIM22_CLK_ENABLE();
- timer_handles[TIMER2_INDEX] = htim;
}
#endif
}
/**
* @brief Disable the timer clock
- * @param htim : one of the defined timer
+ * @param htim: TIM handle
* @retval None
*/
-void timer_disable_clock(TIM_HandleTypeDef *htim)
+void disableTimerClock(TIM_HandleTypeDef *htim)
{
// Enable TIM clock
#if defined(TIM1_BASE)
@@ -515,384 +347,130 @@ void timer_disable_clock(TIM_HandleTypeDef *htim)
}
/**
- * @brief This function will set the timer to the required value
- * @param timer_id : timer_id_e
- * @param period : Timer period in milliseconds
- * @param prescaler : clock divider
- * @retval None
- */
-void TimerHandleInit(stimer_t *obj, uint16_t period, uint16_t prescaler)
-{
- if (obj == NULL) {
- return;
- }
-
- TIM_HandleTypeDef *handle = &(obj->handle);
-
- handle->Instance = obj->timer;
- handle->Init.Prescaler = prescaler;
- handle->Init.CounterMode = TIM_COUNTERMODE_UP;
- handle->Init.Period = period;
- handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
-#if !defined(STM32L0xx) && !defined(STM32L1xx)
- handle->Init.RepetitionCounter = 0x0000;
-#endif
- if (HAL_TIM_Base_Init(handle) != HAL_OK) {
- return;
- }
-
- if (HAL_TIM_Base_Start_IT(handle) != HAL_OK) {
- return;
- }
-}
-
-/**
- * @brief This function will reset the timer
- * @param timer_id : timer_id_e
- * @retval None
- */
-void TimerHandleDeinit(stimer_t *obj)
-{
- if (obj != NULL) {
- HAL_TIM_Base_DeInit(&(obj->handle));
- HAL_TIM_Base_Stop_IT(&(obj->handle));
- }
-}
-
-/**
- * @brief This function will set the tone timer to the required value and
- * configure the pin to toggle.
- * @param port : pointer to GPIO_TypeDef
- * @param pin : pin number to toggle
- * @param frequency : toggle frequency (in hertz)
- * @param duration : toggle time
- * @retval None
- */
-void TimerPinInit(stimer_t *obj, uint32_t frequency, uint32_t duration)
-{
- uint8_t end = 0;
- uint32_t timClkFreq = 0;
- // TIMER_TONE freq is twice frequency
- uint32_t timFreq = 2 * frequency;
- uint32_t prescaler = 1;
- uint32_t period = 0;
- uint32_t scale = 0;
-
- if (frequency > MAX_FREQ) {
- return;
- }
-
- if (obj->timer == NULL) {
-#ifdef TIMER_TONE
- obj->timer = TIMER_TONE;
-#else
- return;
-#endif
- }
-
- obj->pinInfo.state = 0;
-
- if (frequency == 0) {
- TimerPinDeinit(obj);
- return;
- }
-
- //Calculate the toggle count
- if (duration > 0) {
- obj->pinInfo.count = ((timFreq * duration) / 1000);
- } else {
- obj->pinInfo.count = -1;
- }
-
- pin_function(obj->pin, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0));
- timClkFreq = getTimerClkFreq(obj->timer);
-
- // Do this once
- scale = timClkFreq / timFreq;
- while (end == 0) {
- period = ((uint32_t)(scale / prescaler)) - 1;
-
- if ((period >= 0xFFFF) && (prescaler < 0xFFFF)) {
- prescaler++; //prescaler *= 2;
- }
-
- else {
- end = 1;
- }
- }
-
- if ((period < 0xFFFF) && (prescaler < 0xFFFF)) {
- obj->irqHandle = HAL_TIMx_PeriodElapsedCallback;
- TimerHandleInit(obj, period, prescaler - 1);
- } else {
- TimerHandleDeinit(obj);
- }
-}
-
-/**
- * @brief This function will reset the tone timer
- * @param port : pointer to port
- * @param pin : pin number to toggle
- * @retval None
- */
-void TimerPinDeinit(stimer_t *obj)
-{
- if (obj->timer != NULL) {
- TimerHandleDeinit(obj);
- pin_function(obj->pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
- }
-}
-
-/**
- * @brief This function will set the timer to generate pulse in interrupt mode with a particular duty cycle
- * @param timer_id : timer_id_e
- * @param period : timer period in microseconds
- * @param pulseWidth : pulse width in microseconds
- * @param irqHandle : interrupt routine to call
- * @retval None
- */
-void TimerPulseInit(stimer_t *obj, uint16_t period, uint16_t pulseWidth, void (*irqHandle)(stimer_t *, uint32_t))
-{
- TIM_HandleTypeDef *handle = &(obj->handle);
-
- if (obj->timer == NULL) {
-#ifdef TIMER_SERVO
- obj->timer = TIMER_SERVO;
-#else
- return;
-#endif
- }
-
- //min pulse = 1us - max pulse = 65535us
- handle->Instance = obj->timer;
- handle->Init.Period = period;
- handle->Init.Prescaler = (uint32_t)(getTimerClkFreq(obj->timer) / (1000000)) - 1;
- handle->Init.ClockDivision = 0;
- handle->Init.CounterMode = TIM_COUNTERMODE_UP;
-#if !defined(STM32L0xx) && !defined(STM32L1xx)
- handle->Init.RepetitionCounter = 0;
-#endif
- obj->irqHandleOC = irqHandle;
-
- attachIntHandleOC(obj, NULL, TIM_CHANNEL_1, pulseWidth);
-}
-
-/**
- * @brief This function will reset the pulse generation
- * @param timer_id : timer_id_e
- * @retval None
- */
-void TimerPulseDeinit(stimer_t *obj)
-{
- TIM_HandleTypeDef *handle = &(obj->handle);
- obj->irqHandleOC = NULL;
- obj->irqHandleOC_CH1 = NULL;
- obj->irqHandleOC_CH2 = NULL;
- obj->irqHandleOC_CH3 = NULL;
- obj->irqHandleOC_CH4 = NULL;
-
- if (obj->timer != NULL) {
- HAL_NVIC_DisableIRQ(getTimerIrq(obj->timer));
-
- if (HAL_TIM_OC_DeInit(handle) != HAL_OK) {
- return;
- }
- if (HAL_TIM_OC_Stop_IT(handle, TIM_CHANNEL_1) != HAL_OK) {
- return;
- }
- }
-}
-
-/**
- * @brief Get the counter value.
- * @param timer_id : id of the timer
- * @retval Counter value
- */
-uint32_t getTimerCounter(stimer_t *obj)
-{
- return __HAL_TIM_GET_COUNTER(&(obj->handle));
-}
-
-/**
- * @brief Set the counter value.
- * @param timer_id : id of the timer
- * @param value : counter value
- * @retval None
- */
-void setTimerCounter(stimer_t *obj, uint32_t value)
-{
- __HAL_TIM_SET_COUNTER(&(obj->handle), value);
-}
-
-/**
- * @brief Set the TIM Capture Compare Register value.
- * @param timer_id : id of the timer
- * @param channel : TIM Channel associated with the capture compare register.
- * This parameter can be one of the following values:
- * @arg TIM_CHANNEL_1: TIM Channel 1 selected
- * @arg TIM_CHANNEL_2: TIM Channel 2 selected
- * @arg TIM_CHANNEL_3: TIM Channel 3 selected
- * @arg TIM_CHANNEL_4: TIM Channel 4 selected
- * @retval CRR value.
- */
-uint32_t getCCRRegister(stimer_t *obj, uint32_t channel)
-{
- return __HAL_TIM_GET_COMPARE(&(obj->handle), channel);
-}
-
-/**
- * @brief Set the TIM Capture Compare Register value.
- * @param timer_id : id of the timer
- * @param channel : TIM Channels to be configured.
- * This parameter can be one of the following values:
- * @arg TIM_CHANNEL_1: TIM Channel 1 selected
- * @arg TIM_CHANNEL_2: TIM Channel 2 selected
- * @arg TIM_CHANNEL_3: TIM Channel 3 selected
- * @arg TIM_CHANNEL_4: TIM Channel 4 selected
- * @param value : register new register.
- * @retval None
- */
-void setCCRRegister(stimer_t *obj, uint32_t channel, uint32_t value)
-{
- __HAL_TIM_SET_COMPARE(&(obj->handle), channel, value);
-}
-
-/**
- * @brief Set the TIM Capture Compare Register value.
- * @param timer_id : id of the timer
- * @param prescaler : prescaler value to set for this timer.
- * @retval None
- */
-void setTimerPrescalerRegister(stimer_t *obj, uint32_t prescaler)
-{
- __HAL_TIM_SET_PRESCALER(&(obj->handle), prescaler);
-}
-
-/**
- * @brief This function return the timer clock source.
+ * @brief This function return IRQ number corresponding to update interrupt event of timer instance.
* @param tim: timer instance
- * @retval 1 = PCLK1 or 2 = PCLK2 or 0 = unknown
+ * @retval IRQ number
*/
-uint32_t getTimerIrq(TIM_TypeDef *tim)
+IRQn_Type getTimerUpIrq(TIM_TypeDef *tim)
{
- uint32_t IRQn = 0;
+ 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:
+ case (uint32_t)TIM1_BASE:
IRQn = TIM1_IRQn;
break;
#endif
#if defined(TIM2_BASE)
- case (uint32_t)TIM2:
+ case (uint32_t)TIM2_BASE:
IRQn = TIM2_IRQn;
break;
#endif
#if defined(TIM3_BASE)
- case (uint32_t)TIM3:
+ case (uint32_t)TIM3_BASE:
IRQn = TIM3_IRQn;
break;
#endif
#if defined(TIM4_BASE)
- case (uint32_t)TIM4:
+ case (uint32_t)TIM4_BASE:
IRQn = TIM4_IRQn;
break;
#endif
#if defined(TIM5_BASE)
- case (uint32_t)TIM5:
+ case (uint32_t)TIM5_BASE:
IRQn = TIM5_IRQn;
break;
#endif
#if defined(TIM6_BASE)
- case (uint32_t)TIM6:
+ case (uint32_t)TIM6_BASE:
IRQn = TIM6_IRQn;
break;
#endif
#if defined(TIM7_BASE)
- case (uint32_t)TIM7:
+ case (uint32_t)TIM7_BASE:
IRQn = TIM7_IRQn;
break;
#endif
#if defined(TIM8_BASE)
- case (uint32_t)TIM8:
+ case (uint32_t)TIM8_BASE:
IRQn = TIM8_IRQn;
break;
#endif
#if defined(TIM9_BASE)
- case (uint32_t)TIM9:
+ case (uint32_t)TIM9_BASE:
IRQn = TIM9_IRQn;
break;
#endif
#if defined(TIM10_BASE)
- case (uint32_t)TIM10:
+ case (uint32_t)TIM10_BASE:
IRQn = TIM10_IRQn;
break;
#endif
#if defined(TIM11_BASE)
- case (uint32_t)TIM11:
+ case (uint32_t)TIM11_BASE:
IRQn = TIM11_IRQn;
break;
#endif
#if defined(TIM12_BASE)
- case (uint32_t)TIM12:
+ case (uint32_t)TIM12_BASE:
IRQn = TIM12_IRQn;
break;
#endif
#if defined(TIM13_BASE)
- case (uint32_t)TIM13:
+ case (uint32_t)TIM13_BASE:
IRQn = TIM13_IRQn;
break;
#endif
#if defined(TIM14_BASE)
- case (uint32_t)TIM14:
+ case (uint32_t)TIM14_BASE:
IRQn = TIM14_IRQn;
break;
#endif
#if defined(TIM15_BASE)
- case (uint32_t)TIM15:
+ case (uint32_t)TIM15_BASE:
IRQn = TIM15_IRQn;
break;
#endif
#if defined(TIM16_BASE)
- case (uint32_t)TIM16:
+ case (uint32_t)TIM16_BASE:
IRQn = TIM16_IRQn;
break;
#endif
#if defined(TIM17_BASE)
- case (uint32_t)TIM17:
+ case (uint32_t)TIM17_BASE:
IRQn = TIM17_IRQn;
break;
#endif
#if defined(TIM18_BASE)
- case (uint32_t)TIM18:
+ case (uint32_t)TIM18_BASE:
IRQn = TIM18_IRQn;
break;
#endif
#if defined(TIM19_BASE)
- case (uint32_t)TIM19:
+ case (uint32_t)TIM19_BASE:
IRQn = TIM19_IRQn;
break;
#endif
#if defined(TIM20_BASE)
- case (uint32_t)TIM20:
+ case (uint32_t)TIM20_BASE:
IRQn = TIM20_IRQn;
break;
#endif
#if defined(TIM21_BASE)
- case (uint32_t)TIM21:
+ case (uint32_t)TIM21_BASE:
IRQn = TIM21_IRQn;
break;
#endif
#if defined(TIM22_BASE)
- case (uint32_t)TIM22:
+ case (uint32_t)TIM22_BASE:
IRQn = TIM22_IRQn;
break;
#endif
- break;
+
default:
- core_debug("TIM: Unknown timer IRQn");
+ _Error_Handler("TIM: Unknown timer IRQn", (int)tim);
break;
}
}
@@ -900,640 +478,233 @@ uint32_t getTimerIrq(TIM_TypeDef *tim)
}
/**
- * @brief This function return the timer clock source.
+ * @brief This function return IRQ number corresponding to Capture or Compare interrupt event of timer instance.
* @param tim: timer instance
- * @retval 1 = PCLK1 or 2 = PCLK2 or 0 = unknown
+ * @retval IRQ number
*/
-uint8_t getTimerClkSrc(TIM_TypeDef *tim)
+IRQn_Type getTimerCCIrq(TIM_TypeDef *tim)
{
- uint8_t clkSrc = 0;
+ IRQn_Type IRQn = NonMaskableInt_IRQn;
- if (tim != (TIM_TypeDef *)NC)
-#ifdef STM32F0xx
- /* TIMx source CLK is PCKL1 */
- clkSrc = 1;
-#else
- {
- /* Get source clock depending on TIM instance */
+ 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:
+ case (uint32_t)TIM2_BASE:
+ IRQn = TIM2_IRQn;
+ break;
#endif
#if defined(TIM3_BASE)
- case (uint32_t)TIM3:
+ case (uint32_t)TIM3_BASE:
+ IRQn = TIM3_IRQn;
+ break;
#endif
#if defined(TIM4_BASE)
- case (uint32_t)TIM4:
+ case (uint32_t)TIM4_BASE:
+ IRQn = TIM4_IRQn;
+ break;
#endif
#if defined(TIM5_BASE)
- case (uint32_t)TIM5:
+ case (uint32_t)TIM5_BASE:
+ IRQn = TIM5_IRQn;
+ break;
#endif
#if defined(TIM6_BASE)
- case (uint32_t)TIM6:
+ case (uint32_t)TIM6_BASE:
+ IRQn = TIM6_IRQn;
+ break;
#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;
+ case (uint32_t)TIM7_BASE:
+ IRQn = TIM7_IRQn;
break;
-#if defined(TIM1_BASE)
- case (uint32_t)TIM1:
#endif
#if defined(TIM8_BASE)
- case (uint32_t)TIM8:
+ case (uint32_t)TIM8_BASE:
+ IRQn = TIM8_CC_IRQn;
+ break;
#endif
#if defined(TIM9_BASE)
- case (uint32_t)TIM9:
+ case (uint32_t)TIM9_BASE:
+ IRQn = TIM9_IRQn;
+ break;
#endif
#if defined(TIM10_BASE)
- case (uint32_t)TIM10:
+ case (uint32_t)TIM10_BASE:
+ IRQn = TIM10_IRQn;
+ break;
#endif
#if defined(TIM11_BASE)
- case (uint32_t)TIM11:
+ 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:
+ case (uint32_t)TIM15_BASE:
+ IRQn = TIM15_IRQn;
+ break;
#endif
#if defined(TIM16_BASE)
- case (uint32_t)TIM16:
+ case (uint32_t)TIM16_BASE:
+ IRQn = TIM16_IRQn;
+ break;
#endif
#if defined(TIM17_BASE)
- case (uint32_t)TIM17:
+ 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:
+ case (uint32_t)TIM19_BASE:
+ IRQn = TIM19_IRQn;
+ break;
#endif
#if defined(TIM20_BASE)
- case (uint32_t)TIM20:
+ case (uint32_t)TIM20_BASE:
+ IRQn = TIM20_CC_IRQn;
+ break;
#endif
#if defined(TIM21_BASE)
- case (uint32_t)TIM21:
+ case (uint32_t)TIM21_BASE:
+ IRQn = TIM21_IRQn;
+ break;
#endif
#if defined(TIM22_BASE)
- case (uint32_t)TIM22:
+ case (uint32_t)TIM22_BASE:
+ IRQn = TIM22_IRQn;
+ break;
#endif
- clkSrc = 2;
break;
default:
- core_debug("TIM: Unknown timer instance");
+ _Error_Handler("TIM: Unknown timer IRQn", (int)tim);
break;
}
}
-#endif
- return clkSrc;
+ return IRQn;
}
/**
- * @brief This function return the timer clock frequency.
+ * @brief This function return the timer clock source.
* @param tim: timer instance
- * @retval frequency in Hz
+ * @retval 1 = PCLK1 or 2 = PCLK2
*/
-uint32_t getTimerClkFreq(TIM_TypeDef *tim)
+uint8_t getTimerClkSrc(TIM_TypeDef *tim)
{
- RCC_ClkInitTypeDef clkconfig = {};
- uint32_t pFLatency = 0U;
- uint32_t uwTimclock = 0U, uwAPBxPrescaler = 0U;
-
- /* Get clock configuration */
- HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
- switch (getTimerClkSrc(tim)) {
- case 1:
- uwAPBxPrescaler = clkconfig.APB1CLKDivider;
- uwTimclock = HAL_RCC_GetPCLK1Freq();
- break;
-#if !defined(STM32F0xx) && !defined(STM32G0xx)
- case 2:
- uwAPBxPrescaler = clkconfig.APB2CLKDivider;
- uwTimclock = HAL_RCC_GetPCLK2Freq();
- break;
-#endif
- default:
- case 0:
- core_debug("TIM: Unknown clock source");
- break;
- }
-
-#if defined(STM32H7xx)
- /* 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);
+ uint8_t clkSrc = 0;
- 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:
- 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:
- // uwTimclock*=1;
- 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;
- }
- }
+ if (tim != (TIM_TypeDef *)NC)
+#ifdef STM32F0xx
+ /* TIMx source CLK is PCKL1 */
+ clkSrc = 1;
#else
- /* When TIMPRE bit of the RCC_DCKCFGR register is reset,
- * if APBx prescaler is 1, then TIMxCLK = PCLKx,
- * otherwise TIMxCLK = 2x PCLKx.
- * When TIMPRE bit in the RCC_DCKCFGR register is set,
- * if APBx prescaler is 1,2 or 4, then TIMxCLK = HCLK,
- * otherwise TIMxCLK = 4x PCLKx
- */
-#if defined(STM32F4xx) || defined(STM32F7xx)
-#if !defined(STM32F405xx) && !defined(STM32F415xx) &&\
- !defined(STM32F407xx) && !defined(STM32F417xx)
- RCC_PeriphCLKInitTypeDef PeriphClkConfig = {};
- HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkConfig);
-
- if (PeriphClkConfig.TIMPresSelection == RCC_TIMPRES_ACTIVATED)
- switch (uwAPBxPrescaler) {
- default:
- case RCC_HCLK_DIV1:
- case RCC_HCLK_DIV2:
- case RCC_HCLK_DIV4:
- uwTimclock = HAL_RCC_GetHCLKFreq();
- break;
- case RCC_HCLK_DIV8:
- case RCC_HCLK_DIV16:
- uwTimclock *= 4;
- break;
- } else
-#endif
-#endif
- switch (uwAPBxPrescaler) {
- default:
- case RCC_HCLK_DIV1:
- // uwTimclock*=1;
- break;
- case RCC_HCLK_DIV2:
- case RCC_HCLK_DIV4:
- case RCC_HCLK_DIV8:
- case RCC_HCLK_DIV16:
- uwTimclock *= 2;
- break;
- }
-#endif /* STM32H7xx */
- return uwTimclock;
-}
-
-/**
- * @brief Attached an interrupt handler
- * @param timer_id : id of the timer
- * @param irqHandle : interrupt handler
- * @retval none
- */
-void attachIntHandle(stimer_t *obj, void (*irqHandle)(stimer_t *))
-{
- obj->irqHandle = irqHandle;
-}
-
-/**
- * @brief This function will attach timer interrupt to with a particular duty cycle on channel x
- * @param timer_id : timer_id_e
- * @param irqHandle : interrupt routine to call
- * @param timChannel : TIM Channel to use
- * This parameter can be one of the following values:
- * @arg TIM_CHANNEL_1: TIM Channel 1 selected
- * @arg TIM_CHANNEL_2: TIM Channel 2 selected
- * @arg TIM_CHANNEL_3: TIM Channel 3 selected
- * @arg TIM_CHANNEL_4: TIM Channel 4 selected
- * @param pulseWidth : phase of the timer where the callback will happen
- * @retval None
- */
-void attachIntHandleOC(stimer_t *obj, void (*irqHandle)(void), uint32_t timChannel, uint16_t pulseWidth)
-{
- TIM_OC_InitTypeDef sConfig = {};
- TIM_HandleTypeDef *handle = &(obj->handle);
-
- sConfig.OCMode = TIM_OCMODE_TIMING;
- sConfig.Pulse = pulseWidth;
- sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
- sConfig.OCFastMode = TIM_OCFAST_DISABLE;
-#if !defined(STM32L0xx) && !defined(STM32L1xx)
- sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
- sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
- sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
-#endif
- HAL_NVIC_SetPriority(getTimerIrq(obj->timer), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
- HAL_NVIC_EnableIRQ(getTimerIrq(obj->timer));
-
- if (HAL_TIM_OC_Init(handle) != HAL_OK) {
- return;
- }
- switch (timChannel) {
- case TIM_CHANNEL_1:
- obj->irqHandleOC_CH1 = irqHandle;
- if (HAL_TIM_OC_ConfigChannel(handle, &sConfig, TIM_CHANNEL_1) == HAL_OK) {
- HAL_TIM_OC_Start_IT(handle, TIM_CHANNEL_1);
- }
- break;
- case TIM_CHANNEL_2:
- obj->irqHandleOC_CH2 = irqHandle;
- if (HAL_TIM_OC_ConfigChannel(handle, &sConfig, TIM_CHANNEL_2) == HAL_OK) {
- HAL_TIM_OC_Start_IT(handle, TIM_CHANNEL_2);
- }
- break;
- case TIM_CHANNEL_3:
- obj->irqHandleOC_CH3 = irqHandle;
- if (HAL_TIM_OC_ConfigChannel(handle, &sConfig, TIM_CHANNEL_3) == HAL_OK) {
- HAL_TIM_OC_Start_IT(handle, TIM_CHANNEL_3);
- }
- break;
- case TIM_CHANNEL_4:
- obj->irqHandleOC_CH4 = irqHandle;
- if (HAL_TIM_OC_ConfigChannel(handle, &sConfig, TIM_CHANNEL_4) == HAL_OK) {
- HAL_TIM_OC_Start_IT(handle, TIM_CHANNEL_4);
- }
- break;
- default:
- break;
- }
- return;
-}
-
-/******************************************************************************/
-/* TIMx IRQ HANDLER */
-/******************************************************************************/
-
-#if defined(TIM1_BASE)
-/**
- * @brief TIM1 IRQHandler common with TIM10 and TIM16 on some STM32F1xx
- * @param None
- * @retval None
- */
-void TIM1_IRQHandler(void)
-{
- if (timer_handles[TIMER1_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER1_INDEX]);
- }
-
-#if defined(STM32F1xx) || defined(STM32F2xx) || defined(STM32F4xx) || defined(STM32F7xx)
-#if defined (TIM10_BASE)
- if (timer_handles[TIMER10_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER10_INDEX]);
- }
-#endif
-#endif
-
-#if defined(STM32F1xx) || defined(STM32F3xx) || defined(STM32G4xx) || defined(STM32L4xx) || \
- defined(STM32WBxx)
-#if defined (TIM16_BASE)
- if (timer_handles[TIMER16_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER16_INDEX]);
- }
-#endif
-#endif
-}
-#endif //TIM1_BASE
-
+ {
+ /* Get source clock depending on TIM instance */
+ switch ((uint32_t)tim) {
#if defined(TIM2_BASE)
-/**
- * @brief TIM2 IRQHandler
- * @param None
- * @retval None
- */
-void TIM2_IRQHandler(void)
-{
- if (timer_handles[TIMER2_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER2_INDEX]);
- }
-}
-#endif //TIM2_BASE
-
+ case (uint32_t)TIM2:
+#endif
#if defined(TIM3_BASE)
-/**
- * @brief TIM3 IRQHandler
- * @param None
- * @retval None
- */
-void TIM3_IRQHandler(void)
-{
- if (timer_handles[TIMER3_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER3_INDEX]);
- }
-}
-#endif //TIM3_BASE
-
+ case (uint32_t)TIM3:
+#endif
#if defined(TIM4_BASE)
-/**
- * @brief TIM4 IRQHandler
- * @param None
- * @retval None
- */
-void TIM4_IRQHandler(void)
-{
- if (timer_handles[TIMER4_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER4_INDEX]);
- }
-}
-#endif //TIM4_BASE
-
+ case (uint32_t)TIM4:
+#endif
#if defined(TIM5_BASE)
-/**
- * @brief TIM5 IRQHandler
- * @param None
- * @retval None
- */
-void TIM5_IRQHandler(void)
-{
- if (timer_handles[TIMER5_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER5_INDEX]);
- }
-}
-#endif //TIM5_BASE
-
+ case (uint32_t)TIM5:
+#endif
#if defined(TIM6_BASE)
-/**
- * @brief TIM6 IRQHandler
- * @param None
- * @retval None
- */
-void TIM6_IRQHandler(void)
-{
- if (timer_handles[TIMER6_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER6_INDEX]);
- }
-}
-#endif //TIM6_BASE
-
+ case (uint32_t)TIM6:
+#endif
#if defined(TIM7_BASE)
-/**
- * @brief TIM7 IRQHandler
- * @param None
- * @retval None
- */
-void TIM7_IRQHandler(void)
-{
- if (timer_handles[TIMER7_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER7_INDEX]);
- }
-}
-#endif //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)
-/**
- * @brief TIM8 IRQHandler
- * @param None
- * @retval None
- */
-void TIM8_IRQHandler(void)
-{
- if (timer_handles[TIMER8_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER8_INDEX]);
- }
-
-#if defined(STM32F1xx) || defined(STM32F2xx) ||defined(STM32F4xx) || defined(STM32F7xx)
- if (timer_handles[TIMER13_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER13_INDEX]);
- }
+ case (uint32_t)TIM8:
#endif
-}
-#endif //TIM8_BASE
-
#if defined(TIM9_BASE)
-/**
- * @brief TIM9 IRQHandler
- * @param None
- * @retval None
- */
-void TIM9_IRQHandler(void)
-{
- if (timer_handles[TIMER9_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER9_INDEX]);
- }
-}
-#endif //TIM9_BASE
-
+ case (uint32_t)TIM9:
+#endif
#if defined(TIM10_BASE)
-#if !defined(STM32F1xx) && !defined(STM32F2xx) && !defined(STM32F4xx) && !defined(STM32F7xx)
-/**
- * @brief TIM10 IRQHandler
- * @param None
- * @retval None
- */
-void TIM10_IRQHandler(void)
-{
- if (timer_handles[TIMER10_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER10_INDEX]);
- }
-}
+ case (uint32_t)TIM10:
#endif
-#endif //TIM10_BASE
-
#if defined(TIM11_BASE)
-/**
- * @brief TIM11 IRQHandler
- * @param None
- * @retval None
- */
-void TIM11_IRQHandler(void)
-{
- if (timer_handles[TIMER11_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER11_INDEX]);
- }
-}
-#endif //TIM11_BASE
-
-#if defined(TIM12_BASE)
-/**
- * @brief TIM12 IRQHandler
- * @param None
- * @retval None
- */
-void TIM12_IRQHandler(void)
-{
- if (timer_handles[TIMER12_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER12_INDEX]);
- }
-}
-#endif //TIM12_BASE
-
-#if defined(TIM13_BASE)
-#if !defined(STM32F1xx) && !defined(STM32F2xx) && !defined(STM32F4xx) && !defined(STM32F7xx)
-/**
- * @brief TIM13 IRQHandler
- * @param None
- * @retval None
- */
-void TIM13_IRQHandler(void)
-{
- if (timer_handles[TIMER13_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER13_INDEX]);
- }
-}
+ case (uint32_t)TIM11:
#endif
-#endif //TIM13_BASE
-
-#if defined(TIM14_BASE)
-/**
- * @brief TIM14 IRQHandler
- * @param None
- * @retval None
- */
-void TIM14_IRQHandler(void)
-{
- if (timer_handles[TIMER14_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER14_INDEX]);
- }
-}
-#endif //TIM14_BASE
-
#if defined(TIM15_BASE)
-/**
- * @brief TIM15 IRQHandler
- * @param None
- * @retval None
- */
-void TIM15_IRQHandler(void)
-{
- if (timer_handles[TIMER15_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER15_INDEX]);
- }
-}
-#endif //TIM15_BASE
-
+ case (uint32_t)TIM15:
+#endif
#if defined(TIM16_BASE)
-#if !defined(STM32F1xx) && !defined(STM32F3xx) && !defined(STM32G4xx) && !defined(STM32L4xx)
-/**
- * @brief TIM16 IRQHandler
- * @param None
- * @retval None
- */
-void TIM16_IRQHandler(void)
-{
- if (timer_handles[TIMER16_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER16_INDEX]);
- }
-}
+ case (uint32_t)TIM16:
#endif
-#endif //TIM16_BASE
-
#if defined(TIM17_BASE)
-/**
- * @brief TIM17 IRQHandler
- * @param None
- * @retval None
- */
-void TIM17_IRQHandler(void)
-{
- if (timer_handles[TIMER17_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER17_INDEX]);
- }
-}
-#endif //TIM17_BASE
-
-#if defined(TIM18_BASE)
-/**
- * @brief TIM18 IRQHandler
- * @param None
- * @retval None
- */
-void TIM18_IRQHandler(void)
-{
- if (timer_handles[TIMER18_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER18_INDEX]);
- }
-}
-#endif //TIM18_BASE
-
+ case (uint32_t)TIM17:
+#endif
#if defined(TIM19_BASE)
-/**
- * @brief TIM19 IRQHandler
- * @param None
- * @retval None
- */
-void TIM19_IRQHandler(void)
-{
- if (timer_handles[TIMER19_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER19_INDEX]);
- }
-}
-#endif //TIM19_BASE
-
+ case (uint32_t)TIM19:
+#endif
#if defined(TIM20_BASE)
-/**
- * @brief TIM20 IRQHandler
- * @param None
- * @retval None
- */
-void TIM20_IRQHandler(void)
-{
- if (timer_handles[TIMER20_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER20_INDEX]);
- }
-}
-#endif //TIM20_BASE
-
+ case (uint32_t)TIM20:
+#endif
#if defined(TIM21_BASE)
-/**
- * @brief TIM21 IRQHandler
- * @param None
- * @retval None
- */
-void TIM21_IRQHandler(void)
-{
- if (timer_handles[TIMER21_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER21_INDEX]);
- }
-}
-#endif //TIM21_BASE
-
+ case (uint32_t)TIM21:
+#endif
#if defined(TIM22_BASE)
-/**
- * @brief TIM22 IRQHandler
- * @param None
- * @retval None
- */
-void TIM22_IRQHandler(void)
-{
- if (timer_handles[TIMER22_INDEX] != NULL) {
- HAL_TIM_IRQHandler(timer_handles[TIMER22_INDEX]);
+ case (uint32_t)TIM22:
+#endif
+ clkSrc = 2;
+ break;
+ default:
+ _Error_Handler("TIM: Unknown timer instance", (int)tim);
+ break;
+ }
}
+#endif
+ return clkSrc;
}
-#endif //TIM22_BASE
+
+
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef __cplusplus
diff --git a/cores/arduino/stm32/timer.h b/cores/arduino/stm32/timer.h
index 02c2bc5c38..9c471b7d59 100644
--- a/cores/arduino/stm32/timer.h
+++ b/cores/arduino/stm32/timer.h
@@ -1,39 +1,15 @@
-/**
- ******************************************************************************
- * @file timer.h
- * @author WI6LABS
- * @version V1.0.0
- * @date 01-August-2016
- * @brief Header for timer module
- ******************************************************************************
- * @attention
- *
- * © COPYRIGHT(c) 2016 STMicroelectronics
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- ******************************************************************************
- */
+/*
+ *******************************************************************************
+ * 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 __TIMER_H
@@ -48,35 +24,6 @@ extern "C" {
#endif
#ifdef HAL_TIM_MODULE_ENABLED
-/* Exported types ------------------------------------------------------------*/
-#define OFFSETOF(type, member) ((uint32_t) (&(((type *)(0))->member)))
-
-typedef struct {
- int32_t count;
- uint8_t state;
-} timerPinInfo_t;
-
-typedef struct timer_s stimer_t;
-
-struct timer_s {
- /* The 1st 2 members TIM_TypeDef *timer
- * and TIM_HandleTypeDef handle should
- * be kept as the first members of this struct
- * to have get_timer_obj() function work as expected
- */
- TIM_TypeDef *timer;
- TIM_HandleTypeDef handle;
- uint8_t idx;
- void (*irqHandle)(stimer_t *);
- void (*irqHandleOC)(stimer_t *, uint32_t);
- void (*irqHandleOC_CH1)(void);
- void (*irqHandleOC_CH2)(void);
- void (*irqHandleOC_CH3)(void);
- void (*irqHandleOC_CH4)(void);
- PinName pin;
- volatile timerPinInfo_t pinInfo;
-};
-
/* Exported constants --------------------------------------------------------*/
#ifndef TIM_IRQ_PRIO
#if (__CORTEX_M == 0x00U)
@@ -89,8 +36,6 @@ struct timer_s {
#define TIM_IRQ_SUBPRIO 0
#endif
-#define MAX_FREQ 65535
-
#if defined(TIM1_BASE) && !defined(TIM1_IRQn)
#if defined(STM32F0xx) || defined(STM32G0xx)
#define TIM1_IRQn TIM1_BRK_UP_TRG_COM_IRQn
@@ -213,32 +158,88 @@ struct timer_s {
#endif
#endif
-/* Exported functions ------------------------------------------------------- */
-
-void timer_enable_clock(TIM_HandleTypeDef *htim);
-void timer_disable_clock(TIM_HandleTypeDef *htim);
-
-void TimerHandleInit(stimer_t *obj, uint16_t period, uint16_t prescaler);
-void TimerHandleDeinit(stimer_t *obj);
-
-void TimerPinInit(stimer_t *obj, uint32_t frequency, uint32_t duration);
-void TimerPinDeinit(stimer_t *obj);
+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;
-void TimerPulseInit(stimer_t *obj, uint16_t period, uint16_t pulseWidth, void (*irqHandle)(stimer_t *, uint32_t));
-void TimerPulseDeinit(stimer_t *obj);
+/* Exported functions ------------------------------------------------------- */
-uint32_t getTimerCounter(stimer_t *obj);
-void setTimerCounter(stimer_t *obj, uint32_t value);
-uint32_t getCCRRegister(stimer_t *obj, uint32_t channel);
-void setCCRRegister(stimer_t *obj, uint32_t channel, uint32_t value);
-void setTimerPrescalerRegister(stimer_t *obj, uint32_t prescaler);
+void enableTimerClock(TIM_HandleTypeDef *htim);
+void disableTimerClock(TIM_HandleTypeDef *htim);
uint32_t getTimerIrq(TIM_TypeDef *tim);
uint8_t getTimerClkSrc(TIM_TypeDef *tim);
-uint32_t getTimerClkFreq(TIM_TypeDef *tim);
-void attachIntHandle(stimer_t *obj, void (*irqHandle)(stimer_t *));
-void attachIntHandleOC(stimer_t *obj, void (*irqHandle)(void), uint32_t timChannel, uint16_t pulseWidth);
+IRQn_Type getTimerUpIrq(TIM_TypeDef *tim);
+IRQn_Type getTimerCCIrq(TIM_TypeDef *tim);
+
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef __cplusplus
diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h
index 081a82c7bf..45d32cbb85 100644
--- a/cores/arduino/wiring.h
+++ b/cores/arduino/wiring.h
@@ -41,6 +41,7 @@
#include
#ifdef __cplusplus
+#include "HardwareTimer.h"
#include "Tone.h"
#include "WCharacter.h"
#include "WSerial.h"
diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c
index ba1455a925..e4b6c4e3ab 100644
--- a/cores/arduino/wiring_analog.c
+++ b/cores/arduino/wiring_analog.c
@@ -52,10 +52,13 @@ static inline uint32_t mapResolution(uint32_t value, uint32_t from, uint32_t to)
if (from == to) {
return value;
}
+ if (value == 0) {
+ return value;
+ }
if (from > to) {
- return value >> (from - to);
+ return (((value + 1) >> (from - to)) - 1);
} else {
- return value << (to - from);
+ return (((value + 1) << (to - from)) - 1);
}
}
@@ -92,7 +95,7 @@ void analogOutputInit(void)
// to digital output.
void analogWrite(uint32_t ulPin, uint32_t ulValue)
{
-#if defined(HAL_DAC_MODULE_ENABLED) || defined(HAL_TIM_MODULE_ENABLED)
+#if defined(HAL_DAC_MODULE_ENABLED)
uint8_t do_init = 0;
#endif
PinName p = digitalPinToPinName(ulPin);
@@ -110,13 +113,10 @@ void analogWrite(uint32_t ulPin, uint32_t ulValue)
#ifdef HAL_TIM_MODULE_ENABLED
if (pin_in_pinmap(p, PinMap_PWM)) {
if (is_pin_configured(p, g_anOutputPinConfigured) == false) {
- do_init = 1;
set_pin_configured(p, g_anOutputPinConfigured);
}
ulValue = mapResolution(ulValue, _writeResolution, PWM_RESOLUTION);
- pwm_start(p, _writeFreq * PWM_MAX_DUTY_CYCLE,
- PWM_MAX_DUTY_CYCLE,
- ulValue, do_init);
+ pwm_start(p, _writeFreq, ulValue);
} else
#endif /* HAL_TIM_MODULE_ENABLED */
{
diff --git a/keywords.txt b/keywords.txt
index 0e496d3285..91d5863ac4 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -834,3 +834,52 @@ GPIO_PIN_12 LITERAL1
GPIO_PIN_13 LITERAL1
GPIO_PIN_14 LITERAL1
GPIO_PIN_15 LITERAL1
+
+# HardwareTimer
+TIMER_DISABLED LITERAL1
+TIMER_OUTPUT_COMPARE LITERAL1
+TIMER_OUTPUT_COMPARE_ACTIVE LITERAL1
+TIMER_OUTPUT_COMPARE_INACTIVE LITERAL1
+TIMER_OUTPUT_COMPARE_TOGGLE LITERAL1
+TIMER_OUTPUT_COMPARE_PWM1 LITERAL1
+TIMER_OUTPUT_COMPARE_PWM2 LITERAL1
+TIMER_OUTPUT_COMPARE_FORCED_ACTIVE LITERAL1
+TIMER_OUTPUT_COMPARE_FORCED_INACTIVE LITERAL1
+TIMER_INPUT_CAPTURE_RISING LITERAL1
+TIMER_INPUT_CAPTURE_FALLING LITERAL1
+TIMER_INPUT_CAPTURE_BOTHEDGE LITERAL1
+TIMER_INPUT_FREQ_DUTY_MEASUREMENT LITERAL1
+TIMER_NOT_USED LITERAL1
+TICK_FORMAT LITERAL1
+MICROSEC_FORMAT LITERAL1
+HERTZ_FORMAT LITERAL1
+TICK_COMPARE_FORMAT LITERAL1
+MICROSEC_COMPARE_FORMAT LITERAL1
+HERTZ_COMPARE_FORMAT LITERAL1
+PERCENT_COMPARE_FORMAT LITERAL1
+RESOLUTION_8B_COMPARE_FORMAT LITERAL1
+RESOLUTION_12B_COMPARE_FORMAT LITERAL1
+
+HardwareTimer KEYWORD1
+
+pause KEYWORD2
+resume KEYWORD2
+setPrescaleFactor KEYWORD2
+getPrescaleFactor KEYWORD2
+setOverflow KEYWORD2
+getOverflow KEYWORD2
+setPWM KEYWORD2
+setCount KEYWORD2
+getCount KEYWORD2
+setMode KEYWORD2
+getCaptureCompare KEYWORD2
+setCaptureCompare KEYWORD2
+attachInterrupt KEYWORD2
+detachInterrupt KEYWORD2
+attachInterrupt KEYWORD2
+detachInterrupt KEYWORD2
+timerHandleDeinit KEYWORD2
+refresh KEYWORD2
+getTimerClkFreq KEYWORD2
+captureCompareCallback KEYWORD2
+updateCallback KEYWORD2
diff --git a/libraries/Servo/src/stm32/Servo.cpp b/libraries/Servo/src/stm32/Servo.cpp
index 33c386c734..4365767c67 100644
--- a/libraries/Servo/src/stm32/Servo.cpp
+++ b/libraries/Servo/src/stm32/Servo.cpp
@@ -20,18 +20,16 @@
#include
#include
+#include
+
+#if defined(HAL_TIM_MODULE_ENABLED) && defined(TIMER_SERVO)
static servo_t servos[MAX_SERVOS]; // static array of servo structures
-static volatile int8_t timerChannel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
+static volatile int8_t timerChannel[_Nbr_16timers] = {-1}; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
-uint8_t ServoCount = 0; // the total number of attached servos
-stimer_t _timer;
+static HardwareTimer TimerServo(TIMER_SERVO);
-// convenience macros
-#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
-#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
-#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
-#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
+uint8_t ServoCount = 0; // the total number of attached servos
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
@@ -40,57 +38,62 @@ stimer_t _timer;
#define SERVO_TIMER(_timer_id) ((timer16_Sequence_t)(_timer_id))
/************ static functions common to all instances ***********************/
-static void ServoIrqHandle(stimer_t *obj, uint32_t channel)
+
+volatile uint32_t CumulativeCountSinceRefresh = 0;
+static void Servo_PeriodElapsedCallback(HardwareTimer *HT)
{
- uint8_t timer_id = obj->idx;
+ UNUSED(HT);
+ // Only 1 timer used
+ timer16_Sequence_t timer_id = _timer1;
- if (timerChannel[SERVO_TIMER(timer_id)] < 0) {
- setTimerCounter(obj, 0); // channel set to -1 indicated that refresh interval completed so reset the timer
+ if (timerChannel[timer_id] < 0) {
+ // Restart from 1st servo
+ CumulativeCountSinceRefresh = 0;
} else {
- if (SERVO_INDEX(SERVO_TIMER(timer_id), timerChannel[SERVO_TIMER(timer_id)]) < ServoCount &&
- SERVO(SERVO_TIMER(timer_id), timerChannel[SERVO_TIMER(timer_id)]).Pin.isActive == true) {
- digitalWrite(SERVO(SERVO_TIMER(timer_id), timerChannel[SERVO_TIMER(timer_id)]).Pin.nbr, LOW); // pulse this channel low if activated
+ if (timerChannel[timer_id] < ServoCount && servos[timerChannel[timer_id]].Pin.isActive == true) {
+ digitalWrite(servos[timerChannel[timer_id]].Pin.nbr, LOW); // pulse this channel low if activated
}
}
- timerChannel[SERVO_TIMER(timer_id)]++; // increment to the next channel
- if (SERVO_INDEX(SERVO_TIMER(timer_id), timerChannel[SERVO_TIMER(timer_id)]) < ServoCount &&
- timerChannel[SERVO_TIMER(timer_id)] < SERVOS_PER_TIMER) {
- if (SERVO(SERVO_TIMER(timer_id), timerChannel[SERVO_TIMER(timer_id)]).Pin.isActive == true) { // check if activated
- digitalWrite(SERVO(SERVO_TIMER(timer_id), timerChannel[SERVO_TIMER(timer_id)]).Pin.nbr, HIGH); // its an active channel so pulse it high
+ timerChannel[timer_id]++; // increment to the next channel
+ if (timerChannel[timer_id] < ServoCount && timerChannel[timer_id] < SERVOS_PER_TIMER) {
+ TimerServo.setOverflow(servos[timerChannel[timer_id]].ticks);
+ CumulativeCountSinceRefresh += servos[timerChannel[timer_id]].ticks;
+ if (servos[timerChannel[timer_id]].Pin.isActive == true) {
+ // check if activated
+ digitalWrite(servos[timerChannel[timer_id]].Pin.nbr, HIGH); // its an active channel so pulse it high
}
- setCCRRegister(obj, channel, getTimerCounter(obj) + SERVO(SERVO_TIMER(timer_id), timerChannel[SERVO_TIMER(timer_id)]).ticks);
} else {
// finished all channels so wait for the refresh period to expire before starting over
- if (getTimerCounter(obj) + 4 < REFRESH_INTERVAL) { // allow a few ticks to ensure the next OCR1A not missed
- setCCRRegister(obj, channel, (unsigned int)REFRESH_INTERVAL);
+ if (CumulativeCountSinceRefresh + 4 < REFRESH_INTERVAL) {
+ // allow a few ticks to ensure the next OCR1A not missed
+ TimerServo.setOverflow(REFRESH_INTERVAL - CumulativeCountSinceRefresh);
} else {
- setCCRRegister(obj, channel, getTimerCounter(obj) + 4); // at least REFRESH_INTERVAL has elapsed
+ // generate update to restart immediately from the beginning with the 1st servo
+ TimerServo.refresh();
}
- timerChannel[SERVO_TIMER(timer_id)] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
+ timerChannel[timer_id] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
}
-static void initISR(stimer_t *obj)
+static void TimerServoInit()
{
- /*
- * Timer clock set by default at 1us.
- * Period set to REFRESH_INTERVAL*3
- * Default pulse width set to DEFAULT_PULSE_WIDTH
- */
- TimerPulseInit(obj, REFRESH_INTERVAL * 3, DEFAULT_PULSE_WIDTH, ServoIrqHandle);
+ // prescaler is computed so that timer tick correspond to 1 microseconde
+ uint32_t prescaler = TimerServo.getTimerClkFreq() / 1000000;
+
+ TimerServo.setMode(1, TIMER_OUTPUT_COMPARE, NC);
+ TimerServo.setPrescaleFactor(prescaler);
+ TimerServo.setOverflow(REFRESH_INTERVAL); // thanks to prescaler Tick = microsec
+ TimerServo.attachInterrupt(Servo_PeriodElapsedCallback);
+ TimerServo.resume();
}
-static void finISR(stimer_t *obj)
-{
- TimerPulseDeinit(obj);
-}
-static bool isTimerActive(timer16_Sequence_t timer)
+static bool isTimerActive()
{
// returns true if any servo is active on this timer
for (uint8_t channel = 0; channel < SERVOS_PER_TIMER; channel++) {
- if (SERVO(timer, channel).Pin.isActive == true) {
+ if (servos[channel].Pin.isActive == true) {
return true;
}
}
@@ -116,19 +119,16 @@ uint8_t Servo::attach(int pin)
uint8_t Servo::attach(int pin, int min, int max)
{
- timer16_Sequence_t timer;
-
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
+ servos[this->servoIndex].ticks = DEFAULT_PULSE_WIDTH;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min) / 4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max) / 4;
// initialize the timer if it has not already been initialized
- timer = SERVO_INDEX_TO_TIMER(servoIndex);
- if (isTimerActive(timer) == false) {
- _timer.idx = timer;
- initISR(&_timer);
+ if (isTimerActive() == false) {
+ TimerServoInit();
}
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
@@ -137,12 +137,10 @@ uint8_t Servo::attach(int pin, int min, int max)
void Servo::detach()
{
- timer16_Sequence_t timer;
-
servos[this->servoIndex].Pin.isActive = false;
- timer = SERVO_INDEX_TO_TIMER(servoIndex);
- if (isTimerActive(timer) == false) {
- finISR(&_timer);
+
+ if (isTimerActive() == false) {
+ TimerServo.pause();
}
}
@@ -198,4 +196,41 @@ bool Servo::attached()
return servos[this->servoIndex].Pin.isActive;
}
+#else
+
+#warning "TIMER_TONE or HAL_TIM_MODULE_ENABLED not defined"
+Servo::Servo() {}
+uint8_t Servo::attach(int pin)
+{
+ UNUSED(pin);
+ return 0;
+}
+uint8_t Servo::attach(int pin, int min, int max)
+{
+ UNUSED(pin);
+ UNUSED(min);
+ UNUSED(max);
+ return 0;
+}
+void Servo::detach() {}
+void Servo::write(int value)
+{
+ UNUSED(value);
+}
+void Servo::writeMicroseconds(int value)
+{
+ UNUSED(value);
+}
+int Servo::read()
+{
+ return 0;
+}
+int Servo::readMicroseconds()
+{
+ return 0;
+}
+bool Servo::attached() {}
+
+#endif /* HAL_TIM_MODULE_ENABLED && TIMER_SERVO */
+
#endif // ARDUINO_ARCH_STM32
diff --git a/variants/ARMED_V1/variant.h b/variants/ARMED_V1/variant.h
index d60e12d4b1..871feeb682 100644
--- a/variants/ARMED_V1/variant.h
+++ b/variants/ARMED_V1/variant.h
@@ -134,7 +134,7 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-// Do not use timer used by PWM pin. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
#define TIMER_SERVO TIM7
diff --git a/variants/BLACK_F407XX/variant.h b/variants/BLACK_F407XX/variant.h
index cf9e7bf0e9..79035a9968 100644
--- a/variants/BLACK_F407XX/variant.h
+++ b/variants/BLACK_F407XX/variant.h
@@ -295,11 +295,9 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
// Define here Serial instance number to map on Serial generic name
diff --git a/variants/BLUE_F407VE_Mini/variant.h b/variants/BLUE_F407VE_Mini/variant.h
index d5d1fd31cf..9ec1c11b62 100644
--- a/variants/BLUE_F407VE_Mini/variant.h
+++ b/variants/BLUE_F407VE_Mini/variant.h
@@ -170,11 +170,9 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
// Define here Serial instance number to map on Serial generic name
diff --git a/variants/DEMO_F030F4/variant.h b/variants/DEMO_F030F4/variant.h
index 464710f2ae..08930af491 100644
--- a/variants/DEMO_F030F4/variant.h
+++ b/variants/DEMO_F030F4/variant.h
@@ -76,11 +76,9 @@ extern "C" {
#define PIN_WIRE_SCL PA9 // Default for Arduino connector compatibility
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM17
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM16 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM16
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/DISCO_F030R8/variant.h b/variants/DISCO_F030R8/variant.h
index 85f5aa25f4..95fe58d723 100644
--- a/variants/DISCO_F030R8/variant.h
+++ b/variants/DISCO_F030R8/variant.h
@@ -127,11 +127,9 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-//Do not use basic timer: OC is required
-#define TIMER_SERVO TIM3 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM14
// UART Definitions
#define SERIAL_UART_INSTANCE 1 // USART 1
diff --git a/variants/DISCO_F072RB/variant.h b/variants/DISCO_F072RB/variant.h
index 07f94a8321..32a7fec7a4 100644
--- a/variants/DISCO_F072RB/variant.h
+++ b/variants/DISCO_F072RB/variant.h
@@ -139,11 +139,9 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-//Do not use basic timer: OC is required
-#define TIMER_SERVO TIM3 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 1 // USART 1
diff --git a/variants/DISCO_F100RB/variant.h b/variants/DISCO_F100RB/variant.h
index 97ec1db718..3622cbaba9 100644
--- a/variants/DISCO_F100RB/variant.h
+++ b/variants/DISCO_F100RB/variant.h
@@ -106,11 +106,9 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM15
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM17 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/DISCO_F407VG/variant.h b/variants/DISCO_F407VG/variant.h
index a487af59a5..ee7671d13b 100644
--- a/variants/DISCO_F407VG/variant.h
+++ b/variants/DISCO_F407VG/variant.h
@@ -138,7 +138,7 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-// Do not use timer used by PWM pin. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
#define TIMER_SERVO TIM7
diff --git a/variants/DISCO_F746NG/variant.h b/variants/DISCO_F746NG/variant.h
index 5fd696ca97..92de9a8a4f 100644
--- a/variants/DISCO_F746NG/variant.h
+++ b/variants/DISCO_F746NG/variant.h
@@ -68,11 +68,9 @@ extern "C" {
#define USER_BTN PI11
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 1 //Connected to ST-Link
diff --git a/variants/DISCO_L072CZ_LRWAN1/variant.h b/variants/DISCO_L072CZ_LRWAN1/variant.h
index 7dd7a36718..9f65dd6826 100644
--- a/variants/DISCO_L072CZ_LRWAN1/variant.h
+++ b/variants/DISCO_L072CZ_LRWAN1/variant.h
@@ -105,11 +105,9 @@ extern "C" {
#define RADIO_DIO_5_PORT PA4
//Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM22
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/DISCO_L475VG_IOT/variant.h b/variants/DISCO_L475VG_IOT/variant.h
index 215e5e3aca..6e44bc1eae 100644
--- a/variants/DISCO_L475VG_IOT/variant.h
+++ b/variants/DISCO_L475VG_IOT/variant.h
@@ -128,11 +128,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 1 //Connected to ST-Link
diff --git a/variants/DIYMROE_F407VGT/variant.h b/variants/DIYMROE_F407VGT/variant.h
index ddfc0fcd2f..c5b7da57c1 100644
--- a/variants/DIYMROE_F407VGT/variant.h
+++ b/variants/DIYMROE_F407VGT/variant.h
@@ -162,11 +162,9 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
// Define here Serial instance number to map on Serial generic name
diff --git a/variants/EEXTR_F030_V1/variant.h b/variants/EEXTR_F030_V1/variant.h
index 0e0feae91f..bcd9d39c81 100644
--- a/variants/EEXTR_F030_V1/variant.h
+++ b/variants/EEXTR_F030_V1/variant.h
@@ -105,11 +105,9 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-//Do not use basic timer: OC is required
-#define TIMER_SERVO TIM14 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM14
// UART Definitions
#define SERIAL_UART_INSTANCE 1 // USART 1
diff --git a/variants/FK407M1/variant.h b/variants/FK407M1/variant.h
index 088155bbe2..b728143230 100644
--- a/variants/FK407M1/variant.h
+++ b/variants/FK407M1/variant.h
@@ -144,11 +144,9 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
// Define here Serial instance number to map on Serial generic name
diff --git a/variants/HY_TinySTM103T/variant.h b/variants/HY_TinySTM103T/variant.h
index 0ca4bc5e0b..95cf8161bb 100644
--- a/variants/HY_TinySTM103T/variant.h
+++ b/variants/HY_TinySTM103T/variant.h
@@ -87,11 +87,9 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM4
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM3
+#define TIMER_SERVO TIM4
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/MALYANM200_F070CB/variant.h b/variants/MALYANM200_F070CB/variant.h
index 94fd7a79b2..c2c80b970f 100644
--- a/variants/MALYANM200_F070CB/variant.h
+++ b/variants/MALYANM200_F070CB/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM3
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM3 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/MALYANM200_F103CB/variant.h b/variants/MALYANM200_F103CB/variant.h
index f195d76c7b..f59785c988 100644
--- a/variants/MALYANM200_F103CB/variant.h
+++ b/variants/MALYANM200_F103CB/variant.h
@@ -95,11 +95,8 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM4
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_TONE TIM3
+#define TIMER_SERVO TIM4
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/MAPLEMINI_F103CB/variant.h b/variants/MAPLEMINI_F103CB/variant.h
index 6010425a0f..ad5874374c 100644
--- a/variants/MAPLEMINI_F103CB/variant.h
+++ b/variants/MAPLEMINI_F103CB/variant.h
@@ -98,11 +98,9 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM4
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM3
+#define TIMER_SERVO TIM4
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/NUCLEO_F030R8/variant.h b/variants/NUCLEO_F030R8/variant.h
index 7a90911716..eadc7c0856 100644
--- a/variants/NUCLEO_F030R8/variant.h
+++ b/variants/NUCLEO_F030R8/variant.h
@@ -102,11 +102,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM3 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM3
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F091RC/variant.h b/variants/NUCLEO_F091RC/variant.h
index 63ed5d1d28..b29b7628a8 100644
--- a/variants/NUCLEO_F091RC/variant.h
+++ b/variants/NUCLEO_F091RC/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F103RB/variant.h b/variants/NUCLEO_F103RB/variant.h
index 6f05f7c730..ae97c7da47 100644
--- a/variants/NUCLEO_F103RB/variant.h
+++ b/variants/NUCLEO_F103RB/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM4
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM3
+#define TIMER_SERVO TIM4
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F207ZG/variant.h b/variants/NUCLEO_F207ZG/variant.h
index c48cf63b33..4852b463b9 100644
--- a/variants/NUCLEO_F207ZG/variant.h
+++ b/variants/NUCLEO_F207ZG/variant.h
@@ -144,11 +144,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 3 //Connected to ST-Link
diff --git a/variants/NUCLEO_F302R8/variant.h b/variants/NUCLEO_F302R8/variant.h
index 41ac9e3158..ca42ae910d 100644
--- a/variants/NUCLEO_F302R8/variant.h
+++ b/variants/NUCLEO_F302R8/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM2
+#define TIMER_SERVO TIM6
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F303K8/variant.h b/variants/NUCLEO_F303K8/variant.h
index a82d3a7974..5efff97c3b 100644
--- a/variants/NUCLEO_F303K8/variant.h
+++ b/variants/NUCLEO_F303K8/variant.h
@@ -69,11 +69,9 @@ extern "C" {
#define PIN_WIRE_SCL 5
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F303RE/variant.h b/variants/NUCLEO_F303RE/variant.h
index 6ad737c746..5563830792 100644
--- a/variants/NUCLEO_F303RE/variant.h
+++ b/variants/NUCLEO_F303RE/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-//Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F401RE/variant.h b/variants/NUCLEO_F401RE/variant.h
index 6e5a26431a..5ddd33be79 100644
--- a/variants/NUCLEO_F401RE/variant.h
+++ b/variants/NUCLEO_F401RE/variant.h
@@ -99,11 +99,8 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
#define TIMER_TONE TIM10
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM11
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F411RE/variant.h b/variants/NUCLEO_F411RE/variant.h
index b09249394a..3d97e49e1f 100644
--- a/variants/NUCLEO_F411RE/variant.h
+++ b/variants/NUCLEO_F411RE/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM10
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM11
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F429ZI/variant.h b/variants/NUCLEO_F429ZI/variant.h
index a4f1dc88ea..1dd629038a 100644
--- a/variants/NUCLEO_F429ZI/variant.h
+++ b/variants/NUCLEO_F429ZI/variant.h
@@ -132,11 +132,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 3 //Connected to ST-Link
diff --git a/variants/NUCLEO_F446RE/variant.h b/variants/NUCLEO_F446RE/variant.h
index 4587001e76..f1f5f66245 100644
--- a/variants/NUCLEO_F446RE/variant.h
+++ b/variants/NUCLEO_F446RE/variant.h
@@ -100,11 +100,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM10
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_F767ZI/variant.h b/variants/NUCLEO_F767ZI/variant.h
index b713430bc5..308f27e60d 100644
--- a/variants/NUCLEO_F767ZI/variant.h
+++ b/variants/NUCLEO_F767ZI/variant.h
@@ -132,11 +132,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 3 //Connected to ST-Link
diff --git a/variants/NUCLEO_G071RB/variant.h b/variants/NUCLEO_G071RB/variant.h
index e6df05a752..978357e034 100644
--- a/variants/NUCLEO_G071RB/variant.h
+++ b/variants/NUCLEO_G071RB/variant.h
@@ -106,11 +106,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_H743ZI/variant.h b/variants/NUCLEO_H743ZI/variant.h
index 2acf1bd5e7..07c5c9ebd0 100644
--- a/variants/NUCLEO_H743ZI/variant.h
+++ b/variants/NUCLEO_H743ZI/variant.h
@@ -193,11 +193,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM12
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 3 //Connected to ST-Link
diff --git a/variants/NUCLEO_L031K6/variant.h b/variants/NUCLEO_L031K6/variant.h
index 82ffda7e5b..ac38239ec6 100644
--- a/variants/NUCLEO_L031K6/variant.h
+++ b/variants/NUCLEO_L031K6/variant.h
@@ -78,11 +78,8 @@ extern "C" {
#define PIN_WIRE_SCL 5
//Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c
-#define TIMER_TONE TIM22
-
-//Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_TONE TIM2
+#define TIMER_SERVO TIM21
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //ex: 2 for Serial2 (USART2)
diff --git a/variants/NUCLEO_L053R8/variant.h b/variants/NUCLEO_L053R8/variant.h
index 61fcd6c53c..da150ff60b 100644
--- a/variants/NUCLEO_L053R8/variant.h
+++ b/variants/NUCLEO_L053R8/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM2
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_L073RZ/variant.h b/variants/NUCLEO_L073RZ/variant.h
index e6023fa17c..7a526e5e05 100644
--- a/variants/NUCLEO_L073RZ/variant.h
+++ b/variants/NUCLEO_L073RZ/variant.h
@@ -112,11 +112,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c
-#define TIMER_TONE TIM3
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM3 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //ex: 2 for Serial2 (USART2)
diff --git a/variants/NUCLEO_L152RE/variant.h b/variants/NUCLEO_L152RE/variant.h
index 017394a6ea..9e8aa6767f 100644
--- a/variants/NUCLEO_L152RE/variant.h
+++ b/variants/NUCLEO_L152RE/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM10
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_L412KB/variant.h b/variants/NUCLEO_L412KB/variant.h
index 1aa87d645a..63e29fceed 100644
--- a/variants/NUCLEO_L412KB/variant.h
+++ b/variants/NUCLEO_L412KB/variant.h
@@ -78,11 +78,9 @@ extern "C" {
#define PIN_WIRE_SCL 5
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM2
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_L432KC/variant.h b/variants/NUCLEO_L432KC/variant.h
index fa1a61bee7..e6226fad7f 100644
--- a/variants/NUCLEO_L432KC/variant.h
+++ b/variants/NUCLEO_L432KC/variant.h
@@ -69,11 +69,9 @@ extern "C" {
#define PIN_WIRE_SCL 5
// Timer Definitions
-//Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_L452RE/variant.h b/variants/NUCLEO_L452RE/variant.h
index 52d21aaa46..0ed4fafcc5 100644
--- a/variants/NUCLEO_L452RE/variant.h
+++ b/variants/NUCLEO_L452RE/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM2
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
diff --git a/variants/NUCLEO_L476RG/variant.h b/variants/NUCLEO_L476RG/variant.h
index 5bf06aa719..6c26344b06 100644
--- a/variants/NUCLEO_L476RG/variant.h
+++ b/variants/NUCLEO_L476RG/variant.h
@@ -98,12 +98,9 @@ extern "C" {
// On-board user button
#define USER_BTN PC13
-// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 2 //Connected to ST-Link
@@ -141,6 +138,7 @@ extern "C" {
// pins are NOT connected to anything by default.
#define SERIAL_PORT_MONITOR Serial
#define SERIAL_PORT_HARDWARE Serial
-#endif
+#endif // __cplusplus
+
#endif /* _VARIANT_ARDUINO_STM32_ */
diff --git a/variants/NUCLEO_L496ZG/variant.h b/variants/NUCLEO_L496ZG/variant.h
index 21aa5cf230..f98bc37d7c 100644
--- a/variants/NUCLEO_L496ZG/variant.h
+++ b/variants/NUCLEO_L496ZG/variant.h
@@ -193,11 +193,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 0 //Connected to ST-Link - LPUART1
diff --git a/variants/NUCLEO_L4R5ZI/variant.h b/variants/NUCLEO_L4R5ZI/variant.h
index 695f28b66f..94c2d7eb7e 100644
--- a/variants/NUCLEO_L4R5ZI/variant.h
+++ b/variants/NUCLEO_L4R5ZI/variant.h
@@ -191,11 +191,9 @@ extern "C" {
#define USER_BTN PC13
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 0 //Connected to ST-Link - LPUART1
diff --git a/variants/PILL_F103XX/variant.h b/variants/PILL_F103XX/variant.h
index ad23053eea..2b452f73a6 100644
--- a/variants/PILL_F103XX/variant.h
+++ b/variants/PILL_F103XX/variant.h
@@ -103,11 +103,9 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM3
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM2
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/PILL_F303XX/variant.h b/variants/PILL_F303XX/variant.h
index 69d5f6465e..dffc3271ed 100644
--- a/variants/PILL_F303XX/variant.h
+++ b/variants/PILL_F303XX/variant.h
@@ -99,11 +99,9 @@ extern "C" {
#define PIN_WIRE_SCL PB6
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM2
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/PNUCLEO_WB55RG/variant.h b/variants/PNUCLEO_WB55RG/variant.h
index c86c519e0f..9c767a1397 100644
--- a/variants/PNUCLEO_WB55RG/variant.h
+++ b/variants/PNUCLEO_WB55RG/variant.h
@@ -104,11 +104,9 @@ extern "C" {
#define USER_BTN SW1_BTN
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM16
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM17 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM17
// UART Definitions
#define SERIAL_UART_INSTANCE 1 //Connected to ST-Link
diff --git a/variants/PRNTR_F407_V1/variant.h b/variants/PRNTR_F407_V1/variant.h
index f59346a33d..bac9993d2c 100644
--- a/variants/PRNTR_F407_V1/variant.h
+++ b/variants/PRNTR_F407_V1/variant.h
@@ -192,7 +192,7 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-// Do not use timer used by PWM pin. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
#define TIMER_SERVO TIM7
diff --git a/variants/RAK811_TRACKER/variant.h b/variants/RAK811_TRACKER/variant.h
index 1f28fb79ae..0b3bd0538f 100644
--- a/variants/RAK811_TRACKER/variant.h
+++ b/variants/RAK811_TRACKER/variant.h
@@ -97,11 +97,9 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
-#define TIMER_TONE TIM10
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/REMRAM_V1/variant.h b/variants/REMRAM_V1/variant.h
index 41c4d4a870..fde8e3208c 100644
--- a/variants/REMRAM_V1/variant.h
+++ b/variants/REMRAM_V1/variant.h
@@ -155,12 +155,9 @@ extern "C"
#define LED_BUILTIN LED_YELLOW
// Timer Definitions
-
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM3 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 1
diff --git a/variants/RUMBA32_F446VE/variant.h b/variants/RUMBA32_F446VE/variant.h
index 1f76431e10..44f19c5ede 100644
--- a/variants/RUMBA32_F446VE/variant.h
+++ b/variants/RUMBA32_F446VE/variant.h
@@ -134,7 +134,7 @@ extern "C" {
#define PIN_WIRE_SCL PB8
// Timer Definitions
-// Do not use timer used by PWM pin. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
#define TIMER_SERVO TIM7
diff --git a/variants/SPARKY_F303CC/variant.h b/variants/SPARKY_F303CC/variant.h
index 88cb4415b0..72cbfcf91e 100644
--- a/variants/SPARKY_F303CC/variant.h
+++ b/variants/SPARKY_F303CC/variant.h
@@ -100,11 +100,10 @@ extern "C" {
#define PIN_WIRE_SCL PA9
// Timer Definitions
-// Do not use timer used by PWM pins when possible. See PinMap_PWM.
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
#define TIMER_TONE TIM6
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work
+#define TIMER_SERVO TIM7
// UART Definitions
#define SERIAL_UART_INSTANCE 3
diff --git a/variants/board_template/variant.h b/variants/board_template/variant.h
index d9843a486a..e65b1c3cce 100644
--- a/variants/board_template/variant.h
+++ b/variants/board_template/variant.h
@@ -105,11 +105,9 @@ extern "C" {
//#define I2C_TIMING_FMP 0x00000000
// Timer Definitions (optional)
-//Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c
-#define TIMER_TONE TIMx
-
-// Do not use basic timer: OC is required
-#define TIMER_SERVO TIMx //TODO: advanced-control timers don't work
+// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin
+#define TIMER_TONE TIM6
+#define TIMER_SERVO TIM7
// UART Definitions
// Define here Serial instance number to map on Serial generic name