Syntax for inline assembly code

Hi i'm using an inline assembly routine, trying to write a byte to EEPROM, but i keep getting an error that says "undefined reference to `EEDR'"

#include <EEPROM.h>

int i;
byte countlow, counthigh, on, off;

  // inc duty cycle every 4096 cycles
  on = 10;
  off = 90;
  counthigh = 16;
  countlow = 0;
  EEAR = 0x01;				// EEPROM addres reg

  for (i = 0; i < 400000; i++) {
    digitalWrite(pwm, HIGH);
    delayMicroseconds(on);
    asm volatile (
      "dec %0 \n\t"    			// countlow -= 1
      "brne 1f \n\t"			// skip 1 if countlow != 0 
      "dec %1 \n\t"		    	// counthigh -= 1
      "1: \n\t"
      : "=r" (countlow), "=r" (counthigh)
      :
    );
    digitalWrite(pwm, LOW);
    delayMicroseconds(off);
    asm volatile (
      "lds r24, (counthigh) \n\t"    
      "brne 2f \n\t" 			// skip 7 if counthigh != 0
      "inc %1 \n\t"			    // on += 1
      "dec %0 \n\t"			    // off -= 1 (PWM duty cycle += 1)
      "ldi r24, 0x10 \n\t"
      "sts (counthigh), r24 \n\t"	// count = 4096 
      "out EEDR, %1 \n\t"		// EEPROM data reg     <---undefined reference to `EEDR'
//      "sbi EECR, "EEMPE"
//      "sbi EECR, EEPE"
      "2: \n\t"
      : "=r" (off), "=r" (on)
      :
      : "r24"
    );
    }

what microcontroller are you using?

Atmega16u2

Obvious:
first of all: you write "inline assembly code" not "inline" functions (which is a different topic).

Imagine this:
you enclose assembly code inside C-code. You use MCU instructions. All fine, the compiler knows the instructions.
But it does not know how to deal with "EEDR"! Even you know it is a symbolic name for a registers - the assembler (called from compiler) does not know any register.

So, for your assembly code (like an *.S file), you had to define what "EEDR" is, e.g. an address value. EEDR is nothing what be known by any compiler (actually here the assembler): it is a name for something where you do not resolve what the name is (a register address here).

Simple way to solve: provide instead of EEDR the real physical address of this register, e.g. 0x0123ABCD.
If you do not like it: you need an include file, even for this assembly code, which defines what EEDR is.

1 Like

Bingo now it's compiling. i thought the assembler knew that. THANX

Sure, BTW: it is not the compiler, it is the assembler who has to know what EEDR means (called from compiler in order to deal with your MCU instructions).

1 Like

the way that this is usually done is to pass the symbolic value to the asm code from the C code (where it is "known.")

Something like:

    asm volatile (
      "lds r24, (counthigh) \n\t"    
      "brne 2f \n\t" 			// skip 7 if counthigh != 0
      "inc %1 \n\t"			    // on += 1
      "dec %0 \n\t"			    // off -= 1 (PWM duty cycle += 1)
      "ldi r24, 0x10 \n\t"
      "sts (counthigh), r24 \n\t"	// count = 4096 
      "out %[eedr], %1 \n\t"
      "2: \n\t"
      : "=r" (off), "=r" (on), [port] 
      : [eedr] "I" (_SFR_IO_ADDR(EEDR)
      : "r24"

See: https://www.eit.lth.se/fileadmin/eit/courses/edi021/avr-libc-user-manual/inline_asm.html

1 Like

ok didn't know i could do that. but i don't get what is the meaning of the [port] part. The compiler doesn't like it.

oops. Copy/paste error on my part. Should've been (I think):

"2: \n\t"
      : "=r" (off), "=r" (on)
      : [eedr] "I" (_SFR_IO_ADDR(EEDR)
      : "r24"
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.