Skip to content

Implement HardwareTimer library for Timer management #146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fpistm opened this issue Nov 7, 2017 · 28 comments · Fixed by #576
Closed

Implement HardwareTimer library for Timer management #146

fpistm opened this issue Nov 7, 2017 · 28 comments · Fixed by #576
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@fpistm
Copy link
Member

fpistm commented Nov 7, 2017

This issue is to open discussion around Timer management in order to provide useful API.
Current implementation is limited to support basic Arduino function.
Any help/comment are welcome.

@fpistm fpistm added enhancement New feature or request help wanted 🙏 Extra attention is needed labels Nov 7, 2017
@Adminius
Copy link
Contributor

Adminius commented Nov 7, 2017

@romainreignier
Copy link

romainreignier commented Nov 7, 2017

On AVR, I usually use this library, the API is simple enough: https://www.pjrc.com/teensy/td_libs_TimerOne.html

But it only allows to use timers for interrupt callback. You cannot configure a timer as quadrature encoder counter from it for example.

@Adminius
Copy link
Contributor

Adminius commented Nov 7, 2017

Timer1 and Timer3 are good libs!
This one too: https://github.com/wimleers/flexitimer2

@Adminius
Copy link
Contributor

Adminius commented Nov 7, 2017

My requirements:

  1. Interrupt driven function call with resolution: 1us, 1ms, 1s.
  2. better PWM generation: flexible PWM frequency, flexible counter, up-up/up-down (e.g. https://github.com/Adminius/Dimmer32u4)

@franciscogimeno2000
Copy link

franciscogimeno2000 commented Nov 23, 2017

Someone knows why libraries do not work
Timer1 ... 2 ... flexitimer2 in board STMF303 - F303K8

@fpistm
Copy link
Member Author

fpistm commented Nov 23, 2017

@franciscogimeno2000 simply because not ported for stm32. Ex Flexitimer uses direct register acces but this is not the same for stm32.
Goal of this issue is to collect requirements/proposal/API examples... to implement timers management useful for community.
Any contributions are welcom 😉

@franciscogimeno2000
Copy link

OK, you have some example of using a basic timer.?

@straccio
Copy link
Contributor

straccio commented Nov 29, 2017

For my projects i usually use particle boards, the are also based on STM32.
Take a look on their Software Timer https://docs.particle.io/reference/firmware/photon/#software-timers

They use Free RTOS, also available for more stm32 boards, but if you don't want use Free RTOS can you use the same interface for class.

PS: remember to use also std::function as callback.

@fpistm fpistm added the on going Currently work on this label Jan 27, 2018
@marcdepape
Copy link

marcdepape commented Apr 9, 2018

I have a NUCLEO F1 and F4 and spent the weekend trying to use timer.h / timer.c with them. It was a struggle.

For example (I'm going to truncate my code, and I don't have to use timer_enable_clock(_timer.handle); because I tried, and as far as I can tell it is called by these Inits), this does not work:

stimer_t _timer;
TimerHandleInit(&_timer, 100000, 384);
attachIntHandle(&_timer, handle_clock);

Yet, this does:

stimer_t _timer;
TimerPulseInit(&_timer, 500, 40000, pulse_clock);
TimerHandleInit(&_timer, 100000, 384);

In my callback I blinked an led and I used the following to debug after initializing:

Serial.println(getTimerIrq(_timer.handle.Instance)); Serial.println(getTimerClkSrc(_timer.handle.Instance)); Serial.println(getTimerClkFreq(_timer.handle.Instance));

In the first example I got: 0, 0, 0
In the second example I got: 28, 1, 84000000

From looking through the code, the TimerPulseInit actually assigns a timer:

obj->timer = TIMER_SERVO;

Whereas TimerHandleInit does not assign a timer.

In fact, I couldn't figure out for the life of me how to assign a specific timer to either of these functions, however I tried _timer.timer = TIM2; and it worked:

stimer_t _timer;
_timer.timer = TIM2;
TimerHandleInit(&_timer, 100000, 384);
attachIntHandle(&_timer, handle_clock);

Can I suggest the following:

  1. You should be able to assign a timer when you declare your stimer_t obj:

stimer_t _timer(TIM8);

  1. You should be able to assign a callback to TimerHandleInit:

void TimerHandleInit(stimer_t *obj, uint16_t period, uint16_t prescaler, void (*irqHandle)(stimer_t *))

This would greatly simplify everything. I think this is almost there, and the efforts to simplify the setup are good so far... just needs a bit of polish.

@fpistm fpistm removed the on going Currently work on this label Apr 11, 2018
@fpistm
Copy link
Member Author

fpistm commented Apr 11, 2018

Thanks for the feedback @marcdepape.
I will review all inputs.

@iotlearner0level
Copy link

@fpistm
Copy link
Member Author

fpistm commented Apr 17, 2018

Currently not.
Time is missing, this is in the task list... this will come.

@fpistm fpistm changed the title Timer management Implement HardwareTimer library for Timer management Sep 19, 2018
@fpistm fpistm added the on going Currently work on this label Oct 1, 2018
@fpistm fpistm self-assigned this Oct 1, 2018
@fpistm fpistm added this to the 1.5.0 milestone Oct 21, 2018
@fpistm fpistm modified the milestones: 1.5.0, 1.5.1/1.6.0 Dec 12, 2018
@noisymime
Copy link

Any updates on this request at all?

If not, is there at least any indication of which library / API you're looking to implement (ie Whether it will be the same as the existing HardwareTimer or one of the others mentioned)?

@fpistm
Copy link
Member Author

fpistm commented Jan 24, 2019

I know this is waited, unfortunately, I was not able to work on this. I hope work on this after all USB stuff and core release 1.5.0 done.

@fpistm
Copy link
Member Author

fpistm commented Jun 7, 2019

Maybe this one could be a good starting point:
https://github.com/danieleff/STM32GENERIC/tree/master/STM32/libraries/HardwareTimer

/cc @ABOSTM

@thedirectorone
Copy link

Currently using custom board with f407vgt and f103vet. Tried everything to create pulses (like rc controller) using pwm with no luck. So i decided to try configuring analog.h and c files. Simple configuration changes in pwm_start function solved this problem perfectly. After this point copied necessary functions to ino file. Basically tried everything even including rerouting include parts and using extra libraries external and internal. This method worked only in analog file. So added an extra function to analog h and c files. Working this way without problem so far.

Second problem is using timers with input capture mode. Trying to acquire timings of a ppm like coded pulse without interrupting running function. So far couldn't start any timer with input capture mode.

Can you give me any idea or point to a direction? If i can't solve this problem a huge code is needed to convert to another IDE and this requires massive work load.

Thank you to the team, project is going perfect this far.

@fpistm fpistm added this to the 1.6.1/1.7.0 milestone Jun 18, 2019
@ABOSTM
Copy link
Contributor

ABOSTM commented Jun 19, 2019

@thedirectorone: difficult to understand what is wrong with 1st problem:
what is your use case , what you tried, what changes you modified ...
But at least that is great, as your solution is working so far.
2nd problem: Input capture is clearly part of our thoughts for hardware library.

Meanwhile you may consider using STM32 cube HAL or LL drivers.
Those drivers are already included in Arduino_Core_STM32.
Those drivers can be called directly from your sketch/application.

Example on how to use input capture with HAL is available here:
https://www.st.com/en/embedded-software/stm32cubef4.html
STM32Cube_FW_F4_V1.24.1\Projects\STM32F446ZE-Nucleo\Examples\TIM\TIM_InputCapture\

Similar example is available on github but for a different STM32 family:
https://github.com/STMicroelectronics/STM32CubeG4/tree/master/Projects/NUCLEO-G474RE/Examples/TIM/TIM_InputCapture

Example on how to use input capture with LowLayer (LL) drivers is available here:
https://www.st.com/en/embedded-software/stm32cubef1.html
STM32Cube_FW_F1_V1.7.0\Projects\STM32F103RB-Nucleo\Examples_LL\TIM\TIM_InputCapture
Note: LL drivers is recommended for expert (it needs in-deep MCU Hardware knowledge).

@BennehBoy
Copy link
Contributor

Maybe this one could be a good starting point:
https://github.com/danieleff/STM32GENERIC/tree/master/STM32/libraries/HardwareTimer

Does this work out of the box @fpistm ? I can test this with a quadrature encoder...

@ABOSTM
Copy link
Contributor

ABOSTM commented Jun 20, 2019

@BennehBoy : unfortunately it doesn't work out of the box. And also quadrature encoder is not implemented.

@VitorBoss
Copy link
Contributor

VitorBoss commented Jun 26, 2019

@fpistm I'm currently using the STM32GENERIC HardwareTimer lib from https://github.com/huaweiwx/STM32GENERIC/tree/master/STM32/libraries/HardwareTimer it have more features than Daniel's and is full HAL compatible.

The lib ain't complete but is a good start. For setting a period, start and get into interrupts work well.
PWM is at https://github.com/huaweiwx/STM32GENERIC/blob/master/STM32/cores/arduino/stm32/stm32_PWM.c

@fpistm fpistm modified the milestones: 1.6.1, 1.7.0 Jun 27, 2019
@fpistm fpistm assigned ABOSTM and unassigned fpistm Jun 28, 2019
@Astroghost-Francois
Copy link

Hi ,

will we be able to use arduino timers interrupt commands after ?

François

@ABOSTM
Copy link
Contributor

ABOSTM commented Jul 12, 2019

Hi @Astroghost-Francois,
Yes, it will be possible to use interrupts on HardwareTimer library (through dedicated API from HardwareTimer library) : on update event (timer rollover) as well as compare match event corresponding to one of the channel.

@fpistm
Copy link
Member Author

fpistm commented Jul 26, 2019

Hi all,
@ABOSTM do the PR of the HarwareTimer implementation.
Do not hesitate to give us your feedback.
Thanks

@KJansun
Copy link

KJansun commented Aug 4, 2019

I installed all latest libs/cores but i dont know how to enable the HardwareTimer:
'HardwareTimer' was not declared in this scope

code i used:

HAL_TIM_MODULE_ENABLED

#if defined(LED_BUILTIN)
#define pin  LED_BUILTIN
#else
#define pin  PA1
#endif

void setup()
{
  // no need to configure pin, it will be done by HardwareTimer configuration
  // pinMode(pin, OUTPUT);

  // Automatically retrieve TIM instance and channel associated to pin
  // This is used to be compatible with all STM32 series automatically.
  TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM);
  uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM));


  // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished.
  HardwareTimer *MyTim = new HardwareTimer(Instance);

  // Configure and start PWM
  // MyTim->setPWM(channel, pin, 5, 10, NULL, NULL); // No callback required, we can simplify the function call
  MyTim->setPWM(channel, pin, 5, 10); // 5 Hertz, 10% dutycycle
}


void loop()
{
  /* Nothing to do all is done by hardware. Even no interrupt required. */
}

i'm new with the st's core and not familiar with the HAL configs. I tried diffent stuff but i dont understand how to get it to work. How can i enable this lib?

@BennehBoy
Copy link
Contributor

BennehBoy commented Aug 4, 2019 via email

@KJansun
Copy link

KJansun commented Aug 5, 2019

You have to install the github version of the core & then apply this PR. The last release 1.6.1 will NOT include these changes.

On Sun, Aug 4, 2019 at 9:32 AM KJansun @.***> wrote: I installed all latest libs/cores but i dont know how to enable the HardwareTimer: 'HardwareTimer' was not declared in this scope code i found: HAL_TIM_MODULE_ENABLED #if defined(LED_BUILTIN) #define pin LED_BUILTIN #else #define pin PA1 #endif void setup() { // no need to configure pin, it will be done by HardwareTimer configuration // pinMode(pin, OUTPUT); // Automatically retrieve TIM instance and channel associated to pin // This is used to be compatible with all STM32 series automatically. TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM); uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM)); // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished. HardwareTimer *MyTim = new HardwareTimer(Instance); // Configure and start PWM // MyTim->setPWM(channel, pin, 5, 10, NULL, NULL); // No callback required, we can simplify the function call MyTim->setPWM(channel, pin, 5, 10); // 5 Hertz, 10% dutycycle } void loop() { /* Nothing to do all is done by hardware. Even no interrupt required. */ } i'm new with the st's core and not familiar with the HAL configs. I tried diffent stuff but i dont understand to get it to work. How can i enable this lib? — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub <#146?email_source=notifications&email_token=AF6R4XQOFA3GH63JHULEZGTQC2HZNA5CNFSM4ECSN3NKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3P5CLI#issuecomment-517984557>, or mute the thread https://github.com/notifications/unsubscribe-auth/AF6R4XXCRWO4EIYN25VOJFDQC2HZNANCNFSM4ECSN3NA .

Ok, thanks

fpistm pushed a commit that referenced this issue Aug 19, 2019
* HardwareTimer implementation
  Fixes #146

* Fix: Unchecked reference to TIM13 in TIM8_IRQHandler
  Fixes #585
@fpistm fpistm removed help wanted 🙏 Extra attention is needed on going Currently work on this labels Aug 19, 2019
This was referenced Nov 8, 2019
@MacLeod-D
Copy link

MacLeod-D commented Feb 4, 2020

Hello,
I am using Arduino-IDE and STM32F407 Black Board and STM32GENERIC board definition.
Here is my code to use timers:

// For Arduino-IDE

// Board: BLACK STM32F407, 168 MHz

// Hardware:      STM32GENERIC  (https://github.com/danieleff/STM32GENERIC)
// Board:         F407Vxx
// Serial Comm    SerialUART1
// Spec. Board    Black F407VE (2.0)
// Upload         SerialUART1 [TX:PA9, RX:PA10] connected via FTDI (3.3V)


#include <Arduino.h>
#include "HardwareTimer.h"

volatile uint32_t tick1, tick2, tick3;

// ----------------------------------------
// Attention: STM32F4 specific !!!
// fast GPIO set/reset:
#define GPIO_PIN_SET(PORT,pin)          ((PORT)->BSRR = 1 << (uint32_t)pin)
#define GPIO_PIN_RESET(PORT,pin)        ((PORT)->BSRR = (1 << (uint32_t)pin) << 16)
#define GPIO_HISPEED_SET(port,pin)      (port)->OSPEEDR = (port)->OSPEEDR | (0b11 << (2*pin))
// ----------------------------------------

// ----------------------------------------
// Attention: STM32F4 specific !!!
// Timer1     clocks with 168 MHz
// Timer2,3   clocks with 84  MHz
// ----------------------------------------


// Interrupt routines

void Timer1_ISR() {
  tick1++;
}


void Timer2_ISR() {
  tick2++;
  digitalWrite(PA7,!digitalRead(PA7));
}

void Timer3_ISR() {
  tick3++;
  // Simulate PWM dimmed LED 1/20 = 5% on
  if ((tick3 % 20) == 0)  GPIO_PIN_RESET   (GPIOA,6);  // == digitalWrite(P6,0);
  else                    GPIO_PIN_SET     (GPIOA,6);
  
}  

void setup() {
  Serial.begin(2000000);
  pinMode(PA6,OUTPUT);
  GPIO_HISPEED_SET(GPIOA,6);
  pinMode(PA7,OUTPUT);
  GPIO_HISPEED_SET(GPIOA,7);
  Timer1.pause();
  Timer1.setPrescaleFactor(1680 -1);                   //  0.1 MHz = 10 us / 1 tick = 1/168 us
  Timer1.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);      //  Pin toggles when counter reaches compare (effectively 50% PWM)
  Timer1.setOverflow(20000 - 1);                       //        100000 / 20000 = 5 Interrupts /s 
  Timer1.setCompare(1, 10000);                         // Channel1, 10000 ticks = 50%
  Timer1.attachInterrupt(1, Timer1_ISR);               // channel1, handler
  Timer1.resume();

  Timer2.pause();
  Timer2.setPrescaleFactor(840 -1);                    // 0.1 MHz = 10 us / 1 tick = 1/84 us
  Timer2.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);      // Pin toggles when counter reaches compare (effectively 50% PWM)
  Timer2.setOverflow(20000 - 1);                       // 100000 / 20000 = 5 Interrupts /s 
  Timer2.setCompare(2, 10000);                         // Channel3, 50%
  Timer2.attachInterrupt( 2, Timer2_ISR);              // channel3, handler
  Timer2.resume();

  Timer3.pause();
  Timer3.setPrescaleFactor(84 -1);                     // 1 MHz = 1 us / 1 tick = 1/84 us
  Timer3.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);      // Pin toggles when counter reaches compare (effectively 50% PWM)
  Timer3.setOverflow(2 - 1);                           // every 2 us = >>>>>>> 500.000 Interrupts /s <<<<<<<<<<
  Timer3.setCompare(3, 1);                             // Channel3, 50%
  Timer3.attachInterrupt( 3, Timer3_ISR);              // channel3, handler
  Timer3.resume();

}


void loop() {
  Serial.print(micros()); Serial.print("us: tick1: "); Serial.println(tick1);
  Serial.print(micros()); Serial.print("us: tick2: "); Serial.println(tick2);
  Serial.print(micros()); Serial.print("us: tick3: "); Serial.println(tick3);
  delay(1000); // 1 second
}

output:

1314059001us: tick1: 6570
1314059094us: tick2: 6570
1314059196us: tick3: 657000110
1315059001us: tick1: 6575
1315059094us: tick2: 6575
1315059196us: tick3: 657500110
1316059001us: tick1: 6580
1316059094us: tick2: 6580
1316059196us: tick3: 658000110

Using digitalWrite - not GPIO - it should work on most STM32 boards.

@fpistm
Copy link
Member Author

fpistm commented Feb 5, 2020

Hi @MacLeod-D

I am using Arduino-IDE and STM32F407 Black Board and STM32GENERIC board definition.

Don't know what did you expect?
Here this is for the STM32 core not the STM32GENERIC .
use the forum which is used for primary support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.