BluePill fast 10 us Timer interrupt example code needed

Post here first, or if you can't find a relevant section!
RobertoBerner
Posts: 36
Joined: Tue May 09, 2023 10:45 pm

BluePill fast 10 us Timer interrupt example code needed

Post by RobertoBerner »

For a project in which Arduino Nano was slow, I need a very simple code example to produce a 10 us (microseconds) timer event.

I tried many code examples found here and there but I get compiler errors about missing functions and classes.
My Arduino IDE correctly compiles a simple working code but for a 1 ms resolution as the fastest possible. I can see this on PC13 with my oscilloscope.

How can I make a similar code work for a faster timer resolution ?
No matter if it is done with a libabry or just by calling HAL functions, as long as it works.
Here is a copy of the library working code. I am using the original STMicroelectronics cores definitions and HID-bootloader.

Thank you.
Roberto

Code: Select all

/****************************************************************************************************************************
  TimerInterruptLEDDemo.ino
  For STM32 boards
  Written by Khoi Hoang
  
  Built by Khoi Hoang https://github.com/khoih-prog/STM32_TimerInterrupt
  Licensed under MIT license
  
  Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
  unsigned long miliseconds), you just consume only one STM32 timer and avoid conflicting with other cores' tasks.
  The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
  Therefore, their executions are not blocked by bad-behaving functions / tasks.
  This important feature is absolutely necessary for mission-critical tasks.
*****************************************************************************************************************************/

/*
   Notes:
   Special design is necessary to share data between interrupt code and the rest of your program.
   Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
   variable can not spontaneously change. Because your function may change variables while your program is using them,
   the compiler needs this hint. But volatile alone is often not enough.
   When accessing shared variables, usually interrupts must be disabled. Even with volatile,
   if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
   If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
   or the entire sequence of your code which accesses the data.
*/

#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3)  ||defined(STM32F4) || defined(STM32F7) || \
       defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7)  ||defined(STM32G0) || defined(STM32G4) || \
       defined(STM32WB) || defined(STM32MP1) || defined(STM32L5) )
  #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting.
#endif

// These define's must be placed at the beginning before #include "STM32TimerInterrupt.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
// Don't define TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG         0
#define _TIMERINTERRUPT_LOGLEVEL_     0

#include "STM32TimerInterrupt.h"

#ifndef LED_BUILTIN
  #define LED_BUILTIN       PB0               // Pin 33/PB0 control on-board LED_GREEN on F767ZI
#endif

#ifndef LED_BLUE
  #define LED_BLUE          PB7               // Pin 73/PB7 control on-board LED_BLUE on F767ZI
#endif

#ifndef LED_RED
  #define LED_RED           PB14              // Pin 74/PB14 control on-board LED_BLUE on F767ZI
#endif
   
#include "STM32TimerInterrupt.h"
#include "STM32_ISR_Timer.h"

//#define TIMER_INTERVAL_MS         100  orig
//#define HW_TIMER_INTERVAL_MS      50
//#define HW_TIMER_INTERVAL_MS      5


// Depending on the board, you can select STM32 Hardware Timer from TIM1-TIM22
// For example, F767ZI can select Timer from TIM1-TIM14
// If you select a Timer not correctly, you'll get a message from ci[ompiler
// 'TIMxx' was not declared in this scope; did you mean 'TIMyy'? 

// Init STM32 timer TIM1
STM32Timer ITimer(TIM1);

// Init STM32_ISR_Timer
// Each STM32_ISR_Timer can service 16 different ISR-based timers
STM32_ISR_Timer ISR_Timer;

#define TIMER_INTERVAL_0_1S           100L
#define TIMER_INTERVAL_0_5S           500L
#define TIMER_INTERVAL_1S             1000L
#define TIMER_INTERVAL_1_5S           1500L

volatile long flag , count , temp;

void TimerHandler()
{
  ISR_Timer.run();
}

// In STM32, avoid doing something fancy in ISR, for example complex Serial.print with String() argument
// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment
// Or you can get this run-time error / crash

void doingSomething1()
{
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  if(count++ > 500L)
  {
    temp = count;
    count = 0;
    flag = 1;
  }
}

void doingSomething2()
{
  digitalWrite(LED_BLUE, !digitalRead(LED_BLUE));
}
void doingSomething3()
{
  digitalWrite(LED_RED, !digitalRead(LED_RED));
}

void setup()
{
  Serial.begin(115200);
  while (!Serial);

  delay(100);

  Serial.print(F("\nStarting TimerInterruptLEDDemo on ")); Serial.println(BOARD_NAME);
  Serial.println(STM32_TIMER_INTERRUPT_VERSION);
  Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));

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

  // configure pin in output mode
  pinMode(LED_BUILTIN,  OUTPUT);
  //pinMode(LED_BLUE,     OUTPUT);
  //pinMode(LED_RED,      OUTPUT);

  // Interval in microsecs
  //if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, TimerHandler))
  if (ITimer.attachInterruptInterval(15 , TimerHandler))
  {
    Serial.print(F("Starting ITimer OK, millis() = ")); Serial.println(millis());
  }
  else
    Serial.println(F("Can't set ITimer. Select another freq. or timer"));

  delay(2000);

  // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary
  // You can use up to 16 timer for each ISR_Timer

  ISR_Timer.setInterval(1L,  doingSomething1);
  //ISR_Timer.setInterval(TIMER_INTERVAL_0_5S,  doingSomething1);
  //ISR_Timer.setInterval(TIMER_INTERVAL_1S,    doingSomething2);
  //ISR_Timer.setInterval(TIMER_INTERVAL_1_5S,  doingSomething3);

  while(1)
  {
    if(flag)
    {
      flag = 0;
      Serial.println(temp);  
      temp = 0L;
    }
  }
}


void loop()
{
  /* Nothing to do all is done by hardware. Even no interrupt required. */
}
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 27
Location: Prudnik, Poland

Re: BluePill fast 10 us Timer interrupt example code needed

Post by GonzoG »

You don't need any additional libraries. Use hardware timer: https://github.com/stm32duino/Arduino_C ... er-library

There's "Timebase_callback" example in stm32duino examples that does what you need.
And if you want fast, set optimization to -O3 and use digitalWriteFast() instead digitalWrite();
RobertoBerner
Posts: 36
Joined: Tue May 09, 2023 10:45 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by RobertoBerner »

Thank you so much GonzoG.
I think that your reply is going to solve my problem.
I will give it a test and be back to report.

Thank you !

Roberto
dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by dannyf »

if you are indeed trying to generate square waves, using pwm is much more efficient.

if you are trying to invoke a routine very frequently, isr overhead and all the high level abstraction can be very expensive. I would consider coding directly - it is not that difficult.
RobertoBerner
Posts: 36
Joined: Tue May 09, 2023 10:45 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by RobertoBerner »

PROBLEM SOLVED

Hello GonzoG and dannyf !
Thank you ! I got this running OK.
A combination of Hardware Timer interrupt and digitalWriteFast libraries.

https://github.com/stm32duino/Arduino_C ... er-library
https://github.com/ArminJo/digitalWriteFast

dannyf, I am a total newbie to STM32, I come from many years in the 8 bit world, not precisely Arduino, but from the old Motorola M6800 days to the latest chips today.

You are right. I used PWM as square wave generator many times and yes, there is of course, a complete hardware working for you.
In the case of this project I have to write, I need first to know what the BluePill can do.
I was just about to ask you about how would you write this same library example, but directly coding. Could you give me a small example?
I would consider coding directly - it is not that difficult.
I am studying the way to get a PIN toggle automatically from the timer overflow, I am sure this exists in STM32. This would replace PWM, move the PIN and interrupt so I get the cycle count in a variable at the same time. The purpose is to stop generating after n pulses.

Finally, for this test program I am sharing here, the memory use resulted as follows:
Sketch uses 25488 bytes (38%) of program storage space. Maximum is 65536 bytes.
Global variables use 3856 bytes (18%) of dynamic memory, leaving 16624 bytes for local variables. Maximum is 20480 bytes.
The program does not use RAM variables. Is this caused by the HAL libraries?
Could you illuminate me here?

Thank you!
Roberto

Code: Select all

/*
  Timebase callback
  This example shows how to configure HardwareTimer to execute a callback at regular interval.
  Callback toggles pin.
  Once configured, there is only CPU load for callbacks executions.
  https://github.com/stm32duino/STM32Examples/blob/main/examples/Peripherals/HardwareTimer/Timebase_callback/Timebase_callback.ino
  https://github.com/ArminJo/digitalWriteFast
*/

#include <Arduino.h>
#include <digitalWriteFast.h>

#ifndef _NOP // required for some non Arduino cores
#define _NOP() do { __asm__ volatile ("nop"); } while (0)
#endif

#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION  < 0x01090000)
#error "Due to API change, this sketch is compatible with STM32_CORE_VERSION  >= 0x01090000"
#endif

#define PIN PC13

void Update_IT_callback(void)
{ 
  digitalToggleFast(PIN); // Toggle PIN ~5 us toogle
}

void setup()
{
  Serial.begin(9600);
  while(!Serial);
  delay(100);
  Serial.print(F("START..."));
  pinModeFast(PIN, OUTPUT);
  
#if defined(TIM1)
  TIM_TypeDef *Instance = TIM1;
#else
  TIM_TypeDef *Instance = TIM2;
#endif

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

  //MyTim->setOverflow(10, HERTZ_FORMAT); // 10 Hz   
  MyTim->setOverflow(5, MICROSEC_FORMAT); // this generates around 5 us interrupt tick - 95.24 KHz
  MyTim->attachInterrupt(Update_IT_callback);
  MyTim->resume();
}

void loop()
{
  /* Nothing to do all is done by hardware. Even no interrupt required. */
}
dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by dannyf »

what build environment do you have? if it is built on CMSIS, it should be fairly easy.
RobertoBerner
Posts: 36
Joined: Tue May 09, 2023 10:45 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by RobertoBerner »

dannyf , I have no knowledge about CMSIS.
I have this Arduino IDE adventure to start with, but I have done a couple of test projects on the STM32CubeIDE for the BluePill.
All based on HAL functions.

I have an ST-Link and I could program FLASH via ST-Link SWD or by means of the HID-bootloader.
All these steps happened in less than 10 days.
I know that there are 1300 pages documents with detailed info on HAL functions, a little scary at first, but I took a look to the LL and seems to be simple.

What I've heard is that HAL functions are slow and that take a lot of overhead. No good news.
I don't know about CMSIS ... isn't it similar?

Still have the doubts I posted before about amount of RAM and FLASH for such a simple program.
Sketch uses 25488 bytes (38%) of program storage space. Maximum is 65536 bytes.
Global variables use 3856 bytes (18%) of dynamic memory, leaving 16624 bytes for local variables. Maximum is 20480 bytes.
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 27
Location: Prudnik, Poland

Re: BluePill fast 10 us Timer interrupt example code needed

Post by GonzoG »

DON'T use any fast IO libraries with stm32duino.
1. this library for AVR based boards. With STM32 core it uses standard digitalWrite();
2. digitalWriteFast() and digitalReadFast() are a builtin functions in STM32 core.

Code: Select all

digitalWriteFast(digitalPinToPinName(PA1),1);
//or
digitalWriteFast(PA_1,1);
RobertoBerner
Posts: 36
Joined: Tue May 09, 2023 10:45 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by RobertoBerner »

Thank you GonzoG !!!
I will test it right away and return to report results.

Roberto
dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by dannyf »

what chip are you using?
Post Reply

Return to “General discussion”