Can I create a PlatformIO AVR project from existing code, including the LUFA library?

What you really want to do in this case is to compile the project (UsbGpib in this case) with the intended build system.

E.g., get a Ubuntu 24 VM, sudo apt install gcc-avr avr-libc make, clone the UsbGpip repo, and git clone https://github.com/abcminiuser/lufa inside that repo to get LUFA at the expected place. Then build the e.g. bootloader verbosely with cd SW/MassStorage/ && make V=1. All compile commands should appear, e.g.,

max@max-VirtualBox:~/temp/UsbGpib/SW/MassStorage$ make V=1
 [INFO]    : Begin compilation of project "BootloaderMassStorage"...

avr-gcc (GCC) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 [GCC]     : Compiling C file "BootloaderMassStorage.c"
avr-gcc -c -pipe -gdwarf-2 -g2 -mmcu=atmega32u4 -fshort-enums -fno-inline-small-functions -Wall -fno-strict-aliasing -funsigned-char -funsigned-bitfields -ffunction-sections -I. -DARCH=ARCH_AVR8 -DDMBS_ARCH_AVR8 -mrelax -fno-jump-tables -flto -fuse-linker-plugin -x c -Os -std=gnu99 -Wstrict-prototypes -DF_CPU=16000000UL -DUSE_LUFA_CONFIG_HEADER -IConfig/ -DBOOT_START_ADDR=0x7000 -DAUX_BOOT_SECTION_SIZE='((8 - 4) * 1024)' -I. -I../../LUFA/.. -DARCH=ARCH_AVR8 -DBOARD=BOARD_ -DF_USB=16000000UL   -MMD -MP -MF obj/BootloaderMassStorage.d BootloaderMassStorage.c -o obj/BootloaderMassStorage.o
 [GCC]     : Compiling C file "Descriptors.c"
avr-gcc -c -pipe -gdwarf-2 -g2 -mmcu=atmega32u4 -fshort-enums -fno-inline-small-functions -Wall -fno-strict-aliasing -funsigned-char -funsigned-bitfields -ffunction-sections -I. -DARCH=ARCH_AVR8 -DDMBS_ARCH_AVR8 -mrelax -fno-jump-tables -flto -fuse-linker-plugin -x c -Os -std=gnu99 -Wstrict-prototypes -DF_CPU=16000000UL -DUSE_LUFA_CONFIG_HEADER -IConfig/ -DBOOT_START_ADDR=0x7000 -DAUX_BOOT_SECTION_SIZE='((8 - 4) * 1024)' -I. -I../../LUFA/.. -DARCH=ARCH_AVR8 -DBOARD=BOARD_ -DF_USB=16000000UL   -MMD -MP -MF obj/Descriptors.d Descriptors.c -o obj/Descriptors.o
[..]
avr-size --mcu=atmega32u4 --format=avr BootloaderMassStorage.elf
AVR Memory Usage
----------------
Device: atmega32u4

Program:    3010 bytes (9.2% Full)
(.text + .data + .bootloader)

Data:        395 bytes (15.4% Full)
(.data + .bss + .noinit)

You take very good note of all compiler settings used there, during the compile and linking stage. Fundamentally, you have to match them with the PlatformIO build system using build_flags, build_unflags (docs), etc. PlatformIO also shows you the verbose compiler commands with Advanced → Verbose Build (docs). This will lead you to add e.g. settings such as

build_flags = 
   -DF_USB=16000000UL
   -DBOARD=BOARD_
   -DUSE_LUFA_CONFIG_HEADER
   -IConfig/
   ; and lots more ...

When it comes to LUFA, you need to tell PlatformIO how to build the library in terms of to-be-compiled files, include directories, compiler settings etc., best using a library.json file. I’ve created a simple one, the most important parts of which are

Again, the “srcFilter” selects the to be compiled files – these can be read from the build log obtained earlier. libArchive: false needs to be set too because the library implements ISRs, which are not correctly linked when this is true.

All in all, this then gives a compilable bootloader and firmware. I’ve prepared them at

The bootloader (MassStorage) in PlatformIO compiles exactly to the same size as with the makefile buildsystem on my Ubuntu machine.

Checking size .pio\build\sparkfun_promicro16\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [==        ]  15.4% (used 395 bytes from 2560 bytes)
Flash: [=         ]   9.2% (used 3010 bytes from 32768 bytes)
Building .pio\build\sparkfun_promicro16\firmware.hex
==========================[SUCCESS] Took 4.04 seconds ==========================

The firmware (TestAndMeasurement) is slightly smaller because PlatformIO gives the object files in a different order to the linker, which then places functions at different address – this enables sometimes the usage of the smaller relative-jump (rjmp) instruction, sometimes the bigger absolute jump (jmp) instruction. PlatformIO’s linking order seems more advantegous here. This should have no effect on the workings of the firmrware, though. The firmware could in fact be even smaller because the author seems to have forgotten to turn on -flto and -fdata-sections to further reduce the size and removed unused functions / data.

In any case though, I would always still use the original build system to build and upload the firmware, too. There can still be discrepancies and slight overlooks between the two build system. It’s fine if you just need PlatformIO here so that the project is nicely editable in VSCode or whatever, but I would not force a different build system onto the project or author.

1 Like