stm32duino / Arduino_Core_STM32

STM32 core support for Arduino
https://github.com/stm32duino/Arduino_Core_STM32/wiki
Other
2.86k stars 980 forks source link

Implement HardwareTimer library for Timer management #146

Closed fpistm closed 5 years ago

fpistm commented 7 years ago

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.

Adminius commented 7 years ago

I need this feature: https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F1/libraries/A_STM32_Examples/examples/Maple/TimerInterrupts/TimerInterrupts.ino#L35

Something like this, but user friendly: https://github.com/adafruit/Adafruit_ZeroTimer/

Edit @fpistm: Add #104 request here.

romainreignier commented 7 years ago

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 commented 7 years ago

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

Adminius commented 7 years ago

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 commented 7 years ago

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

fpistm commented 7 years ago

@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 commented 7 years ago

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

straccio commented 7 years ago

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.

marcdepape commented 6 years ago

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);

2) 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 commented 6 years ago

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

iotlearner0level commented 6 years ago

hello is this implimented already? http://docs.leaflabs.com/static.leaflabs.com/pub/leaflabs/maple-docs/latest/lang/api/hardwaretimer.html

fpistm commented 6 years ago

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

noisymime commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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

/cc @ABOSTM

thedirectorone commented 5 years ago

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.

ABOSTM commented 5 years ago

@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 commented 5 years ago

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 commented 5 years ago

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

VitorBoss commented 5 years ago

@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

Astroghost-Francois commented 5 years ago

Hi ,

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

François

ABOSTM commented 5 years ago

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 commented 5 years ago

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

KJansun commented 5 years ago

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 commented 5 years ago

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 notifications@github.com 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 https://github.com/stm32duino/Arduino_Core_STM32/issues/146?email_source=notifications&email_token=AF6R4XQOFA3GH63JHULEZGTQC2HZNA5CNFSM4ECSN3NKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3P5CLI#issuecomment-517984557, or mute the thread https://github.com/notifications/unsubscribe-auth/AF6R4XXCRWO4EIYN25VOJFDQC2HZNANCNFSM4ECSN3NA .

KJansun commented 5 years ago

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

MacLeod-D commented 4 years ago

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 commented 4 years ago

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.