From 7e682d25c0401b4282f2899b0a8c8f5445cef697 Mon Sep 17 00:00:00 2001 From: Alexandre Bourdiol Date: Thu, 28 Nov 2019 14:17:50 +0100 Subject: [PATCH 1/2] HardwareTimer: rework internal mapping of arduino API with HAL/LL API Main rework: * HAL_TIM_Base_Init() is now called only once at object creation * HAL_TIM_xxx_ConfigChannel is now done in setMode() * HAL_TIM_xxx_Start is done in resumeChannel() * use LL when possible * Configuration are directly made through hardware register access (xhen possible), then remove useless attribut * Add new API to pause only one channel: pauseChannel(uint32_t channel) resumeChannel(uint32_t channel) fixes #763 * integration of PR #767 Flexible interrupts handling --- cores/arduino/HardwareTimer.cpp | 499 ++++++++++++++++++++++---------- cores/arduino/HardwareTimer.h | 15 +- 2 files changed, 349 insertions(+), 165 deletions(-) diff --git a/cores/arduino/HardwareTimer.cpp b/cores/arduino/HardwareTimer.cpp index c3174cc1ba..d077c61f38 100644 --- a/cores/arduino/HardwareTimer.cpp +++ b/cores/arduino/HardwareTimer.cpp @@ -64,38 +64,37 @@ HardwareTimer::HardwareTimer(TIM_TypeDef *instance) _timerObj.handle.Lock = HAL_UNLOCKED; _timerObj.handle.State = HAL_TIM_STATE_RESET; - _timerObj.handle.Instance = instance; _timerObj.__this = (void *)this; _timerObj.preemptPriority = TIM_IRQ_PRIO; _timerObj.subPriority = TIM_IRQ_SUBPRIO; - // Enable Timer clock + /* Enable timer clock. Even if it is also done in HAL_TIM_Base_MspInit(), + it is done there so that it is possible to write registers right now */ enableTimerClock(&(_timerObj.handle)); - // 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; + // Initialize NULL callbacks + for (int i = 0; i < TIMER_CHANNELS + 1 ; i++) { + callbacks[i] = NULL; + } -#if defined(TIM_CR2_OIS1) - _channelOC[i].OCIdleState = TIM_OCIDLESTATE_RESET; -#endif + // Initialize channel mode and complementary + for (int i = 0; i < TIMER_CHANNELS; i++) { #if defined(TIM_CCER_CC1NE) - _channelOC[i].OCNPolarity = TIM_OCNPOLARITY_HIGH; -#if defined(TIM_CR2_OIS1) - _channelOC[i].OCNIdleState = TIM_OCNIDLESTATE_RESET; -#endif + isComplementaryChannel[i] = false; #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 + 1 ; i++) { - callbacks[i] = NULL; - } + _ChannelMode[i] = TIMER_DISABLED; } + + /* Configure timer with some default values */ + _timerObj.handle.Init.Prescaler = 0; + _timerObj.handle.Init.Period = 0xFFFF; // 16bit max value + _timerObj.handle.Init.CounterMode = TIM_COUNTERMODE_UP; + _timerObj.handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; +#if defined(TIM_RCR_REP) + _timerObj.handle.Init.RepetitionCounter = 0; +#endif + _timerObj.handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + HAL_TIM_Base_Init(&(_timerObj.handle)); } /** @@ -105,7 +104,47 @@ HardwareTimer::HardwareTimer(TIM_TypeDef *instance) */ void HardwareTimer::pause() { - HAL_TIM_Base_Stop_IT(&(_timerObj.handle)); + // Disable all IT + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_UPDATE); + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_CC1); + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_CC2); + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_CC3); + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_CC4); + + // Disable timer unconditionally + LL_TIM_DisableCounter(_timerObj.handle.Instance); +} + +/** + * @brief Pause only one channel. + * Timer is still running but channel is disabled (output and interrupt) + * @param Arduino channel [1..4] + * @retval None + */ +void HardwareTimer::pauseChannel(uint32_t channel) +{ + int timAssociatedInputChannel; + int LLChannel = getLLChannel(channel); + if (LLChannel == -1) { + Error_Handler(); + } + + int interrupt = getIT(channel); + if (interrupt == -1) { + Error_Handler(); + } + + // Disable channel and corresponding interrupt + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), interrupt); + LL_TIM_CC_DisableChannel(_timerObj.handle.Instance, LLChannel); + + // In case 2 channels are used, disbale also the 2nd one + if (_ChannelMode[channel - 1] == TIMER_INPUT_FREQ_DUTY_MEASUREMENT) { + // Identify and configure 2nd associated channel + timAssociatedInputChannel = getAssociatedChannel(channel); + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), getIT(timAssociatedInputChannel)); + LL_TIM_CC_DisableChannel(_timerObj.handle.Instance, getLLChannel(timAssociatedInputChannel)); + } } /** @@ -115,21 +154,12 @@ void HardwareTimer::pause() */ void HardwareTimer::resume(void) { - _timerObj.handle.Init.CounterMode = TIM_COUNTERMODE_UP; - _timerObj.handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; -#if defined(TIM_RCR_REP) - _timerObj.handle.Init.RepetitionCounter = 0; -#endif - _timerObj.handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; - HAL_TIM_Base_Init(&(_timerObj.handle)); - - // Start timer with IT if required + // Clear flag and ennable IT if (callbacks[0] != NULL) { - HAL_TIM_Base_Start_IT(&(_timerObj.handle)); - } else { - HAL_TIM_Base_Start(&(_timerObj.handle)); + __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), TIM_FLAG_UPDATE); + __HAL_TIM_ENABLE_IT(&(_timerObj.handle), TIM_IT_UPDATE); } - + // Resume all channels resumeChannel(1); resumeChannel(2); resumeChannel(3); @@ -137,7 +167,7 @@ void HardwareTimer::resume(void) } /** - * @brief Convert arduino into HAL channel + * @brief Convert arduino channel into HAL channel * @param Arduino channel [1..4] * @retval HAL channel. return -1 if arduino channel is invalid */ @@ -164,6 +194,115 @@ int HardwareTimer::getChannel(uint32_t channel) return return_value; } +/** + * @brief Convert arduino channel into LL channel + * @param Arduino channel [1..4] + * @retval LL channel. return -1 if arduino channel is invalid + */ +int HardwareTimer::getLLChannel(uint32_t channel) +{ + uint32_t return_value; +#if defined(TIM_CCER_CC1NE) + if (isComplementaryChannel[channel - 1]) { + // Complementary channel + switch (channel) { + case 1: + return_value = LL_TIM_CHANNEL_CH1N; + break; + case 2: + return_value = LL_TIM_CHANNEL_CH2N; + break; + case 3: + return_value = LL_TIM_CHANNEL_CH3N; + break; +#if defined(LL_TIM_CHANNEL_CH4N) + case 4: + return_value = LL_TIM_CHANNEL_CH4N; + break; +#endif + default: + return_value = -1; + } + } else +#endif + { + // Regular channel not complementary + switch (channel) { + case 1: + return_value = LL_TIM_CHANNEL_CH1; + break; + case 2: + return_value = LL_TIM_CHANNEL_CH2; + break; + case 3: + return_value = LL_TIM_CHANNEL_CH3; + break; + case 4: + return_value = LL_TIM_CHANNEL_CH4; + break; + default: + return_value = -1; + } + } + return return_value; +} + +/** + * @brief Convert arduino channel into HAL Interrupt ID + * @param Arduino channel [1..4] + * @retval HAL channel. return -1 if arduino channel is invalid + */ +int HardwareTimer::getIT(uint32_t channel) +{ + uint32_t return_value; + + switch (channel) { + case 1: + return_value = TIM_IT_CC1; + break; + case 2: + return_value = TIM_IT_CC2; + break; + case 3: + return_value = TIM_IT_CC3; + break; + case 4: + return_value = TIM_IT_CC4; + break; + default: + return_value = -1; + } + return return_value; +} + +/** + * @brief Get input associated channel + * Channel 1 and 2 are associated; channel 3 and 4 are associated + * @param Arduino channel [1..4] + * @retval HAL channel. return -1 if arduino channel is invalid + */ +int HardwareTimer::getAssociatedChannel(uint32_t channel) +{ + int timAssociatedInputChannel = -1; + switch (channel) { + case 1: + timAssociatedInputChannel = 2; + break; + case 2: + timAssociatedInputChannel = 1; + break; + case 3: + timAssociatedInputChannel = 4; + break; + case 4: + timAssociatedInputChannel = 3; + break; + default: + break; + } + return timAssociatedInputChannel; +} + /** * @brief Configure specified channel and resume/start timer * @param Arduino channel [1..4] @@ -172,64 +311,77 @@ int HardwareTimer::getChannel(uint32_t channel) void HardwareTimer::resumeChannel(uint32_t channel) { int timChannel = getChannel(channel); + int timAssociatedInputChannel; if (timChannel == -1) { Error_Handler(); } - if (IS_TIM_PWM_MODE(_channelOC[channel - 1].OCMode)) { - HAL_TIM_PWM_ConfigChannel(&(_timerObj.handle), &_channelOC[channel - 1], timChannel); + int interrupt = getIT(channel); + if (interrupt == -1) { + Error_Handler(); + } - if ((channel < (TIMER_CHANNELS + 1)) && (callbacks[channel] != NULL)) { - // Only channel 1..4 can have interruption + int LLChannel = getLLChannel(channel); + if (LLChannel == -1) { + Error_Handler(); + } + + // Clear flag and enable IT + if (callbacks[channel] != NULL) { + __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), interrupt); + __HAL_TIM_ENABLE_IT(&(_timerObj.handle), interrupt); + } + + switch (_ChannelMode[channel - 1]) { + case TIMER_OUTPUT_COMPARE_PWM1: + case TIMER_OUTPUT_COMPARE_PWM2: { #if defined(TIM_CCER_CC1NE) - if (isComplementaryChannel[channel]) { - HAL_TIMEx_PWMN_Start_IT(&(_timerObj.handle), timChannel); - } else + if (isComplementaryChannel[channel - 1]) { + HAL_TIMEx_PWMN_Start(&(_timerObj.handle), timChannel); + } else #endif - { - HAL_TIM_PWM_Start_IT(&(_timerObj.handle), timChannel); + { + HAL_TIM_PWM_Start(&(_timerObj.handle), timChannel); + } } - } else { + break; + case TIMER_OUTPUT_COMPARE: + case TIMER_OUTPUT_COMPARE_ACTIVE: + case TIMER_OUTPUT_COMPARE_INACTIVE: + case TIMER_OUTPUT_COMPARE_TOGGLE: + case TIMER_OUTPUT_COMPARE_FORCED_ACTIVE: + case TIMER_OUTPUT_COMPARE_FORCED_INACTIVE: { #if defined(TIM_CCER_CC1NE) - if (isComplementaryChannel[channel]) { - HAL_TIMEx_PWMN_Start(&(_timerObj.handle), timChannel); - } else + if (isComplementaryChannel[channel - 1]) { + HAL_TIMEx_OCN_Start(&(_timerObj.handle), timChannel); + } else #endif - { - HAL_TIM_PWM_Start(&(_timerObj.handle), timChannel); + { + HAL_TIM_OC_Start(&(_timerObj.handle), timChannel); + } } - } - } else if (IS_TIM_OC_MODE(_channelOC[channel - 1].OCMode)) { - HAL_TIM_OC_ConfigChannel(&(_timerObj.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(&(_timerObj.handle), timChannel); - } else -#endif - { - HAL_TIM_OC_Start_IT(&(_timerObj.handle), timChannel); + break; + case TIMER_INPUT_FREQ_DUTY_MEASUREMENT: { + HAL_TIM_IC_Start(&(_timerObj.handle), timChannel); + + // Enable 2nd associated channel + timAssociatedInputChannel = getAssociatedChannel(channel); + LL_TIM_CC_EnableChannel(_timerObj.handle.Instance, getLLChannel(timAssociatedInputChannel)); + if (callbacks[channel] != NULL) { + __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), getIT(timAssociatedInputChannel)); + __HAL_TIM_ENABLE_IT(&(_timerObj.handle), getIT(timAssociatedInputChannel)); + } } - } else { -#if defined(TIM_CCER_CC1NE) - if (isComplementaryChannel[channel]) { - HAL_TIMEx_OCN_Start(&(_timerObj.handle), timChannel); - } else -#endif - { - HAL_TIM_OC_Start(&(_timerObj.handle), timChannel); + break; + case TIMER_INPUT_CAPTURE_RISING: + case TIMER_INPUT_CAPTURE_FALLING: + case TIMER_INPUT_CAPTURE_BOTHEDGE: { + HAL_TIM_IC_Start(&(_timerObj.handle), timChannel); } - } - } else if (_channelIC[channel - 1].ICPolarity != TIMER_NOT_USED) { - HAL_TIM_IC_ConfigChannel(&(_timerObj.handle), &_channelIC[channel - 1], timChannel); - - if (callbacks[channel] != NULL) { - HAL_TIM_IC_Start_IT(&(_timerObj.handle), timChannel); - } else { - HAL_TIM_IC_Start(&(_timerObj.handle), timChannel); - } + break; + case TIMER_NOT_USED: + default : + break; } } @@ -241,7 +393,7 @@ void HardwareTimer::resumeChannel(uint32_t channel) uint32_t HardwareTimer::getPrescaleFactor() { // Hardware register correspond to prescaler-1. Example PSC register value 0 means divided by 1 - return (_timerObj.handle.Init.Prescaler + 1); + return (LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1); } /** @@ -252,8 +404,7 @@ uint32_t HardwareTimer::getPrescaleFactor() 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(&_timerObj.handle, prescaler - 1); - _timerObj.handle.Init.Prescaler = prescaler - 1; + LL_TIM_SetPrescaler(_timerObj.handle.Instance, prescaler - 1); } /** @@ -267,8 +418,8 @@ void HardwareTimer::setPrescaleFactor(uint32_t prescaler) 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(&(_timerObj.handle)); - uint32_t Prescalerfactor = _timerObj.handle.Instance->PSC + 1; + uint32_t ARR_RegisterValue = LL_TIM_GetAutoReload(_timerObj.handle.Instance); + uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1; uint32_t return_value; switch (format) { case MICROSEC_FORMAT: @@ -304,15 +455,13 @@ void HardwareTimer::setOverflow(uint32_t overflow, TimerFormat_t format) case MICROSEC_FORMAT: period_cyc = overflow * (getTimerClkFreq() / 1000000); Prescalerfactor = (period_cyc / 0x10000) + 1; - __HAL_TIM_SET_PRESCALER(&_timerObj.handle, Prescalerfactor - 1); - _timerObj.handle.Init.Prescaler = Prescalerfactor - 1; + LL_TIM_SetPrescaler(_timerObj.handle.Instance, 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(&_timerObj.handle, Prescalerfactor - 1); - _timerObj.handle.Init.Prescaler = Prescalerfactor - 1; + LL_TIM_SetPrescaler(_timerObj.handle.Instance, Prescalerfactor - 1); ARR_RegisterValue = (period_cyc / Prescalerfactor) - 1; break; case TICK_FORMAT: @@ -322,7 +471,6 @@ void HardwareTimer::setOverflow(uint32_t overflow, TimerFormat_t format) } __HAL_TIM_SET_AUTORELOAD(&_timerObj.handle, ARR_RegisterValue); - _timerObj.handle.Init.Period = ARR_RegisterValue; } /** @@ -335,8 +483,8 @@ void HardwareTimer::setOverflow(uint32_t overflow, TimerFormat_t format) */ uint32_t HardwareTimer::getCount(TimerFormat_t format) { - uint32_t CNT_RegisterValue = __HAL_TIM_GET_COUNTER(&(_timerObj.handle)); - uint32_t Prescalerfactor = _timerObj.handle.Instance->PSC + 1; + uint32_t CNT_RegisterValue = LL_TIM_GetCounter(_timerObj.handle.Instance); + uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1; uint32_t return_value; switch (format) { case MICROSEC_FORMAT: @@ -365,7 +513,7 @@ uint32_t HardwareTimer::getCount(TimerFormat_t format) void HardwareTimer::setCount(uint32_t counter, TimerFormat_t format) { uint32_t CNT_RegisterValue; - uint32_t Prescalerfactor = _timerObj.handle.Instance->PSC + 1; + uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1; switch (format) { case MICROSEC_FORMAT: CNT_RegisterValue = ((counter * (getTimerClkFreq() / 1000000)) / Prescalerfactor) - 1 ; @@ -402,99 +550,107 @@ void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, uint32_t pin) */ void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, PinName pin) { - if (getChannel(channel) == -1) { + int timChannel = getChannel(channel); + int timAssociatedInputChannel; + TIM_OC_InitTypeDef channelOC; + TIM_IC_InitTypeDef channelIC; + + if (timChannel == -1) { Error_Handler(); } + // Save channel selected mode to object attribute + _ChannelMode[channel - 1] = mode; + + /* Configure some default values. Maybe overwritten later */ + channelOC.OCMode = TIMER_NOT_USED; + channelOC.Pulse = __HAL_TIM_GET_COMPARE(&(_timerObj.handle), timChannel); // keep same value already written in hardware PSC + 1; + uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1; uint32_t CCR_RegisterValue; if (timChannel == -1) { @@ -551,7 +707,6 @@ void HardwareTimer::setCaptureCompare(uint32_t channel, uint32_t compare, TimerC } __HAL_TIM_SET_COMPARE(&(_timerObj.handle), timChannel, CCR_RegisterValue); - _channelOC[channel - 1].Pulse = CCR_RegisterValue; } /** @@ -567,7 +722,7 @@ uint32_t HardwareTimer::getCaptureCompare(uint32_t channel, TimerCompareFormat_ { int timChannel = getChannel(channel); uint32_t CCR_RegisterValue = __HAL_TIM_GET_COMPARE(&(_timerObj.handle), timChannel); - uint32_t Prescalerfactor = _timerObj.handle.Instance->PSC + 1; + uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1; uint32_t return_value; if (timChannel == -1) { @@ -660,6 +815,12 @@ void HardwareTimer::setInterruptPriority(uint32_t preemptPriority, uint32_t subP */ void HardwareTimer::attachInterrupt(void (*callback)(HardwareTimer *)) { + if (callback != NULL) { + // Clear flag before enabling IT + __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), TIM_FLAG_UPDATE); + // Enable update interrupt only if callback is valid + __HAL_TIM_ENABLE_IT(&(_timerObj.handle), TIM_IT_UPDATE); + } callbacks[0] = callback; } @@ -669,6 +830,8 @@ void HardwareTimer::attachInterrupt(void (*callback)(HardwareTimer *)) */ void HardwareTimer::detachInterrupt() { + // Disable update interrupt and clear callback + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), TIM_IT_UPDATE); // disables the interrupt call to save cpu cycles for useless context switching callbacks[0] = NULL; } @@ -680,10 +843,21 @@ void HardwareTimer::detachInterrupt() */ void HardwareTimer::attachInterrupt(uint32_t channel, void (*callback)(HardwareTimer *)) { + int interrupt = getIT(channel); + if (interrupt == -1) { + Error_Handler(); + } + if ((channel == 0) || (channel > (TIMER_CHANNELS + 1))) { Error_Handler(); // only channel 1..4 have an interrupt } + if (callback != NULL) { + // Clear flag before enabling IT + __HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), interrupt); + // Enable interrupt corresponding to channel, only if callback is valid + __HAL_TIM_ENABLE_IT(&(_timerObj.handle), interrupt); + } callbacks[channel] = callback; } @@ -694,10 +868,17 @@ void HardwareTimer::attachInterrupt(uint32_t channel, void (*callback)(HardwareT */ void HardwareTimer::detachInterrupt(uint32_t channel) { + int interrupt = getIT(channel); + if (interrupt == -1) { + Error_Handler(); + } + if ((channel == 0) || (channel > (TIMER_CHANNELS + 1))) { Error_Handler(); // only channel 1..4 have an interrupt } + // Disable interrupt corresponding to channel and clear callback + __HAL_TIM_DISABLE_IT(&(_timerObj.handle), interrupt); callbacks[channel] = NULL; } diff --git a/cores/arduino/HardwareTimer.h b/cores/arduino/HardwareTimer.h index b67c1253f3..dfa94b755a 100644 --- a/cores/arduino/HardwareTimer.h +++ b/cores/arduino/HardwareTimer.h @@ -29,6 +29,7 @@ /* Includes ------------------------------------------------------------------*/ #include "timer.h" +#include "stm32yyxx_ll_tim.h" #if defined(HAL_TIM_MODULE_ENABLED) && !defined(HAL_TIM_MODULE_ONLY) @@ -83,7 +84,9 @@ class HardwareTimer { ~HardwareTimer(); // destructor void pause(void); // Pause counter and all output channels + void pauseChannel(uint32_t channel); // Timer is still running but channel (output and interrupt) is disabled void resume(void); // Resume counter and all output channels + void resumeChannel(uint32_t channel); // Resume only one channel void setPrescaleFactor(uint32_t prescaler); // set prescaler register (which is factor value - 1) uint32_t getPrescaleFactor(); @@ -118,8 +121,7 @@ class HardwareTimer { void timerHandleDeinit(); // Timer deinitialization - // Refresh() can only be called after a 1st call to resume() to be sure timer is initialised. - // It is usefull while timer is running after some registers update + // Refresh() is usefull while timer is running after some registers update void refresh(void); // Generate update event to force all registers (Autoreload, prescaler, compare) to be taken into account @@ -130,14 +132,15 @@ class HardwareTimer { // The following function(s) are available for more advanced timer options TIM_HandleTypeDef *getHandle(); // return the handle address for HAL related configuration + private: - TIM_OC_InitTypeDef _channelOC[TIMER_CHANNELS]; - TIM_IC_InitTypeDef _channelIC[TIMER_CHANNELS]; + TimerModes_t _ChannelMode[TIMER_CHANNELS]; timerObj_t _timerObj; 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); + int getLLChannel(uint32_t channel); + int getIT(uint32_t channel); + int getAssociatedChannel(uint32_t channel); #if defined(TIM_CCER_CC1NE) bool isComplementaryChannel[TIMER_CHANNELS]; #endif From 80dfa09561e7391bcc8b5b0c2f86039c6c602b12 Mon Sep 17 00:00:00 2001 From: Alexandre Bourdiol Date: Tue, 3 Dec 2019 10:37:39 +0100 Subject: [PATCH 2/2] Fix tone after rework of HardwareTimer When timerTonePinDeinit() is called, it will deinitialize timer. It is then necessary to recreate HardwareTimer object to initialize timer. So, when NoTone() is called, without destruct, only pause the timer. Also when frequency is null just pause the timer. --- cores/arduino/Tone.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp index e75099db9a..cb16254d75 100644 --- a/cores/arduino/Tone.cpp +++ b/cores/arduino/Tone.cpp @@ -81,7 +81,9 @@ static void timerTonePinInit(PinName p, uint32_t frequency, uint32_t duration) if (frequency <= MAX_FREQ) { if (frequency == 0) { - timerTonePinDeinit(); + if (TimerTone != NULL) { + TimerTone->pause(); + } } else { TimerTone_pinInfo.pin = p; @@ -121,12 +123,13 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) void noTone(uint8_t _pin, bool destruct) { PinName p = digitalPinToPinName(_pin); - if ((p != NC) && (TimerTone_pinInfo.pin == p)) { - timerTonePinDeinit(); - - if ((destruct) && (TimerTone != NULL)) { + if ((p != NC) && (TimerTone_pinInfo.pin == p) && (TimerTone != NULL)) { + if (destruct) { + timerTonePinDeinit(); delete (TimerTone); TimerTone = NULL; + } else { + TimerTone->pause(); } } }