Skip to content

Commit eb3ea9e

Browse files
committed
stm32: Add support for STM32N6xx MCUs.
This commit adds preliminary support for ST's new STM32N6xx MCUs. Supported features of this MCU so far are: - basic clock tree initialisation, running at 800MHz - fully working USB - XSPI in memory-mapped mode - machine.Pin - machine.UART - RTC and deepsleep support - SD card - filesystem - ROMFS - WiFi and BLE via cyw43-driver (SDIO backend) Note that the N6 does not have internal flash, and has some tricky boot sequence, so using a custom bootloader (mboot) is almost a necessity. Signed-off-by: Damien George <[email protected]>
1 parent 24fd5f7 commit eb3ea9e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1659
-135
lines changed

ports/stm32/Makefile

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,15 @@ CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
123123
CFLAGS += -DMBOOT_VTOR=$(MBOOT_TEXT0_ADDR)
124124
CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR)
125125

126+
ifeq ($(MCU_SERIES),n6)
127+
ifeq ($(USE_MBOOT),1)
128+
CFLAGS += -DMICROPY_HW_RUNS_FROM_EXT_FLASH=1
129+
endif
130+
# as doesn't recognise -mcpu=cortex-m55
131+
AFLAGS += -march=armv8.1-m.main
132+
else
126133
AFLAGS += $(filter -mcpu=%,$(CFLAGS_MCU_$(MCU_SERIES)))
134+
endif
127135

128136
# Configure for nan-boxing object model if requested
129137
ifeq ($(NANBOX),1)
@@ -300,6 +308,7 @@ SRC_C += \
300308
adc.c \
301309
sdio.c \
302310
subghz.c \
311+
xspi.c \
303312
$(wildcard $(BOARD_DIR)/*.c)
304313

305314
SRC_O += \
@@ -316,6 +325,13 @@ CFLAGS += -DUSE_HAL_DRIVER
316325
SRC_O += \
317326
resethandler_m3.o \
318327
shared/runtime/gchelper_thumb2.o
328+
else ifeq ($(MCU_SERIES),n6)
329+
SRC_O += shared/runtime/gchelper_thumb2.o
330+
ifeq ($(USE_MBOOT),1)
331+
SRC_O += resethandler_iram.o
332+
else
333+
SRC_O += resethandler.o
334+
endif
319335
else
320336
SRC_O += \
321337
system_stm32.o \
@@ -329,8 +345,6 @@ HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
329345
hal_adc_ex.c \
330346
hal_cortex.c \
331347
hal_dma.c \
332-
hal_flash.c \
333-
hal_flash_ex.c \
334348
hal_gpio.c \
335349
hal_i2c.c \
336350
hal_pwr.c \
@@ -347,15 +361,30 @@ HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
347361
ll_utils.c \
348362
)
349363

350-
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7 l0 l1 l4 wb))
364+
ifneq ($(MCU_SERIES),n6)
365+
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
366+
hal_flash.c \
367+
hal_flash_ex.c \
368+
)
369+
endif
370+
371+
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7 l0 l1 l4 n6 wb))
351372
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
352373
hal_pcd.c \
353374
hal_pcd_ex.c \
354375
ll_usb.c \
355376
)
356377
endif
357378

358-
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h5 h7 l4))
379+
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),n6))
380+
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
381+
hal_bsec.c \
382+
hal_rif.c \
383+
hal_xspi.c \
384+
)
385+
endif
386+
387+
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h5 h7 l4 n6))
359388
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
360389
hal_sd.c \
361390
ll_sdmmc.c \
@@ -380,7 +409,7 @@ $(BUILD)/$(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_hal_mmc.o: CFLAGS += -Wno
380409
endif
381410
endif
382411

383-
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7))
412+
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7 n6))
384413
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
385414
hal_dma_ex.c \
386415
)
@@ -496,6 +525,12 @@ all: $(TOP)/lib/stm32lib/README.md all_main $(BUILD)/firmware.hex
496525

497526
ifeq ($(MBOOT_ENABLE_PACKING),1)
498527
all_main: $(BUILD)/firmware.pack.dfu
528+
else ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),n6))
529+
ifeq ($(USE_MBOOT),1)
530+
all_main: $(BUILD)/firmware.dfu
531+
else
532+
all_main: $(BUILD)/firmware-trusted.bin
533+
endif
499534
else
500535
all_main: $(BUILD)/firmware.dfu
501536
endif
@@ -556,7 +591,7 @@ define GENERATE_HEX
556591
$(Q)$(OBJCOPY) -O ihex $(2) $(1)
557592
endef
558593

559-
.PHONY: deploy deploy-stlink deploy-openocd
594+
.PHONY: deploy deploy-stlink deploy-openocd deploy-trusted
560595

561596
ifeq ($(MBOOT_ENABLE_PACKING),1)
562597
deploy: $(BUILD)/firmware.pack.dfu
@@ -566,6 +601,9 @@ deploy: $(BUILD)/firmware.dfu
566601
$(call RUN_DFU,$^)
567602
endif
568603

604+
deploy-trusted: $(BUILD)/firmware-trusted.bin
605+
$(STM32_CUBE_PROGRAMMER)/bin/STM32_Programmer.sh -c port=SWD mode=HOTPLUG ap=1 -el $(DKEL) -w $^ 0x70000000 -hardRst
606+
569607
# A board should specify TEXT0_ADDR if to use a different location than the
570608
# default for the firmware memory location. A board can also optionally define
571609
# TEXT1_ADDR to split the firmware into two sections; see below for details.
@@ -620,6 +658,10 @@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf
620658
$(BUILD)/firmware.elf: $(OBJ)
621659
$(call GENERATE_ELF,$@,$^)
622660

661+
$(BUILD)/firmware-trusted.bin: $(BUILD)/firmware.bin
662+
/bin/rm -f $@
663+
$(STM32_CUBE_PROGRAMMER)/bin/STM32_SigningTool_CLI -bin $^ -nk -of 0x80000000 -t fsbl -o $@ -hv $(STM32_N6_HEADER_VERSION)
664+
623665
# List of sources for qstr extraction
624666
SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SHARED_SRC_C) $(GEN_PINS_SRC)
625667

ports/stm32/adc.c

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
/// val = adc.read_core_vref() # read MCU VREF
5252

5353
/* ADC definitions */
54-
#if defined(STM32H5)
54+
#if defined(STM32H5) || defined(STM32N6)
5555
// STM32H5 features two ADC instances, ADCx and pin_adc_table are set dynamically
5656
#define PIN_ADC_MASK (PIN_ADC1 | PIN_ADC2)
5757
#else
@@ -107,7 +107,7 @@
107107
#define ADC_CAL2 ((uint16_t *)(ADC_CAL_ADDRESS + 4))
108108
#define ADC_CAL_BITS (12)
109109

110-
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L1) || defined(STM32L4) || defined(STM32WB)
110+
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L1) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
111111

112112
#define ADC_SCALE_V (((float)VREFINT_CAL_VREF) / 1000.0f)
113113
#define ADC_CAL_ADDRESS (VREFINT_CAL_ADDR)
@@ -166,6 +166,9 @@
166166
#define VBAT_DIV (3)
167167
#elif defined(STM32L152xE)
168168
// STM32L152xE does not have vbat.
169+
#elif defined(STM32N6)
170+
// ADC2 VINP 16
171+
#define VBAT_DIV (4)
169172
#else
170173
#error Unsupported processor
171174
#endif
@@ -247,7 +250,7 @@ static bool is_adcx_channel(int channel) {
247250
handle.Instance = ADCx;
248251
return __HAL_ADC_IS_CHANNEL_INTERNAL(channel)
249252
|| IS_ADC_CHANNEL(&handle, __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel));
250-
#elif defined(STM32H5)
253+
#elif defined(STM32H5) || defined(STM32N6)
251254
// The first argument to the IS_ADC_CHANNEL macro is unused.
252255
return __HAL_ADC_IS_CHANNEL_INTERNAL(channel)
253256
|| IS_ADC_CHANNEL(NULL, __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel));
@@ -260,7 +263,7 @@ static void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t ti
260263
uint32_t tickstart = HAL_GetTick();
261264
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
262265
while ((adcHandle->Instance->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
263-
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
266+
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
264267
while (READ_BIT(adcHandle->Instance->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
265268
#else
266269
#error Unsupported processor
@@ -279,7 +282,7 @@ static void adcx_clock_enable(ADC_HandleTypeDef *adch) {
279282
__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
280283
#elif defined(STM32G0)
281284
__HAL_RCC_ADC_CLK_ENABLE();
282-
#elif defined(STM32G4)
285+
#elif defined(STM32G4) || defined(STM32N6)
283286
__HAL_RCC_ADC12_CLK_ENABLE();
284287
#elif defined(STM32H5)
285288
__HAL_RCC_ADC_CLK_ENABLE();
@@ -352,6 +355,15 @@ static void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
352355
adch->Init.OversamplingMode = DISABLE;
353356
adch->Init.DataAlign = ADC_DATAALIGN_RIGHT;
354357
adch->Init.DMAContinuousRequests = DISABLE;
358+
#elif defined(STM32N6)
359+
adch->Init.GainCompensation = 0;
360+
adch->Init.ScanConvMode = ADC_SCAN_DISABLE;
361+
adch->Init.LowPowerAutoWait = DISABLE;
362+
adch->Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL;
363+
adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
364+
adch->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
365+
adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
366+
adch->Init.OversamplingMode = DISABLE;
355367
#else
356368
#error Unsupported processor
357369
#endif
@@ -384,7 +396,7 @@ static void adc_init_single(pyb_obj_adc_t *adc_obj, ADC_TypeDef *adc) {
384396
static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) {
385397
ADC_ChannelConfTypeDef sConfig;
386398

387-
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
399+
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
388400
sConfig.Rank = ADC_REGULAR_RANK_1;
389401
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel) == 0) {
390402
channel = __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel);
@@ -433,6 +445,18 @@ static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
433445
sConfig.SingleDiff = ADC_SINGLE_ENDED;
434446
sConfig.OffsetNumber = ADC_OFFSET_NONE;
435447
sConfig.Offset = 0;
448+
#elif defined(STM32N6)
449+
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
450+
sConfig.SamplingTime = ADC_SAMPLETIME_246CYCLES_5;
451+
} else {
452+
sConfig.SamplingTime = ADC_SAMPLETIME_11CYCLES_5;
453+
}
454+
sConfig.SingleDiff = ADC_SINGLE_ENDED;
455+
sConfig.OffsetNumber = ADC_OFFSET_NONE;
456+
sConfig.Offset = 0;
457+
sConfig.OffsetSignedSaturation = DISABLE;
458+
sConfig.OffsetSaturation = DISABLE;
459+
sConfig.OffsetSign = ADC_OFFSET_SIGN_POSITIVE;
436460
#else
437461
#error Unsupported processor
438462
#endif
@@ -510,7 +534,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
510534
// 1st argument is the pin name
511535
mp_obj_t pin_obj = args[0];
512536

513-
#if defined(STM32H5)
537+
#if defined(STM32H5) || defined(STM32N6)
514538
// STM32H5 has two ADC instances where some pins are only available on ADC1 or ADC2 (but not both).
515539
// Assume we're using a channel of ADC1. Can be overridden for ADC2 later in this function.
516540
ADC_TypeDef *adc = ADC1;
@@ -527,7 +551,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
527551
// No ADC function on the given pin.
528552
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Pin(%q) doesn't have ADC capabilities"), pin->name);
529553
}
530-
#if defined(STM32H5)
554+
#if defined(STM32H5) || defined(STM32N6)
531555
if ((pin->adc_num & PIN_ADC2) == PIN_ADC2) {
532556
adc = ADC2;
533557
pin_adc_table = pin_adc2;
@@ -542,7 +566,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
542566
}
543567

544568
// If this channel corresponds to a pin then configure the pin in ADC mode.
545-
#if defined(STM32H5)
569+
#if defined(STM32H5) || defined(STM32N6)
546570
if (channel < num_adc_pins) {
547571
const machine_pin_obj_t *pin = pin_adc_table[channel];
548572
if (pin != NULL) {
@@ -563,7 +587,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
563587
o->base.type = &pyb_adc_type;
564588
o->pin_name = pin_obj;
565589
o->channel = channel;
566-
#if defined(STM32H5)
590+
#if defined(STM32H5) || defined(STM32N6)
567591
adc_init_single(o, adc);
568592
#else
569593
adc_init_single(o, ADCx);
@@ -654,7 +678,7 @@ static mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
654678
// for subsequent samples we can just set the "start sample" bit
655679
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
656680
self->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
657-
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
681+
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
658682
SET_BIT(self->handle.Instance->CR, ADC_CR_ADSTART);
659683
#else
660684
#error Unsupported processor
@@ -764,7 +788,7 @@ static mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i
764788
// ADC is started: set the "start sample" bit
765789
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
766790
adc->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
767-
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
791+
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
768792
SET_BIT(adc->handle.Instance->CR, ADC_CR_ADSTART);
769793
#else
770794
#error Unsupported processor
@@ -898,6 +922,8 @@ int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
898922
} else {
899923
return 0;
900924
}
925+
#elif defined(STM32N6)
926+
int32_t raw_value = 0; // TODO
901927
#else
902928
int32_t raw_value = adc_config_and_read_ref(adcHandle, ADC_CHANNEL_TEMPSENSOR);
903929
#endif
@@ -909,6 +935,10 @@ int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
909935
static volatile float adc_refcor = 1.0f;
910936

911937
float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
938+
#if defined(STM32N6)
939+
return 0.0f; // TODO
940+
#else
941+
912942
#if defined(STM32G4) || defined(STM32L1) || defined(STM32L4)
913943
// Update the reference correction factor before reading tempsensor
914944
// because TS_CAL1 and TS_CAL2 of STM32G4,L1/L4 are at VDDA=3.0V
@@ -931,6 +961,8 @@ float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
931961
float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 80.0f;
932962
#endif
933963
return (((float)raw_value * adc_refcor - *ADC_CAL1) / core_temp_avg_slope) + 30.0f;
964+
965+
#endif
934966
}
935967

936968
float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {

ports/stm32/adc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) {
4848
adc_common = ADC_COMMON_REGISTER(0);
4949
#elif defined(STM32F7)
5050
adc_common = ADC123_COMMON;
51-
#elif defined(STM32G4) || defined(STM32H5)
51+
#elif defined(STM32G4) || defined(STM32H5) || defined(STM32N6)
5252
adc_common = ADC12_COMMON;
5353
#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
5454
adc_common = ADC12_COMMON;

ports/stm32/boardctrl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,6 @@ int boardctrl_run_boot_py(boardctrl_state_t *state);
122122
int boardctrl_run_main_py(boardctrl_state_t *state);
123123
void boardctrl_start_soft_reset(boardctrl_state_t *state);
124124
void boardctrl_end_soft_reset(boardctrl_state_t *state);
125+
void boardctrl_enter_standby(void);
125126

126127
#endif // MICROPY_INCLUDED_STM32_BOARDCTRL_H

ports/stm32/boards/common_n6_flash.ld

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* Memory layout for N6 when the application runs from external flash in XIP mode.
2+
3+
FLASH_APP .isr_vector
4+
FLASH_APP .text
5+
FLASH_APP .data
6+
7+
RAM .data
8+
RAM .bss
9+
RAM .heap
10+
RAM .stack
11+
*/
12+
13+
ENTRY(Reset_Handler)
14+
15+
REGION_ALIAS("FLASH_COMMON", FLASH_APP);
16+
17+
/* define output sections */
18+
SECTIONS
19+
{
20+
.isr_vector :
21+
{
22+
_siram = .;
23+
24+
/* This ISR is used for normal application mode. */
25+
. = ALIGN(1024);
26+
KEEP(*(.isr_vector));
27+
28+
/* This ISR is used when waking from STANDBY. */
29+
. = ALIGN(1024);
30+
KEEP(*(.rodata.iram_bootloader_isr_vector));
31+
32+
/* Need to place in RAM all the code necessary to write to
33+
* flash, and to resume from STANDBY. */
34+
*(.*.iram_bootloader_reset);
35+
*(.*.memcpy);
36+
*(.*.mp_hal_gpio_clock_enable);
37+
*(.*.mp_hal_pin_config);
38+
*(.*.mp_hal_pin_config_speed);
39+
*drivers/memory/spiflash.o(.text.* .rodata.*)
40+
*xspi.o(.text.* .rodata.*);
41+
*boards*(.rodata.spiflash_config*)
42+
*boards*(.*.board_leave_standby);
43+
*(*.rodata.pin_N*_obj);
44+
*(.text.LL_AHB4_GRP1_EnableClock);
45+
*(.text.LL_APB4_GRP2_EnableClock);
46+
47+
. = ALIGN(4);
48+
_eiram = .;
49+
} >IRAM AT> FLASH_COMMON
50+
51+
INCLUDE common_text.ld
52+
INCLUDE common_extratext_data_in_flash.ld
53+
INCLUDE common_bss_heap_stack.ld
54+
}
55+
56+
/* Used by the start-up code to initialise data */
57+
_siiram = LOADADDR(.isr_vector);

ports/stm32/boards/common_text.ld

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@
1212
. = ALIGN(4);
1313
_etext = .; /* define a global symbol at end of code */
1414
} >FLASH_COMMON
15+
16+
/* Secure Gateway stubs */
17+
.gnu.sgstubs :
18+
{
19+
. = ALIGN(4);
20+
*(.gnu.sgstubs*)
21+
. = ALIGN(4);
22+
} >FLASH_COMMON

0 commit comments

Comments
 (0)