From 84887afe40ed731230429997efb3799dba8d4805 Mon Sep 17 00:00:00 2001 From: Daniel Fekete Date: Mon, 17 Jul 2017 21:31:52 +0200 Subject: [PATCH] hardwaretimer: Add hardwaretimer library --- STM32/libraries/HardwareTimer/keywords.txt | 15 + .../HardwareTimer/library.properties | 9 + .../HardwareTimer/src/HardwareTimer.cpp | 439 ++++++++++++++++++ .../HardwareTimer/src/HardwareTimer.h | 109 +++++ 4 files changed, 572 insertions(+) create mode 100644 STM32/libraries/HardwareTimer/keywords.txt create mode 100644 STM32/libraries/HardwareTimer/library.properties create mode 100644 STM32/libraries/HardwareTimer/src/HardwareTimer.cpp create mode 100644 STM32/libraries/HardwareTimer/src/HardwareTimer.h diff --git a/STM32/libraries/HardwareTimer/keywords.txt b/STM32/libraries/HardwareTimer/keywords.txt new file mode 100644 index 0000000..726c150 --- /dev/null +++ b/STM32/libraries/HardwareTimer/keywords.txt @@ -0,0 +1,15 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/STM32/libraries/HardwareTimer/library.properties b/STM32/libraries/HardwareTimer/library.properties new file mode 100644 index 0000000..90afcd6 --- /dev/null +++ b/STM32/libraries/HardwareTimer/library.properties @@ -0,0 +1,9 @@ +name=HardwareTimer +version=1.0 +author=Daniel Fekete +maintainer=Daniel Fekete +sentence=HardwareTimer compatible with libmaple +paragraph=HardwareTimer compatible with libmaple +category=Timing +url= +architectures=STM32 diff --git a/STM32/libraries/HardwareTimer/src/HardwareTimer.cpp b/STM32/libraries/HardwareTimer/src/HardwareTimer.cpp new file mode 100644 index 0000000..84d7531 --- /dev/null +++ b/STM32/libraries/HardwareTimer/src/HardwareTimer.cpp @@ -0,0 +1,439 @@ +/* + 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. +*/ + +#include "HardwareTimer.h" + +#include CHIP_PERIPHERAL_INCLUDE + +HardwareTimer *interruptTimers[18]; + +void (*pwm_callback_func)(); +static void handleInterrupt(HardwareTimer *timer); + +static const uint32_t OCMODE_NOT_USED = 0xFFFF; + +HardwareTimer::HardwareTimer(TIM_TypeDef *instance, const stm32_tim_pin_list_type *pin_list, int pin_list_size) { + this->tim_pin_list = pin_list; + this->tim_pin_list_size = pin_list_size; + + handle.Instance = instance; + + for(int i=0; i<4; i++) { + channelOC[i].OCMode = OCMODE_NOT_USED; + channelOC[i].OCPolarity = TIM_OCPOLARITY_HIGH; + channelOC[i].OCNPolarity = TIM_OCNPOLARITY_HIGH; + channelOC[i].OCFastMode = TIM_OCFAST_DISABLE; + channelOC[i].OCIdleState = TIM_OCIDLESTATE_RESET; + channelOC[i].OCNIdleState = TIM_OCNIDLESTATE_RESET; + } + +} + +void HardwareTimer::pause() { + HAL_TIM_Base_Stop(&handle); +} + +void HardwareTimer::resume() { + bool hasInterrupt = false; + for(size_t i=0; isetPrescaleFactor(1); + this->setOverflow(1); + return this->getOverflow(); + } + + uint32_t period_cyc = microseconds * (getBaseFrequency() / 1000000); //TODO! + + uint32_t prescaler = (uint32_t)(period_cyc / MAX_RELOAD + 1); + + uint32_t overflow = (uint32_t)((period_cyc + (prescaler / 2)) / prescaler); + + this->setPrescaleFactor(prescaler); + this->setOverflow(overflow); + return overflow; +} + +static bool isSameChannel(int channel, uint8_t signal) { + switch(signal) { + case TIM_CH1: + case TIM_CH1N: + return channel == 1; + case TIM_CH2: + case TIM_CH2N: + return channel == 2; + case TIM_CH3: + case TIM_CH3N: + return channel == 3; + case TIM_CH4: + case TIM_CH4N: + return channel == 4; + } + return false; +} + +static const uint32_t PIN_NOT_USED = 0xFF; + +void HardwareTimer::setMode(int channel, TIMER_MODES mode, uint8_t pin) { + int pinMode = PIN_NOT_USED; + + switch(mode) { + case TIMER_PWM: + channelOC[channel - 1].OCMode = TIM_OCMODE_PWM1; + pinMode = GPIO_MODE_AF_PP; + break; + + case TIMER_OUTPUT_COMPARE: + channelOC[channel - 1].OCMode = TIM_OCMODE_TIMING; + break; + + case TIMER_OUTPUT_COMPARE_ACTIVE: + channelOC[channel - 1].OCMode = TIM_OCMODE_ACTIVE; + pinMode = GPIO_MODE_AF_PP; + break; + + case TIMER_OUTPUT_COMPARE_INACTIVE: + channelOC[channel - 1].OCMode = TIM_OCMODE_ACTIVE; + pinMode = GPIO_MODE_AF_PP; + break; + + case TIMER_OUTPUT_COMPARE_TOGGLE: + channelOC[channel - 1].OCMode = TIM_OCMODE_TOGGLE; + pinMode = GPIO_MODE_AF_PP; + break; + + case TIMER_OUTPUT_COMPARE_PWM1: + channelOC[channel - 1].OCMode = TIM_OCMODE_PWM1; + pinMode = GPIO_MODE_AF_PP; + break; + + case TIMER_OUTPUT_COMPARE_PWM2: + channelOC[channel - 1].OCMode = TIM_OCMODE_PWM2; + pinMode = GPIO_MODE_AF_PP; + break; + + case TIMER_OUTPUT_COMPARE_FORCED_ACTIVE: + channelOC[channel - 1].OCMode = TIM_OCMODE_FORCED_ACTIVE; + pinMode = GPIO_MODE_AF_PP; + break; + + case TIMER_OUTPUT_COMPARE_FORCED_INACTIVE: + channelOC[channel - 1].OCMode = TIM_OCMODE_FORCED_INACTIVE; + pinMode = GPIO_MODE_AF_PP; + break; + } + + if (pinMode != PIN_NOT_USED) { + for(int i=0; ihandle, TIM_FLAG_UPDATE) != RESET) { + __HAL_TIM_CLEAR_IT(&timer->handle, TIM_IT_UPDATE); + if (timer->callbacks[0] != NULL) timer->callbacks[0](); + } + + if(__HAL_TIM_GET_FLAG(&timer->handle, TIM_FLAG_CC1) != RESET) { + __HAL_TIM_CLEAR_IT(&timer->handle, TIM_IT_CC1); + if (timer->callbacks[1] != NULL) timer->callbacks[1](); + } + + if(__HAL_TIM_GET_FLAG(&timer->handle, TIM_FLAG_CC2) != RESET) { + __HAL_TIM_CLEAR_IT(&timer->handle, TIM_IT_CC2); + if (timer->callbacks[2] != NULL) timer->callbacks[2](); + } + + if(__HAL_TIM_GET_FLAG(&timer->handle, TIM_FLAG_CC3) != RESET) { + __HAL_TIM_CLEAR_IT(&timer->handle, TIM_IT_CC3); + if (timer->callbacks[3] != NULL) timer->callbacks[3](); + } + + if(__HAL_TIM_GET_FLAG(&timer->handle, TIM_FLAG_CC4) != RESET) { + __HAL_TIM_CLEAR_IT(&timer->handle, TIM_IT_CC4); + if (timer->callbacks[4] != NULL) timer->callbacks[4](); + } +} + +#ifdef TIM1 + HardwareTimer Timer1(TIM1, chip_tim1, sizeof(chip_tim1) / sizeof(chip_tim1[0])); +#endif + +#ifdef TIM2 + HardwareTimer Timer2(TIM2, chip_tim2, sizeof(chip_tim2) / sizeof(chip_tim2[0])); +#endif + +#ifdef TIM3 + HardwareTimer Timer3(TIM3, chip_tim3, sizeof(chip_tim3) / sizeof(chip_tim3[0])); +#endif + +#ifdef TIM4 + HardwareTimer Timer4(TIM4, chip_tim4, sizeof(chip_tim4) / sizeof(chip_tim4[0])); +#endif + + +//Timer interrupts: + +extern "C" void TIM1_CC_IRQHandler(void) { + if (interruptTimers[0] != NULL) handleInterrupt(interruptTimers[0]); +} +extern "C" void TIM1_UP_IRQHandler(void) { + if (interruptTimers[0] != NULL) handleInterrupt(interruptTimers[0]); +} +#ifndef TIM1_UP_TIM10_IRQHandler + extern "C" void TIM1_UP_TIM10_IRQHandler(void) { + if (interruptTimers[0] != NULL) handleInterrupt(interruptTimers[0]); + if (interruptTimers[9] != NULL) handleInterrupt(interruptTimers[9]); + } +#endif + +// in stm32_PWM.c +/* +extern "C" void TIM2_IRQHandler(void) { + handleInterrupt(interruptTimers[1]); +}*/ + +extern "C" void TIM3_IRQHandler(void) { + if (interruptTimers[2] != NULL) handleInterrupt(interruptTimers[2]); +} +extern "C" void TIM4_IRQHandler(void) { + if (interruptTimers[3] != NULL) handleInterrupt(interruptTimers[3]); +} diff --git a/STM32/libraries/HardwareTimer/src/HardwareTimer.h b/STM32/libraries/HardwareTimer/src/HardwareTimer.h new file mode 100644 index 0000000..53637c0 --- /dev/null +++ b/STM32/libraries/HardwareTimer/src/HardwareTimer.h @@ -0,0 +1,109 @@ +#ifndef HARDWARETIMER_H_ +#define HARDWARETIMER_H_ + +#include "Arduino.h" +#include "stm32_gpio_af.h" + +typedef enum { + //libmaple: // HAL compatible + TIMER_DISABLED, + TIMER_PWM, // == TIM_OCMODE_PWM1 + TIMER_OUTPUT_COMPARE, // == TIM_OCMODE_TIMING no output, useful for only-interrupt + + //other: + 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 + + //PWM input capture on channel 1 + channel 2 + //TIMER_INPUT_CAPTURE_PWM, // == TIM_INPUTCHANNELPOLARITY_RISING (channel 1) + TIM_INPUTCHANNELPOLARITY_FALLING (channel 2) + + //Encoder mode + //TIMER_ENCODER // == TIM_ENCODERMODE_TI1 +} TIMER_MODES; + +#define TIMER_DEFAULT_PIN 0xFF + +class HardwareTimer { +public: + HardwareTimer(TIM_TypeDef *instance, const stm32_tim_pin_list_type *pin_list, int pin_list_size); + + void pause(void); + + void resume(void); + + uint32_t getPrescaleFactor(); + + void setPrescaleFactor(uint32_t factor); + + uint32_t getOverflow(); + + void setOverflow(uint32_t val); + + uint32_t getCount(void); + + void setCount(uint32_t val); + + uint32_t setPeriod(uint32_t microseconds); + + void setMode(int channel, TIMER_MODES mode, uint8_t pin = TIMER_DEFAULT_PIN); + + uint32_t getCompare(int channel); + + void setCompare(int channel, uint32_t compare); + + //Add interrupt to period update + void attachInterrupt(void (*handler)(void)); + + void detachInterrupt(); + + //Add interrupt to channel + void attachInterrupt(int channel, void (*handler)(void)); + + void detachInterrupt(int channel); + + void refresh(void); + + uint32_t getBaseFrequency(); + + TIM_HandleTypeDef handle = {0}; + + TIM_OC_InitTypeDef channelOC[4]; + + //Callbacks: 0 for update, 1-4 for channels + void (*callbacks[5])(void); + + const stm32_tim_pin_list_type *tim_pin_list; + + int tim_pin_list_size; + +private: + void resumeChannel(int channel, int timChannel); + +}; + +#ifdef TIM1 + extern HardwareTimer Timer1; +#endif + +#ifdef TIM2 + extern HardwareTimer Timer2; +#endif + +#ifdef TIM3 + extern HardwareTimer Timer3; +#endif + +#ifdef TIM4 + extern HardwareTimer Timer4; +#endif + +#endif