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