Sync betaflight to Gitea
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
*.bin
|
||||
*.elf
|
||||
*.o
|
||||
*.map
|
||||
@@ -0,0 +1,4 @@
|
||||
#Opt Id Name Type IP Offset Binary
|
||||
P 0x1 fsbl-openbl Binary none 0x0 ../../STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/OpenBootloader_STM32N6570-DK-trusted.stm32
|
||||
P 0x3 fsbl-extfl Binary none 0x0 ../../STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/MX66UW1G45G_STM32N6570-DK-OBL.bin
|
||||
P 0x4 combined Binary nor0 0x0 prebuilt/combined.bin
|
||||
|
@@ -0,0 +1,4 @@
|
||||
#Opt Id Name Type IP Offset Binary
|
||||
P 0x1 fsbl-openbl Binary none 0x0 ../../STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/OpenBootloader_STM32N6570-DK-trusted.stm32
|
||||
P 0x3 fsbl-extfl Binary none 0x0 ../../STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/MX66UW1G45G_STM32N6570-DK-OBL.bin
|
||||
P 0x4 bf-fsbl Binary nor0 0x0 prebuilt/bf_as_fsbl.stm32
|
||||
|
@@ -0,0 +1,4 @@
|
||||
#Opt Id Name Type IP Offset Binary
|
||||
P 0x1 fsbl-openbl Binary none 0x0 ../../STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/OpenBootloader_STM32N6570-DK-trusted.stm32
|
||||
P 0x3 fsbl-extfl Binary none 0x0 ../../STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/MX66UW1G45G_STM32N6570-DK-OBL.bin
|
||||
P 0x4 obl-bf Binary nor0 0x0 /tmp/obl_bf_combined.bin
|
||||
|
@@ -0,0 +1,4 @@
|
||||
#Opt Id Name Type IP Offset Binary
|
||||
P 0x1 fsbl-openbl Binary none 0x0 ../../../modules/STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/OpenBootloader_STM32N6570-DK-trusted.stm32
|
||||
P 0x3 fsbl-extfl Binary none 0x0 ../../../modules/STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/MX66UW1G45G_STM32N6570-DK-OBL.bin
|
||||
P 0x4 obl-only Binary nor0 0x0 ../n6_obl/prebuilt/obl_only_combined.bin
|
||||
|
@@ -0,0 +1,186 @@
|
||||
# STM32N6 FSBL stub — standalone build. Not invoked by betaflight's main
|
||||
# build; the signed blob in prebuilt/ is what gets bundled into the combined
|
||||
# image.
|
||||
#
|
||||
# Usage:
|
||||
# make # produce n6_fsbl.elf and n6_fsbl.bin
|
||||
# make signed # also re-sign the .bin into prebuilt/
|
||||
# make combined # rebuild prebuilt/combined.bin = signed FSBL padded
|
||||
# # to 1 MiB + RAM_ONLY betaflight .bin (read by the
|
||||
# # FSBL stub from 0x70100000 and shadow-copied into
|
||||
# # AXISRAM1 at 0x24000000)
|
||||
# make clean
|
||||
#
|
||||
# `combined` requires CONFIG and CONFIG_DIR for the betaflight build:
|
||||
# make combined CONFIG=STM32N657DK_DSK320 CONFIG_DIR=$$HOME/src/config
|
||||
|
||||
ROOT := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))/../../../..)
|
||||
TOOLCHAIN_BIN := $(ROOT)/tools/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin
|
||||
PREFIX := $(if $(wildcard $(TOOLCHAIN_BIN)/arm-none-eabi-gcc),$(TOOLCHAIN_BIN)/,)arm-none-eabi-
|
||||
|
||||
CC := $(PREFIX)gcc
|
||||
AS := $(PREFIX)gcc -x assembler-with-cpp
|
||||
LD := $(PREFIX)gcc
|
||||
OBJCOPY := $(PREFIX)objcopy
|
||||
SIZE := $(PREFIX)size
|
||||
|
||||
HAL_DIR := $(ROOT)/lib/modules/STM32N6/Drivers/STM32N6xx_HAL_Driver
|
||||
CMSIS_ST := $(ROOT)/lib/modules/STM32N6/Drivers/CMSIS/Device/ST/STM32N6xx/Include
|
||||
CMSIS := $(ROOT)/lib/modules/STM32N6/Drivers/CMSIS/Include
|
||||
|
||||
INCLUDES := \
|
||||
-I. \
|
||||
-I$(HAL_DIR)/Inc \
|
||||
-I$(CMSIS_ST) \
|
||||
-I$(CMSIS)
|
||||
|
||||
# Match the betaflight main build: no -mcmse and no CPU_IN_SECURE_STATE, so
|
||||
# peripheral macros resolve to the NS (0x4xxxxxxx) aliases that the boot
|
||||
# ROM's RIFSC defaults allow. Defining CPU_IN_SECURE_STATE pulls in
|
||||
# HAL_MPU_*_NS variants that need -mcmse.
|
||||
DEFINES := \
|
||||
-DSTM32N657xx \
|
||||
-DUSE_HAL_DRIVER \
|
||||
-DHSE_VALUE=48000000
|
||||
|
||||
ARCH_FLAGS := -mthumb -mcpu=cortex-m55 -mfloat-abi=hard -mfpu=fpv5-d16
|
||||
|
||||
CFLAGS := \
|
||||
$(ARCH_FLAGS) \
|
||||
-Os -g3 \
|
||||
-ffunction-sections -fdata-sections \
|
||||
-Wall -Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-std=gnu11 \
|
||||
$(INCLUDES) $(DEFINES)
|
||||
|
||||
ASFLAGS := $(ARCH_FLAGS) -g3 $(INCLUDES) $(DEFINES)
|
||||
|
||||
LDSCRIPT := STM32N657XX_FSBL.ld
|
||||
LDFLAGS := \
|
||||
$(ARCH_FLAGS) \
|
||||
-T$(LDSCRIPT) \
|
||||
-nostartfiles \
|
||||
-specs=nano.specs -specs=nosys.specs \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,-Map=n6_fsbl.map \
|
||||
-Wl,--print-memory-usage
|
||||
|
||||
LOCAL_C_SRCS := \
|
||||
main.c \
|
||||
stm32n6xx_hal_msp.c \
|
||||
stm32n6xx_it.c \
|
||||
system_stm32n6xx_fsbl.c
|
||||
|
||||
HAL_C_SRCS := \
|
||||
stm32n6xx_hal.c \
|
||||
stm32n6xx_hal_cortex.c \
|
||||
stm32n6xx_hal_rcc.c \
|
||||
stm32n6xx_hal_rcc_ex.c \
|
||||
stm32n6xx_hal_pwr.c \
|
||||
stm32n6xx_hal_pwr_ex.c \
|
||||
stm32n6xx_hal_gpio.c \
|
||||
stm32n6xx_hal_xspi.c \
|
||||
stm32n6xx_hal_dma.c \
|
||||
stm32n6xx_hal_dma_ex.c
|
||||
|
||||
LOCAL_OBJS := $(LOCAL_C_SRCS:.c=.o) startup_stm32n657xx_fsbl.o
|
||||
HAL_OBJS := $(HAL_C_SRCS:.c=.hal.o)
|
||||
OBJS := $(LOCAL_OBJS) $(HAL_OBJS)
|
||||
|
||||
ELF := n6_fsbl.elf
|
||||
BIN := n6_fsbl.bin
|
||||
|
||||
# Override SIGNING_TOOL on the make command line if STM32CubeProgrammer's bin
|
||||
# directory isn't on $PATH, e.g.:
|
||||
# make signed SIGNING_TOOL=/path/to/STM32_SigningTool_CLI
|
||||
SIGNING_TOOL ?= STM32_SigningTool_CLI
|
||||
SIGNED_BLOB := prebuilt/n6_fsbl_signed.stm32
|
||||
|
||||
# Combined-image inputs. The signed FSBL stub + XIP-linked betaflight
|
||||
# image (linked at 0x70100000, runs in-place from XSPI). The stub brings
|
||||
# XSPI memory-mapped + jumps to 0x70100000 without copying or deinit'ing
|
||||
# the peripheral.
|
||||
CONFIG ?= STM32N657DK_DSK320
|
||||
COMBINED := prebuilt/combined.bin
|
||||
FSBL_SLOT := 1048576 # 1 MiB — XSPI offset where the BF XIP slot starts
|
||||
BF_OBJ := $(ROOT)/obj
|
||||
BF_BIN := $(BF_OBJ)/betaflight_2026.6.0-alpha_STM32N657_$(CONFIG).bin
|
||||
BF_HEX := $(BF_OBJ)/betaflight_2026.6.0-alpha_STM32N657_$(CONFIG).hex
|
||||
|
||||
.PHONY: all signed combined bf-ram bf-ram-elf clean
|
||||
all: $(BIN)
|
||||
|
||||
$(BIN): $(ELF)
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
$(SIZE) $<
|
||||
|
||||
$(ELF): $(OBJS) $(LDSCRIPT)
|
||||
$(LD) $(LDFLAGS) $(OBJS) -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.o: %.s
|
||||
$(AS) $(ASFLAGS) -c $< -o $@
|
||||
|
||||
%.hal.o: $(HAL_DIR)/Src/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Re-sign and overwrite the committed blob. Run only after verifying the
|
||||
# rebuilt stub on hardware. -t ssbl produces Binary type 0x0 in the v2.3
|
||||
# header, which is what the N6 boot ROM accepts; -t fsbl produces type
|
||||
# 0x10 and is rejected.
|
||||
signed: $(SIGNED_BLOB)
|
||||
$(SIGNED_BLOB): $(BIN) | prebuilt
|
||||
$(SIGNING_TOOL) -bin $< -nk -of 0x80000000 -t ssbl -hv 2.3 -align -o $@ -s
|
||||
|
||||
prebuilt:
|
||||
mkdir -p $@
|
||||
|
||||
# Build the betaflight XIP ELF/BIN via the main build. bf-xip-elf is phony
|
||||
# so the recursive make is always invoked (it handles its own incremental
|
||||
# dependency tracking).
|
||||
bf-xip: $(BF_BIN)
|
||||
|
||||
bf-xip-elf:
|
||||
$(MAKE) -C $(ROOT) CONFIG_DIR=$(CONFIG_DIR) CONFIG=$(CONFIG) XIP=1 binary
|
||||
|
||||
$(BF_BIN): bf-xip-elf
|
||||
|
||||
# Combined flash image: signed FSBL padded to FSBL_SLOT, then the XIP
|
||||
# betaflight image at offset 0x100000. cp --no-preserve=mode strips the
|
||||
# read-only bit on the signed source so truncate can grow it.
|
||||
combined: $(COMBINED)
|
||||
$(COMBINED): $(SIGNED_BLOB) $(BF_BIN) | prebuilt
|
||||
cp --no-preserve=mode $(SIGNED_BLOB) $@.tmp
|
||||
truncate -s $(FSBL_SLOT) $@.tmp
|
||||
cat $(BF_BIN) >> $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
# BF-as-FSBL debug variant: build the entire betaflight image with
|
||||
# BF_AS_FSBL=1 (link via STM32N657XX_FSBL_FULL.ld), sign the resulting .bin
|
||||
# with the same SSBL recipe used for the stub, and write it directly to
|
||||
# nor0 0x0 via the OpenBootloader-staged TSV. Replaces the
|
||||
# stub→XSPI-memory-map→memcpy→jump handoff for bring-up debug.
|
||||
BF_FSBL_BIN := $(BF_OBJ)/../betaflight_2026.6.0-alpha_STM32N657_$(CONFIG).bin
|
||||
BF_FSBL_SIGNED := prebuilt/bf_as_fsbl.stm32
|
||||
BF_FSBL_TSV := FlashLayout_BF_AS_FSBL.tsv
|
||||
|
||||
bf-as-fsbl: $(BF_FSBL_SIGNED)
|
||||
|
||||
bf-as-fsbl-elf:
|
||||
$(MAKE) -C $(ROOT) CONFIG=$(CONFIG) BF_AS_FSBL=1 binary
|
||||
|
||||
$(BF_FSBL_BIN): bf-as-fsbl-elf
|
||||
|
||||
$(BF_FSBL_SIGNED): $(BF_FSBL_BIN) | prebuilt
|
||||
$(SIGNING_TOOL) -bin $< -nk -of 0x80000000 -t ssbl -hv 2.3 -align -o $@ -s
|
||||
|
||||
bf-as-fsbl-flash: $(BF_FSBL_SIGNED)
|
||||
STM32_Programmer_CLI -c port=USB1 mode=HotPlug -d $(BF_FSBL_TSV)
|
||||
|
||||
.PHONY: bf-as-fsbl bf-as-fsbl-elf bf-as-fsbl-flash
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(ELF) $(BIN) n6_fsbl.map
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Linker script for the Betaflight N6570-DK FSBL stub.
|
||||
*
|
||||
* Boot ROM loads the signed FSBL into AXISRAM2 secure starting at 0x34180400
|
||||
* (the 0x400 offset matches `STM32_SigningTool_CLI -align`). All sections
|
||||
* live in this single region — the boot ROM populates .data alongside
|
||||
* .text during load, so .data LMA == VMA and the startup .data copy is a
|
||||
* no-op. 256 KiB sits within the system DFU FSBL slot's payload cap and
|
||||
* well below AXISRAM2's 1 MiB limit.
|
||||
*/
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
_Min_Stack_Size = 0x1000;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
RAM (rwx) : ORIGIN = 0x34180400, LENGTH = 256K
|
||||
}
|
||||
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_sstack = _estack - _Min_Stack_Size;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.isr_vector :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.isr_vector))
|
||||
. = ALIGN(4);
|
||||
} > RAM
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.glue_7)
|
||||
*(.glue_7t)
|
||||
*(.eh_frame)
|
||||
. = ALIGN(4);
|
||||
} > RAM
|
||||
|
||||
.rodata :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
. = ALIGN(4);
|
||||
} > RAM
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > RAM
|
||||
|
||||
.ARM :
|
||||
{
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
__exidx_end = .;
|
||||
} > RAM
|
||||
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
__bss_start__ = .;
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
|
||||
/* Reserve stack at the top of RAM. Linker fails the build if we
|
||||
* overflow into .bss. */
|
||||
._stack_reservation :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
. = . + _Min_Stack_Size;
|
||||
. = ALIGN(8);
|
||||
} > RAM
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.ARM.attributes)
|
||||
*(.comment)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* STM32N6 FSBL stub for the Betaflight N6 platform.
|
||||
*
|
||||
* Boot flow (BOOT0=USER, BOOT1=2):
|
||||
* 1. Boot ROM verifies the signed FSBL header at XSPI 0x70000000,
|
||||
* copies the payload to AXISRAM2 secure (0x34180400), branches to
|
||||
* Reset_Handler.
|
||||
* 2. Reset_Handler -> SystemInit -> .data copy / .bss zero -> main().
|
||||
* 3. main() initialises XSPI2, walks MX66UW1G45G into 1S-1S-1S
|
||||
* 4-byte addressing, engages memory-mapped mode, then jumps directly
|
||||
* to the betaflight XIP entry at 0x70100000 (vector table SP / PC
|
||||
* validated against the AXI-mapped flash window). Betaflight is
|
||||
* linked execute-in-place via STM32N657XX_XIP.ld; only initialised
|
||||
* data and explicit RAM-resident sections are copied to AXISRAM by
|
||||
* Reset_Handler. The stub leaves XSPI2 fully configured + memory-
|
||||
* mapped and does NOT deinit the peripheral before jumping.
|
||||
*
|
||||
* Signing recipe (output is committed under prebuilt/):
|
||||
*
|
||||
* STM32_SigningTool_CLI \
|
||||
* -bin n6_fsbl.bin \
|
||||
* -nk -of 0x80000000 -t ssbl -hv 2.3 -align \
|
||||
* -o prebuilt/n6_fsbl_signed.stm32 -s
|
||||
*
|
||||
* -nk : empty signature, accepted by boot ROM on dev chips.
|
||||
* -align : pad payload to start at 0x400 in the .stm32.
|
||||
* -t ssbl: emits Binary type 0x0 in the v2.3 header. -t fsbl emits
|
||||
* type 0x10 which the N6 boot ROM rejects.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#define APP_XIP_BASE 0x70100000U
|
||||
#define MX66_RETRIES 3
|
||||
/* Inter-XSPI-step delay so the MX66 leaves the controller cleanly idle
|
||||
* between commands. Empirically 250-600 ms is enough; keep generous. */
|
||||
#define SETTLE_DELAY_MS 600
|
||||
|
||||
/* MX66UW1G45G command set (1S-1S-1S, post-reset state). */
|
||||
#define MX66_CMD_RESET_ENABLE 0x66U
|
||||
#define MX66_CMD_RESET 0x99U
|
||||
/* 4-byte FAST_READ + 8 dummy cycles. Plain 0x13 4READ at 0 dummy only
|
||||
* specs to 86 MHz; the XSPI2 kernel comes out of the boot ROM faster
|
||||
* than that and 0x13 mis-samples the first data byte after the address
|
||||
* phase. 0x0C with 8 dummy cycles is reliable to 133 MHz. */
|
||||
#define MX66_CMD_READ_4B 0x0CU
|
||||
#define MX66_CMD_READ_4B_DUMMY 8U
|
||||
#define MX66_CMD_RDSR 0x05U /* Read Status Register */
|
||||
#define MX66_SR_WIP 0x01U /* Write In Progress bit */
|
||||
|
||||
XSPI_HandleTypeDef hxspi2;
|
||||
|
||||
/*
|
||||
* Poll the flash status register until the WIP bit is cleared.
|
||||
*/
|
||||
static HAL_StatusTypeDef mx66_wait_ready(uint32_t timeout_ms)
|
||||
{
|
||||
XSPI_RegularCmdTypeDef sCommand = {0};
|
||||
uint8_t status;
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
|
||||
sCommand.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
|
||||
sCommand.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
|
||||
sCommand.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
|
||||
sCommand.Instruction = MX66_CMD_RDSR;
|
||||
sCommand.DataMode = HAL_XSPI_DATA_1_LINE;
|
||||
sCommand.DataLength = 1;
|
||||
sCommand.AddressMode = HAL_XSPI_ADDRESS_NONE;
|
||||
sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
|
||||
sCommand.DummyCycles = 0;
|
||||
|
||||
do {
|
||||
if (HAL_XSPI_Command(&hxspi2, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if (HAL_XSPI_Receive(&hxspi2, &status, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if ((status & MX66_SR_WIP) == 0) {
|
||||
return HAL_OK;
|
||||
}
|
||||
} while ((HAL_GetTick() - tickstart) < timeout_ms);
|
||||
|
||||
return HAL_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Bring up XSPI2 in 1S-1S-1S 4-byte addressing mode. MSP_Init enables
|
||||
* peripheral + XSPIM + GPION clocks and configures GPIO N pins to AF11
|
||||
* (XSPIM_P2). */
|
||||
static void MX_XSPI2_Init(void)
|
||||
{
|
||||
XSPIM_CfgTypeDef sXspiManagerCfg = {0};
|
||||
|
||||
hxspi2.Instance = XSPI2;
|
||||
hxspi2.Init.FifoThresholdByte = 4;
|
||||
hxspi2.Init.MemoryMode = HAL_XSPI_SINGLE_MEM;
|
||||
hxspi2.Init.MemoryType = HAL_XSPI_MEMTYPE_MACRONIX;
|
||||
hxspi2.Init.MemorySize = HAL_XSPI_SIZE_1GB;
|
||||
hxspi2.Init.ChipSelectHighTimeCycle = 2;
|
||||
hxspi2.Init.FreeRunningClock = HAL_XSPI_FREERUNCLK_DISABLE;
|
||||
hxspi2.Init.ClockMode = HAL_XSPI_CLOCK_MODE_0;
|
||||
hxspi2.Init.WrapSize = HAL_XSPI_WRAP_NOT_SUPPORTED;
|
||||
hxspi2.Init.ClockPrescaler = 0;
|
||||
hxspi2.Init.SampleShifting = HAL_XSPI_SAMPLE_SHIFT_NONE;
|
||||
hxspi2.Init.DelayHoldQuarterCycle = HAL_XSPI_DHQC_DISABLE;
|
||||
hxspi2.Init.ChipSelectBoundary = HAL_XSPI_BONDARYOF_NONE;
|
||||
hxspi2.Init.MaxTran = 0;
|
||||
hxspi2.Init.Refresh = 0;
|
||||
hxspi2.Init.MemorySelect = HAL_XSPI_CSSEL_NCS1;
|
||||
if (HAL_XSPI_Init(&hxspi2) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
sXspiManagerCfg.nCSOverride = HAL_XSPI_CSSEL_OVR_NCS1;
|
||||
sXspiManagerCfg.IOPort = HAL_XSPIM_IOPORT_2;
|
||||
sXspiManagerCfg.Req2AckTime = 1;
|
||||
if (HAL_XSPIM_Config(&hxspi2, &sXspiManagerCfg, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a single 1S-1S-1S no-data command. */
|
||||
static HAL_StatusTypeDef mx66_cmd_1s(uint8_t opcode)
|
||||
{
|
||||
XSPI_RegularCmdTypeDef cmd = {0};
|
||||
cmd.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
|
||||
cmd.IOSelect = HAL_XSPI_SELECT_IO_7_0;
|
||||
cmd.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
|
||||
cmd.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
|
||||
cmd.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
|
||||
cmd.Instruction = opcode;
|
||||
cmd.AddressMode = HAL_XSPI_ADDRESS_NONE;
|
||||
cmd.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
|
||||
cmd.DataMode = HAL_XSPI_DATA_NONE;
|
||||
cmd.DummyCycles = 0;
|
||||
cmd.DQSMode = HAL_XSPI_DQS_DISABLE;
|
||||
return HAL_XSPI_Command(&hxspi2, &cmd, HAL_XSPI_TIMEOUT_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
/* Send a single 8-line DTR no-data command. The chip in 8D-DTR mode
|
||||
* expects a 16-bit instruction = opcode | (~opcode << 8) on all eight
|
||||
* IOs; harmless if the chip is currently in 1S mode (IO[7:1] aren't
|
||||
* being watched), required if it isn't. */
|
||||
static HAL_StatusTypeDef mx66_cmd_8dtr(uint8_t opcode)
|
||||
{
|
||||
XSPI_RegularCmdTypeDef cmd = {0};
|
||||
cmd.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
|
||||
cmd.IOSelect = HAL_XSPI_SELECT_IO_7_0;
|
||||
cmd.InstructionMode = HAL_XSPI_INSTRUCTION_8_LINES;
|
||||
cmd.InstructionWidth = HAL_XSPI_INSTRUCTION_16_BITS;
|
||||
cmd.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_ENABLE;
|
||||
cmd.Instruction = ((uint16_t)opcode << 8) | (uint8_t)(~opcode);
|
||||
cmd.AddressMode = HAL_XSPI_ADDRESS_NONE;
|
||||
cmd.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
|
||||
cmd.DataMode = HAL_XSPI_DATA_NONE;
|
||||
cmd.DummyCycles = 0;
|
||||
cmd.DQSMode = HAL_XSPI_DQS_DISABLE;
|
||||
return HAL_XSPI_Command(&hxspi2, &cmd, HAL_XSPI_TIMEOUT_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
/* Walk MX66UW1G45G to a known 1S-1S-1S state regardless of how the boot
|
||||
* ROM left it. The 8D-DTR pair drops the chip to 1S if it's there, then
|
||||
* the 1S pair issues the actual reset. Datasheet requires >= 30 us
|
||||
* between RESET and the next command. */
|
||||
static HAL_StatusTypeDef mx66_software_reset(void)
|
||||
{
|
||||
for (int i = 0; i < MX66_RETRIES; i++) {
|
||||
(void)mx66_cmd_8dtr(MX66_CMD_RESET_ENABLE);
|
||||
(void)mx66_cmd_8dtr(MX66_CMD_RESET);
|
||||
HAL_Delay(1);
|
||||
|
||||
if (mx66_cmd_1s(MX66_CMD_RESET_ENABLE) == HAL_OK) {
|
||||
if (mx66_cmd_1s(MX66_CMD_RESET) == HAL_OK) {
|
||||
HAL_Delay(1);
|
||||
return mx66_wait_ready(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
/* Latch the READ_CFG and a placeholder WRITE_CFG into the XSPI handle.
|
||||
* Both sides are required to advance the handle's state to CMD_CFG;
|
||||
* without the write side HAL_XSPI_MemoryMapped() returns
|
||||
* INVALID_SEQUENCE. The write opcode is never issued — memory-mapped
|
||||
* XSPI is read-only here — so 0x12 (4-byte PAGE PROGRAM) is just a
|
||||
* legal placeholder. */
|
||||
static HAL_StatusTypeDef xspi2_latch_read_cmd(void)
|
||||
{
|
||||
XSPI_RegularCmdTypeDef cmd = {0};
|
||||
cmd.IOSelect = HAL_XSPI_SELECT_IO_7_0;
|
||||
cmd.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
|
||||
cmd.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
|
||||
cmd.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
|
||||
cmd.AddressMode = HAL_XSPI_ADDRESS_1_LINE;
|
||||
cmd.AddressWidth = HAL_XSPI_ADDRESS_32_BITS;
|
||||
cmd.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
|
||||
cmd.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
|
||||
cmd.DataMode = HAL_XSPI_DATA_1_LINE;
|
||||
cmd.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
|
||||
cmd.DummyCycles = 0;
|
||||
cmd.DQSMode = HAL_XSPI_DQS_DISABLE;
|
||||
|
||||
cmd.OperationType = HAL_XSPI_OPTYPE_READ_CFG;
|
||||
cmd.Instruction = MX66_CMD_READ_4B; /* 4-byte FAST_READ */
|
||||
cmd.DummyCycles = MX66_CMD_READ_4B_DUMMY;
|
||||
if (HAL_XSPI_Command(&hxspi2, &cmd, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
|
||||
return HAL_ERROR;
|
||||
}
|
||||
cmd.DummyCycles = 0;
|
||||
|
||||
cmd.OperationType = HAL_XSPI_OPTYPE_WRITE_CFG;
|
||||
cmd.Instruction = 0x12U; /* 4-byte PAGE PROGRAM (placeholder) */
|
||||
return HAL_XSPI_Command(&hxspi2, &cmd, HAL_XSPI_TIMEOUT_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
static HAL_StatusTypeDef xspi2_engage_mem_mapped(void)
|
||||
{
|
||||
XSPI_MemoryMappedTypeDef memMappedCfg = {0};
|
||||
memMappedCfg.TimeOutActivation = HAL_XSPI_TIMEOUT_COUNTER_DISABLE;
|
||||
/* Disable prefetch — speculative reads against a chip in an
|
||||
* unexpected mode (e.g. still 8D-DTR while we use 1S) would stall
|
||||
* the AXI bus indefinitely. With prefetch off, stalls are bounded
|
||||
* to a single explicit CPU read. */
|
||||
memMappedCfg.NoPrefetchData = HAL_XSPI_AUTOMATIC_PREFETCH_DISABLE;
|
||||
memMappedCfg.NoPrefetchAXI = HAL_XSPI_AXI_PREFETCH_DISABLE;
|
||||
return HAL_XSPI_MemoryMapped(&hxspi2, &memMappedCfg);
|
||||
}
|
||||
|
||||
static __attribute__((noreturn)) void jump_to_app(uint32_t app_base)
|
||||
{
|
||||
const uint32_t app_sp = *(volatile uint32_t *)(app_base);
|
||||
const uint32_t app_pc = *(volatile uint32_t *)(app_base + 4U);
|
||||
|
||||
/* Sanity gate: SP must point into AXISRAM (0x2xxxxxxx). An erased flash
|
||||
* slot reads 0xFFFFFFFF and would fail this check. */
|
||||
if ((app_sp & 0xF8000000U) != 0x20000000U) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
HAL_SuspendTick();
|
||||
__disable_irq();
|
||||
|
||||
/* Leave XSPI2 fully configured + memory-mapped. The app runs XIP from
|
||||
* 0x70100000 — any DeInit / FORCE_RESET here would un-map the window
|
||||
* and the next instruction fetch would bus-fault. */
|
||||
|
||||
SCB_DisableICache();
|
||||
SCB_DisableDCache();
|
||||
|
||||
SCB->VTOR = app_base;
|
||||
__DSB();
|
||||
__ISB();
|
||||
__set_MSP(app_sp);
|
||||
/* Re-enable IRQs so the app inherits PRIMASK=0. App startup_*.s files
|
||||
* that don't call cpsie would otherwise run with interrupts masked
|
||||
* and SysTick never fires (HAL_Delay / PLL-lock waits would hang). */
|
||||
__enable_irq();
|
||||
((void (*)(void))app_pc)();
|
||||
|
||||
while (1) {
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
HAL_Init();
|
||||
|
||||
/* Leave RIFSC alone. The boot ROM has already set up master/slave
|
||||
* tagging for the OPEN-lifecycle dev path; the registers are
|
||||
* clamped immediately after that and any writes here would either
|
||||
* clobber working tagging or silently drop. */
|
||||
|
||||
MX_XSPI2_Init();
|
||||
HAL_Delay(SETTLE_DELAY_MS);
|
||||
|
||||
if (mx66_software_reset() != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
HAL_Delay(SETTLE_DELAY_MS);
|
||||
|
||||
if (xspi2_latch_read_cmd() != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
HAL_Delay(SETTLE_DELAY_MS);
|
||||
|
||||
if (xspi2_engage_mem_mapped() != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/* "STM2" little-endian = 0x324D5453. */
|
||||
if (*(volatile uint32_t *)0x70000000U != 0x324D5453U) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/* The app at APP_XIP_BASE is XIP-linked: vector table SP/PC are read
|
||||
* straight from the memory-mapped XSPI window. Validate the head of
|
||||
* the table before handing off — SP in AXISRAM (0x2xxxxxxx),
|
||||
* Reset_Handler within the 0x70100000 XIP slot with thumb bit set.
|
||||
* An erased slot reads 0xFFFFFFFF and fails the SP check. */
|
||||
const uint32_t app_sp = *(volatile uint32_t *)APP_XIP_BASE;
|
||||
const uint32_t app_pc = *(volatile uint32_t *)(APP_XIP_BASE + 4U);
|
||||
if ((app_sp & 0xF8000000U) != 0x20000000U
|
||||
|| (app_pc & 0xFFF00000U) != APP_XIP_BASE
|
||||
|| (app_pc & 1U) == 0U) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
jump_to_app(APP_XIP_BASE);
|
||||
}
|
||||
|
||||
void Error_Handler(void)
|
||||
{
|
||||
__disable_irq();
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* STM32N6 FSBL stub — public include hub.
|
||||
*
|
||||
* Mirrors ST's Template_FSBL_XIP/FSBL/Inc/main.h pattern: the HAL config
|
||||
* is the single user-visible header that pulls in the rest of the HAL via
|
||||
* stm32n6xx.h.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "stm32n6xx_hal.h"
|
||||
|
||||
void Error_Handler(void);
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* STM32N6 FSBL stub Cortex-M55 startup for the GCC toolchain.
|
||||
*
|
||||
* The boot ROM loads the entire payload (incl. .text + .data) into AXISRAM2
|
||||
* at the address in the FSBL header, so only a .data LMA->VMA copy is
|
||||
* required (no flash-to-RAM .text copy).
|
||||
*
|
||||
* .data copy and .bss zero must run BEFORE SystemInit, otherwise SystemInit
|
||||
* writes to HAL globals (uwTick, SystemCoreClock) land in uninitialised
|
||||
* memory and HAL_GetTick() reads garbage on the first HAL timeout.
|
||||
*
|
||||
* The default exception handlers are stub infinite loops. SysTick_Handler
|
||||
* is overridden by stm32n6xx_it.c which calls HAL_IncTick.
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.arch armv8.1-m.main
|
||||
.fpu softvfp
|
||||
.thumb
|
||||
|
||||
.global g_pfnVectors
|
||||
.global Default_Handler
|
||||
|
||||
/* Linker symbols used below */
|
||||
.word _sidata
|
||||
.word _sdata
|
||||
.word _edata
|
||||
.word _sbss
|
||||
.word _ebss
|
||||
|
||||
.section .text.Reset_Handler
|
||||
.weak Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
ldr r0, =_sstack
|
||||
msr MSPLIM, r0
|
||||
ldr r0, =_estack
|
||||
mov sp, r0
|
||||
|
||||
/* Copy .data from LMA (end of .text in ROM region) to VMA (RAM). */
|
||||
ldr r0, =_sdata
|
||||
ldr r1, =_edata
|
||||
ldr r2, =_sidata
|
||||
movs r3, #0
|
||||
b LoopCopyDataInit
|
||||
CopyDataInit:
|
||||
ldr r4, [r2, r3]
|
||||
str r4, [r0, r3]
|
||||
adds r3, r3, #4
|
||||
LoopCopyDataInit:
|
||||
adds r4, r0, r3
|
||||
cmp r4, r1
|
||||
bcc CopyDataInit
|
||||
|
||||
/* Zero-fill .bss. */
|
||||
ldr r2, =_sbss
|
||||
ldr r4, =_ebss
|
||||
movs r3, #0
|
||||
b LoopFillZerobss
|
||||
FillZerobss:
|
||||
str r3, [r2]
|
||||
adds r2, r2, #4
|
||||
LoopFillZerobss:
|
||||
cmp r2, r4
|
||||
bcc FillZerobss
|
||||
|
||||
bl SystemInit
|
||||
bl main
|
||||
LoopForever:
|
||||
b LoopForever
|
||||
.size Reset_Handler, .-Reset_Handler
|
||||
|
||||
.section .text.Default_Handler, "ax", %progbits
|
||||
Default_Handler:
|
||||
b Default_Handler
|
||||
.size Default_Handler, .-Default_Handler
|
||||
|
||||
/* Cortex-M55 vector table — only the system vectors are populated.
|
||||
* IRQ handlers default to Default_Handler via .weak aliases. */
|
||||
.section .isr_vector, "a", %progbits
|
||||
.type g_pfnVectors, %object
|
||||
g_pfnVectors:
|
||||
.word _estack
|
||||
.word Reset_Handler
|
||||
.word NMI_Handler
|
||||
.word HardFault_Handler
|
||||
.word MemManage_Handler
|
||||
.word BusFault_Handler
|
||||
.word UsageFault_Handler
|
||||
.word SecureFault_Handler
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word SVC_Handler
|
||||
.word DebugMon_Handler
|
||||
.word 0
|
||||
.word PendSV_Handler
|
||||
.word SysTick_Handler
|
||||
.size g_pfnVectors, .-g_pfnVectors
|
||||
|
||||
.weak NMI_Handler
|
||||
.thumb_set NMI_Handler, Default_Handler
|
||||
.weak HardFault_Handler
|
||||
.thumb_set HardFault_Handler, Default_Handler
|
||||
.weak MemManage_Handler
|
||||
.thumb_set MemManage_Handler, Default_Handler
|
||||
.weak BusFault_Handler
|
||||
.thumb_set BusFault_Handler, Default_Handler
|
||||
.weak UsageFault_Handler
|
||||
.thumb_set UsageFault_Handler, Default_Handler
|
||||
.weak SecureFault_Handler
|
||||
.thumb_set SecureFault_Handler, Default_Handler
|
||||
.weak SVC_Handler
|
||||
.thumb_set SVC_Handler, Default_Handler
|
||||
.weak DebugMon_Handler
|
||||
.thumb_set DebugMon_Handler, Default_Handler
|
||||
.weak PendSV_Handler
|
||||
.thumb_set PendSV_Handler, Default_Handler
|
||||
.weak SysTick_Handler
|
||||
.thumb_set SysTick_Handler, Default_Handler
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Trimmed HAL configuration for the FSBL stub. Only the modules required to
|
||||
* bring up XSPI2 in memory-mapped mode are enabled — anything that would
|
||||
* pull in extra .c files we don't compile stays disabled.
|
||||
*/
|
||||
|
||||
#ifndef STM32N6xx_HAL_CONF_H
|
||||
#define STM32N6xx_HAL_CONF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HAL_MODULE_ENABLED
|
||||
#define HAL_CORTEX_MODULE_ENABLED
|
||||
#define HAL_RCC_MODULE_ENABLED
|
||||
#define HAL_PWR_MODULE_ENABLED
|
||||
#define HAL_GPIO_MODULE_ENABLED
|
||||
#define HAL_DMA_MODULE_ENABLED
|
||||
#define HAL_XSPI_MODULE_ENABLED
|
||||
|
||||
#if !defined(HSE_VALUE)
|
||||
#define HSE_VALUE 48000000UL
|
||||
#endif
|
||||
#if !defined(HSE_STARTUP_TIMEOUT)
|
||||
#define HSE_STARTUP_TIMEOUT 100UL
|
||||
#endif
|
||||
#if !defined(LSE_VALUE)
|
||||
#define LSE_VALUE 32768UL
|
||||
#endif
|
||||
#if !defined(LSE_STARTUP_TIMEOUT)
|
||||
#define LSE_STARTUP_TIMEOUT 5000UL
|
||||
#endif
|
||||
#if !defined(MSI_VALUE)
|
||||
#define MSI_VALUE 4000000UL
|
||||
#endif
|
||||
#if !defined(HSI_VALUE)
|
||||
#define HSI_VALUE 64000000UL
|
||||
#endif
|
||||
#if !defined(LSI_VALUE)
|
||||
#define LSI_VALUE 32000UL
|
||||
#endif
|
||||
|
||||
#define VDD_VALUE 3300UL
|
||||
#define TICK_INT_PRIORITY 15U
|
||||
#define USE_RTOS 0U
|
||||
|
||||
#define USE_HAL_XSPI_REGISTER_CALLBACKS 0U
|
||||
#define USE_HAL_PWR_REGISTER_CALLBACKS 0U
|
||||
#define USE_SPI_CRC 0U
|
||||
|
||||
#ifdef HAL_RCC_MODULE_ENABLED
|
||||
#include "stm32n6xx_hal_rcc.h"
|
||||
#endif
|
||||
#ifdef HAL_GPIO_MODULE_ENABLED
|
||||
#include "stm32n6xx_hal_gpio.h"
|
||||
#endif
|
||||
#ifdef HAL_CORTEX_MODULE_ENABLED
|
||||
#include "stm32n6xx_hal_cortex.h"
|
||||
#endif
|
||||
#ifdef HAL_PWR_MODULE_ENABLED
|
||||
#include "stm32n6xx_hal_pwr.h"
|
||||
#endif
|
||||
#ifdef HAL_DMA_MODULE_ENABLED
|
||||
#include "stm32n6xx_hal_dma.h"
|
||||
#endif
|
||||
#ifdef HAL_XSPI_MODULE_ENABLED
|
||||
#include "stm32n6xx_hal_xspi.h"
|
||||
#endif
|
||||
|
||||
#define assert_param(expr) ((void)0U)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STM32N6xx_HAL_CONF_H */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Minimal HAL MSP for the FSBL stub. Only XSPI2's MSP is non-trivial: it
|
||||
* enables the peripheral + XSPIM + GPION clocks and configures the eleven
|
||||
* GPIO N pins for XSPIM_P2. The boot ROM already picked a working XSPI2
|
||||
* clock source; we don't reconfigure it. 1S-1S-1S READ at the boot-ROM rate
|
||||
* is sufficient for XIP and works regardless of HSLV fuse state, so no BSEC
|
||||
* read is needed.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void HAL_MspInit(void)
|
||||
{
|
||||
HAL_PWREx_EnableVddIO3();
|
||||
}
|
||||
|
||||
void HAL_XSPI_MspInit(XSPI_HandleTypeDef *hxspi)
|
||||
{
|
||||
if (hxspi->Instance != XSPI2) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
/* PWR clock is left on by the boot ROM. __HAL_RCC_PWR_CLK_ENABLE
|
||||
* lives behind CPU_IN_SECURE_STATE in stm32n6xx_hal_rcc.h, which pulls
|
||||
* in HAL_MPU_*_NS variants that require -mcmse. */
|
||||
HAL_PWREx_EnableVddIO3();
|
||||
HAL_PWREx_ConfigVddIORange(PWR_VDDIO3, PWR_VDDIO_RANGE_1V8);
|
||||
|
||||
__HAL_RCC_XSPIM_CLK_ENABLE();
|
||||
__HAL_RCC_XSPI2_CLK_ENABLE();
|
||||
__HAL_RCC_GPION_CLK_ENABLE();
|
||||
|
||||
/* PN0 -> DQS0, PN1 -> NCS1, PN2..PN5 -> IO0..IO3, PN6 -> CLK,
|
||||
* PN8..PN11 -> IO4..IO7. AF9 = XSPIM_P2 on every pin in this bank. */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
|
||||
| GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_8
|
||||
| GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF9_XSPIM_P2;
|
||||
HAL_GPIO_Init(GPION, &GPIO_InitStruct);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Interrupt handlers for the FSBL stub. Only SysTick is wired up — HAL_Init
|
||||
* starts a 1 ms tick that HAL_XSPI_Command and friends use for timeout
|
||||
* accounting. Everything else stays defaulted to the spin-loops in the
|
||||
* startup file (the FSBL doesn't enable any interrupts beyond SysTick).
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
HAL_IncTick();
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* CMSIS system file for the FSBL stub. The stub does not build with
|
||||
* -mcmse and never transitions to non-secure state, so the usual
|
||||
* TrustZone bring-up (SAU region clear, SCB_NS->CPACR, CMSE_NS_ENTRY
|
||||
* exports) is omitted.
|
||||
*/
|
||||
|
||||
#include "stm32n6xx.h"
|
||||
#include <math.h>
|
||||
|
||||
#if !defined(HSE_VALUE)
|
||||
#define HSE_VALUE 48000000UL
|
||||
#endif
|
||||
#if !defined(HSI_VALUE)
|
||||
#define HSI_VALUE 64000000UL
|
||||
#endif
|
||||
#if !defined(MSI_VALUE)
|
||||
#define MSI_VALUE 4000000UL
|
||||
#endif
|
||||
#if !defined(EXTERNAL_I2S_CLOCK_VALUE)
|
||||
#define EXTERNAL_I2S_CLOCK_VALUE 12288000UL
|
||||
#endif
|
||||
|
||||
uint32_t SystemCoreClock = HSI_VALUE;
|
||||
|
||||
extern void *g_pfnVectors;
|
||||
#define INTVECT_START ((uint32_t)&g_pfnVectors)
|
||||
|
||||
void SystemInit(void)
|
||||
{
|
||||
SCB->VTOR = INTVECT_START;
|
||||
|
||||
/* Hold the debug subsystem clock on first thing so SWD is attachable
|
||||
* even if a later init step faults. The boot ROM closes AP1 on
|
||||
* BOOT0=USER paths; DBGCLKEN reopens it on OPEN-lifecycle silicon
|
||||
* without going through Debug Authentication. DBG_SLEEP/STOP/STANDBY
|
||||
* keep the core debuggable across low-power transitions too. */
|
||||
RCC->MISCENSR = RCC_MISCENSR_DBGENS;
|
||||
(void)RCC->MISCENR;
|
||||
DBGMCU->CR |= DBGMCU_CR_DBGCLKEN
|
||||
| DBGMCU_CR_DBG_SLEEP
|
||||
| DBGMCU_CR_DBG_STOP
|
||||
| DBGMCU_CR_DBG_STANDBY;
|
||||
(void)DBGMCU->CR;
|
||||
|
||||
/* RNG reset + clock-disable. The boot ROM may have left it ticking. */
|
||||
RCC->AHB3RSTSR = RCC_AHB3RSTSR_RNGRSTS;
|
||||
RCC->AHB3RSTCR = RCC_AHB3RSTCR_RNGRSTC;
|
||||
RCC->AHB3ENCR = RCC_AHB3ENCR_RNGENC;
|
||||
|
||||
/* SYSCFG clock + VDDIOx supply rails (errata ES0620). */
|
||||
RCC->APB4ENSR2 = RCC_APB4ENSR2_SYSCFGENS;
|
||||
(void)RCC->APB4ENR2;
|
||||
|
||||
SYSCFG->INITSVTORCR = SCB->VTOR;
|
||||
|
||||
PWR->SVMCR1 |= PWR_SVMCR1_VDDIO4SV;
|
||||
PWR->SVMCR2 |= PWR_SVMCR2_VDDIO5SV;
|
||||
PWR->SVMCR3 |= PWR_SVMCR3_VDDIO2SV | PWR_SVMCR3_VDDIO3SV;
|
||||
|
||||
SYSCFG->VDDIO2CCCR = 0x00000287UL;
|
||||
SYSCFG->VDDIO3CCCR = 0x00000287UL;
|
||||
SYSCFG->VDDIO4CCCR = 0x00000287UL;
|
||||
SYSCFG->VDDIO5CCCR = 0x00000287UL;
|
||||
SYSCFG->VDDCCCR = 0x00000287UL;
|
||||
|
||||
/* VDDADC clamp + VREF buffer. */
|
||||
PWR->SVMCR3 |= PWR_SVMCR3_ASV;
|
||||
PWR->SVMCR3 |= PWR_SVMCR3_AVMEN;
|
||||
(void)PWR->SVMCR3;
|
||||
RCC->APB4ENR1 |= RCC_APB4ENR1_VREFBUFEN;
|
||||
|
||||
/* RCC fix per ST template — pulse a reserved bit to lower power. */
|
||||
RCC->APB4ENR2 |= 0x00000010UL;
|
||||
(void)RCC->APB4ENR2;
|
||||
RCC->APB4ENR2 &= ~(0x00000010UL);
|
||||
|
||||
/* Reset XSPI2 + XSPIM so we start from a known state regardless of how
|
||||
* boot ROM left them after loading us. */
|
||||
RCC->AHB5RSTSR = RCC_AHB5RSTSR_XSPIMRSTS | RCC_AHB5RSTSR_XSPI2RSTS;
|
||||
RCC->AHB5RSTCR = RCC_AHB5RSTCR_XSPIMRSTC | RCC_AHB5RSTCR_XSPI2RSTC;
|
||||
|
||||
/* TIM2 reset + clock-disable. */
|
||||
RCC->APB1RSTSR1 = RCC_APB1RSTSR1_TIM2RSTS;
|
||||
RCC->APB1RSTCR1 = RCC_APB1RSTCR1_TIM2RSTC;
|
||||
RCC->APB1ENCR1 = RCC_APB1ENCR1_TIM2ENC;
|
||||
|
||||
/* Boot ROM left GPIOG clocked; we'll re-enable in xspi MSP if needed. */
|
||||
RCC->AHB4ENCR = RCC_AHB4ENCR_GPIOGENC;
|
||||
|
||||
/* Enable AXISRAM1..6 clocks. Boot ROM only clocks AXISRAM2; the rest
|
||||
* (notably AXISRAM1 where the app's stack and .text live) must be
|
||||
* brought up here or the first store from the app's Reset_Handler
|
||||
* busfaults silently. */
|
||||
RCC->MEMENSR = RCC_MEMENSR_AXISRAM1ENS | RCC_MEMENSR_AXISRAM2ENS
|
||||
| RCC_MEMENSR_AXISRAM3ENS | RCC_MEMENSR_AXISRAM4ENS
|
||||
| RCC_MEMENSR_AXISRAM5ENS | RCC_MEMENSR_AXISRAM6ENS;
|
||||
(void)RCC->MEMENR;
|
||||
|
||||
(void)SYSCFG->INITSVTORCR;
|
||||
RCC->APB4ENCR2 = RCC_APB4ENCR2_SYSCFGENC;
|
||||
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
SCB->CPACR |= ((3UL << 20U) | (3UL << 22U)); /* CP10/CP11 full access */
|
||||
#endif
|
||||
}
|
||||
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
uint32_t sysclk = 0;
|
||||
uint32_t pllm = 0;
|
||||
uint32_t plln = 0;
|
||||
uint32_t pllfracn = 0;
|
||||
uint32_t pllp1 = 0;
|
||||
uint32_t pllp2 = 0;
|
||||
uint32_t pllcfgr;
|
||||
uint32_t pllsource = 0;
|
||||
uint32_t pllbypass = 0;
|
||||
uint32_t ic_divider;
|
||||
float_t pllvco;
|
||||
|
||||
switch (RCC->CFGR1 & RCC_CFGR1_CPUSWS) {
|
||||
case 0:
|
||||
sysclk = HSI_VALUE >> ((RCC->HSICFGR & RCC_HSICFGR_HSIDIV) >> RCC_HSICFGR_HSIDIV_Pos);
|
||||
break;
|
||||
|
||||
case RCC_CFGR1_CPUSWS_0:
|
||||
sysclk = (READ_BIT(RCC->MSICFGR, RCC_MSICFGR_MSIFREQSEL) == 0UL) ? MSI_VALUE : 16000000UL;
|
||||
break;
|
||||
|
||||
case RCC_CFGR1_CPUSWS_1:
|
||||
sysclk = HSE_VALUE;
|
||||
break;
|
||||
|
||||
case (RCC_CFGR1_CPUSWS_1 | RCC_CFGR1_CPUSWS_0):
|
||||
switch (READ_BIT(RCC->IC1CFGR, RCC_IC1CFGR_IC1SEL)) {
|
||||
case 0:
|
||||
pllcfgr = READ_REG(RCC->PLL1CFGR1);
|
||||
pllsource = pllcfgr & RCC_PLL1CFGR1_PLL1SEL;
|
||||
pllbypass = pllcfgr & RCC_PLL1CFGR1_PLL1BYP;
|
||||
if (pllbypass == 0U) {
|
||||
pllm = (pllcfgr & RCC_PLL1CFGR1_PLL1DIVM) >> RCC_PLL1CFGR1_PLL1DIVM_Pos;
|
||||
plln = (pllcfgr & RCC_PLL1CFGR1_PLL1DIVN) >> RCC_PLL1CFGR1_PLL1DIVN_Pos;
|
||||
pllfracn = READ_BIT(RCC->PLL1CFGR2, RCC_PLL1CFGR2_PLL1DIVNFRAC) >> RCC_PLL1CFGR2_PLL1DIVNFRAC_Pos;
|
||||
pllcfgr = READ_REG(RCC->PLL1CFGR3);
|
||||
pllp1 = (pllcfgr & RCC_PLL1CFGR3_PLL1PDIV1) >> RCC_PLL1CFGR3_PLL1PDIV1_Pos;
|
||||
pllp2 = (pllcfgr & RCC_PLL1CFGR3_PLL1PDIV2) >> RCC_PLL1CFGR3_PLL1PDIV2_Pos;
|
||||
}
|
||||
break;
|
||||
case RCC_IC1CFGR_IC1SEL_0:
|
||||
pllcfgr = READ_REG(RCC->PLL2CFGR1);
|
||||
pllsource = pllcfgr & RCC_PLL2CFGR1_PLL2SEL;
|
||||
pllbypass = pllcfgr & RCC_PLL2CFGR1_PLL2BYP;
|
||||
if (pllbypass == 0U) {
|
||||
pllm = (pllcfgr & RCC_PLL2CFGR1_PLL2DIVM) >> RCC_PLL2CFGR1_PLL2DIVM_Pos;
|
||||
plln = (pllcfgr & RCC_PLL2CFGR1_PLL2DIVN) >> RCC_PLL2CFGR1_PLL2DIVN_Pos;
|
||||
pllfracn = READ_BIT(RCC->PLL2CFGR2, RCC_PLL2CFGR2_PLL2DIVNFRAC) >> RCC_PLL2CFGR2_PLL2DIVNFRAC_Pos;
|
||||
pllcfgr = READ_REG(RCC->PLL2CFGR3);
|
||||
pllp1 = (pllcfgr & RCC_PLL2CFGR3_PLL2PDIV1) >> RCC_PLL2CFGR3_PLL2PDIV1_Pos;
|
||||
pllp2 = (pllcfgr & RCC_PLL2CFGR3_PLL2PDIV2) >> RCC_PLL2CFGR3_PLL2PDIV2_Pos;
|
||||
}
|
||||
break;
|
||||
case RCC_IC1CFGR_IC1SEL_1:
|
||||
pllcfgr = READ_REG(RCC->PLL3CFGR1);
|
||||
pllsource = pllcfgr & RCC_PLL3CFGR1_PLL3SEL;
|
||||
pllbypass = pllcfgr & RCC_PLL3CFGR1_PLL3BYP;
|
||||
if (pllbypass == 0U) {
|
||||
pllm = (pllcfgr & RCC_PLL3CFGR1_PLL3DIVM) >> RCC_PLL3CFGR1_PLL3DIVM_Pos;
|
||||
plln = (pllcfgr & RCC_PLL3CFGR1_PLL3DIVN) >> RCC_PLL3CFGR1_PLL3DIVN_Pos;
|
||||
pllfracn = READ_BIT(RCC->PLL3CFGR2, RCC_PLL3CFGR2_PLL3DIVNFRAC) >> RCC_PLL3CFGR2_PLL3DIVNFRAC_Pos;
|
||||
pllcfgr = READ_REG(RCC->PLL3CFGR3);
|
||||
pllp1 = (pllcfgr & RCC_PLL3CFGR3_PLL3PDIV1) >> RCC_PLL3CFGR3_PLL3PDIV1_Pos;
|
||||
pllp2 = (pllcfgr & RCC_PLL3CFGR3_PLL3PDIV2) >> RCC_PLL3CFGR3_PLL3PDIV2_Pos;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pllcfgr = READ_REG(RCC->PLL4CFGR1);
|
||||
pllsource = pllcfgr & RCC_PLL4CFGR1_PLL4SEL;
|
||||
pllbypass = pllcfgr & RCC_PLL4CFGR1_PLL4BYP;
|
||||
if (pllbypass == 0U) {
|
||||
pllm = (pllcfgr & RCC_PLL4CFGR1_PLL4DIVM) >> RCC_PLL4CFGR1_PLL4DIVM_Pos;
|
||||
plln = (pllcfgr & RCC_PLL4CFGR1_PLL4DIVN) >> RCC_PLL4CFGR1_PLL4DIVN_Pos;
|
||||
pllfracn = READ_BIT(RCC->PLL4CFGR2, RCC_PLL4CFGR2_PLL4DIVNFRAC) >> RCC_PLL4CFGR2_PLL4DIVNFRAC_Pos;
|
||||
pllcfgr = READ_REG(RCC->PLL4CFGR3);
|
||||
pllp1 = (pllcfgr & RCC_PLL4CFGR3_PLL4PDIV1) >> RCC_PLL4CFGR3_PLL4PDIV1_Pos;
|
||||
pllp2 = (pllcfgr & RCC_PLL4CFGR3_PLL4PDIV2) >> RCC_PLL4CFGR3_PLL4PDIV2_Pos;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pllsource) {
|
||||
case 0:
|
||||
sysclk = HSI_VALUE >> ((RCC->HSICFGR & RCC_HSICFGR_HSIDIV) >> RCC_HSICFGR_HSIDIV_Pos);
|
||||
break;
|
||||
case RCC_PLL1CFGR1_PLL1SEL_0:
|
||||
sysclk = (READ_BIT(RCC->MSICFGR, RCC_MSICFGR_MSIFREQSEL) == 0UL) ? MSI_VALUE : 16000000UL;
|
||||
break;
|
||||
case RCC_PLL1CFGR1_PLL1SEL_1:
|
||||
sysclk = HSE_VALUE;
|
||||
break;
|
||||
case (RCC_PLL1CFGR1_PLL1SEL_1 | RCC_PLL1CFGR1_PLL1SEL_0):
|
||||
sysclk = EXTERNAL_I2S_CLOCK_VALUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pllbypass == 0U) {
|
||||
pllvco = ((float_t)sysclk * ((float_t)plln + ((float_t)pllfracn / (float_t)0x1000000UL))) / (float_t)pllm;
|
||||
sysclk = (uint32_t)((float_t)(pllvco / (((float_t)pllp1) * ((float_t)pllp2))));
|
||||
}
|
||||
ic_divider = (READ_BIT(RCC->IC1CFGR, RCC_IC1CFGR_IC1INT) >> RCC_IC1CFGR_IC1INT_Pos) + 1UL;
|
||||
sysclk = sysclk / ic_divider;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SystemCoreClock = sysclk;
|
||||
}
|
||||
Reference in New Issue
Block a user