Skip to content

Commit 15ddc20

Browse files
committed
stm32: Add new component, the mboot bootloader.
Mboot is a custom bootloader for STM32 MCUs. It can provide a USB DFU interface on either the FS or HS peripherals, as well as a custom I2C bootloader interface.
1 parent f47eeab commit 15ddc20

6 files changed

Lines changed: 1906 additions & 0 deletions

File tree

ports/stm32/mboot/Makefile

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Select the board to build for: if not given on the command line,
2+
# then default to PYBV10.
3+
BOARD ?= PYBV10
4+
ifeq ($(wildcard ../boards/$(BOARD)/.),)
5+
$(error Invalid BOARD specified)
6+
endif
7+
8+
# If the build directory is not given, make it reflect the board name.
9+
BUILD ?= build-$(BOARD)
10+
11+
include ../../../py/mkenv.mk
12+
include ../boards/$(BOARD)/mpconfigboard.mk
13+
14+
CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include
15+
MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]')
16+
HAL_DIR=lib/stm32lib/STM32$(MCU_SERIES_UPPER)xx_HAL_Driver
17+
USBDEV_DIR=usbdev
18+
DFU=$(TOP)/tools/dfu.py
19+
PYDFU ?= $(TOP)/tools/pydfu.py
20+
DEVICE=0483:df11
21+
STFLASH ?= st-flash
22+
OPENOCD ?= openocd
23+
OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg
24+
25+
CROSS_COMPILE = arm-none-eabi-
26+
27+
INC += -I.
28+
INC += -I..
29+
INC += -I$(TOP)
30+
INC += -I$(BUILD)
31+
INC += -I$(TOP)/lib/cmsis/inc
32+
INC += -I$(CMSIS_DIR)/
33+
INC += -I$(TOP)/$(HAL_DIR)/Inc
34+
INC += -I../$(USBDEV_DIR)/core/inc -I../$(USBDEV_DIR)/class/inc
35+
36+
# Basic Cortex-M flags
37+
CFLAGS_CORTEX_M = -mthumb
38+
39+
# Options for particular MCU series
40+
CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
41+
CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
42+
CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
43+
44+
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA)
45+
CFLAGS += -D$(CMSIS_MCU)
46+
CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES))
47+
CFLAGS += $(COPT)
48+
CFLAGS += -I../boards/$(BOARD)
49+
CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
50+
CFLAGS += -DBOARD_$(BOARD)
51+
CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR)
52+
53+
LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref
54+
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
55+
56+
# Remove uncalled code from the final image.
57+
CFLAGS += -fdata-sections -ffunction-sections
58+
LDFLAGS += --gc-sections
59+
60+
# Debugging/Optimization
61+
ifeq ($(DEBUG), 1)
62+
CFLAGS += -g -DPENDSV_DEBUG
63+
COPT = -O0
64+
else
65+
COPT += -Os -DNDEBUG
66+
endif
67+
68+
SRC_LIB = $(addprefix lib/,\
69+
libc/string0.c \
70+
)
71+
72+
SRC_C = \
73+
main.c \
74+
drivers/bus/softspi.c \
75+
drivers/bus/softqspi.c \
76+
drivers/memory/spiflash.c \
77+
ports/stm32/i2cslave.c \
78+
ports/stm32/qspi.c \
79+
ports/stm32/flashbdev.c \
80+
ports/stm32/spibdev.c \
81+
ports/stm32/usbd_conf.c \
82+
$(patsubst $(TOP)/%,%,$(wildcard $(TOP)/ports/stm32/boards/$(BOARD)/*.c))
83+
84+
SRC_O = \
85+
ports/stm32/boards/startup_stm32$(MCU_SERIES).o \
86+
ports/stm32/resethandler.o \
87+
88+
SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
89+
hal_cortex.c \
90+
hal_flash.c \
91+
hal_flash_ex.c \
92+
hal_pcd.c \
93+
hal_pcd_ex.c \
94+
ll_usb.c \
95+
)
96+
97+
SRC_USBDEV = $(addprefix ports/stm32/$(USBDEV_DIR)/,\
98+
core/src/usbd_core.c \
99+
core/src/usbd_ctlreq.c \
100+
core/src/usbd_ioreq.c \
101+
)
102+
103+
OBJ =
104+
OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))
105+
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
106+
OBJ += $(addprefix $(BUILD)/, $(SRC_O))
107+
OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
108+
OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o))
109+
110+
all: $(TOP)/lib/stm32lib/README.md $(BUILD)/firmware.dfu $(BUILD)/firmware.hex
111+
112+
# For convenience, automatically fetch required submodules if they don't exist
113+
$(TOP)/lib/stm32lib/README.md:
114+
$(ECHO) "stm32lib submodule not found, fetching it now..."
115+
(cd $(TOP) && git submodule update --init lib/stm32lib)
116+
117+
.PHONY: deploy
118+
119+
deploy: $(BUILD)/firmware.dfu
120+
$(ECHO) "Writing $< to the board"
121+
$(Q)$(PYTHON) $(PYDFU) -u $<
122+
123+
FLASH_ADDR = 0x08000000
124+
125+
$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
126+
$(ECHO) "Create $@"
127+
$(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin
128+
$(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware.bin $@
129+
130+
$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
131+
$(ECHO) "Create $@"
132+
$(Q)$(OBJCOPY) -O ihex $< $@
133+
134+
$(BUILD)/firmware.elf: $(OBJ)
135+
$(ECHO) "LINK $@"
136+
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
137+
$(Q)$(SIZE) $@
138+
139+
#########################################
140+
141+
vpath %.S . $(TOP)
142+
$(BUILD)/%.o: %.S
143+
$(ECHO) "CC $<"
144+
$(Q)$(CC) $(CFLAGS) -c -o $@ $<
145+
146+
vpath %.s . $(TOP)
147+
$(BUILD)/%.o: %.s
148+
$(ECHO) "AS $<"
149+
$(Q)$(AS) -o $@ $<
150+
151+
define compile_c
152+
$(ECHO) "CC $<"
153+
$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $<
154+
@# The following fixes the dependency file.
155+
@# See http://make.paulandlesley.org/autodep.html for details.
156+
@# Regex adjusted from the above to play better with Windows paths, etc.
157+
@$(CP) $(@:.o=.d) $(@:.o=.P); \
158+
$(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \
159+
-e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
160+
$(RM) -f $(@:.o=.d)
161+
endef
162+
163+
vpath %.c . $(TOP)
164+
$(BUILD)/%.o: %.c
165+
$(call compile_c)
166+
167+
# $(sort $(var)) removes duplicates
168+
#
169+
# The net effect of this, is it causes the objects to depend on the
170+
# object directories (but only for existence), and the object directories
171+
# will be created if they don't exist.
172+
OBJ_DIRS = $(sort $(dir $(OBJ)))
173+
$(OBJ): | $(OBJ_DIRS)
174+
$(OBJ_DIRS):
175+
$(MKDIR) -p $@
176+
177+
clean:
178+
$(RM) -rf $(BUILD) $(CLEAN_EXTRA)
179+
.PHONY: clean
180+
181+
###########################################
182+
183+
$(BUILD)/main.o: $(BUILD)/genhdr/qstrdefs.generated.h
184+
185+
$(BUILD)/genhdr/qstrdefs.generated.h:
186+
$(MKDIR) -p $(BUILD)/genhdr
187+
$(Q)echo "// empty" > $@
188+
189+
-include $(OBJ:.o=.P)

ports/stm32/mboot/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
Mboot - MicroPython boot loader
2+
===============================
3+
4+
Mboot is a custom bootloader for STM32 MCUs, and currently supports the
5+
STM32F4xx and STM32F7xx families. It can provide a standard USB DFU interface
6+
on either the FS or HS peripherals, as well as a sophisticated, custom I2C
7+
interface. It fits in 16k of flash space.
8+
9+
How to use
10+
----------
11+
12+
1. Configure your board to use a boot loader by editing the mpconfigboard.mk
13+
and mpconfigboard.h files. For example, for an F767 be sure to have these
14+
lines in mpconfigboard.mk:
15+
16+
LD_FILES = boards/stm32f767.ld boards/common_bl.ld
17+
TEXT0_ADDR = 0x08008000
18+
19+
And this in mpconfigboard.h (recommended to put at the end of the file):
20+
21+
// Bootloader configuration
22+
#define MBOOT_I2C_PERIPH_ID 1
23+
#define MBOOT_I2C_SCL (pin_B8)
24+
#define MBOOT_I2C_SDA (pin_B9)
25+
#define MBOOT_I2C_ALTFUNC (4)
26+
27+
To configure a pin to force entry into the boot loader the following
28+
options can be used (with example configuration):
29+
30+
#define MBOOT_BOOTPIN_PIN (pin_A0)
31+
#define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_UP)
32+
#define MBOOT_BOOTPIN_ACTIVE (0)
33+
34+
2. Build the board's main application firmware as usual.
35+
36+
3. Build mboot via:
37+
38+
$ cd mboot
39+
$ make BOARD=<board-id>
40+
41+
That should produce a DFU file for mboot. It can be deployed using
42+
USB DFU programming via (it will be placed at location 0x08000000):
43+
44+
$ make BOARD=<board-id> deploy
45+
46+
4. Reset the board while holding USR until all 3 LEDs are lit (the 4th option in
47+
the cycle) and then release USR. LED0 will then blink once per second to
48+
indicate that it's in mboot
49+
50+
5. Use either USB DFU or I2C to download firmware. The script mboot.py shows how
51+
to communicate with the I2C boot loader interface. It should be run on a
52+
pyboard connected via I2C to the target board.

0 commit comments

Comments
 (0)