Best way to add delay / do nothing for n cpu loops

I need to add a delay to my code of n processor cycles (~ 30). My current solution is the next one that works, but not very elegant.

In addition, the delay should be known at compile time. I can work with this, but it would be ideal if I could change the delay at runtime. (This is normal if there is overhead, but I need a resolution of 1 cycle.)

I have no peripheral timers that I could use, so it should be a software solution.

do_something(); #define NUMBER_OF_NOPS (SOME_DELAY + 3) #include "nops.h" #undef NUMBER_OF_NOPS do_the_next_thing(); 

nops.h:

 #if NUMBER_OF_NOPS > 0 __ASM volatile ("nop"); #endif #if NUMBER_OF_NOPS > 1 __ASM volatile ("nop"); #endif #if NUMBER_OF_NOPS > 2 __ASM volatile ("nop"); #endif ... 
+5
source share
3 answers

NOP cortex devices have something that literally means nothing. There is no guarantee that the NOP will consume any time. They are used only for filling. You will have several consecutive NOPs, they will simply be dropped from the pipeline.

See your Cortex-M0 documentation for more information. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDJJGFB.html

software delays are quite complex on Cortex devices, and instead you should use other + instructions, possibly barrier instructions.

use ISB instructions 4 hours + flash access time, which depend on the speed of the kernel. For very accurate delays, this part of the code in SRAM

+1
source

Edit: there is a better answer from another SO Q & A here . However, in an assembly, AFAIK uses a counter such as SysTick - the only way to guarantee any semblance of cycle accuracy.

Edit 2: To avoid counter overflow, which will lead to a very long delay, clear the SysTick counter before use, i.e. SysTick->VAL = 0;

Original:

Cortex-Ms has a built-in SysTick timer that can be used for accurate timing of the cycle.

Start the timer first:

 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk; 

You can then read the current account using the VAL register. Then you can implement tactical loop delay as follows:

 int count = SysTick->VAL; while(SysTick->VAL < (count+30)); 

Please note that this will lead to some overhead due to load, comparison, and branching in the loop, so the final loop will be slightly smaller, no more than a few ticks in my estimation.

+1
source

You can use the free time counter as follows:

 uint32_t t = <periph>.count; while ((<periph>.count - t) < delay); 

As long as delay less than half the counter period, it does not depend on the wrapping of the counter value - unsigned arithmetic gives the correct time delta.

Please note that since you do not need to control the counter value in any way, you can use any such counter in the system - even if it is used for another purpose (for how long, of course, since it really runs continuously and freely and with speed, which gives you the required time resolution).

-1
source

Source: https://habr.com/ru/post/1269028/


All Articles