3

I understand that I can program the Arduino in C, but with my current project (a tiny Arduino kernel), I would really rather use Assembly for some sections to both learn Assembly and possibly improve efficiency the SLIGHTEST bit.

Is there something I can use like __ASM__()? I have only really been able to find people online trying to convince people who have asked similar questions to learn C, and not actually answering the question.

Thanks!

  • inline assembly is advanced and you should learn assembly language first, then later if you really have a good reason, inline assembly. You can absolutely program the AVR (on an arduino or not) in assembly language. – old_timer May 21 '17 at 18:20
  • So how would I go about programming the AVR in assembly? Something like the \__asm__ tag that would be used in a C function? –  May 21 '17 at 18:26
  • no that is inline assembly... – old_timer May 21 '17 at 18:38
  • 1
    TONS of examples out there, where did you look? – old_timer May 21 '17 at 18:38
  • Google with the term "arduino using assembly", and some variations. Most of the responses to questions like mine are just people talking about how it's better to program in C. –  May 21 '17 at 18:40
  • sure if you search like that, did you try avr assembly blinker example? example after example after example... – old_timer May 21 '17 at 18:47
  • Arduino is not C. – gre_gor May 22 '17 at 15:56
  • It uses AVR C/C++. –  May 25 '17 at 21:34

1 Answers1

4

one I wrote and posted ages ago.

.device ATmega168
.equ  DDRB       = 0x04
.equ  PORTB      = 0x05

.org 0x0000
    rjmp RESET

RESET:
    ldi R16,0x20
    out DDRB,R16

    ldi R18,0x00
    ldi R17,0x00
    ldi R20,0x20
Loop:

    ldi R19,0xE8
aloop:
    inc R17
    cpi R17,0x00
    brne aloop

    inc R18
    cpi R18,0x00
    brne aloop

    inc R19
    cpi R19,0x00
    brne aloop

    eor R16,R20
    out PORTB, R16
    rjmp Loop

I used avra and likely wrote my own arduino loader

blinker01.s.hex : blinker01.s
    avra -fI blinker01.s

clean :
    rm -f blinker01.s.*

you could use avr_dude of course.

With gnu something a little different:

.globl _start
_start:
    rjmp RESET

RESET:
    ldi R18,0x00
    ldi R17,0x00
    ldi R20,0x20
Loop:

    ldi R19,0xE8
aloop:
    inc R17
    cpi R17,0x00
    brne aloop

    inc R18
    cpi R18,0x00
    brne aloop

    inc R19
    cpi R19,0x00
    brne aloop

    rjmp Loop

you dont really need the header files to define ports, you can declare those yourself.

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
}

avr-as so.s -o so.o
avr-ld -T so.ld so.o -o so.elf
avr-objdump -D so.elf > so.list
avr-objcopy so.elf -O ihex so.hex

Using an apt-got avr-gcc (and binutils) possibly the same tools used with the arduino sandbox and should be directly accessible, but I dont use the sandbox so dont know.

EDIT

another approach is limited, but more likely to succeed with the toolchain since you start with a working C application and environment then add an object, also helps with assembly basics, see what the compiler does then go read up on it:

unsigned short fun ( unsigned short x, unsigned short y )
{
    return(x+y+5);
}

avr-gcc -c -O2 so.c -o so.o
avr-objdump -D so.o

00000000 <fun>:
   0:   6b 5f           subi    r22, 0xFB   ; 251
   2:   7f 4f           sbci    r23, 0xFF   ; 255
   4:   86 0f           add r24, r22
   6:   97 1f           adc r25, r23
   8:   08 95           ret

so

create so.s

.globl fun
fun:
    subi r22, 0xFB  ; 251
    sbci r23, 0xFF  ; 255
    add  r24, r22
    adc  r25, r23
    ret



avr-as so.s -o so.o
avr-objdump -D so.o

00000000 <fun>:
   0:   6b 5f           subi    r22, 0xFB   ; 251
   2:   7f 4f           sbci    r23, 0xFF   ; 255
   4:   86 0f           add r24, r22
   6:   97 1f           adc r25, r23
   8:   08 95           ret

and then instead of linking in the C produced object, link in the assembly produced object, you have to learn the calling convention which through experiments you can figure out.

unsigned char fun ( unsigned char x, unsigned char y )
{
    return(x+(y<<1));
}
00000000 <fun>:
   0:   66 0f           add r22, r22
   2:   86 0f           add r24, r22
   4:   08 95           ret

in this case second parameter in r22 first in r24, return value in r24. so 22/23 is probably for the first parameter for larger items like a short, and 24/25 for the second. it will be documented somewhere as well, the compiler conforms to it, there will be exceptions so crafting a proper example to see what the compiler does rather than just assume everything from one example is critical, even if you read the docs it is probably vague or uses terminology that might not make sense until you experiment.

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • you ARE going to want to see the various examples out there, AVR is not the first assembly you want to learn (not the last, the harvard architecture nature of it makes it quite painful, msp430 or arm thumb (cortex-m) would be a better start. All of them you can find (or write in an afternoon) an instruction set simulator, and use free as in beer tools. and can buy boards for what is usually a fraction of the cost of an arduino around $10 for one you just plug in and use. – old_timer May 21 '17 at 18:49
  • Yeah, definitely going to be reading some example code. Fortunately, I found that one of the ATmega PDFs has example code in both Assembly and C. I think that'll be a good place to start. Thanks for the help, and I'll keep your advice in mind! –  May 21 '17 at 18:54