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

Re: BluePill fast 10 us Timer interrupt example code needed

Post by RobertoBerner »

I am using STM32F103C8T6 in a BluePill board
This code is making the pin toggle at 533 KHz, minimum pulse with is around 940 us
As GonzoG suggested, I am not using digitalWriteFast anymore.
I was expecting a higher speed. Am I wrong?

Here is the code:

Code: Select all

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

#define PIN PC13

void setup()
{
  pinMode(PIN, OUTPUT);

  while(true)
  {
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
  }
}

void loop()
{
}
RobertoBerner
Posts: 36
Joined: Tue May 09, 2023 10:45 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by RobertoBerner »

This works the same way, almost no while() delay.

Code: Select all

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

#define PIN PC13

void setup()
{
  pinMode(PIN, OUTPUT);

  while(true)
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
}

void loop()
{
}
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 »

RobertoBerner wrote: Sun May 14, 2023 2:50 am ...
As GonzoG suggested, I am not using digitalWriteFast anymore.
I was expecting a higher speed. Am I wrong?

Here is the code:

Code: Select all

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

#define PIN PC13

void setup()
{
  pinMode(PIN, OUTPUT);

  while(true)
  {
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
    digitalToggle(PIN); // Toggle PIN ~5 us toogle
  }
}

void loop()
{
}
Id did not say not to use digitalWriteFast. I said do not use any fast IO libraries.
If you want fastest possible digital IO use digitalWriteFast() and digitalReadFast() and fastest optimization (-O3).
But F103 isn't the fastest MCU when it comes to IO. F4 chips (eg. F401 or F411 that's on WeAct black pills) is at least 2x faster.

With F103 you'll better use a variable to store pin state then to use digitalToggle(), as reading pin is 2x slower than setting it.

Code: Select all

uint8_t pin_state = 1;

void loop(){
pin_state=!pin_state;
  digitalWriteFast(digitalPinToPinName(pin),pin_state);
  }
dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by dannyf »

maybe something like this will help.

Code: Select all

#define LED_PORT		GPIOC
#define LED_PIN			(1<<13)		//LED on C13

#define IO_SET(port, pins)	port |= (pins)
#define IO_CLR(port, pins)	port &=~(pins)
#define IO_FLP(port, pins)	port ^= (pins)

#define GIO_SET(gpio, pins)	IO_SET(gpio->ODR, pins)
#define GIO_CLR(gpio, pins)	IO_CLR(gpio->ODR, pins)
#define GIO_FLP(gpio, pins)	IO_FLP(gpio->ODR, pins)

#define FIO_SET(gpio, pins)	IO_SET(gpio->BSRRL, pins)		//normally BSRR
#define FIO_CLR(gpio, pins)	IO_CLR(gpio->BSRRH, pins)		//normally BRR
#define FIO_FLP(gpio, pins)	GIO_FLP(gpio, pins)				//fast io not available


int main(void) {
	while (1) {
		GIO_SET(LED_PORT, LED_PIN); GIO_CLR(LED_PORT, LED_PIN);
		FIO_SET(LED_PORT, LED_PIN); FIO_CLR(LED_PORT, LED_PIN);
		FIO_FLP(LED_PORT, LED_PIN);
	}
	
	return 0;
}
It provides a few ways to flip a pin:
1. GIO_SET() / GIO_CLR(): sets and clears pins;
2. FIO_SET() / FIO_CLR(): uses BSRR/BRR to set / clear pins. On this particular chip (F4, it is split to a BSRRH..BSRRL pair.)
3. GIO_FLP(): flips pins

it should take less than 10 instructions unoptimized - I have gotten it to just 4 instructions. You can also do tricks to minimize loop overhead.

This approach isn't without downside, BTW.
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 »

dannyf wrote: Sun May 14, 2023 11:13 am maybe something like this will help.

Code: Select all

#define LED_PORT		GPIOC
#define LED_PIN			(1<<13)		//LED on C13

#define IO_SET(port, pins)	port |= (pins)
#define IO_CLR(port, pins)	port &=~(pins)
#define IO_FLP(port, pins)	port ^= (pins)

#define GIO_SET(gpio, pins)	IO_SET(gpio->ODR, pins)
#define GIO_CLR(gpio, pins)	IO_CLR(gpio->ODR, pins)
#define GIO_FLP(gpio, pins)	IO_FLP(gpio->ODR, pins)

#define FIO_SET(gpio, pins)	IO_SET(gpio->BSRRL, pins)		//normally BSRR
#define FIO_CLR(gpio, pins)	IO_CLR(gpio->BSRRH, pins)		//normally BRR
#define FIO_FLP(gpio, pins)	GIO_FLP(gpio, pins)				//fast io not available


int main(void) {
	while (1) {
		GIO_SET(LED_PORT, LED_PIN); GIO_CLR(LED_PORT, LED_PIN);
		FIO_SET(LED_PORT, LED_PIN); FIO_CLR(LED_PORT, LED_PIN);
		FIO_FLP(LED_PORT, LED_PIN);
	}
	
	return 0;
}
It provides a few ways to flip a pin:
1. GIO_SET() / GIO_CLR(): sets and clears pins;
2. FIO_SET() / FIO_CLR(): uses BSRR/BRR to set / clear pins. On this particular chip (F4, it is split to a BSRRH..BSRRL pair.)
3. GIO_FLP(): flips pins

it should take less than 10 instructions unoptimized - I have gotten it to just 4 instructions. You can also do tricks to minimize loop overhead.

This approach isn't without downside, BTW.
digitalWriteFast/digitalReadFast need 1 MCU cycle. On F411 black pill you can get 50MHz output on pin with those.
Only digitalPinToPinName() needs additional cycles if you provide variable as a parameter and it won't be optimized.
So flipping pin state takes even 2 cycles.
dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by dannyf »

digitalWriteFast/digitalReadFast need 1 MCU cycle.
that would be very difficult to do.

digitalWriteFast() calls digital_io_write(), which goes through a if..then statement before calling LL_GPIO_SetOutputPin(), which goes to a set of register writes.

Hard to believe all that could be done in one cycle.

regardless, it would be interesting to see how fast it actually does.
RobertoBerner
Posts: 36
Joined: Tue May 09, 2023 10:45 pm

Re: BluePill fast 10 us Timer interrupt example code needed

Post by RobertoBerner »

...I am reading and learning, dear friends. A little. confused yet, but it is a very interesting discussion !

I am testing all this on my my Blue Pill that is the hardware that I recently got and easy to get locally in Buenos Aires.

I have seen an F4 NUCLEO board 180 MHz clock. That would be my next.

But first I need to listen...

BTW, where do I change the -O3 setting?
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 sending a gpio pattern to a pin/pins with tight timing, using DMA to ODR (or BSRR) register would be the way to go.
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 don't have experience with DMA, but your tip was noted. I first need to do simpler things. I am a newbie to STM32.

I have much experience with anolog and digital discrete designs. Also with the 8 bit world MPUs and MCUs.

Yesterday I could make LL work in the Arduino IDE. I have a temporary reason to start with the Arduino environment, but I have the STM32 tools installed. I will try to migrate there as soon as possible. The F4 is very tempting and GonzoG says it allows 50MHz signals on a pin. That's fast!

My goal now is to get a very fast timer interrupt event. 10 us is the fastest I could get, but I think that using LL direct access to registers this has to improve.

A 72 MHz machine should do better, I have Freescale MC9S08JM60 projects interrupting at a 80 us rate and we are talking of a 20 MHz CPU clock 8 bits machine.

So I will carefully read all the advice here, your's and GonzoG's and learn how to do it.

I find HAL very tedious, but I could compile a HAL and also LL with Arduino.

In the case of HAL in Arduino, the necessary #includes are confusing.
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: BluePill fast 10 us Timer interrupt example code needed

Post by ag123 »

try things like a stm32f401ccu
https://stm32-base.org/boards/STM32F401 ... -V1.2.html
https://www.st.com/en/evaluation-tools/ ... 401re.html

the f4xx series has that 'art accelerator' - on chip cache, occasionally it helps, i.e. for codes that run only in the cpu.
for IO (e.g. gpios, digitalWrite(), digitalRead() etc, that won't help

if you are generating repetitive (e.g. PWM) *simple* sequences, that say have a *fixed* (or slowly changing) duty cycle, hardware timer is the way to go.
https://github.com/stm32duino/Arduino_C ... er-library

Interrupts has limits in the 100k - 500k per sec range, and there are many interrupts while stm32 is running with a sketch, at least
- systick every 1 ms - this is what make millis() works, and probably other stuff (e.g. context switching RTOS)
- usb start of frame interrupt
if you add any other interrupts, they compete for time to be served. there are interrupt priorities which make things somewhat more complicated.
when the interrupt calls back your code, other than servicing the interrupt, it need to load code from flash, that can be several wait states, say 3 wait states
so even if your cpu runs at 72 mhz, divide that by 3 a memory fetch from flash is a mere 24 mhz
that 'art accelerator' in stm32f401 can *occasionally* help if the code is in cache, reducing the wait states from say 3 to *zero*, practically 3 times faster in a 'lucky' cache-hit scenario, it won't work in all situations and the microcontroller has very limited cache compared to extreme high density desktop cpus.

codes running from interrupts can be *extremely* slow, and is often the limit for 'fast' apps.
e.g. i made a little 'oscilloscope' (more correctly DAQ) - this is for the 'old' libmaple core
https://github.com/ag88/GirinoSTM32F103 ... ree/master
I used a timer call back to vary the ADC sample rates, so that I can have 'variable' sample rates as i prefer
the timer call back code is like
https://github.com/ag88/GirinoSTM32F103 ... r.cpp#L129

Code: Select all

void CAdcMgr::adctimerhandle(void) {
	//start conversion when called
	ADC1->regs->CR2 |= ADC_CR2_SWSTART;
}
Which 'merely' start the ADC to take the next sample.
For this code alone, the interrupts limits is around 500 k samples per sec, no faster on a stm32f103.
I've not ported the same code to stm32f401, though, so I can't offer a basis for comparison.
But that between stm32f103 and stm32f401 - at least is that 'art accelerator' - on chip cache and stm32f401 has a FPU making 32 bits FP maths very fast.

The other techniques like mentioned 'DMA' is about one of those means to do things that is 'impossible' in codes (e.g. with interrupts).
DMA is considered 'advanced' topic and take some time to learn and try things out. And often in conjunction with other hardware like SPI
Last edited by ag123 on Sun May 14, 2023 6:43 pm, edited 5 times in total.
Post Reply

Return to “General discussion”