asm macro error

Hi,

I wrote a program that should create an square wave using an assembly macro (just to see how it worked), using the asm keyword in C. I am using 64 “NOPs” at 16MHz.
It works just fine, but if I call several times the same macro I get the following error:

/tmp/ccQo9mux.o: In function `main':
/home/luis/project.c:103: relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
make: *** [video.hex] Error 1

What does this mean?

This is the code I am using:

           PORTB &= ~(1<<PB3); //Sets pin PB3 LOW
               asm("Delay4");
               asm("Delay4");
               asm("Delay4");
               asm("Delay4");
               asm("Delay4");
               asm("Delay4");
               PORTB |= (1<<PB3); //Sets pin PB3 HIGH
               asm("Delay4");
               asm("Delay4");
               asm("Delay4");
               PORTB &= ~(1<<PB3); //LOW

The Delay4 macro are just 64 NOPs…

asm(".MACRO Delay4\n\t"
"NOP\n\t ; NO Operation"
...
//64 NOPs
".ENDM\n\t");

This code works just fine, but if I call the macro more times, I get that error. I am not using jmp or rjmp to go back to the macro, I just call it.

Thank you

I'm guessing that the code block with the six consecutive macros (64 * 6 = 384) is too long for a program counter-relative jump to get around. The compiler would normally be able to insert "dead" instructions to allow it to leap-frog through long code sections, or generate direct jump instructions, but because these are your macros, it can't. Not sure how to fix that at the moment.

Maybe an equivalent-timed loop (possibly padded with a few NOPs), which would consist of fewer instructions, and so would reduce the lenght of code generated.

I replaced all of my macros definition with a rept directive…
This is my new code:

asm(".MACRO Delay4\n\t\n\t"
".rept 64\n\t"
"NOP\n\t"
".endr\n\t"
".ENDM");

asm(".MACRO Delay8\n\t\n\t"
".rept 128\n\t"
"NOP\n\t"
".endr\n\t"
".ENDM");

asm(".MACRO Delay16\n\t\n\t"
".rept 256\n\t"
"NOP\n\t"
".endr\n\t"
".ENDM");
               PORTB &= ~(1<<PB3);
               asm("Delay16");
               asm("Delay8");
               PORTB |= (1<<PB3);
               asm("Delay8");
               asm("Delay4");
               PORTB &= ~(1<<PB3);

Should that help? Because I am still getting the same error :frowning:

All the REPT does is saves you having to type 'n' lots of "NOP", it doesn't change the length of the code generated, which is what is probably upsetting the compiler. A PC relative jump will have limited (signed) range - I'm guessing you're busting this, but I don't have an AVR ASM manual to hand.

Try the calibrated loop approach.

[edit]Hmm, a quick google suggest an RJMP should have a 12 bit range, so my explanation seems unlikely. Sorry, I'm stumped.[/edit]

Hmm what could be causing my problem then? Does someone has any idea?

Thank you

I get the same error when I put your code inside a for loop, but not when it's "bare" inside a function (or even an unconditional loop.) I suspect that you're exceeding the range of the conditional jumps (which are only +/-63 instructions, unlike the unconditional relative jump), and that the use of asm() confuses the compiler so that it doesn't know that things are that far away (probably a compiler bug.)

1 Like

Learn more assembler.

Push a register into the stack (push)

set it to 63 (ldi)

decrement and jump until zero (dec and rjmp)

pop the stack back into the register (pop)

I think the problem has been diagnosed correctly: it's a compiler bug due to the size of the code the asm inserts.

Having 64 NOPs inline is a silly way to delay, so use this bug to learn more assembler.

1 Like