mimxrt: Add support for a UF2 bootloader.
Allowing to use e.g. the Adafruit bootloaders with MicroPython. The .uf2 file is created in addition to the .bin and .hex files allowing to use the latter ones without the bootloader for debugging and testing. Changes: - Set the location of the ISR Vector and .text segment to 0x6000C000 and 0x6000C400. - Reserve an area at the start of ITCM for a copy of the interrupt vector table and copy the table on reset to this place. - Extend `machine.bootloader()` by setting the magic number to enable the bootloader on reset. - Create a .uf2 file which skips the segments below 0x6000C000. The bootloader has to be installed as a preparation step using the board specific methods, but then the firmware's .uf2 file version can be installed using the bootloader. The bootloader can be invoked with: - double reset - calling machine.bootloader() - Using the touch1200 method Double reset is hard to achieve on MIMXRT boards, since there is no clean reset pin. Some MIMXRT boards provide it by switching the power. Some boards are excluded from the .uf2 build: - MIMXRT1050_EVK: The uf2 bootloader is built for the QSPI version of the board. MicroPython supports the Hyperflash version. - MIMXRT1176_EVK: No support for this board yet, but it should be possible. Signed-off-by: robert-hh <robert@hammelrath.com>
This commit is contained in:
@@ -21,6 +21,7 @@ BUILD ?= build-$(BOARD)
|
||||
PORT ?= /dev/ttyACM0
|
||||
CROSS_COMPILE ?= arm-none-eabi-
|
||||
GIT_SUBMODULES += lib/tinyusb lib/nxp_driver
|
||||
UF2CONV ?= $(TOP)/tools/uf2conv.py
|
||||
|
||||
# MicroPython feature configurations
|
||||
MICROPY_VFS_LFS2 ?= 1
|
||||
@@ -162,6 +163,13 @@ SRC_HAL_IMX_C += \
|
||||
$(MCU_DIR)/drivers/fsl_romapi.c
|
||||
endif
|
||||
|
||||
# If not empty, then it is 10xx.
|
||||
ifneq ($(findstring MIMXRT10, $(MCU_SERIES)),)
|
||||
APPLICATION_ADDR := 0x6000C000
|
||||
else
|
||||
APPLICATION_ADDR := 0x3000C000
|
||||
endif
|
||||
|
||||
ifeq ($(MCU_SERIES), MIMXRT1176)
|
||||
INC += -I$(TOP)/$(MCU_DIR)/drivers/cm7
|
||||
|
||||
@@ -253,6 +261,11 @@ else
|
||||
$(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE))
|
||||
endif
|
||||
|
||||
# Set a flag if the UF2 bootloader is used
|
||||
ifeq ($(USE_UF2_BOOTLOADER),1)
|
||||
CFLAGS += -DMICROPY_MACHINE_UF2_BOOTLOADER=1
|
||||
endif
|
||||
|
||||
# Add sources for respective board flash type
|
||||
# Add hal/flexspi_nor_flash.c or hal/flashspi_hyper_flash.c respectively
|
||||
SRC_HAL_C += hal/flexspi_$(subst qspi_,,$(FLEXSPI_FLASH_TYPE)).c
|
||||
@@ -470,7 +483,11 @@ $(BUILD)/lib/tinyusb/src/device/usbd.o: CFLAGS += -Wno-missing-braces
|
||||
# Build targets
|
||||
# =============================================================================
|
||||
|
||||
ifeq ($(USE_UF2_BOOTLOADER),1)
|
||||
all: $(BUILD)/firmware.hex $(BUILD)/firmware.bin $(BUILD)/firmware.uf2
|
||||
else
|
||||
all: $(BUILD)/firmware.hex $(BUILD)/firmware.bin
|
||||
endif
|
||||
|
||||
# Process linker scripts with C preprocessor to exchange LDDEFINES and
|
||||
# aggregate output of preprocessor in a single linker script `link.ld`
|
||||
@@ -487,6 +504,10 @@ $(BUILD)/firmware.bin: $(BUILD)/firmware.elf
|
||||
$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
|
||||
$(Q)$(OBJCOPY) -O ihex -R .eeprom $< $@
|
||||
|
||||
$(BUILD)/firmware.uf2: $(BUILD)/firmware.elf
|
||||
$(Q)$(OBJCOPY) -O binary -R .stack -R .ivt -R .flash_config $^ $@-binpart
|
||||
$(Q)$(PYTHON) $(UF2CONV) -b $(APPLICATION_ADDR) -f MIMXRT10XX -c -o $@ $@-binpart
|
||||
|
||||
# Making OBJ use an order-only dependency on the generated pins.h file
|
||||
# has the side effect of making the pins.h file before we actually compile
|
||||
# any of the objects. The normal dependency generation will deal with the
|
||||
|
||||
@@ -8,3 +8,5 @@ MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB
|
||||
MICROPY_PY_NETWORK_NINAW10 ?= 1
|
||||
MICROPY_PY_SSL ?= 1
|
||||
MICROPY_SSL_MBEDTLS ?= 1
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
@@ -5,6 +5,8 @@ MICROPY_FLOAT_IMPL = single
|
||||
MICROPY_HW_FLASH_TYPE = qspi_nor_flash
|
||||
MICROPY_HW_FLASH_SIZE = 0x1000000 # 16MB
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
JLINK_PATH ?= /media/RT1010-EVK/
|
||||
JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ flash_config_start = flash_start + 0x00000400;
|
||||
flash_config_size = 0x00000C00;
|
||||
ivt_start = flash_start + 0x00001000;
|
||||
ivt_size = 0x00001000;
|
||||
interrupts_start = flash_start + 0x00002000;
|
||||
interrupts_start = flash_start + 0x0000C000;
|
||||
interrupts_size = 0x00000400;
|
||||
text_start = flash_start + 0x00002400;
|
||||
text_start = flash_start + 0x0000C400;
|
||||
vfs_start = flash_start + 0x00100000;
|
||||
text_size = ((vfs_start) - (text_start));
|
||||
vfs_size = ((flash_end) - (vfs_start));
|
||||
|
||||
@@ -14,9 +14,9 @@ flash_config_start = flash_start;
|
||||
flash_config_size = 0x00001000;
|
||||
ivt_start = flash_start + 0x00001000;
|
||||
ivt_size = 0x00001000;
|
||||
interrupts_start = flash_start + 0x00002000;
|
||||
interrupts_start = flash_start + 0x0000C000;
|
||||
interrupts_size = 0x00000400;
|
||||
text_start = flash_start + 0x00002400;
|
||||
text_start = flash_start + 0x0000C400;
|
||||
vfs_start = flash_start + 0x00100000;
|
||||
text_size = ((vfs_start) - (text_start));
|
||||
vfs_size = ((flash_end) - (vfs_start));
|
||||
|
||||
@@ -6,3 +6,5 @@ MICROPY_HW_FLASH_TYPE = qspi_nor_flash
|
||||
MICROPY_HW_FLASH_SIZE = 0x1000000 # 16MB
|
||||
|
||||
MICROPY_BOOT_BUFFER_SIZE = (32 * 1024)
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
@@ -12,6 +12,8 @@ MICROPY_PY_LWIP = 1
|
||||
MICROPY_PY_SSL = 1
|
||||
MICROPY_SSL_MBEDTLS = 1
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
|
||||
|
||||
JLINK_PATH ?= /media/RT1020-EVK/
|
||||
|
||||
@@ -14,9 +14,9 @@ flash_config_start = flash_start;
|
||||
flash_config_size = 0x00001000;
|
||||
ivt_start = flash_start + 0x00001000;
|
||||
ivt_size = 0x00001000;
|
||||
interrupts_start = flash_start + 0x00002000;
|
||||
interrupts_start = flash_start + 0x0000C000;
|
||||
interrupts_size = 0x00000400;
|
||||
text_start = flash_start + 0x00002400;
|
||||
text_start = flash_start + 0x0000C400;
|
||||
vfs_start = flash_start + 0x00100000;
|
||||
text_size = ((vfs_start) - (text_start));
|
||||
vfs_size = ((flash_end) - (vfs_start));
|
||||
|
||||
@@ -16,9 +16,9 @@ flash_config_start = flash_start;
|
||||
flash_config_size = 0x00001000;
|
||||
ivt_start = flash_start + 0x00001000;
|
||||
ivt_size = 0x00001000;
|
||||
interrupts_start = flash_start + 0x00002000;
|
||||
interrupts_start = flash_start + 0x0000C000;
|
||||
interrupts_size = 0x00000400;
|
||||
text_start = flash_start + 0x00002400;
|
||||
text_start = flash_start + 0x0000C400;
|
||||
vfs_start = flash_start + 0x00200000;
|
||||
text_size = ((vfs_start) - (text_start));
|
||||
vfs_size = ((flash_end) - (vfs_start));
|
||||
|
||||
@@ -12,6 +12,8 @@ MICROPY_PY_LWIP = 1
|
||||
MICROPY_PY_SSL = 1
|
||||
MICROPY_SSL_MBEDTLS = 1
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
|
||||
|
||||
JLINK_PATH ?= /media/RT1060-EVK/
|
||||
|
||||
@@ -16,9 +16,9 @@ flash_config_start = flash_start;
|
||||
flash_config_size = 0x00001000;
|
||||
ivt_start = flash_start + 0x00001000;
|
||||
ivt_size = 0x00001000;
|
||||
interrupts_start = flash_start + 0x00002000;
|
||||
interrupts_start = flash_start + 0x0000C000;
|
||||
interrupts_size = 0x00000400;
|
||||
text_start = flash_start + 0x00002400;
|
||||
text_start = flash_start + 0x0000C400;
|
||||
vfs_start = flash_start + 0x00100000;
|
||||
text_size = ((vfs_start) - (text_start));
|
||||
vfs_size = ((flash_end) - (vfs_start));
|
||||
|
||||
@@ -10,9 +10,9 @@ flash_config_start = flash_start;
|
||||
flash_config_size = 0x00001000;
|
||||
ivt_start = flash_start + 0x00001000;
|
||||
ivt_size = 0x00001000;
|
||||
interrupts_start = flash_start + 0x00002000;
|
||||
interrupts_start = flash_start + 0x0000C000;
|
||||
interrupts_size = 0x00000400;
|
||||
text_start = flash_start + 0x00002400;
|
||||
text_start = flash_start + 0x0000C400;
|
||||
vfs_start = flash_start + 0x00100000;
|
||||
text_size = ((vfs_start) - (text_start));
|
||||
vfs_size = ((flash_end) - (vfs_start));
|
||||
|
||||
@@ -12,6 +12,8 @@ MICROPY_PY_LWIP = 1
|
||||
MICROPY_PY_SSL = 1
|
||||
MICROPY_SSL_MBEDTLS = 1
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
|
||||
|
||||
JLINK_PATH ?= /media/RT1064-EVK/
|
||||
|
||||
@@ -6,6 +6,8 @@ MICROPY_HW_FLASH_TYPE = qspi_nor_flash
|
||||
MICROPY_HW_FLASH_SIZE = 0x200000 # 2MB
|
||||
MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
CFLAGS += -DMICROPY_HW_FLASH_DQS=kFlexSPIReadSampleClk_LoopbackInternally
|
||||
|
||||
SRC_C += \
|
||||
|
||||
@@ -12,6 +12,8 @@ MICROPY_PY_LWIP = 1
|
||||
MICROPY_PY_SSL = 1
|
||||
MICROPY_SSL_MBEDTLS = 1
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
|
||||
|
||||
CFLAGS += -DSPI_RETRY_TIMES=1000000
|
||||
|
||||
@@ -6,5 +6,7 @@ MICROPY_HW_FLASH_TYPE = qspi_nor_flash
|
||||
MICROPY_HW_FLASH_SIZE = 0x200000 # 2MB
|
||||
MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
deploy: $(BUILD)/firmware.hex
|
||||
teensy_loader_cli --mcu=imxrt1062 -v -w $<
|
||||
|
||||
@@ -10,6 +10,8 @@ MICROPY_PY_LWIP = 1
|
||||
MICROPY_PY_SSL = 1
|
||||
MICROPY_SSL_MBEDTLS = 1
|
||||
|
||||
USE_UF2_BOOTLOADER = 1
|
||||
|
||||
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
|
||||
|
||||
deploy: $(BUILD)/firmware.hex
|
||||
|
||||
@@ -42,7 +42,8 @@ MEMORY
|
||||
m_vfs (RX) : ORIGIN = vfs_start, LENGTH = vfs_size
|
||||
/* Teensy uses the last bit of flash for recovery. */
|
||||
m_reserved (RX) : ORIGIN = (vfs_start + vfs_size), LENGTH = reserved_size
|
||||
m_itcm (RX) : ORIGIN = itcm_start, LENGTH = itcm_size
|
||||
m_isr (RX) : ORIGIN = itcm_start, LENGTH = 0x400
|
||||
m_itcm (RX) : ORIGIN = itcm_start + 0x400, LENGTH = itcm_size - 0x400
|
||||
m_dtcm (RW) : ORIGIN = dtcm_start, LENGTH = dtcm_size
|
||||
m_ocrm (RW) : ORIGIN = ocrm_start, LENGTH = ocrm_size
|
||||
|
||||
@@ -80,7 +81,8 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} > m_ivt
|
||||
|
||||
/* The startup code goes first into internal RAM */
|
||||
/* ISR Vector table in flash. Copied to ITCM by ResetHandler(). */
|
||||
|
||||
.interrupts :
|
||||
{
|
||||
__Vectors = .;
|
||||
@@ -90,10 +92,9 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} > m_interrupts
|
||||
|
||||
__VECTOR_RAM = __Vectors;
|
||||
__RAM_VECTOR_TABLE_SIZE_BYTES = 0x0;
|
||||
__Vectors_RAM = ORIGIN(m_isr);
|
||||
|
||||
/* The program code and other data goes into internal RAM */
|
||||
/* Some program code and other data goes into internal RAM */
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
|
||||
@@ -64,6 +64,19 @@ Reset_Handler:
|
||||
* __ram_function_start__/__ram_function_end__ : ramfunction region
|
||||
* copied to. Both must be aligned to 4 bytes boundary. */
|
||||
|
||||
/* Copy the ISR Vector table to the start of ITCM to be available when the
|
||||
.uf2 bootloader is used */
|
||||
|
||||
ldr r1, = __Vectors
|
||||
ldr r2, = __Vectors_RAM
|
||||
movs r3, 1024
|
||||
|
||||
.LC_ISR:
|
||||
subs r3, #4
|
||||
ldr r0, [r1, r3]
|
||||
str r0, [r2, r3]
|
||||
bgt .LC_ISR
|
||||
|
||||
ldr r1, =__etext
|
||||
ldr r2, =__data_start__
|
||||
ldr r3, =__data_end__
|
||||
|
||||
@@ -76,6 +76,11 @@ typedef enum {
|
||||
MP_SOFT_RESET
|
||||
} reset_reason_t;
|
||||
|
||||
// Copied from inc/uf2.h in https://github.com/Microsoft/uf2-samd21
|
||||
#define DBL_TAP_REG SNVS->LPGPR[3]
|
||||
#define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set
|
||||
#define DBL_TAP_MAGIC_QUICK_BOOT 0xf02669ef
|
||||
|
||||
static mp_obj_t mp_machine_unique_id(void) {
|
||||
unsigned char id[8];
|
||||
mp_hal_get_unique_id(id);
|
||||
@@ -158,12 +163,17 @@ NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args) {
|
||||
#if defined(MICROPY_BOARD_ENTER_BOOTLOADER)
|
||||
// If a board has a custom bootloader, call it first.
|
||||
MICROPY_BOARD_ENTER_BOOTLOADER(n_args, args);
|
||||
#elif FSL_ROM_HAS_RUNBOOTLOADER_API
|
||||
#elif FSL_ROM_HAS_RUNBOOTLOADER_API && !MICROPY_MACHINE_UF2_BOOTLOADER
|
||||
// If not, enter ROM bootloader in serial downloader / USB mode.
|
||||
// Skip that in case of the UF2 bootloader being available.
|
||||
uint32_t arg = 0xEB110000;
|
||||
ROM_RunBootloader(&arg);
|
||||
#else
|
||||
// No custom bootloader, or run bootloader API, then just reset.
|
||||
// No custom bootloader, or run bootloader API, the set
|
||||
// the flag for the UF2 bootloader
|
||||
// Pretend to be the first of the two reset presses needed to enter the
|
||||
// bootloader. That way one reset will end in the bootloader.
|
||||
DBL_TAP_REG = DBL_TAP_MAGIC;
|
||||
WDOG_TriggerSystemSoftwareReset(WDOG1);
|
||||
#endif
|
||||
while (1) {
|
||||
|
||||
@@ -115,6 +115,7 @@ uint32_t trng_random_u32(void);
|
||||
#define MICROPY_PY_MACHINE_UART_SENDBREAK (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
#define MICROPY_PY_ONEWIRE (1)
|
||||
#define MICROPY_PY_MACHINE_BOOTLOADER (1)
|
||||
|
||||
// fatfs configuration used in ffconf.h
|
||||
#define MICROPY_FATFS_ENABLE_LFN (2)
|
||||
@@ -151,6 +152,7 @@ uint32_t trng_random_u32(void);
|
||||
|
||||
#define MICROPY_HW_ENABLE_USBDEV (1)
|
||||
#define MICROPY_HW_USB_CDC (1)
|
||||
#define MICROPY_HW_USB_CDC_1200BPS_TOUCH (1)
|
||||
|
||||
// Hooks to add builtins
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ function build_esp8266_boards {
|
||||
}
|
||||
|
||||
function build_mimxrt_boards {
|
||||
build_boards modmimxrt.c $1 $2 bin hex
|
||||
build_boards modmimxrt.c $1 $2 bin hex uf2
|
||||
}
|
||||
|
||||
function build_nrf_boards {
|
||||
|
||||
Reference in New Issue
Block a user