how to #define an asm loop

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I want to do something like this.

#define DELAY_1US 	asm("ldi r19,  3\n oneUS: \n dec r19\n brne oneUS\n");

but using my define more than once gives me the oneUS is already defined. I can not just use a lot of nop's as my code gets to big.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try using the label "1:" and make the branch to destination "1b" (if it had been a forward jump that would have been "1f" instead)

This is explained on this page of the user manual (also on your hard drive if you use WinAVR):

http://sourceware.org/binutils/d...

(you may be more interested in "dollar local labels" at the bottom of the page)

Last Edited: Fri. Jun 11, 2010 - 03:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I understand it correctly, you are getting 1 us from a LDI and then iterating a DEC and a BRNE three times. What's that? About 10 clocks?

Will a RCALL and a RET be less than 10 clocks? IIRC it should be something like 6 clocks. So make an assembler subroutine delay_one_us that only does the RET. Then fill up the subroutine with as man NOPs as needed to get to one us for the CALL, NOPs ans RET.

The subroutine sequence will be about the same length as your sequence above, but will only occur once in your machine code. The RCALL will occur same number of times as your asm sequence above, but will be smaller. So less memory consumption with the same net delay effect.

And you also get rid of intricate embedded assembler coding (you of-course assemble the new DELAY_1MS in a separate source file). In your C ode you have:

#define DELAY_1US asm("rcall delay_1_us\n");

Do I win the Grand Prize?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl, the timing is calculated yet, it was just an example.

clawson , thx for the info!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just out of interest why are you re-inventing the wheel? Will _delay_us() from not do the job for you?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

it would seem that _delay drifts too much. When i use delay sometimes its a clock or two more than it should be.

With asm its always spot on. Also it would seem using delay (.950) and (.910) have the same meaning, so rather than trying to figure it out I just reinvented it.

Sure works nicely now!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yep, I am all too familiar with the cycle rounding issues of the _delay_xxx() routines.
If you are using C, you could either switch to this version of of the delay routines:
https://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_id=665&item_type=project

Or to have total control over things, use the built in gcc delay cycles funtion:

extern void __builtin_avr_delay_cycles(unsigned long __n);

The parameter to this function is an unsigned long which is an unsigned 32-bit number of cycles to delay. When you use this function in your application, GCC will replace the function with "do-nothing" assembly code that will delay the specified number of cycles

With the built in function, you can even write a simple 1 line macro wrapper that can calculate the cycles based on the elapsed time (i.e. s, ms, us, or even ns)
and the F_CPU value.

--- bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just remember to disable all interrupts ;)