Close

A lazy person avoided installing the AVR-gcc toolchain

ken-yapKen Yap wrote 05/28/2020 at 10:28 • 5 min read • Like

(Updated for Arduino 2 IDE.)

As all my friends know, my mugshot is used to illustrate the word lazy in dictionaries. 😉

Anyway I found this AVR MCU in my junkspares box and wanted to test it out. I quickly ascertained that I should install the AVR-gcc toolchain. Work! Four-letter word!

Wait a moment, isn't the toolchain already included in the Arduino IDE which I already have? I didn't want to use the IDE for bare metal programming because it assumes a bootloader to transfer to a boilerplate main() that calls setup() and loop(), a programmer like an Arduino board, and a definition for your MCU's board. (But if you want to go that way, look into MiniCore.) I just wanted the tools. In Arduino 1.8 they lived under /opt/arduino-1.8.12/hardware/tools/avr on my Linux machine, and the binaries were under bin/. However in the Arduino 2 IDE, the toolchain is a package and installed under ~/.arduino15, in particular ~/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/ Note that this may be different depending on the release version, so check it yourself. So the iinstructions differ just a bit between the versions.

For Arduino 1.8:

So, first I make a symbolic link

$ ln -s /opt/arduino-1.8.12 /opt/arduino

and use /opt/arduino for other symlinks so that when I upgrade I only have to shift the arduino link and not redo all the other symlinks.

Now there are two ways to make the executables available, add /opt/arduino/hardware/tools/avr/bin to $PATH, or make symlinks from another PATH directory to them. I used the latter.

$ cd /usr/local/bin
$ ln -s /opt/arduino/hardware/tools/avr/bin/* .

End Arduino 1.8.

For Arduino 2 IDE:

Only the binary directory differs. You may wish to make a symbolic link as above but that's optional.

$ cd /usr/local/bin
$ ln -s ~/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/* .

End Arduino 2 IDE.

Check that it works

$ which avr-gcc
/usr/local/bin/avr-gcc

Setting that up only took a few minutes. By the way you probably need to use sudo or su to do some of those things.

Now to write a very special program, blink.c: 😉

#define __AVR_AT90S8515__       1

#include        <avr/io.h>
#include        <util/delay.h>

void delay(unsigned int ms)
{
    while (--ms)
        _delay_ms(1.0);
}

int main(void) {
    PORTB = 0;
    DDRB = 0xFF; // LED bank

    while (1) {
        PORTB = 0x55;
        delay(500);
        PORTB = 0xAA;
        delay(500);
    }
}

The Makefile that controls the build:

CC=avr-gcc
F_CPU=4000000
DEBUG=
CFLAGS=-Wall $(DEBUG) -Os -DF_CPU=$(F_CPU)
INCLUDES=
AVRSIZE=avr-size
OBJCOPY=avr-objcopy

blink.hex:      blink.bin

blink.bin:      blink.c Makefile

%.s:            %.c
        $(CC) $(CFLAGS) $(INCLUDES) -S $<

%.bin:          %.c
        $(CC) $(CFLAGS) $(INCLUDES) $< -o $(<:.c=.bin)
        $(AVRSIZE) -C $(<:.c=.bin)

%.hex:          %.bin
        $(OBJCOPY) -j .text -j .data -O ihex $< $(<:.bin=.hex)

clean:
        rm -f *.s *.bin *.hex

As it turned out I didn't need any -I options because the Arduino toolchain implicitly includes .h files from the toolchain include directory. All you have to do is define the MCU type before the #include <avr/io.h>. F_CPU is defined to be the crystal frequency for correct delays. Notice that there is no flash rule that calls avrdude. This because I will be flashing the program with my programmer.

And here is the resulting blink.s:

        .file   "blink.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
        .text
.global delay
        .type   delay, @function
delay:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
.L2:
        sbiw r24,1
        brne .L3
/* epilogue start */
        ret
.L3:
        ldi r30,lo8(999)
        ldi r31,hi8(999)
1:      sbiw r30,1
        brne 1b
        rjmp .
        nop
        rjmp .L2
        .size   delay, .-delay
        .section        .text.startup,"ax",@progbits
.global main
        .type   main, @function
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
        out 0x18,__zero_reg__
        ldi r24,lo8(-1)
        out 0x17,r24
        ldi r29,lo8(85)
        ldi r28,lo8(-86)
.L5:
        out 0x18,r29
        ldi r24,lo8(-12)
        ldi r25,lo8(1)
        rcall delay
        out 0x18,r28
        ldi r24,lo8(-12)
        ldi r25,lo8(1)
        rcall delay
        rjmp .L5
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.0"

I flashed this to the MCU with the programmer. Unfortunately when I put it on the development board described in #Adventures with a STC89C52 development board nothing happened. Maybe the chip is bad, or maybe the board isn't suitable for it. I did at first make the mistake of using the onboard 11.0592 MHz crystal until I realised that was out of the specifications of the AVR MCU I had, but substituting a slower crystal didn't help. Maybe I'll have to put the MCU on a breadboard.

But that's for another day. I'm satisfied that I now have a toolchain so I can cross AVR off my to-do list.

Like

Discussions