Sunday, April 21, 2013

Compiling Arduino program using Standard GNU toolchains

Arduino IDE has simplified our life when developing firmware for Atmel-based MCU, but for more advanced programmers, it's not a quick-and-fast way to compile.  A code developed using "Processing", a thin layer between C++ and Arduino code cannot be compiled using avr-gcc toolchains straightforward.

The following steps are needed to make the compilation becomes standard compilation as other open-source code compilation.

  1. Copy the folder <arduino root>/arduino/hardware/arduino/cores/* and <arduino root>/arduino/hardware/arduino/variants/* to a new folder, e.g. /home/myname/src/arduino/include
  2. Run the Makefile below to build a library.  In my case, I tried to build a lib for my AtMega328p-based Arduino Uno.  Goto the folder and do "make"
  3. Once the library is built, we can link it to our program (we need to rename our program's extension from *.ino to *.cpp).  See the second Makefile for an example how to build and link with the newly created lib file.
  4. To upload the program to the target (Arduino Uno), we need an ICSP programmer (available for cheap on eBay) and use "avrdude" command to do the programming.

The Makefile to build atmega328p

#MCU_TARGET     = at90s2313
#MCU_TARGET     = at90s2333
#MCU_TARGET     = at90s4414
#MCU_TARGET     = at90s4433
#MCU_TARGET     = at90s4434
#MCU_TARGET     = at90s8515
#MCU_TARGET     = at90s8535
#MCU_TARGET     = atmega128
#MCU_TARGET     = atmega1280
#MCU_TARGET     = atmega1281
#MCU_TARGET     = atmega1284p
#MCU_TARGET     = atmega16
#MCU_TARGET     = atmega163
#MCU_TARGET     = atmega164p
#MCU_TARGET     = atmega165
#MCU_TARGET     = atmega165p
#MCU_TARGET     = atmega168
#MCU_TARGET     = atmega169
#MCU_TARGET     = atmega169p
#MCU_TARGET     = atmega2560
#MCU_TARGET     = atmega2561
#MCU_TARGET     = atmega32
#MCU_TARGET     = atmega324p
#MCU_TARGET     = atmega325
#MCU_TARGET     = atmega3250
#MCU_TARGET     = atmega329
#MCU_TARGET     = atmega3290
MCU_TARGET      = atmega328p
#MCU_TARGET     = atmega48
#MCU_TARGET     = atmega64
#MCU_TARGET     = atmega640
#MCU_TARGET     = atmega644
#MCU_TARGET     = atmega644p
#MCU_TARGET     = atmega645
#MCU_TARGET     = atmega6450
#MCU_TARGET     = atmega649
#MCU_TARGET     = atmega6490
#MCU_TARGET     = atmega8
#MCU_TARGET     = atmega8515
#MCU_TARGET     = atmega8535
#MCU_TARGET     = atmega88
#MCU_TARGET     = attiny2313
#MCU_TARGET     = attiny24
#MCU_TARGET     = attiny25
#MCU_TARGET     = attiny26
#MCU_TARGET     = attiny261
#MCU_TARGET     = attiny44
#MCU_TARGET     = attiny45
#MCU_TARGET     = attiny461
#MCU_TARGET     = attiny84
#MCU_TARGET     = attiny85
#MCU_TARGET     = attiny861

#DEFS           = -DF_CPU=16000000UL
DEFS           = -D__AVR_ATmega328P__ -DF_CPU=16000000UL
ARDUINO           = /opt/arduino-1.0.4
MYARDUINO       = .
INCS           = -I $(MYARDUINO)/ \
                 -I $(MYARDUINO)/arduino \
                 -I $(MYARDUINO)/variants \
                 -I $(MYARDUINO)/variants/standard

LIBS           = -lm -lc

OPTIMIZE       = -O2 -finline-small-functions

# You should not have to change anything below here.

CC             = avr-gcc
CXX               = avr-c++
AR               = avr-ar

# Override is only needed by avr-lib build system.

override CFLAGS        = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) $(INCS)
override CXXFLAGS      = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) $(INCS)
override LDFLAGS       = -Wl,-Map,$(PRG).map

OBJCOPY        = avr-objcopy
OBJDUMP        = avr-objdump


PRG            = libatmega328p
SRCS           = \
                 $(MYARDUINO)/arduino/Print.cpp \
                 $(MYARDUINO)/arduino/WString.cpp \
                 $(MYARDUINO)/arduino/Stream.cpp \
                 $(MYARDUINO)/arduino/CDC.cpp \
                 $(MYARDUINO)/arduino/HardwareSerial.cpp \
                 $(MYARDUINO)/arduino/HID.cpp \
                 $(MYARDUINO)/arduino/IPAddress.cpp \
                 $(MYARDUINO)/arduino/main.cpp \
                 $(MYARDUINO)/arduino/new.cpp \
                 $(MYARDUINO)/arduino/Tone.cpp \
                 $(MYARDUINO)/arduino/USBCore.cpp \
                 $(MYARDUINO)/arduino/WMath.cpp \
                 $(MYARDUINO)/arduino/malloc.c \
                 $(MYARDUINO)/arduino/WInterrupts.c \
                 $(MYARDUINO)/arduino/wiring_analog.c \
                 $(MYARDUINO)/arduino/wiring_digital.c \
                 $(MYARDUINO)/arduino/wiring_pulse.c \
                 $(MYARDUINO)/arduino/wiring_shift.c \
                 $(MYARDUINO)/arduino/wiring.c

BUILDDIR = ./build

all: $(PRG).a $(OBJS)

#OBJS := $(patsubst %.cpp, obj/%.o, $(SRCS))
#OBJS := $(patsubst %.c, obj/%.o, $(SRCS))

OBJS := $(notdir $(SRCS))
OBJS := $(OBJS:.cpp=.o)
OBJS := $(OBJS:.c=.o)
OBJS := $(patsubst %.o, $(BUILDDIR)/%.o, $(OBJS))

#----------------------------- dependency:

$(OBJS): | $(BUILDDIR)

$(BUILDDIR):
      @mkdir -p $@

$(BUILDDIR)/%.o: $(MYARDUINO)/arduino/%.c
    @echo $<
    $(CC) -c $(CFLAGS) $< -o $@

$(BUILDDIR)/%.o: $(MYARDUINO)/arduino/%.cpp
    @echo $<
    $(CXX) -c $(CXXFLAGS) $< -o $@

#$(OBJS): $(SRCS)
#    @echo "Compiling $< to $@"
#    $(CXX) -S $(CXXFLAGS) $< -o $@


$(PRG).a: $(OBJS)
    @echo "***********************************************************"
    @echo OBJS=$(OBJS)
    @echo "***********************************************************"
    @echo "Building LIB=$(PRG).a from $?"
    @echo "-----------------------------------------------------------"
    $(AR) qusv $@ $?


clean:
    rm -rf *.o $(PRG).a *.eps *.png *.pdf *.bak $(OBJS)
    rm -rf *.lst *.map $(EXTRA_CLEAN_FILES)

lst:  $(PRG).lst

%.lst: %.a
    $(OBJDUMP) -h -S $< > $@

# Rules for building the .text rom images

text: hex bin srec

hex:  $(PRG).hex
bin:  $(PRG).bin
srec: $(PRG).srec

%.hex: %.elf
    $(OBJCOPY) -j .text -j .data -O ihex $< $@

%.srec: %.elf
    $(OBJCOPY) -j .text -j .data -O srec $< $@

%.bin: %.elf
    $(OBJCOPY) -j .text -j .data -O binary $< $@

# Rules for building the .eeprom rom images

eeprom: ehex ebin esrec

ehex:  $(PRG)_eeprom.hex
ebin:  $(PRG)_eeprom.bin
esrec: $(PRG)_eeprom.srec

%_eeprom.hex: %.elf
    $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ \
    || { echo empty $@ not generated; exit 0; }

%_eeprom.srec: %.elf
    $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@ \
    || { echo empty $@ not generated; exit 0; }

%_eeprom.bin: %.elf
    $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@ \
    || { echo empty $@ not generated; exit 0; }

# Every thing below here is used by avr-libc's build system and can be ignored
# by the casual user.

FIG2DEV                 = fig2dev
EXTRA_CLEAN_FILES       = *.hex *.bin *.srec

dox: eps png pdf

eps: $(PRG).eps
png: $(PRG).png
pdf: $(PRG).pdf

%.eps: %.fig
    $(FIG2DEV) -L eps $< $@

%.pdf: %.fig
    $(FIG2DEV) -L pdf $< $@

%.png: %.fig
    $(FIG2DEV) -L png $< $@



A Makefile to build our application:

#MCU_TARGET     = at90s2313
#MCU_TARGET     = at90s2333
#MCU_TARGET     = at90s4414
#MCU_TARGET     = at90s4433
#MCU_TARGET     = at90s4434
#MCU_TARGET     = at90s8515
#MCU_TARGET     = at90s8535
#MCU_TARGET     = atmega128
#MCU_TARGET     = atmega1280
#MCU_TARGET     = atmega1281
#MCU_TARGET     = atmega1284p
#MCU_TARGET     = atmega16
#MCU_TARGET     = atmega163
#MCU_TARGET     = atmega164p
#MCU_TARGET     = atmega165
#MCU_TARGET     = atmega165p
#MCU_TARGET     = atmega168
#MCU_TARGET     = atmega169
#MCU_TARGET     = atmega169p
#MCU_TARGET     = atmega2560
#MCU_TARGET     = atmega2561
#MCU_TARGET     = atmega32
#MCU_TARGET     = atmega324p
#MCU_TARGET     = atmega325
#MCU_TARGET     = atmega3250
#MCU_TARGET     = atmega329
#MCU_TARGET     = atmega3290
MCU_TARGET      = atmega328p
#MCU_TARGET     = atmega48
#MCU_TARGET     = atmega64
#MCU_TARGET     = atmega640
#MCU_TARGET     = atmega644
#MCU_TARGET     = atmega644p
#MCU_TARGET     = atmega645
#MCU_TARGET     = atmega6450
#MCU_TARGET     = atmega649
#MCU_TARGET     = atmega6490
#MCU_TARGET     = atmega8
#MCU_TARGET     = atmega8515
#MCU_TARGET     = atmega8535
#MCU_TARGET     = atmega88
#MCU_TARGET     = attiny2313
#MCU_TARGET     = attiny24
#MCU_TARGET     = attiny25
#MCU_TARGET     = attiny26
#MCU_TARGET     = attiny261
#MCU_TARGET     = attiny44
#MCU_TARGET     = attiny45
#MCU_TARGET     = attiny461
#MCU_TARGET     = attiny84
#MCU_TARGET     = attiny85
#MCU_TARGET     = attiny861
OPTIMIZE       = -O2

DEFS           = -D__AVR_ATmega328P__ -DF_CPU=16000000UL
ARDUINO           = /opt/arduino-1.0.4
MYARDUINO       = /home/myname/src/arduino

INCS           = -I $(MYARDUINO)/include \
                 -I $(MYARDUINO)/include/arduino \
                 -I $(MYARDUINO)/include/variants \
                 -I $(MYARDUINO)/include/variants/standard \
                 -I /opt/arduino-1.0.4/libraries/LiquidCrystal

LIBS           = -L $(MYARDUINO)/include -lm -lc

# You should not have to change anything below here.

CC             = avr-gcc
CXX               = avr-c++

# Override is only needed by avr-lib build system.

CFLAGS        = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) $(INCS)
override LDFLAGS       = -Wl,-Map,$(PRG).map

OBJCOPY        = avr-objcopy
OBJDUMP        = avr-objdump


PRG            = HelloWorld
SRCS           = \
                 HelloWorld.cpp \
                 /opt/arduino-1.0.4/libraries/LiquidCrystal/LiquidCrystal.cpp


all: $(PRG).elf lst text eeprom

OBJS := $(SRCS:.cpp=.o)
OBJS := $(OBJS:.c=.o)

%.o: %.c
    $(CC) -c $(CFLAGS) $? -o $@

%.o: %.cpp
    $(CXX) -c $(CFLAGS) $? -o $@

$(PRG).elf: $(OBJS)
    @echo "***********************************************************"
    @echo OBJS=$(OBJS)
    @echo "***********************************************************"
    @echo "Compiling $?"
    @echo "-----------------------------------------------------------"
    $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBS) $? ./include/libatmega328p.a

# dependency:


clean:
    rm -rf *.o $(PRG).elf *.eps *.png *.pdf *.bak
    rm -rf *.lst *.map $(EXTRA_CLEAN_FILES)

lst:  $(PRG).lst

%.lst: %.elf
    $(OBJDUMP) -h -S $< > $@

# Rules for building the .text rom images

text: hex bin srec

hex:  $(PRG).hex
bin:  $(PRG).bin
srec: $(PRG).srec

%.hex: %.elf
    $(OBJCOPY) -j .text -j .data -O ihex $< $@

%.srec: %.elf
    $(OBJCOPY) -j .text -j .data -O srec $< $@

%.bin: %.elf
    $(OBJCOPY) -j .text -j .data -O binary $< $@

# Rules for building the .eeprom rom images

eeprom: ehex ebin esrec

ehex:  $(PRG)_eeprom.hex
ebin:  $(PRG)_eeprom.bin
esrec: $(PRG)_eeprom.srec

%_eeprom.hex: %.elf
    $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ \
    || { echo empty $@ not generated; exit 0; }

%_eeprom.srec: %.elf
    $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@ \
    || { echo empty $@ not generated; exit 0; }

%_eeprom.bin: %.elf
    $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@ \
    || { echo empty $@ not generated; exit 0; }

# Every thing below here is used by avr-libc's build system and can be ignored
# by the casual user.

FIG2DEV                 = fig2dev
EXTRA_CLEAN_FILES       = *.hex *.bin *.srec

dox: eps png pdf

eps: $(PRG).eps
png: $(PRG).png
pdf: $(PRG).pdf

%.eps: %.fig
    $(FIG2DEV) -L eps $< $@

%.pdf: %.fig
    $(FIG2DEV) -L pdf $< $@

%.png: %.fig
    $(FIG2DEV) -L png $< $@
 

Thursday, March 28, 2013

Raspberry Pi Rev 2.0 Pin headers

Got my new Raspberry Pi mode-B rev 2.0 yesterday.  After looking around the info about some new unpopulated through holes on it, finally I got all the info.  Here's the summary:

Silkscreen label: P2
It is a 1x8-pin connection for JTAG to the main SoC (Broadcom MCU).
Silkscreen label: P3
It is 1x7 pins to be used for JTAG header connected to the USB hub + ethernet chip.
Silkscreen Label: P5
2x4 pins.  It's for extra connection
Pin 1 (square solder plate): +5 V output
Pin 2: +3.3v
Pin 3: GPIO28 (can be configured as I2C's SDA)
Pin 4: GPIO29 (can be configured as I2C's SCL)
Pin 5: GPIO30 
Pin 6: GPIO31 
Pin 7 and 8: Ground

Silkscreen label: P6
1x2 pins.  For MCU reset (short them will reset the MCU)

By the way, here is the info about the board (I have no idea my the Hardware below shows BCM2708, not BCM28xx):

pi@raspberrypi ~ $ cat /proc/cpuinfo
Processor    : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS    : 464.48
Features    : swp half thumb fastmult vfp edsp java tls
CPU implementer    : 0x41
CPU architecture: 7
CPU variant    : 0x0
CPU part    : 0xb76
CPU revision    : 7

Hardware    : BCM2708
Revision    : 000e
Serial      : 00000000xxxxxxxx



Thursday, February 28, 2013

My SMT Soldering result

Using X-Tronic hot air iron station, I was able to solder some ssop ICs (mostly the tiny ms430 microcontrollers) to their breakout pcb. The ICs are free samples from Texas Instrements.

Not bad for such small devices. Look professional to me.





Monday, February 25, 2013

Microsoft Empire



Found this diagram somewhere on the Internet.  As it is said on the top, it is permitted to repost here.  Very true and interesting!