Skip to content

Commit

Permalink
Make it easier to flash different devices and use ST-Link programmer
Browse files Browse the repository at this point in the history
- Added parameters to specify a programmer (interface) for openocd to use

- Added device name to firmware blobs so the flash command won't upload
  firmware to a device unless it was compiled for that device.

- Added small scripts to leverage the DEVICE parameter as much as possible
  in the build process. This includes automatically determining openocd
  target config from DEVICE, and getting the ROM/RAM size information
  already present in libopencm3 (but poorly exposed)

- Moved Makefile to project root for consistency with other projects

- Removed opencm3 build as a makefile dependency. `genlink-config.mk` in
  opencm3 isn't written in a way that can be used as a build dependency,
  since it refuses to set a library name if the name it wants to use
  doesn't exist on disk already. This means the make has to be run twice
  to actually succeed.

- Added credit to size script. This was mentioned in an Embedded Artistry
  newsletter a while ago and I hadn't intended to widely distribute this
  copy of it.

Resolves #5
  • Loading branch information
stecman committed May 8, 2021
1 parent 100433a commit 2083908
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 88 deletions.
83 changes: 83 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Device to build for
# See libopencm3/ld/devices.data for valid device name patterns
DEVICE ?= stm32f103c8

# Programmer to use (name of interface config in OpenOCD)
# For ST-Link v1 or v2 programmers, use "stlink"
# See the interfaces/*.cfg files installed by openocd for options
PROGRAMMER ?= jlink

# Serial number for USB interface (must be 12 or more characters in hex)
SERIALNUM ?= D000000000E7
CDEFS += -DUSB_SERIALNUM="\"$(SERIALNUM)\""

# Base OpenCM3 build
PROJECT = boot-swtich

CFILES = \
src/clock.c \
src/fat.c \
src/main.c \
src/usb.c \

CSTD = -std=c11
OPT = -Os

# Flag specific devices that needs special pin mapping
ifeq ($(DEVICE), stm32f070f6)
CDEFS += -DSTM32F070F6
endif


# Pick OpenOCD target config based on DEVICE parameter if not set externally
OOCD_TARGET ?= $(shell python ./scripts/openocd_target.py $(DEVICE))

# Pick appropriate transport for programmer
ifeq ($(PROGRAMMER), stlink)
TRANSPORT ?= hla_swd
else
TRANSPORT ?= swd
endif

OOCD_FLAGS = -f interface/$(PROGRAMMER).cfg \
-c "transport select $(TRANSPORT)" \
-f target/$(OOCD_TARGET).cfg \
-f openocd.cfg


# Generate the actual build targets based on this what's configured above
OPENCM3_DIR=libopencm3
include $(OPENCM3_DIR)/mk/genlink-config.mk
include rules.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk

# Extract parameters for size script from generated device flags
genlink_defs = $(shell $(OPENCM3_DIR)/scripts/genlink.py $(DEVICES_DATA) $(DEVICE) DEFS)
FLASH_SIZE_BYTES = $(shell python ./scripts/parse_defs.py _ROM $(genlink_defs))
SRAM_SIZE_BYTES = $(shell python ./scripts/parse_defs.py _RAM $(genlink_defs))

test:
@echo $(genlink_cppflags)
@echo $(FLASH_SIZE_BYTES) $(SRAM_SIZE_BYTES)

reset:
$(OOCD) -f $(OOCD_FILE) -c 'reset ()'

flash: all
BINARY=$(OUTPUT_ELF) $(OOCD) $(OOCD_FLAGS) -c 'program_and_run ()'

flash_and_debug: all
BINARY=$(OUTPUT_ELF) $(OOCD) $(OOCD_FLAGS) -c 'program_and_attach ()'

debug_server:
# This doesn't like being backgrounded from make for some reason
# Run this as a background task, then run debug_gdb
$(OOCD) $(OOCD_FLAGS) -c 'attach ()'

debug_gdb:
$(GDB) $(OUTPUT_ELF) -ex 'target remote :3333' \

disasm: $(OUTPUT_ELF)
$(OBJDUMP) -d $(OUTPUT_ELF)

.PHONY: flash reset debug_gdb debug_server disasm
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,30 @@ git submodule init
git submodule update

# Build libopencm3 (only needed once)
cd libopencm3
make -j8
make -C libopencm3 -j8

# Build the firmware
cd src
make

# Flash (assumes a J-Link programmer connected to SWD on the device)
# Flash with a J-Link programmer connected by SWD
make flash

# Flash with an ST-Link programmer connected by SWD
make flash PROGRAMMER=stlink
```

This project supports building for multiple different parts. Use `make DEVICE=partnumber` to build for a specific part. These parts have been tested:
This project supports building and flashing multiple different parts. These parts have been tested:

- `stm32f103c8` (default): found on the "blue pill" and "maple" STM32 dev boards
- `stm32f070f6`

To build for your specific part, pass the `DEVICE` parameter to `make` on the command line (or export `DEVICE` as an environment variable):

```sh
make DEVICE=stm32f070f6
make flash DEVICE=stm32f070f6
```

Valid patterns for the `DEVICE` parameter can be found in `libopencm3/ld/devices.data`.


Expand Down
8 changes: 2 additions & 6 deletions openocd-jlink.cfg → openocd.cfg
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# Configure JLink in SWD mode
source [find interface/jlink.cfg]
transport select swd

# STM32F070 target
source [find target/stm32f0x.cfg]
# Interface and target device config are specified on the command line
# See src/Makefile OOCD_FLAGS

# Init and flash target
proc program () {
Expand Down
20 changes: 7 additions & 13 deletions rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ ifndef GDB
GDB = $(PREFIX)gdb
endif

# Filename to build to
OUTPUT_ELF = $(PROJECT).$(DEVICE).elf
OUTPUT_BIN = $(PROJECT).$(DEVICE).bin

OPENCM3_INC = $(OPENCM3_DIR)/include

Expand All @@ -75,7 +78,7 @@ INCLUDES += $(patsubst %,-I%, . $(OPENCM3_INC) )

OBJS = $(CFILES:%.c=$(BUILD_DIR)/%.o)
OBJS += $(AFILES:%.S=$(BUILD_DIR)/%.o)
GENERATED_BINS = $(PROJECT).elf $(PROJECT).bin $(PROJECT).map $(PROJECT).list $(PROJECT).lss
GENERATED_BINS = $(PROJECT)*.elf $(PROJECT)*.bin $(PROJECT)*.map $(PROJECT)*.list $(PROJECT)*.lss

TGT_CPPFLAGS += -MD
TGT_CPPFLAGS += -Wall -Wundef $(INCLUDES)
Expand Down Expand Up @@ -127,7 +130,7 @@ LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group
%: s.%
%: SCCS/s.%

all: $(PROJECT).elf $(PROJECT).bin
all: $(OUTPUT_ELF) $(OUTPUT_BIN)

# error if not using linker script generator
ifeq (,$(DEVICE))
Expand All @@ -140,10 +143,6 @@ else
GENERATED_BINS += $(LDSCRIPT)
endif

# Ensure the platform we want from libopencm3 is compiled
opencm3:
$(Q)$(MAKE) -C $(OPENCM3_DIR) TARGETS=stm32/f0

# Need a special rule to have a bin dir
$(BUILD_DIR)/%.o: %.c
@printf " CC\t$<\n"
Expand All @@ -160,7 +159,7 @@ $(BUILD_DIR)/%.o: %.S
@mkdir -p $(dir $@)
$(Q)$(CC) $(TGT_ASFLAGS) $(ASFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $@ -c $<

$(PROJECT).elf: opencm3 $(OBJS) $(LDSCRIPT) $(LIBDEPS)
$(OUTPUT_ELF): opencm3 $(OBJS) $(LDSCRIPT) $(LIBDEPS)
@printf " LD\t$@\n"
$(Q)$(LD) $(TGT_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@

Expand All @@ -169,7 +168,7 @@ $(PROJECT).elf: opencm3 $(OBJS) $(LDSCRIPT) $(LIBDEPS)
$(Q)$(OBJCOPY) -O binary $< $@

@printf "\nFirmware size ($<):\n"
@../scripts/size.sh $< $(FLASH_SIZE_BYTES) $(SRAM_SIZE_BYTES)
@./scripts/size.sh $< $(FLASH_SIZE_BYTES) $(SRAM_SIZE_BYTES)

%.lss: %.elf
$(OBJDUMP) -h -S $< > $@
Expand All @@ -180,11 +179,6 @@ $(PROJECT).elf: opencm3 $(OBJS) $(LDSCRIPT) $(LIBDEPS)
clean:
rm -rf $(BUILD_BASE) $(GENERATED_BINS)

$(Q)if [ -d $* ]; then \
printf " CLEAN $*\n"; \
$(MAKE) -C $* clean OPENCM3_DIR=$(OPENCM3_DIR) || exit $?; \
fi;

.PHONY: all clean opencm3
-include $(OBJS:.o=.d)

23 changes: 23 additions & 0 deletions scripts/openocd_target.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#
# Print an OpenOCD target name for a given libopencm3 device name
# This could be done with sed from Make, but I expect this to grow
#

from __future__ import print_function

import sys
import re

if len(sys.argv) < 2:
print("Usage: %s <DEVICE>")
sys.exit(1)

device = sys.argv[1]

if device.startswith('stm32'):
match = re.match(r'(stm32f[0-9]).*', device)
print(match.group(1) + "x")

else:
sys.stderr.write("Unsure how to determine OpenOCD target config for '%s'" % device)
sys.exit(2)
35 changes: 35 additions & 0 deletions scripts/parse_defs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#
# Extract a particular definition (-D) value from passed compiler args
#
# This is a bit messy as the genlink.py script in libopencm3 isn't written in
# a way that allows reuse of its parsing code in other Python scripts. This
# script primarily exists to parse RAM and ROM size data from genlink.py.
#

from __future__ import print_function

import re
import sys

if len(sys.argv) < 2:
print("Usage: %s <NAME> [-Dvar=value, ...]")
sys.exit(1)

search = sys.argv[1]
pattern = "-D%s=" % search
value = None

for arg in sys.argv[2:]:
if arg.startswith(pattern):
value = arg[len(pattern):]
break
else:
print("Couldn't find variable named '%s' in args: %s" % (search, sys.argv[2:]))
sys.exit(2)

# Convert kilobytes to bytes
match = re.match(r'([0-9]+)K', value)
if match:
value = int(match.group(1)) * 1024

print(value)
3 changes: 3 additions & 0 deletions scripts/size.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash

# Print the RAM and ROM use percent of compiled firmware
# Based on https://interrupt.memfault.com/blog/best-firmware-size-tools

if [ $# -le 2 ]
then
echo "This script requires 3 arguments."
Expand Down
64 changes: 0 additions & 64 deletions src/Makefile

This file was deleted.

0 comments on commit 2083908

Please sign in to comment.