1
\$\begingroup\$

Im trying to compile the following simple assembly program but there is a problem with the compiler that i cannot find its reason and fix it.

So here is the code :

  1 #define __SFR_OFFSET 0 
  2 #include <avr/io.h> 
  3 
  4 
  5 rjmp Init 
  6 
  7 .global Init 
  8 
  9 Init:   sbi _SFR_IO_ADDR(PORTB),5 
 10         rjmp In

and when im going to compile it with
avr-as -c -mmcu=atmega168a -o ledON.o ledON.s

i am getting this error:

ledON.s: Assembler messages:  
ledON.s:9: Error: constant value required
ledON.s:9: Error: `,' required  
ledON.s:9: Error: constant value required
ledON.s:9: Error: garbage at end of line

I also change a little bit the code as you can see above but there is still an error

  1 ;#define _SFR_OFFSET 0 
  2 #include <avr/io.h> 
  3 
  4 rjmp Init
  5 
  6 .global Init
  7 
  8 Init:   sbi PORTB,0x05
  9         rjmp Init

ledON.s: Assembler messages:

ledON.s:8: Error: constant value required

Any ideas?

\$\endgroup\$
5
  • \$\begingroup\$ What version avr-as are you using, mine doesn't support the -c flag, what does it do? \$\endgroup\$
    – jippie
    Nov 16, 2013 at 17:32
  • \$\begingroup\$ Even without -c flag im getting the same error :s \$\endgroup\$
    – F.N
    Nov 16, 2013 at 17:38
  • \$\begingroup\$ Clearly the include files are not processed at all, now only to figure out how why that is. \$\endgroup\$
    – jippie
    Nov 16, 2013 at 18:01
  • \$\begingroup\$ And where to look to determine that ? Can you give me some hint ? \$\endgroup\$
    – F.N
    Nov 16, 2013 at 18:20
  • \$\begingroup\$ I've been experimenting a bit and clearly the include files are not processed. It has to do with the fact that as doesn't call the C-preprocessor, but I don't know how to force the files being processed \$\endgroup\$
    – jippie
    Nov 16, 2013 at 18:34

1 Answer 1

5
\$\begingroup\$

I figured out how to assemble without error messages.

The error messages you see are caused by the fact that avr-as does not invoke the C-preprocessor and therefore the #include lines are read as regular comments.

Create a file ledON.S and notice the CAPITAL S in the filename. The capital S indicates that the C-preprocessor must be invoked first. Create the file with the following content:

#include <avr/io.h> 

init:   sbi     _SFR_IO_ADDR(DDRB),0x05         ; Configure port B pin 5 as output
        ret

.global main

main:
        call init

loop:
        sbi     _SFR_IO_ADDR(PORTB),0x05        ; Toggle output pin HIGH
        cbi     _SFR_IO_ADDR(PORTB),0x05        ; Toggle output pin LOW
        rjmp loop

The main part is required in the source code, this is where usually the main program is located. If you remove it, no real code is executed ever and thus the compiler will complain about that. Code in a routine called init should be explicitly called from main. Although the pin toggles, in practice this will be too fast to see with the bare eye. If you check with an oscilloscope you'll see a square wave (I estimate at 25% duty cycle).

Then assemble the source code with:

avr-gcc -mmcu=atmega168a ledON.S -o ledON.o

Again avr-gcc is required to invoke the C-preprocessor.

To check the result of the assembled program run the following command:

avr-objdump -C -d ./ledON.o

And the resulting disassembly listing looks like this:

./ledON.o:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   0c 94 34 00     jmp     0x68    ; 0x68 <__ctors_end>
   4:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
   8:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
   c:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  10:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  14:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  18:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  1c:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  20:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  24:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  28:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  2c:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  30:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  34:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  38:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  3c:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  40:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  44:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  48:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  4c:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  50:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  54:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  58:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  5c:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  60:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
  64:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>

00000068 <__ctors_end>:
  68:   11 24           eor     r1, r1
  6a:   1f be           out     0x3f, r1        ; 63
  6c:   cf ef           ldi     r28, 0xFF       ; 255
  6e:   d4 e0           ldi     r29, 0x04       ; 4
  70:   de bf           out     0x3e, r29       ; 62
  72:   cd bf           out     0x3d, r28       ; 61
  74:   0e 94 42 00     call    0x84    ; 0x84 <main>
  78:   0c 94 47 00     jmp     0x8e    ; 0x8e <_exit>

0000007c <__bad_interrupt>:
  7c:   0c 94 00 00     jmp     0       ; 0x0 <__vectors>

00000080 <init>:
  80:   25 9a           sbi     0x04, 5 ; 4
  82:   08 95           ret

00000084 <main>:
  84:   0e 94 40 00     call    0x80    ; 0x80 <init>

00000088 <loop>:
  88:   2d 9a           sbi     0x05, 5 ; 5
  8a:   2d 98           cbi     0x05, 5 ; 5
  8c:   fd cf           rjmp    .-6             ; 0x88 <loop>

0000008e <_exit>:
  8e:   f8 94           cli

00000090 <__stop_program>:
  90:   ff cf           rjmp    .-2             ; 0x90 <__stop_program>

INTERMEZZO

You'll notice the assembler will automatically initialize the stack pointer and status register in __ctors_end. Also it will automatically add a rjmp at the end of the code. Default behaviour of a program assembled by gcc-avr when it ends is:

  • turn off interrupts (_exit, cli)
  • infinite empty loop that does nothing (__stop_program, rjmp .-2)
\$\endgroup\$
12
  • \$\begingroup\$ Yes. I have already try the .S but once again it returns me an error and it doesn't create the object file. ledON.S: Assembler messages: ledON.S:8: Error: number must be positive and less than 32 such errors i believe that means that the I/O register is not editable. \$\endgroup\$
    – F.N
    Nov 16, 2013 at 19:00
  • \$\begingroup\$ Copy the exact source as in my answer and work from there. My proposed source builds on my system, otherwise I couldn't show you the disassembly listing. \$\endgroup\$
    – jippie
    Nov 16, 2013 at 19:02
  • \$\begingroup\$ OK. the object file now created but why all these happens ? I cannot understand. Also in your code the rjmp to main will never be executed because there is init's infinity loop above. Btw i cannot upvote because i am new user and i don't have reputation. \$\endgroup\$
    – F.N
    Nov 16, 2013 at 19:23
  • \$\begingroup\$ Fair enough, I removed the last rjmp. The main label is a required part of the program, if you remove it you get receive an error message. Normally that is the where the main program is located. \$\endgroup\$
    – jippie
    Nov 16, 2013 at 19:27
  • \$\begingroup\$ @F.N I updated the answer to reflect a somewhat useful proof of concept. \$\endgroup\$
    – jippie
    Nov 16, 2013 at 19:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.