stm32/mboot: Add support for STM32N6xx MCUs.

Works in the usual USB DFU mode, and can program external SPI flash.  It
will enable XSPI memory-mapped mode before jumping to the application
firmware in the external SPI flash.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George
2024-09-10 00:02:18 +10:00
parent 96b8f3aebc
commit acb294f61a
6 changed files with 112 additions and 10 deletions

View File

@@ -34,7 +34,13 @@ include ../../../py/mkenv.mk
include $(BOARD_DIR)/mpconfigboard.mk
# A board can set MBOOT_TEXT0_ADDR to a custom location where mboot should reside.
ifeq ($(MCU_SERIES),n6)
MBOOT_TEXT0_ADDR ?= 0x34180400
MBOOT_LD_FILES ?= stm32_memory_n6.ld stm32_sections.ld
else
MBOOT_TEXT0_ADDR ?= 0x08000000
MBOOT_LD_FILES ?= stm32_memory.ld stm32_sections.ld
endif
# The string in MBOOT_VERSION (default defined in version.c if not defined by a
# board) will be stored in the final MBOOT_VERSION_ALLOCATED_BYTES bytes of mboot flash.
@@ -89,7 +95,6 @@ CFLAGS += -DMBOOT_VERSION=\"$(MBOOT_VERSION)\"
endif
CFLAGS += -DMBOOT_VERSION_ALLOCATED_BYTES=$(MBOOT_VERSION_ALLOCATED_BYTES) -DMBOOT_VERSION_INCLUDE_OPTIONS=$(MBOOT_VERSION_INCLUDE_OPTIONS)
MBOOT_LD_FILES ?= stm32_memory.ld stm32_sections.ld
LDFLAGS += -nostdlib -L . $(addprefix -T,$(MBOOT_LD_FILES)) -Map=$(@:.elf=.map) --cref
LDFLAGS += --defsym mboot_version_len=$(MBOOT_VERSION_ALLOCATED_BYTES)
LIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
@@ -137,12 +142,11 @@ SRC_C += \
drivers/bus/softqspi.c \
drivers/memory/spiflash.c \
ports/stm32/flash.c \
ports/stm32/flashbdev.c \
ports/stm32/i2cslave.c \
ports/stm32/powerctrlboot.c \
ports/stm32/qspi.c \
ports/stm32/spibdev.c \
ports/stm32/usbd_conf.c \
ports/stm32/xspi.c \
$(wildcard $(BOARD_DIR)/*.c)
SRC_O += \
@@ -169,16 +173,22 @@ SRC_HAL += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
hal.c \
hal_cortex.c \
hal_dma.c \
hal_flash.c \
hal_flash_ex.c \
hal_pcd.c \
hal_pcd_ex.c \
hal_pwr_ex.c \
hal_rcc.c \
hal_rcc_ex.c \
ll_rcc.c \
ll_usb.c \
)
ifneq ($(MCU_SERIES),n6)
SRC_HAL += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
hal_flash.c \
hal_flash_ex.c \
)
endif
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7))
SRC_HAL += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
hal_mmc.c \
@@ -187,6 +197,12 @@ SRC_HAL += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
)
endif
ifeq ($(MCU_SERIES),n6)
SRC_HAL += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
hal_bsec.c \
)
endif
SRC_USBDEV += $(addprefix ports/stm32/$(USBDEV_DIR)/,\
core/src/usbd_core.c \
core/src/usbd_ctlreq.c \
@@ -206,7 +222,7 @@ $(TOP)/lib/stm32lib/README.md:
$(ECHO) "stm32lib submodule not found, fetching it now..."
(cd $(TOP) && git submodule update --init lib/stm32lib)
.PHONY: deploy deploy-stlink
.PHONY: deploy deploy-stlink deploy-trusted
deploy: $(BUILD)/firmware.dfu
$(ECHO) "Writing $< to the board"
@@ -216,9 +232,15 @@ deploy-stlink: $(BUILD)/firmware.dfu
$(ECHO) "Writing $< to the board via ST-LINK"
$(Q)$(STFLASH) write $(BUILD)/firmware.bin $(MBOOT_TEXT0_ADDR)
$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
deploy-trusted: $(BUILD)/firmware-trusted.bin
$(STM32_CUBE_PROGRAMMER)/bin/STM32_Programmer.sh -c port=SWD mode=HOTPLUG ap=1 -el $(DKEL) -w $^ 0x70000000 -hardRst
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
$(ECHO) "Create $@"
$(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data -j .mboot_version_text $^ $(BUILD)/firmware.bin
$(BUILD)/firmware.dfu: $(BUILD)/firmware.bin
$(ECHO) "Create $@"
$(Q)$(PYTHON) $(DFU) -b $(MBOOT_TEXT0_ADDR):$(BUILD)/firmware.bin $@
$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
@@ -230,6 +252,10 @@ $(BUILD)/firmware.elf: $(OBJ)
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(SIZE) $@
$(BUILD)/firmware-trusted.bin: $(BUILD)/firmware.bin
/bin/rm -f $@
$(STM32_CUBE_PROGRAMMER)/bin/STM32_SigningTool_CLI -bin $^ -nk -of 0x80000000 -t fsbl -o $@ -hv $(STM32_N6_HEADER_VERSION)
#########################################
# Rules to generate header files

View File

@@ -1,3 +1,5 @@
// Include the main ADC driver, so mboot can use adc_config() and adc_config_and_read_u16().
#include "py/obj.h"
#if MICROPY_PY_MACHINE_ADC
#include "../machine_adc.c"
#endif

View File

@@ -41,6 +41,7 @@
#include "sdcard.h"
#include "dfu.h"
#include "pack.h"
#include "xspi.h"
// Whether the bootloader will leave via reset, or direct jump to the application.
#ifndef MBOOT_LEAVE_BOOTLOADER_VIA_RESET
@@ -373,7 +374,7 @@ void SystemClock_Config(void) {
#elif defined(STM32G0)
#define AHBxENR IOPENR
#define AHBxENR_GPIOAEN_Pos RCC_IOPENR_GPIOAEN_Pos
#elif defined(STM32H7)
#elif defined(STM32H7) || defined(STM32N6)
#define AHBxENR AHB4ENR
#define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos
#elif defined(STM32H5) || defined(STM32WB)
@@ -424,6 +425,10 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) {
#define MBOOT_SPIFLASH2_LAYOUT ""
#endif
#if defined(STM32N6)
#define FLASH_LAYOUT_STR "@Internal Flash " MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
#else
#if defined(STM32F4) \
|| defined(STM32F722xx) \
|| defined(STM32F723xx) \
@@ -584,12 +589,18 @@ static int mboot_flash_write(uint32_t addr, const uint8_t *src8, size_t len) {
return 0;
}
#endif
/******************************************************************************/
// Writable address space interface
static int do_mass_erase(void) {
#if defined(STM32N6)
return -1;
#else
// TODO spiflash erase ?
return mboot_flash_mass_erase();
#endif
}
#if defined(MBOOT_SPIFLASH_ADDR) || defined(MBOOT_SPIFLASH2_ADDR)
@@ -625,7 +636,12 @@ int hw_page_erase(uint32_t addr, uint32_t *next_addr) {
} else
#endif
{
#if defined(STM32N6)
dfu_context.status = DFU_STATUS_ERROR_ADDRESS;
dfu_context.error = MBOOT_ERROR_STR_INVALID_ADDRESS_IDX;
#else
ret = mboot_flash_page_erase(addr, next_addr);
#endif
}
mboot_state_change(MBOOT_STATE_ERASE_END, ret);
@@ -678,9 +694,12 @@ int hw_write(uint32_t addr, const uint8_t *src8, size_t len) {
ret = mp_spiflash_write(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, src8);
} else
#endif
#if !defined(STM32N6)
if (flash_is_valid_addr(addr)) {
ret = mboot_flash_write(addr, src8, len);
} else {
} else
#endif
{
dfu_context.status = DFU_STATUS_ERROR_ADDRESS;
dfu_context.error = MBOOT_ERROR_STR_INVALID_ADDRESS_IDX;
}
@@ -1509,7 +1528,7 @@ void stm32_main(uint32_t initial_r0) {
// Make sure IRQ vector table points to flash where this bootloader lives.
SCB->VTOR = MBOOT_VTOR;
#if __CORTEX_M != 33
#if __CORTEX_M != 33 && __CORTEX_M != 55
// Enable 8-byte stack alignment for IRQ handlers, in accord with EABI
SCB->CCR |= SCB_CCR_STKALIGN_Msk;
#endif
@@ -1539,6 +1558,12 @@ void stm32_main(uint32_t initial_r0) {
SCB_EnableDCache();
#endif
#if defined(STM32N6)
LL_PWR_EnableBkUpAccess();
initial_r0 = TAMP_S->BKP31R;
TAMP_S->BKP31R = 0;
#endif
MBOOT_BOARD_EARLY_INIT(&initial_r0);
#ifdef MBOOT_BOOTPIN_PIN
@@ -1748,6 +1773,12 @@ void USB_DRD_FS_IRQHandler(void) {
HAL_PCD_IRQHandler(&pcd_fs_handle);
}
#elif defined(STM32N6)
void USB1_OTG_HS_IRQHandler(void) {
HAL_PCD_IRQHandler(&pcd_hs_handle);
}
#elif defined(STM32WB)
void USB_LP_IRQHandler(void) {

View File

@@ -239,3 +239,20 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed);
#define pin_J13 (GPIOJ_BASE | 13)
#define pin_J14 (GPIOJ_BASE | 14)
#define pin_J15 (GPIOJ_BASE | 15)
#define pin_N0 (GPION_BASE | 0)
#define pin_N1 (GPION_BASE | 1)
#define pin_N2 (GPION_BASE | 2)
#define pin_N3 (GPION_BASE | 3)
#define pin_N4 (GPION_BASE | 4)
#define pin_N5 (GPION_BASE | 5)
#define pin_N6 (GPION_BASE | 6)
#define pin_N7 (GPION_BASE | 7)
#define pin_N8 (GPION_BASE | 8)
#define pin_N9 (GPION_BASE | 9)
#define pin_N10 (GPION_BASE | 10)
#define pin_N11 (GPION_BASE | 11)
#define pin_N12 (GPION_BASE | 12)
#define pin_N13 (GPION_BASE | 13)
#define pin_N14 (GPION_BASE | 14)
#define pin_N15 (GPION_BASE | 15)

View File

@@ -0,0 +1,18 @@
/*
Linker script fragment for mboot on an STM32N6xx MCU.
This defines the memory sections for the bootloader to use.
On N6, the hardware bootloader loads the first 512k of external flash into
the upper part of SRAM2 AXI S, starting at 0x34180000. The first 1024 bytes
is a header. Then comes the actual code, starting with the vector table.
*/
MEMORY
{
FLASH_BL (rx) : ORIGIN = 0x34180400, LENGTH = 31744 /* AXISRAM2_S */
RAM (xrw) : ORIGIN = 0x341e0000, LENGTH = 128K /* AXISRAM2_S */
}
/* Location of protected flash area which must not be modified, because mboot lives there. */
_mboot_protected_flash_start = ORIGIN(FLASH_BL);
_mboot_protected_flash_end_exclusive = ORIGIN(FLASH_BL) + LENGTH(FLASH_BL);

View File

@@ -33,6 +33,14 @@ SECTIONS
_etext = .;
} >FLASH_BL
/* Secure Gateway stubs */
.gnu.sgstubs :
{
. = ALIGN(4);
*(.gnu.sgstubs*)
. = ALIGN(4);
} >FLASH_BL
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);