ICCAVR delay_cycles

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

Working on the zbaird's radar gun project. I want to do some bit banging and am trying to use the __delay_cycles in ICCAVR. I can not seem to get it to work though, admittedly I have never tried this before so I do not know the correct way of using it. I can not seem to find any documentation on how to use it. I have searched but dont see it (I am sure that someone will show me a google query -im feeling lucky- with the answer, you know an egg in the face answer, that is just my luck)

I have tried
#define delay() __delay_cycles(CLOCK/2400); but this
gives me the wonderful error message: undefined symbol '___delay_cycles' .

The example I saw using this did not mention anything special I needed to do. I am using the demo version of ICCAVR 7.14c

Chip: mega88
Freq 20MHz

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

At a guess, because I have not got ICC. There will probably be a system header file.

So read the docs on delay, #include the correct header file and use the functions or macros as advised.

David.

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

I use something like this to get multiple ms delays in iccavr....

//-------------------
void delnms(int n){
//delay n ms
int x;

  while(n--){
    x=2600;       //empirically determined fudge factor  16 mhz
    while(x--);
  }
}

Imagecraft compiler user

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

You need to include the intrinsics.h file to get the declaration of __delay_cycles(). For IAR with optimizations turned on, the following is efficient:

#define _delay_us(us) __delay_cycles(((us * F_CPU)/1e6) + 0.5)
#define _delay_ms(ms) __delay_cycles(((ms * F_CPU)/1e3) + 0.5)
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The ImageCraft ICCAVR C compiler doesnt have a delay.h, that I could find. You either need to make your own custom delays or use a hardware timer...

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

Oh, I get it. ICCAVR means ImageCraft compiler. It's ambiguous since IAR for AVR defines the C preprocessor symbol __ICCAVR__ as the standard definition for their AVR compiler, presumably meaning "IAR C Compiler AVR".

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

An unfortunate overloading of the letters ICC. Caused me some confusion early on trying to figure out which compiler was used on certain code examples.... Imagecraft compiler installs in a dir called iccv7avr. What does IAR call their directory?

Imagecraft compiler user

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

I agree about the unfortunateness of the overload. From cygwin:

$ ls -l /cygdrive/c/Program\ Files/IAR\ Systems/Embedded\ Workbench\ 4.0/
total 12
4 -r-x------+  1 Administrators Domain Users 2040 Nov 27 08:05 Product.log*
4 drwx------+ 12 Administrators Domain Users 4096 Nov 27 07:52 avr/
4 drwx------+ 11 Administrators Domain Users 4096 Nov 27 08:13 avr32/
0 drwx------+  7 Administrators Domain Users    0 Nov 27 07:44 common/
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
An unfortunate overloading of the letters ICC. Caused me some confusion early on trying to figure out which compiler was used on certain code examples....

One of the reasons, if you'll notice, I always refer to the ImageCraft C compiler as "ImageCraft ICCAVR " and not just "ICCAVR. "
This seems to eliminate the confusion.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

microcarl wrote:
One of the reasons, if you'll notice, I always refer to the ImageCraft C compiler as "ImageCraft ICCAVR " and not just "ICCAVR. "
This seems to eliminate the confusion.
Yes, it does. It seems to me my first thought of the identity of the referred object comes from their canonical C preprocessor definitions, __ICCAVR__ (IAR) and __IMAGECRAFT__ (straightforwardly enough, ImageCraft). Unfortunately, Carl, the increased verbosity does seem be needed if either sufficient additional context is either not provided or properly interpreted by the reader.

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

imagecraft iccavr installs in \iccv7avr

Yes unfortunately It appears my best choice is to do a for(x=0;x<=y;x++); to get the delays I need. Pretty much what bobgardner suggested right off the bat.

Thank you for your all of your suggestions.

I think the only question that remains is to determine how many clock cycles each loop takes in the above for loop.

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

dgabler wrote:
imagecraft iccavr installs in \iccv7avr
Yes, Bob mentioned that.
Quote:
I think the only question that remains is to determine how many clock cycles each loop takes in the above for loop.
You can look at the assembly language output of the compiler and then count the cycles each instruction requires. You may want to download the PDF of the AVR instruction set for that information if you have not already done so.

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

I think if I owned Imagecraft AVR, I'd spend the time to write a few assembly language library functions to delay a certain number of cycles. A function take takes a 8-bit and 16-bit number of cycles would be the most helpful. A third function taking up to a 32-bit number from C would give even longer delays.

Then, with Imagecraft, one could then do something like:

#define USEC_TO_CYCLES(us) (((us * F_CPU)/1e6) + 0.5)
#define MSEC_TO_CYCLES(ms) (((ms * F_CPU)/1e3) + 0.5)

// an ideal C compiler will compile the below to a compile-time constant not requiring any SRAM
static const unsigned int 15ms_cycles = MSEC_TO_CYCLES(15);

main() {
...
  delay_cycles_16 (15ms_cycles);
...
}

But, I don't own Imagecraft. The compilers that do I have, IAR and GCC, already have assembly language delay_cycles functions available.

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

This is one form of delay that I have been using for nearly as long as I've been using AVR.

// Clock cycle = 67nS @ 14.7456MHz	
// Delay resolution ~ 1uS @ 14.7456MHz
void LCD_Delay (unsigned int d) {
	 while (d-- != 0);
}

It's short, sweet & simple to understand.

Actually, in resent projects, I've renamed it..

// Clock cycle = 67nS @ 14.7456MHz	
// Delay resolution ~ 1uS @ 14.7456MHz
void Sleep_uS (unsigned int d) {
	 while (d-- != 0);
}

I could get all fancy and use some math to take account for the various CLK frequencies that I use but and increase the accuracy but... Laziness prevails.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

microcarl wrote:

// Clock cycle = 67nS @ 14.7456MHz	
// Delay resolution ~ 1uS @ 14.7456MHz
void Sleep_uS (unsigned int d) {
	 while (d-- != 0);
}

Comaring the 1us and 67ns, each loop takes 15 cycles? If so, I wonder if you could put a NOP within the loop and have it take 16 cycles. Then, you could have this mildly low-resolution delay_cycle function:
void delay_cycles(unsigned int cyc) {
  cyc >>= 4;
  while (cyc-- != 0)
    asm("NOP");
}

Edit: Carl, I assume this number of cycles this loop requires does not vary by optimization level. The possibility of changing delays based on optimization level made me think of using assembly language for this function.

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

kmr wrote:
microcarl wrote:

// Clock cycle = 67nS @ 14.7456MHz	
// Delay resolution ~ 1uS @ 14.7456MHz
void Sleep_uS (unsigned int d) {
	 while (d-- != 0);
}

Comaring the 1us and 67ns, each loop takes 15 cycles? If so, I wonder if you could put a NOP within the loop and have it take 16 cycles. Then, you could have this mildly low-resolution delay_cycle function:
void delay_cycles(unsigned int cyc) {
  cyc >>= 4;
  while (cyc-- != 0)
    asm("NOP");
}

Edit: Carl, I assume this number of cycles this loop requires does not vary by optimization level. The possibility of changing delays based on optimization level made me think of using assembly language for this function.

I had the delay function that way because I wanted the resolution. In fact, there was originally a nop just below the while() statement, but out side of it, where, I had the delay tweaked via my scope for exact microsecond timing. But I didn't need the delay to be that tight.

And if I wanted really good precision, as well as resolution, I'd have used a hardware timer to establish the delay function. But I didn't! I only wanted something with fairly finite resolution and moderate accuracy...

No, I have seen op optimization of the delay accuracy.

In fact, Jorg and I had a discussion about this a while back, as GCC will optimize the entire delay out of the program but, ImageCraft, by default, does not.

I quoted in an earlier thread today:

"If it ain't broke, don't fix it! " John Kerr, 1982
That was excellent advice to me, from my very good friend Mr. Kerr, advice I usually try to practice!!!

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

Thanks for the additional information, Carl, appreciated!

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

I made a loop with ten calls to delnms(1) in it (reduces loop overhead) and timed 1000 loops with my watch and it took 10 seconds. Thats accurate to 2 significant figures. If there are a bunch of interrupts running, bets are off.

Imagecraft compiler user

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

That's a reasonable way, Bob. Still, for flexibility, it'd be nice to have a fairly accurate, high-resolution delay_cycles() function for Imagecraft. All my musing has been for cross-compiler compatibility so that I can have a delay function that works correctly on Imagecraft, GCC, and IAR. Using a cycle-based delay, rather than time-based, allows compile-time adjustment of the cycle count as F_CPU preprocessor definition changes to keep the delay a constant time.

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

Quote:

All my musing has been for cross-compiler compatibility so that I can have a delay function that works correctly on Imagecraft, GCC, and IAR.

I assume CodeVision isn't listed because delay_us() and delay_ms() already work correctly.

And poor latecomer CrossWorks never gets any respect.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

No prejudice against CodeVision or CrossWorks. But, my current effort is supporting a firmware using cross-compatibility macros/definition header file that support Imagecraft, GCC, and IAR. Currently, Imagecraft is about 80% supported compared to GCC and IAR. The limitation of ImageCraft I haven't found a flexibile delay routine based on F_CPU and that ImageCraft requires #pramga to be output in the code. As you likely know, the C preprocessor can not output the sharp ('#') character.

I understand from Richard (of Imagecraft) that Imagecraft will support _Pragma() declaration form (like IAR) so that I can emit code for things like register binding, interrupt service routines, and no-initialization variables.

All that is a prelude for a few questions, Lee.

Does CodeVision have a delay_cycles function (like IAR and GCC)?

Does CodeVision require #pramga to be emitted for interrupt service definitions?

Does CodeVision allow for register binding to variables? No initialization variables?

Does CodeVision support inline functions?

If you have time, I'd appreciate your input. Otherwise, I can just RTFM when I get in the mood to add CodeVision support to my compatibility header. (Soon to be released under a BSD license).

Thanks

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

Quote:

Does CodeVision have a delay_cycles function (like IAR and GCC)?

No. It has delay_us() with constant parameter generated as an inline loop, and delay_ms() with variable parameter (integer number of ms, up to 30 seconds IIRC). Both are based on the given project speed, the equivalent of F_CPU.

Quote:

Does CodeVision require #pramga to be emitted for interrupt service definitions?

No. ISR declarations/definitions are of the form

interrupt [ADC_INT] void adc_isr(void)

using the "interrupt" keyword and a vector number in [], typically a #define from the chip include file. There are project options for truncating the vector table, or for rolling your own for different default handling and the like.

Quote:
Does CodeVision allow for register binding to variables? No initialization variables?

I don't know exactly what you mean. There are a number of "rules" and options for global ragister variables using R2-R14. Local variables use registers R16-R22. The allocation can be automatic or manual. "bit" variables are also register based--again, with some variations using GPIOR. I guess I don't know what an "initialization variable" is.

Quote:

Does CodeVision support inline functions?

No. At least not in the active version; IIRC there is something in the works.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Lee,

What he meant by "no initialization variable" is like GCC's concept of .noinit - Normally if you have a global and provide an initialiser then (well in GCC anyway) it goes into a memory section called .data and when C starts it copies the initial value out of flash and to that RAM location. If you didn't provide an initial value then it is located in a .bss memory section and, instead of it being copied out from flash, another loop in the startup simply arranges to write 0's to thise items in .bss - those two memory sections are generated automatically simply by the presence or absence of initial values on globals. It is, however, possible to add a compiler specific rider to some variable defintions to say you want it placed in a section called ".noinit" which is separate from .data and .bss but that is guaranteed NOT to be touched by the C pre-amble. So if you set a value into a .noinit variable then "jmp 0", when you get back to where you were the variable still holds the same value (and wasn't touched by the preamble).

My previous trek out into CV territory suggests that the preamble there actually writes 0 to EVERY memory location before it's equivalent of .data are brought out from flash. So I think it's fair to say that it doesn't support the concept of .noinit unless there's some way to tell it to "don't do that complete memory wipe" - (well I know there's always the backstop of providing your own C preamble in fact!) - but I don't think it has a simple directive one can include in the source to say "by the way, leave the 0x200..0x220 locations alone please" or whatever.

Having said all that I've been puzzled by .noinit - I don't think I've ever been able to think of a scenario in which you'd want to use it - but presumably whoever suggested it in the first place had some reason - maybe it was to cope with our old friend - bootloader to app value passing?

Cliff

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

Quote:

well I know there's always the backstop of providing your own C preamble in fact!

That's the way. ;)

Yep, I understand about the .noinit . Like you, I've never found the need. For controlled SRAM contents after a reset, it is too scary given the different reset types and only under the controlled reset conditions would it be valid.

Another possible scenario might be a bank of external SRAM that you don't want to "waste" the time initing. Lessee--at 1us/byte and 64k, that would be 64ms. I almost always have a longer startup delay to let things settle anyway so it wouldn't be a biggie.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

noinit section is a good place to hide a magic number like 0xaa55 so the program knows if it is a warmstart or a coldstart. Shouldnt delay param be us or ms? That solves the problem of converting cycles or loops to time units.

Imagecraft compiler user

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

Bob,

Isn't that what MCUCSR exists for? If you read it at startup then either a bit says which reset mechanism got you there or, if no bits set then it was a "jmp 0" (or possibly execution passed FLASHED or a RET to address 0 or similar)

Cliff

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

theusch wrote:
No. It has delay_us() with constant parameter generated as an inline loop, and delay_ms() with variable parameter (integer number of ms, up to 30 seconds IIRC). Both are based on the given project speed, the equivalent of F_CPU.
Lee, thanks very much for the detailed information. Your statements, mixed with my examination of CodeVision manual, has given me fairly good insight into the areas where I can support CV with my cross-compiler compatibility scheme.

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

theusch wrote:
Yep, I understand about the .noinit . Like you, I've never found the need. For controlled SRAM contents after a reset, it is too scary given the different reset types and only under the controlled reset conditions would it be valid.
I had a pleasant surprise when coding with IAR for a Tiny2313 project. Since I didn't need initiaization of any of the variables, IAR automatically stripped out its data initialization code freeing up flash for more program.

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

Not too long ago, I think there was a thread on at least the interrupt vector part.
https://www.avrfreaks.net/index.p...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

clawson wrote:
Isn't that what MCUCSR exists for? If you read it at startup then either a bit says which reset mechanism got you there or, if no bits set then it was a "jmp 0" (or possibly execution passed FLASHED or a RET to address 0 or similar)
Well, there can be other reasons for a restart. For example, I have a watchdog ISR that I overload in a few ways (as a long-term (days) timer for an Tiny85 AVR where I don't have any additional timers. And, look for a timeout in a calibration function, and if that occurs I set a timeout variable that is monitored.)

I have the watchdog ISR "jmp 0" in a few conditions which I signal to main. I can pass the signal either in a no-init variable or in an unused R/W register. One condition is the plain old watchdog ISR called unexpectedly. Another condition is where the user requested a reset of the MCU via a RS-232 command sequence. Another "jmp 0" occurs every week if there has been no activity for 2 hours, However, in the "refresh" jmp to 0, I skip some startup code to make the reset invisible to the outside.

So, no, MCUCSR in some applications doesn't contain all the reasons for the restart.

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

theusch wrote:
Not too long ago, I think there was a thread on at least the interrupt vector part.
https://www.avrfreaks.net/index.p...
Thanks for the link, Lee!

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

The default startup code will initialise everything.

You can implement your OWN startup code if you desire. You can then selectively initialise whatever you want. Likewise you can do all sorts of scary things.

David.