Skip to main content
CTabo.1
Senior
March 6, 2024
Solved

How to implement a few cycles delay macro or function

Hello,
I need to implement delay macro, lasting just a few cycles.

As the delay is so small I would not like to use TIMs o DWT.

On Texas Instruments DSPs, I was used to implement this nanoseconds delays, using NOP() instructions.
Unfortunately, as also written in STM32 Programming Manual this is not a good pattern on Cortex processors.

On a previous post, related to another issue, I was suggested to use Data Memory Barrier (DMB), Data Synchronization Barrier (DSB), and Instruction Synchronization Barrier (ISB) instructions, instead of NOPs.

How can I use this instructions, to implement a few cycles delay macro?

Regards,
Carlo

This topic has been closed for replies.
Andrew Neil
Andrew NeilBest answer
Super User
March 11, 2024

@CTabo.1 wrote:

I need to read the MISO signal to verify if the device access has been succesful.


Maybe just read the status twice - ignore the 1st reading ... ?

:thinking_face:

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.

12 replies

TDK
March 6, 2024

There's not really a way to do this on Cortex-M33. The processor is more complicated than X operation always takes Y cycles. If you can accept maybe 5-10 cycles of jitter, you can use a loop around DWT->CYCCNT.

Not that just because an operation complete (e.g. writing 1 to an GPIO register controlling an LED) doesn't mean the pin for that LED turns on at exactly that time. There are pipeline delays that are not within your control. Small delays, but significant in the context of "a few cycles".

More discussion here:

https://community.st.com/t5/stm32-mcus-products/cortex-m33-instruction-cycle-counts/td-p/123198

 

"If you feel a post has answered your question, please click ""Accept as Solution""."
Andrew Neil
Super User
March 6, 2024

@CTabo.1 wrote:

I need to implement delay macro, lasting just a few cycles.


It might help if you explain why you feel the need to do that?

There may be other approaches ...

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
CTabo.1
CTabo.1Author
Senior
March 7, 2024

Hello,
this is the situation.

I am developing a driver to handle a device connencted via SPI to the MCU (master).
At the end of each SPI cycle, after CS# deassertion, I need to read the MISO signal to verify if the device access has been succesful.

The device datasheet indicates a minimum time of 15 ns to wait, from CS# deassertion, before reading the MISO signal.
In the past, on TI DSPs, I was used to wait this little time, simply adding some NOP() instructions.

Regards,
Carlo

 

CTabo.1
CTabo.1Author
Senior
March 12, 2024

Yes, it is a better and more accurate solution.
However it may be necessary to encapsulate the two consecutive readings instructions between #pragma directives to disable any optimizations.

 

#pragma GCC push_options
#pragma GCC optimize ("-O0")
sts = LL_GPIO_IsInputPinSet(PORT, PIN);
sts = LL_GPIO_IsInputPinSet(PORT, PIN);
#pragma GCC pop_options

 

Thank you,
Carlo

 

LCE
Principal III
March 8, 2024

I would simply use something like:

 

uint32_t u32WaitCnt = 0;
while( (MISO_pin == x) && (u32WaitCnt++ < y) );
...

 

Set x to the pin level you would like to see,

set y depending on CPU clock.

I agree to most what Tjaekel said, so a small value < 10 for y is probably good enough. 

Or even the incrementing of the variable...

CTabo.1
CTabo.1Author
Senior
March 11, 2024

Hello and thank you all.

As @Andrew Neil  said, the delay must be done in FW, because it is outside the SPI transfer.

Also, as @TDK  said, I got that I cannot implement a "few cycle" accurate delay function, because of processor complexity.

So, in the end, I will use an approximative delay function, that surely guarantees a delay much longer of 15 ns, like this:

static inline delay(uint8_t n)
{
volatile uint8_t i;
while (i++ < n);
}

 

Regards,
Carlo