Microsecond delay.

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Microsecond delay.

Post by rew »

Hi,

I've searched for over an hour to try to introduce a delay of a few microseconds into my program flow.

There are of course other ways to achieve this. But starting timers, and things like that make my program more complex than it needs to be.

Now with a bit of luck your programming environment will provide you with a function that does this. For example, the avr-gcc compiler comes with a header "delay.h" that will define a _delay_us function that allows a constant argument and inlines into the proper delay with quite some accuracy.

With Chibios we however are not so lucky. Until today. I've written a first implementation for a delay_us function that "works for me".

(The "polled delay" function is not available on my STM32F0xx. It took me a while to figure out the new name of the function, all forum posts referred to the old name of that polledDelay function. Then it took me a while to figure out why it could not be found. I really didn't expect that one of the primary platforms (STM32Fxxx) would be "not RT capable".).

Code: Select all

void delay_us (int us)
{
#if 0
  // it would be nice if chibios supported (busywaiting) delays
  // with microsecond resolution.
  //
  osalSysPolledDelayX (US2RTT(us));
#else
  for ( us *= 48/6;us>0;us--)
    __asm__("  nop;");
#endif
}
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Microsecond delay.

Post by Giovanni »

It is not the F0, it is the M0 core missing the RT counter but you can use gptPolledDelay() that does the same thing using one of the STM32 timers.

Giovanni
rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Re: Microsecond delay.

Post by rew »

Giovanni,

There needs to be a "utility function" that users (on all platforms!) can use to introduce a small polled delay with say microsecond resolution. (The one I mentioned on AVR is a bit better: running at 20MHz, it simply has 50ns resolution!).

The idea with a library or "OS" between the sourcecode and the hardware is that you gain some hardware independence. When I write "PORTA=0x81;" on attiny44 or on atmega328, the library will take care of defining PORTA such that both of these statements do what I want (even when ATMEL did or did not put PORTA at the same address). Of course, when we're talking about a low-level library/os like Chibios, you can "descend" so low towards the hardware that you need to know the details of the hardware. But many applications do not need to go that far. A side-goal of Chibios should be that the simple things, toggling IO pins, delays basic UART communication and maybe SPI and I2C should have the source independent of the hardware.
ulikoehler
Posts: 71
Joined: Tue Mar 17, 2015 2:32 am
Been thanked: 3 times

Re: Microsecond delay.

Post by ulikoehler »

@rew:

Why is gptPolledDelay() not such a function? Although I only work with ARM-CMx, as far as I can see, this function should work everywhery, as long as a timer driver is implemented and at least one timer is enabled and available for that purpose.

Best regards, Uli
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Microsecond delay.

Post by Giovanni »

Just a note.

In RT 3.0 the system time can be used for high resolution operations IF the tickless mode is enabled and the frequency is set to 1MHz or greater. That interface is always available.

Giovanni
rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Re: Microsecond delay.

Post by rew »

Partly the problem is in FINDING the function. Searching for such delay functions resulted in forum posts and documentation pages that did NOT result in accurate and usable information.

Second, those functions are documented to work in ticks. I suspect that it ticks at something like 36 or 72MHz. And when I convert microseconds to ticks, are those the same ticks as those functions work in? Why is it a problem to implement and document a delay-microseconds function? That could be a define that calls gptPolledDelay with the proper conversion of the argument. A define won't cost any code-space. It would just provide a convenient function that does what its name implies without bothering me, a lowly programmer, with the implementation details.
ulikoehler
Posts: 71
Joined: Tue Mar 17, 2015 2:32 am
Been thanked: 3 times

Re: Microsecond delay.

Post by ulikoehler »

@rew

OK, I see your issue. In order to address it, I've wrote quite a length blogpost about pretty much any aspect of delays I could come up with spontaneously.

http://techoverflow.net/blog/2015/09/09/accurate-short-long-delays-on-microcontrollers-using-chibios/

Excerpt:
The second parameter to `gptPolledDelay()`, 10, is the number of ticks to wait. Beware, however: These are not systicks! In this context, we are talking about timer ticks. We defined the timer frequency of TIM4 to be 1 MHz in the `gpt4cfg` structure, so 10 ticks are equal to 100 microseconds.


Comments, corrections and suggestions are highly appreciated :D

It is usually impossible to let a timer tick higher than ~12 MHz. It depends on a lot of configuration options and, especially, the clock speed (I think it's the PCLK for the STM32, but I'd need to check), but on an early ChibiOS 2.x STM32F4 setup, the timer ceased to function above 10 or 12 Mhz with a fairly default 168 MHz configuration.

No, a define would by far not be as easy as you think. The tick frequency is not even remotely equal to the CPU / HCLK / PCLK / whatever other clock frequency in the general case. While I think it would be theoretically possible in a hardware-dependent way (read prescaler reg, use PCLK macro etc), I can tell you that with microcontrollers, things are most often way more complicated than they seem (I'm not even talking about FPGAs here... Even the STM32 clock stuff can drive you to late-night madness) Once you have several different clock domains with multiple configurable prescalers, you can't simply write a macro like US2ST() to get your microsecond delay working reliably. Also every time I used gptPolledDelay, I actually wanted to have a number of timer ticks instead of.

For example, take the locking issue discussed at the end of my blogpost. Should delay_us() lock (i.e. disable interrupts) or not? Should it depend on the us parameter? If yes, what correction factor needs to be applied to account for the branch for very short delays? What is the likelihood of a n-microsecond delay to be interrupted with a specific firmware if not locked?
These are questions that don't have simple answers, therefore I can't see any generic method of writing such functions that will work in any case. If you see a way, however, I'd be glad to implement it :D

For a WS2812B controller on the F030 I used the NOP method with Emprical Method A (see blog post) with locking; this was quite successful.

BTW, I successfully use ack-grep to find stuff in the ChibiOS source code. IMO this is often better than looking through the docs.

Best regards, Uli
rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Re: Microsecond delay.

Post by rew »

I have not "messed" with the hclk / pclk / etc settings. So "chibios" knows those things better than I do. Why do we need a timer at all? Why would cycle-counting work on AVR and i386 but not on ARM? (Linux uses "bogomips" for short delays. If your CPU has 2400 bogomips, it will count to 1200 in a microsecond (decrement and jump counted as two instructions). )

Correction: 10 ticks would be equal to 10 microseconds, not 100.
ulikoehler
Posts: 71
Joined: Tue Mar 17, 2015 2:32 am
Been thanked: 3 times

Re: Microsecond delay.

Post by ulikoehler »

Yeah, but by not messing with them you still have some very complicated stuff happening in the backend. ChibiOS/HAL can only make it transparent to you up to a certain degree. For example, it might depend on the configuration in the configuration register. Besides that, it will be hardware-dependent.

You really shouldn't compare AVRs with more complex microcontrollers. What you describe works more easily on AVRs because they don't have a very complex NVIC interrupt controller, multiple DMAs, possibly MACs and at least 3-4 clock domains.
You should not expect that a complex 48 MHz MCU such as a STM32F030 runs as linearly / deterministically as a very simple 8-bit 16 MHz AVR, even with the cycle counting methods.

Also note that CPUs (including ARM A8 etc) usually have dedicated instruction counters. AFAIK MCUs (ARM CMx & AVR, have not checked others) do not.

Even the timers alone are way more complex than the AVR (and MSP430) timers. Depending on the application this might be good or bad.

In general I'd say when operating a STM32 at frequencies comparable to AVR frequencies (provided you have a good clock source), you won't encounter the majory of the issues I dessribed.

At the end of http://techoverflow.net/blog/2015/09/09/accurate-short-long-delays-on-microcontrollers-using-chibios/, I added a section about flash latency issues. If you tell us more about the delay length and the MCU you're using, maybe I can give you some specific tips.

To answer your question, of course cycle counting is possible (see my blog post, section "Sequence of NOP instructions"). But it might or might not be as simple as you think. The simpler the firmware and the slower the MCU clock, the more likely is it that it wil work. I recommend NOP sequences only for delays that are shorter than achievable via a timer.

Thanks for the 10/100 microsecs tip. Fixed

Best regards
rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Re: Microsecond delay.

Post by rew »

If it's not simple in complicated cases, why not provide a simple interface with a caveat: doesn't work in complicated cases?

Chibios provides a way for me to write
palSetPad (...)
on a variety of processors (I'm working with STMF030, 042, 050, (070 shortly) 072, 103, 205, 303, 334, 405, 407, and 429). With a bit of luck making say PA1 high is the same across all these processors. The caveat is that it won't work if you select an alternate function for that pin. But... under normal circumstances stuff like that works.

One level higher, say using an UART, chibios allows me to set the baud rate, and, knowing what peripheral bus speed it selected sets the prescaler and dividers to achieve the requested baud rate. Great. If behind chibios' back I go and modify peripheral clocks that baud rate will be wrong.

Things go downhill when I want to configure an SPI device: Suddenly I have to provide a config structure that holds SPI module config register values. I can't just say I want 100kHz clock rate.

I'm arguing for an interface, that provided I don't mess with too low-level stuff, gives me a simple delay. If things are not trivial to implement, that is to be expected. That's why doing it once in the library pays off: lots of people get to "not worry" about the details.

When I write such a delay loop in C on cortex-m0 (stm32F0xx) it seems I get 6 clocks per loop. But I remember seeing "5" Maybe on my '405... Or could be a different compiler. Such a "delay.h" or "delay.c" might in the next iteration include the assembly for the loop.

One of the restrictions of such a "delay.h" would be: If you mess with the CPU clock, your results will be off. Same holds for AVR: Here is some code I wrote:

Code: Select all

    // The delay functions don't know about the clock scaling. We want
    // to delay by about 20ms to postpone the next check to after the
    // switch bounce has finished....
    if (scale == 1) delay_ms (20);
    else            _delay_us (20000/256);
If scale != 1 it is 256, and then the CPU is running at the normal clock / 256.

The same is to be expected here: Once you mess with the clocks, either don't use the cycle counting delays, or account for the correction factor.
Post Reply