Building Energy Micro EFM32 binaries from OS X

I’m currently evaluating the EFM32 Gecko MCU from Energy Micro for a project. I’m using the Developer’s Kit with the EFM32G290F128 MCU.

I mainly work in OS X and Linux and don’t much like having to boot up the Windows Virtual Machine to develop and debug firmwares. The tools mostly suck (I <3 the CLI) or are very expensive (often both). So I wanted a way to use open source tools like gcc, gdb and openocd.

First step was getting a binary to compile.

1. visit https://github.com/jsnyder/arm-eabi-toolchain and install as directed, make sure you run the make install-bin-extras after all the make-ing and make install-ing.

2. try a sample EFM32G firmware like the one included in the DVK_BSP_1.6.1.zip copy the ‘blink’ one to some directory of your choosing for this project.

3. Download the EFM CMSIS Library and copy it to the parent directory of the project directory you chose in step 2. Do the same with the ‘bsp’ and ‘efm32lib’ directories from the DVK_BSP.

4. Edit the Makefile from the ‘codesourcery’ part of the example. Mine looks like this:

####################################################################
# Makefile #
####################################################################

.SUFFIXES: # ignore builtin rules
.PHONY: all debug release clean

####################################################################
# Definitions #
####################################################################

DEVICE = EFM32G290F128
PROJECTNAME = blinkG290

OBJ_DIR = build
EXE_DIR = exe
LST_DIR = lst

####################################################################
# Definitions of toolchain. #
# You might need to do changes to match your system setup #
####################################################################

# Change path to CodeSourcery tools according to your system configuration
WINDOWSCS = CodeSourcery/Sourcery G++ Lite
LINUXCS = /Users/nemik/code/arm-cs-tools
GCCVERSION = $(shell $(CC) -dumpversion)

ifeq ($(ComSpec),)
ifeq ($(COMSPEC),)
# Assume we are making on a linux platform
TOOLDIR = $(LINUXCS)
RM = rm -rf
else
TOOLDIR = $(PROGRAMFILES)/$(WINDOWSCS)
RM = "$(TOOLDIR)/bin/cs-rm" -rf
endif
else
TOOLDIR = $(ProgramFiles)/$(WINDOWSCS)
RM = "$(TOOLDIR)/bin/cs-rm" -rf
endif

CC = "$(TOOLDIR)/bin/arm-none-eabi-gcc"
LD = "$(TOOLDIR)/bin/arm-none-eabi-ld"
AR = "$(TOOLDIR)/bin/arm-none-eabi-ar"
OBJCOPY = "$(TOOLDIR)/bin/arm-none-eabi-objcopy"
DUMP = "$(TOOLDIR)/bin/arm-none-eabi-objdump" --disassemble

####################################################################
# Flags #
####################################################################

# -MMD : Don't generate dependencies on system header files.
# -MP : Add phony targets, useful when a h-file is removed from a project.
# -MF : Specify a file to write the dependencies to.
DEPFLAGS = -MMD -MP -MF $(@:.o=.d)
# Add -Wa,-ahlms=$(LST_DIR)/$(@F:.o=.lst) to CFLAGS to produce assembly list files
CFLAGS += -D$(DEVICE) -mcpu=cortex-m3 -mthumb -Wall $(DEPFLAGS)
ASMFLAGS += -Ttext 0x0
LDFLAGS += -Xlinker -Map=$(LST_DIR)/$(PROJECTNAME).map -mcpu=cortex-m3 -mthumb -T../CMSIS/CM3/DeviceSupport/EnergyMicro/EFM32/startup/cs3/efm32g.ld -L"$(TOOLDIR)/arm-none-eabi/lib/thumb2" \
-L"$(TOOLDIR)/lib/gcc/arm-none-eabi/$(GCCVERSION)/thumb2"
LIBS += -lc -lcs3 -lcs3unhosted

INCLUDEPATHS += \
-I.. \
-I../CMSIS/CM3/CoreSupport \
-I../CMSIS/CM3/DeviceSupport/EnergyMicro/EFM32 \
-I../efm32lib/inc \
-I../bsp \
-I../drivers

####################################################################
# Files #
####################################################################

C_SRC += \
../CMSIS/CM3/CoreSupport/core_cm3.c \
../CMSIS/CM3/DeviceSupport/EnergyMicro/EFM32/system_efm32.c \
../bsp/dvk.c \
../bsp/dvk_boardcontrol.c \
../bsp/dvk_ebi.c \
../bsp/dvk_spi.c \
../efm32lib/src/efm32_assert.c \
../efm32lib/src/efm32_cmu.c \
../efm32lib/src/efm32_gpio.c \
../efm32lib/src/efm32_emu.c \
../efm32lib/src/efm32_ebi.c \
../efm32lib/src/efm32_system.c \
../efm32lib/src/efm32_usart.c \
blink.c

S_SRC += \
../CMSIS/CM3/DeviceSupport/EnergyMicro/EFM32/startup/cs3/startup_efm32.s

####################################################################
# Rules #
####################################################################

C_FILES = $(notdir $(C_SRC) )
S_FILES = $(notdir $(S_SRC) )
#make list of source paths, sort also removes duplicates
C_PATHS = $(sort $(dir $(C_SRC) ) )
S_PATHS = $(sort $(dir $(S_SRC) ) )

C_OBJS = $(addprefix $(OBJ_DIR)/, $(C_FILES:.c=.o))
S_OBJS = $(addprefix $(OBJ_DIR)/, $(S_FILES:.s=.o))
C_DEPS = $(addprefix $(OBJ_DIR)/, $(C_FILES:.c=.d))

vpath %.c $(C_PATHS)
vpath %.s $(S_PATHS)

# Default build is debug build
all: debug

debug: CFLAGS += -DDEBUG -g3 -O0
debug: $(OBJ_DIR) $(LST_DIR) $(EXE_DIR) $(EXE_DIR)/$(PROJECTNAME).bin

release: CFLAGS += -DNDEBUG -O3
release: $(OBJ_DIR) $(LST_DIR) $(EXE_DIR) $(EXE_DIR)/$(PROJECTNAME).bin

# Create directories
$(OBJ_DIR):
mkdir $(OBJ_DIR)
@echo "Created build directory."

$(EXE_DIR):
mkdir $(EXE_DIR)
@echo "Created executable directory."

$(LST_DIR):
mkdir $(LST_DIR)
@echo "Created list directory."

# Create objects from C SRC files
$(OBJ_DIR)/%.o: %.c
@echo "Building file: $<" $(CC) $(CFLAGS) $(INCLUDEPATHS) -c -o $@ $< # Assemble .s files $(OBJ_DIR)/%.o: %.s @echo "Assembling $<" $(CC) $(ASMFLAGS) $(INCLUDEPATHS) -c -o $@ $< # Link $(EXE_DIR)/$(PROJECTNAME).out: $(C_OBJS) $(S_OBJS) @echo "Linking target: $@" $(CC) $(LDFLAGS) $(C_OBJS) $(S_OBJS) $(LIBS) -o $(EXE_DIR)/$(PROJECTNAME).out # Create binary file $(EXE_DIR)/$(PROJECTNAME).bin: $(EXE_DIR)/$(PROJECTNAME).out @echo "Creating binary file" $(OBJCOPY) -O binary $(EXE_DIR)/$(PROJECTNAME).out $(EXE_DIR)/$(PROJECTNAME).bin # Uncomment next line to produce assembly listing of entire program # $(DUMP) $(EXE_DIR)/$(PROJECTNAME).out>$(EXE_DIR)/$(PROJECTNAME).lst

clean:
$(RM) $(OBJ_DIR) $(LST_DIR) $(EXE_DIR)

# include auto-generated dependency files (explicit rules)
ifneq (clean,$(findstring clean, $(MAKECMDGOALS)))
-include $(C_DEPS)
endif

5. Run the `make` command

6. You should have a ‘blinkG290.bin’ in the ‘exe’ directory. Seems a bit nuts that my bin is 14kb though…seems quite high for a blinking program; could that be CodeSourcery’s libcs3 adding so much?

7. Now you can use the energyAware Commander Windows program to load the firmware onto the board :/. I was not able to get openOCD working with the on-board JLink module and SWD. I’m now in the process of trying to get my BusPirate board to act as a JTAG interface for using the 20-pin adapter of the EFM32 Development Kit and hoping it does JTAG…
If not, one could also write a Python script with some XMODEM-CRC library to try to upload code to the built-in bootloader on the EFM32 chips using some FTDI USB-serial cable with something like the DST pin being used to pulse RESET and some other un-used serial pin to hold down DBG_SWCLK. But even then some way to debug is needed…really hoping JTAG can somehow work.

Has anyone tried to do something similar on Linux or OS X without the official Segger JLink software? They don’t produce OS X binaries and it’s closed source. Or has anyone gotten an EFM32 DK with its built-in JLink debugger to work with openOCD? Any suggestions would be awesome.