Microsecond delay.

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

Moderator: RoccoMarco

hyOzd
Posts: 20
Joined: Tue Jul 21, 2015 12:17 pm
Has thanked: 1 time
Been thanked: 2 times

Re: Microsecond delay.

Post by hyOzd »

@ulikoehler thanks a lot for the blog post. It was great read. @Giovanni maybe you should add this to wiki? I was actually looking for something like this in there.

I have a question about the gptPolledDelay() function. My understanding is that it's also susceptible to thread switch problem like a simple loop. It's listed as a normal function, so can't be called from lock zone. But I've had a look at it's source and it seems like a couple simple register operations (stm32f4 implementation). I understand I cannot trust the implementation being safe unless it's declared so in the API documentation, but I want to know if this implementation (stm32f4) is okay for calling from lock zone?
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 »

Good point, it is a good material for a new article.

Nice blog BTW.

Giovanni
ulikoehler
Posts: 71
Joined: Tue Mar 17, 2015 2:32 am
Been thanked: 3 times

Re: Microsecond delay.

Post by ulikoehler »

@hyOzd @Giovanni Thanks both of you :) Hopefully I'll find time to write more such posts.

@hyOzd Very good point about gptPolledDelay. I have looked at the STM32 TIMv1 gpt_lld_polled_delay() implementation which should not

Maybe it should be an X-class API? If I remember correctly you can call those from anywhere.

Best regards, Uli
ulikoehler
Posts: 71
Joined: Tue Mar 17, 2015 2:32 am
Been thanked: 3 times

Re: Microsecond delay.

Post by ulikoehler »

One more note: I think if not used from within a lock zone, gptPolledDelay() is indeed susceptible to interrupts etc. In the current form, you can IMO just call it from a lock zone and don't worry about it.

Of course you can use my blog stuff for the wiki etc. under public domain. I'd appreciate a link to my blog, but it is not required.

@rew I think we understand your issue. It might be possible in theory to, say, introduce a function where you could input your desired SPI frequency and get out a SPIConfig instance. The issue is that for any given configurations there are only a few clock speeds you can use (and those might be specific to the MCU peripheral). I don't think it is intuitive if you need to try out 25 variants until one works. Moreover, I'm not sure if you could implement it entirely compile-time via preprocessor. It would be a real pain to flash the MCU 25 times, start the debugger etc just to see that the firmware has crashed again just because of the stupid SPI clock config. Using custom config register values that contain a prescaler is failsafe (and possibly fool-proof): Every setting for the prescaler is valid for most MCUs.
However, in general if you could implement it like you said, it might certainly be useful to some people -- in other words, if it would be intuitive and it works I don't think anyone will oppose. However, I think adding something like that by default would actually not really improve the overall situation

Maybe we could write some optional utility macros to compute the prescaler?

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 »

Correct, the function should receive an X suffix, it can be called in any context BUT doing polled delays inside critical zones is, in general, a bad idea.

Giovanni
ulikoehler
Posts: 71
Joined: Tue Mar 17, 2015 2:32 am
Been thanked: 3 times

Re: Microsecond delay.

Post by ulikoehler »

Giovanni, I agree 100% ;-)

However, I think that the TIM polled delay is, practically speaking, a niche delay method. I think I have used it once to add some grace time somewhere in the ChibiOS 2.4 HAL init two years ago, because the system was not initialized at that point so I could not . The thing is, when not using it from within a lock zone, it is pretty much useless for accurate delays. Using it for long delays from within a lock zone will likely cause more issues than it solves. What is left is using it for inaccurate timings and for very short timings e.g. where interrupt latencies are inacceptable (I think a lockzone will be acceptable then).

My blogpost now contains a short section about virtual timers.

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 »

ulikoehler wrote: The issue is that for any given configurations there are only a few clock speeds you can use (and those might be specific to the MCU peripheral).
The specified clock speed would be a maximum. If my chip can handle 2MHz, I'll ask for max 2000000 Hz. If the available options end up landing on say 2.1MHz and 1.05MHz, the 1.05MHz should be chosen.
ulikoehler
Posts: 71
Joined: Tue Mar 17, 2015 2:32 am
Been thanked: 3 times

Re: Microsecond delay.

Post by ulikoehler »

@rew OK, so let me show you how I'd solve this problem.

Let's assume you are using a STM32F0 MCU and you must ensure the SPI clock speed must be between 0.8 and 1.2 MHz (1.0 MHz nominal!). I'll compute that for my STM32F0 board.

When looking e.g. at section 27.9.1 in the reference manual (http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031936.pdf), you can see that the SPI clock speed is derived from PCLK.

Let's calculate the clocks (although ChibiOS does this in macros, you usually need to do it to find out if your concepts work at all):

SYSCLK is equal to the PLL output because STM32_SW = STM32_SW_PLL
The PLL gets fed by a 8 MHz HSE oscillator (STM32_PLLSRC = STM32_PLLSRC_HSE) that is first divided by STM32_PREDIV_VALUE = 1 and then multiplied by STM32_PLLMUL_VALUE = 6. This gives us a 48 MHz SYSCLK (max speed for the F030F4).

HCLK is SYSCLK divided by STM32_HPRE_DIV1 = 1, therefore HCLK is 48 MHz.
PCLK is SYSCLK divided by STM32_PPRE_DIV1 = 1, therefore PCLK is 48 MHz.

OK, now we know that PCLK is 48 MHz. Let's do some elementary math: What do we need to divide 48 MHz by to get 1 MHz. Right: 48.

Now we can look at the table in the refman (search for SPIx_CR1, see above for link & section). What is the correct value for BR[2:0]?

Code: Select all

...
100: fPCLK/32
101: fPCLK/64
...


Ahem... there is no 48 here. Therefore, it won't work :oops:

What can we do?
Unfortunately not too much as long as the CPU clock remains @48MHz. We need to ensure PCLK is 32, 16, 8, 4, 2 or 1 MHz. However, the PCLK can (AFAIK) only be generated by a power-of-2-prescaler from SYSCLK.
This means, we have to set PLLMUL to 4 (instead of 6) to get a 32 MHz sysclock. Then we can use BR[2:0] = 100 (a SPI prescaler of 32 --> 1 MHz).

Of course we could always relax the requirements. But I hope you can see the issue now, it is a complicated process on complicated MCUs. When you have a single, slow clock like on the AVR, it is much easier, but you won't have any of the fancy features like DMA etc.

The F0 family usually can handle up to 18 MBit/s SPI, so you can assume using a 16 MHz SCLK will work (actual limits are listed in the datasheet).
-------------

This was complicated. Welcome to MCUs. However IMO most of the time you can actually avoid doing that calculations
Some practical tips:
a) If possible, use _Static_assert to check the ChibiOS calculated value, e.g.

Code: Select all

_Static_assert (STM32_PCLK < 32000000, "PCLK too large");

b) If you can be sure not to damage the other ICs (or it's cheap to replace), in my experience you can usually waste less time by just trying it out. Start with the maximum prescaler(fPCLK/256) and work your way up until it doesn't work any more (if you care about low power or have EMI issues, try to use a higher prescaler --> lower frequency).
c) In many cases you can just use the default config from the testhal directory. This is my config. As I said, in my experience it wastes less time to change something and measure than to do accurate calculations, assuming you don't have very strict requirements and your equipment is not easily damaged. You can optimize power consumption and EMI later.

Code: Select all

static SPIConfig spi1cfg = {
  NULL,
  /* HW dependent part.*/
  GPIOB,
  GPIOB_ADC1_CS,
  SPI_CR1_BR_0 | SPI_CR1_CPOL | SPI_CR1_CPHA,
  0
};


Best regards, Uli
hyOzd
Posts: 20
Joined: Tue Jul 21, 2015 12:17 pm
Has thanked: 1 time
Been thanked: 2 times

Re: Microsecond delay.

Post by hyOzd »

Guys, when using gptPolledDelay, is 400ns extra delay too bad? Should I lower my expectations : )

I'm using STM32F4 discovery board with default configuration which I assume runs at 168MHz. I'm setting the timer to 1MHz. In this case I measure that each delay is approximately 0,4us extra longer. I'm making the measurement by pulsing a GPIO pin.

I've also tried setting timer to a higher frequency such as 10MHz or 5Mhz but this time delays started to get shorter :s Longer delays had more offset. For example when I call a 52us delay, I get 49,95 us delay. And this is a very consistent behaviour not jitter. Could it be that there is something wrong with the default configuration of the timers? I can provide data and working code if you are interested.
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 »

The delay should have a jitter of 1 clock cycle (timer clock) and have a fixed overhead for function call, timer setup, function return. Additional jitter can be introduced by IRQs serviced out of the timer loop.

If this is not consistent with what you are observing then there could be an error.

Giovanni
Post Reply