mirror of
https://github.com/micropython/micropython.git
synced 2025-12-15 17:30:14 +01:00
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 <damien@micropython.org>
This commit is contained in:
@@ -123,7 +123,15 @@ CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
|
||||
CFLAGS += -DMBOOT_VTOR=$(MBOOT_TEXT0_ADDR)
|
||||
CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR)
|
||||
|
||||
ifeq ($(MCU_SERIES),n6)
|
||||
ifeq ($(USE_MBOOT),1)
|
||||
CFLAGS += -DMICROPY_HW_RUNS_FROM_EXT_FLASH=1
|
||||
endif
|
||||
# as doesn't recognise -mcpu=cortex-m55
|
||||
AFLAGS += -march=armv8.1-m.main
|
||||
else
|
||||
AFLAGS += $(filter -mcpu=%,$(CFLAGS_MCU_$(MCU_SERIES)))
|
||||
endif
|
||||
|
||||
# Configure for nan-boxing object model if requested
|
||||
ifeq ($(NANBOX),1)
|
||||
@@ -300,6 +308,7 @@ SRC_C += \
|
||||
adc.c \
|
||||
sdio.c \
|
||||
subghz.c \
|
||||
xspi.c \
|
||||
$(wildcard $(BOARD_DIR)/*.c)
|
||||
|
||||
SRC_O += \
|
||||
@@ -316,6 +325,13 @@ CFLAGS += -DUSE_HAL_DRIVER
|
||||
SRC_O += \
|
||||
resethandler_m3.o \
|
||||
shared/runtime/gchelper_thumb2.o
|
||||
else ifeq ($(MCU_SERIES),n6)
|
||||
SRC_O += shared/runtime/gchelper_thumb2.o
|
||||
ifeq ($(USE_MBOOT),1)
|
||||
SRC_O += resethandler_iram.o
|
||||
else
|
||||
SRC_O += resethandler.o
|
||||
endif
|
||||
else
|
||||
SRC_O += \
|
||||
system_stm32.o \
|
||||
@@ -329,8 +345,6 @@ HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
|
||||
hal_adc_ex.c \
|
||||
hal_cortex.c \
|
||||
hal_dma.c \
|
||||
hal_flash.c \
|
||||
hal_flash_ex.c \
|
||||
hal_gpio.c \
|
||||
hal_i2c.c \
|
||||
hal_pwr.c \
|
||||
@@ -347,7 +361,14 @@ HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
|
||||
ll_utils.c \
|
||||
)
|
||||
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7 l0 l1 l4 wb))
|
||||
ifneq ($(MCU_SERIES),n6)
|
||||
HAL_SRC_C += $(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 g0 g4 h5 h7 l0 l1 l4 n6 wb))
|
||||
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
|
||||
hal_pcd.c \
|
||||
hal_pcd_ex.c \
|
||||
@@ -355,7 +376,15 @@ HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
|
||||
)
|
||||
endif
|
||||
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h5 h7 l4))
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),n6))
|
||||
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
|
||||
hal_bsec.c \
|
||||
hal_rif.c \
|
||||
hal_xspi.c \
|
||||
)
|
||||
endif
|
||||
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h5 h7 l4 n6))
|
||||
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
|
||||
hal_sd.c \
|
||||
ll_sdmmc.c \
|
||||
@@ -380,7 +409,7 @@ $(BUILD)/$(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_hal_mmc.o: CFLAGS += -Wno
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7))
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7 n6))
|
||||
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
|
||||
hal_dma_ex.c \
|
||||
)
|
||||
@@ -496,6 +525,12 @@ all: $(TOP)/lib/stm32lib/README.md all_main $(BUILD)/firmware.hex
|
||||
|
||||
ifeq ($(MBOOT_ENABLE_PACKING),1)
|
||||
all_main: $(BUILD)/firmware.pack.dfu
|
||||
else ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),n6))
|
||||
ifeq ($(USE_MBOOT),1)
|
||||
all_main: $(BUILD)/firmware.dfu
|
||||
else
|
||||
all_main: $(BUILD)/firmware-trusted.bin
|
||||
endif
|
||||
else
|
||||
all_main: $(BUILD)/firmware.dfu
|
||||
endif
|
||||
@@ -556,7 +591,7 @@ define GENERATE_HEX
|
||||
$(Q)$(OBJCOPY) -O ihex $(2) $(1)
|
||||
endef
|
||||
|
||||
.PHONY: deploy deploy-stlink deploy-openocd
|
||||
.PHONY: deploy deploy-stlink deploy-openocd deploy-trusted
|
||||
|
||||
ifeq ($(MBOOT_ENABLE_PACKING),1)
|
||||
deploy: $(BUILD)/firmware.pack.dfu
|
||||
@@ -566,6 +601,9 @@ deploy: $(BUILD)/firmware.dfu
|
||||
$(call RUN_DFU,$^)
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
# A board should specify TEXT0_ADDR if to use a different location than the
|
||||
# default for the firmware memory location. A board can also optionally define
|
||||
# TEXT1_ADDR to split the firmware into two sections; see below for details.
|
||||
@@ -620,6 +658,10 @@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(call GENERATE_ELF,$@,$^)
|
||||
|
||||
$(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)
|
||||
|
||||
# List of sources for qstr extraction
|
||||
SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SHARED_SRC_C) $(GEN_PINS_SRC)
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
/// val = adc.read_core_vref() # read MCU VREF
|
||||
|
||||
/* ADC definitions */
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
// STM32H5 features two ADC instances, ADCx and pin_adc_table are set dynamically
|
||||
#define PIN_ADC_MASK (PIN_ADC1 | PIN_ADC2)
|
||||
#else
|
||||
@@ -107,7 +107,7 @@
|
||||
#define ADC_CAL2 ((uint16_t *)(ADC_CAL_ADDRESS + 4))
|
||||
#define ADC_CAL_BITS (12)
|
||||
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L1) || defined(STM32L4) || defined(STM32WB)
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L1) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
|
||||
|
||||
#define ADC_SCALE_V (((float)VREFINT_CAL_VREF) / 1000.0f)
|
||||
#define ADC_CAL_ADDRESS (VREFINT_CAL_ADDR)
|
||||
@@ -166,6 +166,9 @@
|
||||
#define VBAT_DIV (3)
|
||||
#elif defined(STM32L152xE)
|
||||
// STM32L152xE does not have vbat.
|
||||
#elif defined(STM32N6)
|
||||
// ADC2 VINP 16
|
||||
#define VBAT_DIV (4)
|
||||
#else
|
||||
#error Unsupported processor
|
||||
#endif
|
||||
@@ -247,7 +250,7 @@ static bool is_adcx_channel(int channel) {
|
||||
handle.Instance = ADCx;
|
||||
return __HAL_ADC_IS_CHANNEL_INTERNAL(channel)
|
||||
|| IS_ADC_CHANNEL(&handle, __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel));
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
// The first argument to the IS_ADC_CHANNEL macro is unused.
|
||||
return __HAL_ADC_IS_CHANNEL_INTERNAL(channel)
|
||||
|| 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
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
|
||||
while ((adcHandle->Instance->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
|
||||
while (READ_BIT(adcHandle->Instance->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
|
||||
#else
|
||||
#error Unsupported processor
|
||||
@@ -279,7 +282,7 @@ static void adcx_clock_enable(ADC_HandleTypeDef *adch) {
|
||||
__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
|
||||
#elif defined(STM32G0)
|
||||
__HAL_RCC_ADC_CLK_ENABLE();
|
||||
#elif defined(STM32G4)
|
||||
#elif defined(STM32G4) || defined(STM32N6)
|
||||
__HAL_RCC_ADC12_CLK_ENABLE();
|
||||
#elif defined(STM32H5)
|
||||
__HAL_RCC_ADC_CLK_ENABLE();
|
||||
@@ -352,6 +355,15 @@ static void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
|
||||
adch->Init.OversamplingMode = DISABLE;
|
||||
adch->Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
adch->Init.DMAContinuousRequests = DISABLE;
|
||||
#elif defined(STM32N6)
|
||||
adch->Init.GainCompensation = 0;
|
||||
adch->Init.ScanConvMode = ADC_SCAN_DISABLE;
|
||||
adch->Init.LowPowerAutoWait = DISABLE;
|
||||
adch->Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL;
|
||||
adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
|
||||
adch->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
|
||||
adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
|
||||
adch->Init.OversamplingMode = DISABLE;
|
||||
#else
|
||||
#error Unsupported processor
|
||||
#endif
|
||||
@@ -384,7 +396,7 @@ static void adc_init_single(pyb_obj_adc_t *adc_obj, ADC_TypeDef *adc) {
|
||||
static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) {
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
|
||||
sConfig.Rank = ADC_REGULAR_RANK_1;
|
||||
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel) == 0) {
|
||||
channel = __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel);
|
||||
@@ -433,6 +445,18 @@ static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
|
||||
sConfig.SingleDiff = ADC_SINGLE_ENDED;
|
||||
sConfig.OffsetNumber = ADC_OFFSET_NONE;
|
||||
sConfig.Offset = 0;
|
||||
#elif defined(STM32N6)
|
||||
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_246CYCLES_5;
|
||||
} else {
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_11CYCLES_5;
|
||||
}
|
||||
sConfig.SingleDiff = ADC_SINGLE_ENDED;
|
||||
sConfig.OffsetNumber = ADC_OFFSET_NONE;
|
||||
sConfig.Offset = 0;
|
||||
sConfig.OffsetSignedSaturation = DISABLE;
|
||||
sConfig.OffsetSaturation = DISABLE;
|
||||
sConfig.OffsetSign = ADC_OFFSET_SIGN_POSITIVE;
|
||||
#else
|
||||
#error Unsupported processor
|
||||
#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_
|
||||
// 1st argument is the pin name
|
||||
mp_obj_t pin_obj = args[0];
|
||||
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
// STM32H5 has two ADC instances where some pins are only available on ADC1 or ADC2 (but not both).
|
||||
// Assume we're using a channel of ADC1. Can be overridden for ADC2 later in this function.
|
||||
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_
|
||||
// No ADC function on the given pin.
|
||||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Pin(%q) doesn't have ADC capabilities"), pin->name);
|
||||
}
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
if ((pin->adc_num & PIN_ADC2) == PIN_ADC2) {
|
||||
adc = ADC2;
|
||||
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_
|
||||
}
|
||||
|
||||
// If this channel corresponds to a pin then configure the pin in ADC mode.
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
if (channel < num_adc_pins) {
|
||||
const machine_pin_obj_t *pin = pin_adc_table[channel];
|
||||
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_
|
||||
o->base.type = &pyb_adc_type;
|
||||
o->pin_name = pin_obj;
|
||||
o->channel = channel;
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
adc_init_single(o, adc);
|
||||
#else
|
||||
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_
|
||||
// for subsequent samples we can just set the "start sample" bit
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
|
||||
self->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
|
||||
SET_BIT(self->handle.Instance->CR, ADC_CR_ADSTART);
|
||||
#else
|
||||
#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
|
||||
// ADC is started: set the "start sample" bit
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
|
||||
adc->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
|
||||
SET_BIT(adc->handle.Instance->CR, ADC_CR_ADSTART);
|
||||
#else
|
||||
#error Unsupported processor
|
||||
@@ -898,6 +922,8 @@ int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#elif defined(STM32N6)
|
||||
int32_t raw_value = 0; // TODO
|
||||
#else
|
||||
int32_t raw_value = adc_config_and_read_ref(adcHandle, ADC_CHANNEL_TEMPSENSOR);
|
||||
#endif
|
||||
@@ -909,6 +935,10 @@ int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
|
||||
static volatile float adc_refcor = 1.0f;
|
||||
|
||||
float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
|
||||
#if defined(STM32N6)
|
||||
return 0.0f; // TODO
|
||||
#else
|
||||
|
||||
#if defined(STM32G4) || defined(STM32L1) || defined(STM32L4)
|
||||
// Update the reference correction factor before reading tempsensor
|
||||
// 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) {
|
||||
float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 80.0f;
|
||||
#endif
|
||||
return (((float)raw_value * adc_refcor - *ADC_CAL1) / core_temp_avg_slope) + 30.0f;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {
|
||||
|
||||
@@ -48,7 +48,7 @@ static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) {
|
||||
adc_common = ADC_COMMON_REGISTER(0);
|
||||
#elif defined(STM32F7)
|
||||
adc_common = ADC123_COMMON;
|
||||
#elif defined(STM32G4) || defined(STM32H5)
|
||||
#elif defined(STM32G4) || defined(STM32H5) || defined(STM32N6)
|
||||
adc_common = ADC12_COMMON;
|
||||
#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
|
||||
adc_common = ADC12_COMMON;
|
||||
|
||||
@@ -122,5 +122,6 @@ int boardctrl_run_boot_py(boardctrl_state_t *state);
|
||||
int boardctrl_run_main_py(boardctrl_state_t *state);
|
||||
void boardctrl_start_soft_reset(boardctrl_state_t *state);
|
||||
void boardctrl_end_soft_reset(boardctrl_state_t *state);
|
||||
void boardctrl_enter_standby(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_BOARDCTRL_H
|
||||
|
||||
57
ports/stm32/boards/common_n6_flash.ld
Normal file
57
ports/stm32/boards/common_n6_flash.ld
Normal file
@@ -0,0 +1,57 @@
|
||||
/* Memory layout for N6 when the application runs from external flash in XIP mode.
|
||||
|
||||
FLASH_APP .isr_vector
|
||||
FLASH_APP .text
|
||||
FLASH_APP .data
|
||||
|
||||
RAM .data
|
||||
RAM .bss
|
||||
RAM .heap
|
||||
RAM .stack
|
||||
*/
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
REGION_ALIAS("FLASH_COMMON", FLASH_APP);
|
||||
|
||||
/* define output sections */
|
||||
SECTIONS
|
||||
{
|
||||
.isr_vector :
|
||||
{
|
||||
_siram = .;
|
||||
|
||||
/* This ISR is used for normal application mode. */
|
||||
. = ALIGN(1024);
|
||||
KEEP(*(.isr_vector));
|
||||
|
||||
/* This ISR is used when waking from STANDBY. */
|
||||
. = ALIGN(1024);
|
||||
KEEP(*(.rodata.iram_bootloader_isr_vector));
|
||||
|
||||
/* Need to place in RAM all the code necessary to write to
|
||||
* flash, and to resume from STANDBY. */
|
||||
*(.*.iram_bootloader_reset);
|
||||
*(.*.memcpy);
|
||||
*(.*.mp_hal_gpio_clock_enable);
|
||||
*(.*.mp_hal_pin_config);
|
||||
*(.*.mp_hal_pin_config_speed);
|
||||
*drivers/memory/spiflash.o(.text.* .rodata.*)
|
||||
*xspi.o(.text.* .rodata.*);
|
||||
*boards*(.rodata.spiflash_config*)
|
||||
*boards*(.*.board_leave_standby);
|
||||
*(*.rodata.pin_N*_obj);
|
||||
*(.text.LL_AHB4_GRP1_EnableClock);
|
||||
*(.text.LL_APB4_GRP2_EnableClock);
|
||||
|
||||
. = ALIGN(4);
|
||||
_eiram = .;
|
||||
} >IRAM AT> FLASH_COMMON
|
||||
|
||||
INCLUDE common_text.ld
|
||||
INCLUDE common_extratext_data_in_flash.ld
|
||||
INCLUDE common_bss_heap_stack.ld
|
||||
}
|
||||
|
||||
/* Used by the start-up code to initialise data */
|
||||
_siiram = LOADADDR(.isr_vector);
|
||||
@@ -12,3 +12,11 @@
|
||||
. = ALIGN(4);
|
||||
_etext = .; /* define a global symbol at end of code */
|
||||
} >FLASH_COMMON
|
||||
|
||||
/* Secure Gateway stubs */
|
||||
.gnu.sgstubs :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.gnu.sgstubs*)
|
||||
. = ALIGN(4);
|
||||
} >FLASH_COMMON
|
||||
|
||||
@@ -293,7 +293,7 @@ def main():
|
||||
break
|
||||
|
||||
# Relax constraint on PLLQ being 48MHz on MCUs which have separate PLLs for 48MHz
|
||||
relax_pll48 = mcu_series.startswith(("stm32f413", "stm32f7", "stm32h5", "stm32h7"))
|
||||
relax_pll48 = mcu_series.startswith(("stm32f413", "stm32f7", "stm32h5", "stm32h7", "stm32n6"))
|
||||
|
||||
hse_valid_plls = compute_pll_table(hse, relax_pll48)
|
||||
if hsi is not None:
|
||||
|
||||
@@ -81,7 +81,7 @@ typedef union {
|
||||
struct _dma_descr_t {
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
|
||||
DMA_Stream_TypeDef *instance;
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
DMA_Channel_TypeDef *instance;
|
||||
#else
|
||||
#error "Unsupported Processor"
|
||||
@@ -93,7 +93,7 @@ struct _dma_descr_t {
|
||||
|
||||
// Default parameters to dma_init() shared by spi and i2c; Channel and Direction
|
||||
// vary depending on the peripheral instance so they get passed separately
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
static const DMA_InitTypeDef dma_init_struct_spi_i2c = {
|
||||
.Request = 0, // set by dma_init_handle
|
||||
.BlkHWRequest = DMA_BREQ_SINGLE_BURST,
|
||||
@@ -157,7 +157,7 @@ static const DMA_InitTypeDef dma_init_struct_i2s = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if ENABLE_SDIO && !defined(STM32H5) && !defined(STM32H7)
|
||||
#if ENABLE_SDIO && !defined(STM32H5) && !defined(STM32H7) && !defined(STM32N6)
|
||||
// Parameters to dma_init() for SDIO tx and rx.
|
||||
static const DMA_InitTypeDef dma_init_struct_sdio = {
|
||||
#if defined(STM32F4) || defined(STM32F7)
|
||||
@@ -830,6 +830,46 @@ static const uint8_t dma_irqn[NSTREAM] = {
|
||||
DMA2_Stream7_IRQn,
|
||||
};
|
||||
|
||||
#elif defined(STM32N6)
|
||||
|
||||
#define NCONTROLLERS (1)
|
||||
#define NSTREAMS_PER_CONTROLLER (16)
|
||||
#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER)
|
||||
|
||||
#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel)
|
||||
|
||||
#define DMA1_ENABLE_MASK (0xffff) // Bits in dma_enable_mask corresponding to GPDMA1
|
||||
|
||||
const dma_descr_t dma_SPI_1_RX = { GPDMA1_Channel0, GPDMA1_REQUEST_SPI1_RX, dma_id_0, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_1_TX = { GPDMA1_Channel1, GPDMA1_REQUEST_SPI1_TX, dma_id_1, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_2_RX = { GPDMA1_Channel2, GPDMA1_REQUEST_SPI2_RX, dma_id_2, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_2_TX = { GPDMA1_Channel3, GPDMA1_REQUEST_SPI2_TX, dma_id_3, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_3_RX = { GPDMA1_Channel4, GPDMA1_REQUEST_SPI3_RX, dma_id_4, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_3_TX = { GPDMA1_Channel5, GPDMA1_REQUEST_SPI3_TX, dma_id_5, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_4_RX = { GPDMA1_Channel6, GPDMA1_REQUEST_SPI4_RX, dma_id_6, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_4_TX = { GPDMA1_Channel7, GPDMA1_REQUEST_SPI4_TX, dma_id_7, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_5_RX = { GPDMA1_Channel8, GPDMA1_REQUEST_SPI5_RX, dma_id_8, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_5_TX = { GPDMA1_Channel9, GPDMA1_REQUEST_SPI5_TX, dma_id_9, &dma_init_struct_spi_i2c };
|
||||
|
||||
static const uint8_t dma_irqn[NSTREAM] = {
|
||||
GPDMA1_Channel0_IRQn,
|
||||
GPDMA1_Channel1_IRQn,
|
||||
GPDMA1_Channel2_IRQn,
|
||||
GPDMA1_Channel3_IRQn,
|
||||
GPDMA1_Channel4_IRQn,
|
||||
GPDMA1_Channel5_IRQn,
|
||||
GPDMA1_Channel6_IRQn,
|
||||
GPDMA1_Channel7_IRQn,
|
||||
GPDMA1_Channel8_IRQn,
|
||||
GPDMA1_Channel9_IRQn,
|
||||
GPDMA1_Channel10_IRQn,
|
||||
GPDMA1_Channel11_IRQn,
|
||||
GPDMA1_Channel12_IRQn,
|
||||
GPDMA1_Channel13_IRQn,
|
||||
GPDMA1_Channel14_IRQn,
|
||||
GPDMA1_Channel15_IRQn,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL};
|
||||
@@ -853,6 +893,10 @@ volatile dma_idle_count_t dma_idle;
|
||||
#define __HAL_RCC_DMA2_CLK_ENABLE __HAL_RCC_GPDMA2_CLK_ENABLE
|
||||
#define __HAL_RCC_DMA1_CLK_DISABLE __HAL_RCC_GPDMA1_CLK_DISABLE
|
||||
#define __HAL_RCC_DMA2_CLK_DISABLE __HAL_RCC_GPDMA2_CLK_DISABLE
|
||||
#elif defined(STM32N6)
|
||||
#define DMA1_IS_CLK_ENABLED() (__HAL_RCC_GPDMA1_IS_CLK_ENABLED())
|
||||
#define __HAL_RCC_DMA1_CLK_ENABLE __HAL_RCC_GPDMA1_CLK_ENABLE
|
||||
#define __HAL_RCC_DMA1_CLK_DISABLE __HAL_RCC_GPDMA1_CLK_DISABLE
|
||||
#else
|
||||
#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0)
|
||||
#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0)
|
||||
@@ -1185,10 +1229,11 @@ void DMA2_Channel8_IRQHandler(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
|
||||
#define DEFINE_IRQ_HANDLER(periph, channel, id) \
|
||||
void GPDMA##periph##_Channel##channel##_IRQHandler(void) { \
|
||||
MP_STATIC_ASSERT(GPDMA##periph##_Channel##channel##_IRQn > 0); \
|
||||
IRQ_ENTER(GPDMA##periph##_Channel##channel##_IRQn); \
|
||||
if (dma_handle[id] != NULL) { \
|
||||
HAL_DMA_IRQHandler(dma_handle[id]); \
|
||||
@@ -1204,6 +1249,7 @@ DEFINE_IRQ_HANDLER(1, 4, dma_id_4)
|
||||
DEFINE_IRQ_HANDLER(1, 5, dma_id_5)
|
||||
DEFINE_IRQ_HANDLER(1, 6, dma_id_6)
|
||||
DEFINE_IRQ_HANDLER(1, 7, dma_id_7)
|
||||
#if defined(STM32H5)
|
||||
DEFINE_IRQ_HANDLER(2, 0, dma_id_8)
|
||||
DEFINE_IRQ_HANDLER(2, 1, dma_id_9)
|
||||
DEFINE_IRQ_HANDLER(2, 2, dma_id_10)
|
||||
@@ -1212,6 +1258,16 @@ DEFINE_IRQ_HANDLER(2, 4, dma_id_12)
|
||||
DEFINE_IRQ_HANDLER(2, 5, dma_id_13)
|
||||
DEFINE_IRQ_HANDLER(2, 6, dma_id_14)
|
||||
DEFINE_IRQ_HANDLER(2, 7, dma_id_15)
|
||||
#else
|
||||
DEFINE_IRQ_HANDLER(1, 8, dma_id_8)
|
||||
DEFINE_IRQ_HANDLER(1, 9, dma_id_9)
|
||||
DEFINE_IRQ_HANDLER(1, 10, dma_id_10)
|
||||
DEFINE_IRQ_HANDLER(1, 11, dma_id_11)
|
||||
DEFINE_IRQ_HANDLER(1, 12, dma_id_12)
|
||||
DEFINE_IRQ_HANDLER(1, 13, dma_id_13)
|
||||
DEFINE_IRQ_HANDLER(1, 14, dma_id_14)
|
||||
DEFINE_IRQ_HANDLER(1, 15, dma_id_15)
|
||||
#endif
|
||||
|
||||
#elif defined(STM32L0)
|
||||
|
||||
@@ -1424,7 +1480,7 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint3
|
||||
dma->Instance = dma_descr->instance;
|
||||
dma->Init = *dma_descr->init;
|
||||
dma->Init.Direction = dir;
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
dma->Init.Request = dma_descr->sub_instance;
|
||||
#else
|
||||
#if !defined(STM32F0) && !defined(STM32L1)
|
||||
@@ -1432,7 +1488,7 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
// Configure src/dest settings based on the DMA direction.
|
||||
if (dir == DMA_MEMORY_TO_PERIPH) {
|
||||
dma->Init.SrcInc = DMA_SINC_INCREMENTED;
|
||||
@@ -1463,13 +1519,24 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir
|
||||
|
||||
dma_enable_clock(dma_id);
|
||||
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
// Always reset and configure the H7 and G0/G4/H7/L0/L4/WB/WL DMA peripheral
|
||||
// (dma->State is set to HAL_DMA_STATE_RESET by memset above)
|
||||
// TODO: understand how L0/L4 DMA works so this is not needed
|
||||
HAL_DMA_DeInit(dma);
|
||||
dma->Parent = data; // HAL_DMA_DeInit may clear Parent, so set it again
|
||||
HAL_DMA_Init(dma);
|
||||
|
||||
#if defined(STM32N6)
|
||||
// Configure security attributes.
|
||||
HAL_DMA_ConfigChannelAttributes(dma, DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC | DMA_CHANNEL_SRC_SEC | DMA_CHANNEL_DEST_SEC);
|
||||
// Configure data handling.
|
||||
DMA_DataHandlingConfTypeDef config;
|
||||
config.DataExchange = DMA_EXCHANGE_NONE;
|
||||
config.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
|
||||
HAL_DMAEx_ConfigDataHandling(dma, &config);
|
||||
#endif
|
||||
|
||||
NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA);
|
||||
#else
|
||||
// if this stream was previously configured for this channel/request and direction then we
|
||||
@@ -1740,7 +1807,7 @@ void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_a
|
||||
dma->CCR |= DMA_CCR_EN;
|
||||
}
|
||||
|
||||
#elif defined(STM32G0) || defined(STM32WB) || defined(STM32WL)
|
||||
#elif defined(STM32G0) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
|
||||
// These functions are currently not implemented or needed for this MCU.
|
||||
|
||||
|
||||
@@ -147,6 +147,19 @@ extern const dma_descr_t dma_I2C_4_RX;
|
||||
extern const dma_descr_t dma_SPI_SUBGHZ_TX;
|
||||
extern const dma_descr_t dma_SPI_SUBGHZ_RX;
|
||||
|
||||
#elif defined(STM32N6)
|
||||
|
||||
extern const dma_descr_t dma_SPI_1_RX;
|
||||
extern const dma_descr_t dma_SPI_1_TX;
|
||||
extern const dma_descr_t dma_SPI_2_RX;
|
||||
extern const dma_descr_t dma_SPI_2_TX;
|
||||
extern const dma_descr_t dma_SPI_3_RX;
|
||||
extern const dma_descr_t dma_SPI_3_TX;
|
||||
extern const dma_descr_t dma_SPI_4_RX;
|
||||
extern const dma_descr_t dma_SPI_4_TX;
|
||||
extern const dma_descr_t dma_SPI_5_RX;
|
||||
extern const dma_descr_t dma_SPI_5_TX;
|
||||
|
||||
#endif
|
||||
|
||||
// API that configures the DMA via the HAL.
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
#define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4)))
|
||||
#endif
|
||||
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
// The L4 MCU supports 40 Events/IRQs lines of the type configurable and direct.
|
||||
// Here we only support configurable line types. Details, see page 330 of RM0351, Rev 1.
|
||||
// The USB_FS_WAKUP event is a direct type and there is no support for it.
|
||||
@@ -170,7 +170,7 @@ static const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
|
||||
ADC1_COMP_IRQn,
|
||||
#endif
|
||||
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32N6) || defined(STM32H5)
|
||||
|
||||
EXTI0_IRQn,
|
||||
EXTI1_IRQn,
|
||||
@@ -189,6 +189,13 @@ static const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
|
||||
EXTI14_IRQn,
|
||||
EXTI15_IRQn,
|
||||
|
||||
#if defined(STM32N6)
|
||||
0,
|
||||
RTC_S_IRQn,
|
||||
RTC_IRQn,
|
||||
TAMP_IRQn,
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn,
|
||||
@@ -307,7 +314,7 @@ void EXTI15_10_IRQHandler(void) {
|
||||
IRQ_EXIT(EXTI15_10_IRQn);
|
||||
}
|
||||
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
|
||||
DEFINE_EXTI_IRQ_HANDLER(0)
|
||||
DEFINE_EXTI_IRQ_HANDLER(1)
|
||||
@@ -440,10 +447,10 @@ void extint_register_pin(const machine_pin_obj_t *pin, uint32_t mode, bool hard_
|
||||
#if !defined(STM32H5) && !defined(STM32WB) && !defined(STM32WL)
|
||||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||
#endif
|
||||
#if defined(STM32G0) || defined(STM32H5)
|
||||
#if defined(STM32G0) || defined(STM32H5) || defined(STM32N6)
|
||||
EXTI->EXTICR[line >> 2] =
|
||||
(EXTI->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
|
||||
| ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03)));
|
||||
(EXTI->EXTICR[line >> 2] & ~(0xff << (8 * (line & 0x03))))
|
||||
| ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (8 * (line & 0x03)));
|
||||
#else
|
||||
SYSCFG->EXTICR[line >> 2] =
|
||||
(SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
|
||||
@@ -480,13 +487,13 @@ void extint_set(const machine_pin_obj_t *pin, uint32_t mode) {
|
||||
pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin);
|
||||
|
||||
// Route the GPIO to EXTI
|
||||
#if !defined(STM32H5) && !defined(STM32WB) && !defined(STM32WL)
|
||||
#if !defined(STM32H5) && !defined(STM32N6) && !defined(STM32WB) && !defined(STM32WL)
|
||||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||
#endif
|
||||
#if defined(STM32G0) || defined(STM32H5)
|
||||
#if defined(STM32G0) || defined(STM32H5) || defined(STM32N6)
|
||||
EXTI->EXTICR[line >> 2] =
|
||||
(EXTI->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
|
||||
| ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03)));
|
||||
(EXTI->EXTICR[line >> 2] & ~(0xff << (8 * (line & 0x03))))
|
||||
| ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (8 * (line & 0x03)));
|
||||
#else
|
||||
SYSCFG->EXTICR[line >> 2] =
|
||||
(SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
|
||||
@@ -526,7 +533,7 @@ void extint_enable(uint line) {
|
||||
if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) {
|
||||
#if defined(STM32H7)
|
||||
EXTI_D1->IMR1 |= (1 << line);
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32WB) || defined(STM32WL)
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
EXTI->IMR1 |= (1 << line);
|
||||
#else
|
||||
EXTI->IMR |= (1 << line);
|
||||
@@ -534,7 +541,7 @@ void extint_enable(uint line) {
|
||||
} else {
|
||||
#if defined(STM32H7)
|
||||
EXTI_D1->EMR1 |= (1 << line);
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32WB) || defined(STM32WL)
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
EXTI->EMR1 |= (1 << line);
|
||||
#else
|
||||
EXTI->EMR |= (1 << line);
|
||||
@@ -560,7 +567,7 @@ void extint_disable(uint line) {
|
||||
#if defined(STM32H7)
|
||||
EXTI_D1->IMR1 &= ~(1 << line);
|
||||
EXTI_D1->EMR1 &= ~(1 << line);
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32WB) || defined(STM32WL)
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
EXTI->IMR1 &= ~(1 << line);
|
||||
EXTI->EMR1 &= ~(1 << line);
|
||||
#else
|
||||
@@ -582,7 +589,7 @@ void extint_swint(uint line) {
|
||||
return;
|
||||
}
|
||||
// we need 0 to 1 transition to trigger the interrupt
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
EXTI->SWIER1 &= ~(1 << line);
|
||||
EXTI->SWIER1 |= (1 << line);
|
||||
#else
|
||||
@@ -662,7 +669,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint);
|
||||
static mp_obj_t extint_regs(void) {
|
||||
const mp_print_t *print = &mp_plat_print;
|
||||
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
mp_printf(print, "EXTI_IMR1 %08x\n", (unsigned int)EXTI->IMR1);
|
||||
mp_printf(print, "EXTI_IMR2 %08x\n", (unsigned int)EXTI->IMR2);
|
||||
mp_printf(print, "EXTI_EMR1 %08x\n", (unsigned int)EXTI->EMR1);
|
||||
@@ -673,7 +680,7 @@ static mp_obj_t extint_regs(void) {
|
||||
mp_printf(print, "EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2);
|
||||
mp_printf(print, "EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1);
|
||||
mp_printf(print, "EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2);
|
||||
#if defined(STM32G0) || defined(STM32H5)
|
||||
#if defined(STM32G0) || defined(STM32N6) || defined(STM32H5)
|
||||
mp_printf(print, "EXTI_RPR1 %08x\n", (unsigned int)EXTI->RPR1);
|
||||
mp_printf(print, "EXTI_FPR1 %08x\n", (unsigned int)EXTI->FPR1);
|
||||
mp_printf(print, "EXTI_RPR2 %08x\n", (unsigned int)EXTI->RPR2);
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
#if defined(STM32F0) || defined(STM32G4) || defined(STM32L1) || defined(STM32L4) || defined(STM32WL)
|
||||
#define EXTI_RTC_TIMESTAMP (19)
|
||||
#define EXTI_RTC_WAKEUP (20)
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
#define EXTI_RTC_WAKEUP (17)
|
||||
#define EXTI_RTC_TAMP (19)
|
||||
#elif defined(STM32H7) || defined(STM32WB)
|
||||
@@ -55,8 +55,6 @@
|
||||
#elif defined(STM32G0)
|
||||
#define EXTI_RTC_WAKEUP (19)
|
||||
#define EXTI_RTC_TIMESTAMP (21)
|
||||
#elif defined(STM32H5)
|
||||
#define EXTI_RTC_WAKEUP (17)
|
||||
#else
|
||||
#define EXTI_RTC_TIMESTAMP (21)
|
||||
#define EXTI_RTC_WAKEUP (22)
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "py/mphal.h"
|
||||
#include "flash.h"
|
||||
|
||||
#if !defined(STM32N6)
|
||||
|
||||
#if defined(STM32F0)
|
||||
|
||||
#define FLASH_FLAG_ALL_ERRORS (FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR)
|
||||
@@ -509,3 +511,5 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
|
||||
|
||||
return mp_hal_status_to_neg_errno(status);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -51,6 +51,16 @@ static inline void i2c_slave_init(i2c_slave_t *i2c, int irqn, int irq_pri, int a
|
||||
RCC->APB1LENR |= 1 << (RCC_APB1LENR_I2C1EN_Pos + i2c_idx);
|
||||
volatile uint32_t tmp = RCC->APB1LENR; // Delay after enabling clock
|
||||
(void)tmp;
|
||||
#elif defined(STM32N6)
|
||||
if (i2c_idx == 3) {
|
||||
RCC->APB4ENR1 |= RCC_APB4ENR1_I2C4EN;
|
||||
volatile uint32_t tmp = RCC->APB4ENR1; // Delay after enabling clock
|
||||
(void)tmp;
|
||||
} else {
|
||||
RCC->APB1ENR1 |= 1 << (RCC_APB1ENR1_I2C1EN_Pos + i2c_idx);
|
||||
volatile uint32_t tmp = RCC->APB1ENR1; // Delay after enabling clock
|
||||
(void)tmp;
|
||||
}
|
||||
#elif defined(STM32WB)
|
||||
RCC->APB1ENR1 |= 1 << (RCC_APB1ENR1_I2C1EN_Pos + i2c_idx);
|
||||
volatile uint32_t tmp = RCC->APB1ENR1; // Delay after enabling clock
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "py/mphal.h"
|
||||
#include "adc.h"
|
||||
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
#define ADC_V2 (1)
|
||||
#else
|
||||
#define ADC_V2 (0)
|
||||
@@ -85,6 +85,9 @@
|
||||
#elif defined(STM32L4) || defined(STM32WB)
|
||||
#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_12CYCLES_5
|
||||
#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_247CYCLES_5
|
||||
#elif defined(STM32N6)
|
||||
#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_11CYCLES_5
|
||||
#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_246CYCLES_5
|
||||
#endif
|
||||
|
||||
// Timeout for waiting for end-of-conversion
|
||||
@@ -127,6 +130,8 @@ static uint32_t adc_ll_channel(uint32_t channel_id) {
|
||||
case MACHINE_ADC_INT_CH_TEMPSENSOR:
|
||||
#if defined(STM32G4)
|
||||
adc_ll_ch = ADC_CHANNEL_TEMPSENSOR_ADC1;
|
||||
#elif defined(STM32N6)
|
||||
adc_ll_ch = ADC_CHANNEL_0; // TODO
|
||||
#else
|
||||
adc_ll_ch = ADC_CHANNEL_TEMPSENSOR;
|
||||
#endif
|
||||
@@ -183,7 +188,7 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) {
|
||||
if (adc == ADC1) {
|
||||
#if defined(STM32H5)
|
||||
__HAL_RCC_ADC_CLK_ENABLE();
|
||||
#elif defined(STM32G4) || defined(STM32H7)
|
||||
#elif defined(STM32G4) || defined(STM32H7) || defined(STM32N6)
|
||||
__HAL_RCC_ADC12_CLK_ENABLE();
|
||||
#else
|
||||
__HAL_RCC_ADC1_CLK_ENABLE();
|
||||
@@ -193,7 +198,7 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) {
|
||||
if (adc == ADC2) {
|
||||
#if defined(STM32H5)
|
||||
__HAL_RCC_ADC_CLK_ENABLE();
|
||||
#elif defined(STM32G4) || defined(STM32H7)
|
||||
#elif defined(STM32G4) || defined(STM32H7) || defined(STM32N6)
|
||||
__HAL_RCC_ADC12_CLK_ENABLE();
|
||||
#else
|
||||
__HAL_RCC_ADC2_CLK_ENABLE();
|
||||
@@ -233,7 +238,7 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) {
|
||||
ADC_COMMON->CCR = 0 << ADC_CCR_PRESC_Pos; // PRESC=1
|
||||
#endif
|
||||
|
||||
#if defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
#if defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
|
||||
if (adc->CR & ADC_CR_DEEPPWD) {
|
||||
adc->CR = 0; // disable deep powerdown
|
||||
}
|
||||
@@ -257,6 +262,11 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) {
|
||||
LL_ADC_StartCalibration(adc);
|
||||
#elif defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32WB)
|
||||
LL_ADC_StartCalibration(adc, LL_ADC_SINGLE_ENDED);
|
||||
#elif defined(STM32N6)
|
||||
ADC_HandleTypeDef hadc;
|
||||
hadc.Instance = adc;
|
||||
hadc.State = 0;
|
||||
HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);
|
||||
#else
|
||||
LL_ADC_StartCalibration(adc, LL_ADC_CALIB_OFFSET_LINEARITY, LL_ADC_SINGLE_ENDED);
|
||||
#endif
|
||||
@@ -312,11 +322,17 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) {
|
||||
uint32_t cfgr = res << ADC_CFGR_RES_Pos;
|
||||
adc->CFGR = (adc->CFGR & ~cfgr_clr) | cfgr;
|
||||
|
||||
#elif defined(STM32N6)
|
||||
|
||||
uint32_t cfgr1_clr = ADC_CFGR1_CONT | ADC_CFGR1_EXTEN;
|
||||
uint32_t cfgr1 = res << ADC_CFGR1_RES_Pos;
|
||||
adc->CFGR1 = (adc->CFGR1 & ~cfgr1_clr) | cfgr1;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static int adc_get_bits(ADC_TypeDef *adc) {
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32L0) || defined(STM32WL)
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32L0) || defined(STM32N6) || defined(STM32WL)
|
||||
uint32_t res = (adc->CFGR1 & ADC_CFGR1_RES) >> ADC_CFGR1_RES_Pos;
|
||||
#elif defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
|
||||
uint32_t res = (adc->CR1 & ADC_CR1_RES) >> ADC_CR1_RES_Pos;
|
||||
@@ -412,9 +428,9 @@ static void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp
|
||||
}
|
||||
*smpr = (*smpr & ~(7 << (channel * 3))) | sample_time << (channel * 3); // select sample time
|
||||
|
||||
#elif defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
#elif defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
|
||||
|
||||
#if defined(STM32G4) || defined(STM32H5) || defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
|
||||
#if defined(STM32G4) || defined(STM32H5) || defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) || defined(STM32N6)
|
||||
ADC_Common_TypeDef *adc_common = ADC12_COMMON;
|
||||
#elif defined(STM32H7)
|
||||
#if defined(ADC_VER_V5_V90)
|
||||
@@ -432,6 +448,7 @@ static void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp
|
||||
#endif
|
||||
if (channel == ADC_CHANNEL_VREFINT) {
|
||||
adc_common->CCR |= ADC_CCR_VREFEN;
|
||||
#if !defined(STM32N6)
|
||||
#if defined(STM32G4)
|
||||
} else if (channel == ADC_CHANNEL_TEMPSENSOR_ADC1) {
|
||||
adc_common->CCR |= ADC_CCR_VSENSESEL;
|
||||
@@ -440,18 +457,19 @@ static void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp
|
||||
adc_common->CCR |= ADC_CCR_TSEN;
|
||||
#endif
|
||||
adc_stabilisation_delay_us(ADC_TEMPSENSOR_DELAY_US);
|
||||
#endif
|
||||
} else if (channel == ADC_CHANNEL_VBAT) {
|
||||
#if defined(STM32G4)
|
||||
adc_common->CCR |= ADC_CCR_VBATSEL;
|
||||
#else
|
||||
adc_common->CCR |= ADC_CCR_VBATEN;
|
||||
#endif
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
} else if (channel == ADC_CHANNEL_VDDCORE) {
|
||||
adc->OR |= ADC_OR_OP0; // Enable Vddcore channel on ADC2
|
||||
#endif
|
||||
}
|
||||
#if defined(STM32G4) || defined(STM32H5) || defined(STM32WB)
|
||||
#if defined(STM32G4) || defined(STM32H5) || defined(STM32N6) || defined(STM32WB)
|
||||
// MCU uses encoded literals for internal channels -> extract ADC channel for following code
|
||||
if (__LL_ADC_IS_CHANNEL_INTERNAL(channel)) {
|
||||
channel = __LL_ADC_CHANNEL_TO_DECIMAL_NB(channel);
|
||||
|
||||
@@ -399,7 +399,7 @@ static bool mp_machine_uart_txdone(machine_uart_obj_t *self) {
|
||||
|
||||
// Send a break condition.
|
||||
static void mp_machine_uart_sendbreak(machine_uart_obj_t *self) {
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
self->uartx->RQR = USART_RQR_SBKRQ; // write-only register
|
||||
#else
|
||||
self->uartx->CR1 |= USART_CR1_SBK;
|
||||
|
||||
@@ -306,11 +306,30 @@ static bool init_sdcard_fs(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STM32N6)
|
||||
static void risaf_init(void) {
|
||||
RIMC_MasterConfig_t rimc_master = {0};
|
||||
|
||||
__HAL_RCC_RIFSC_CLK_ENABLE();
|
||||
LL_AHB3_GRP1_EnableClockLowPower(LL_AHB3_GRP1_PERIPH_RIFSC | LL_AHB3_GRP1_PERIPH_RISAF);
|
||||
|
||||
rimc_master.MasterCID = RIF_CID_1;
|
||||
rimc_master.SecPriv = RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV;
|
||||
|
||||
HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_SDMMC1, &rimc_master);
|
||||
HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_SDMMC1, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
|
||||
HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_SDMMC2, &rimc_master);
|
||||
HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_SDMMC2, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
|
||||
}
|
||||
#endif
|
||||
|
||||
void stm32_main(uint32_t reset_mode) {
|
||||
// Low-level MCU initialisation.
|
||||
stm32_system_init();
|
||||
|
||||
#if !defined(STM32F0)
|
||||
// Set VTOR, the location of the interrupt vector table.
|
||||
// On N6, SystemInit does this, setting VTOR to &g_pfnVectors.
|
||||
#if !defined(STM32F0) && !defined(STM32N6)
|
||||
#if MICROPY_HW_ENABLE_ISR_UART_FLASH_FUNCS_IN_RAM
|
||||
// Copy IRQ vector table to RAM and point VTOR there
|
||||
extern uint32_t __isr_vector_flash_addr, __isr_vector_ram_start, __isr_vector_ram_end;
|
||||
@@ -325,8 +344,7 @@ void stm32_main(uint32_t reset_mode) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#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
|
||||
@@ -349,7 +367,7 @@ void stm32_main(uint32_t reset_mode) {
|
||||
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
|
||||
#endif
|
||||
|
||||
#elif defined(STM32F7) || defined(STM32H7)
|
||||
#elif defined(STM32F7) || defined(STM32H7) || defined(STM32N6)
|
||||
|
||||
#if ART_ACCLERATOR_ENABLE
|
||||
__HAL_FLASH_ART_ENABLE();
|
||||
@@ -376,6 +394,23 @@ void stm32_main(uint32_t reset_mode) {
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(STM32N6)
|
||||
// SRAM, XSPI needs to remain awake during sleep, eg so DMA from flash works.
|
||||
LL_MEM_EnableClockLowPower(0xffffffff);
|
||||
LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_XSPI2 | LL_AHB5_GRP1_PERIPH_XSPIM);
|
||||
LL_APB4_GRP1_EnableClock(LL_APB4_GRP1_PERIPH_RTC | LL_APB4_GRP1_PERIPH_RTCAPB);
|
||||
LL_APB4_GRP1_EnableClockLowPower(LL_APB4_GRP1_PERIPH_RTC | LL_APB4_GRP1_PERIPH_RTCAPB);
|
||||
|
||||
// Enable some AHB peripherals during sleep.
|
||||
LL_AHB1_GRP1_EnableClockLowPower(0xffffffff); // GPDMA1, ADC12
|
||||
LL_AHB4_GRP1_EnableClockLowPower(0xffffffff); // GPIOA-Q, PWR, CRC
|
||||
|
||||
// Enable some APB peripherals during sleep.
|
||||
LL_APB1_GRP1_EnableClockLowPower(0xffffffff); // I2C, I3C, LPTIM, SPI, TIM, UART, WWDG
|
||||
LL_APB2_GRP1_EnableClockLowPower(0xffffffff); // SAI, SPI, TIM, UART
|
||||
LL_APB4_GRP1_EnableClockLowPower(0xffffffff); // I2C, LPTIM, LPUART, RTC, SPI
|
||||
#endif
|
||||
|
||||
mpu_init();
|
||||
|
||||
#if __CORTEX_M >= 0x03
|
||||
@@ -389,6 +424,10 @@ void stm32_main(uint32_t reset_mode) {
|
||||
// set the system clock to be HSE
|
||||
SystemClock_Config();
|
||||
|
||||
#if defined(STM32N6)
|
||||
risaf_init();
|
||||
#endif
|
||||
|
||||
#if defined(STM32F4) || defined(STM32F7)
|
||||
#if defined(__HAL_RCC_DTCMRAMEN_CLK_ENABLE)
|
||||
// The STM32F746 doesn't really have CCM memory, but it does have DTCM,
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
#define RCC_CSR_PORRSTF RCC_CSR_PWRRSTF
|
||||
#endif
|
||||
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
#define RCC_SR RSR
|
||||
#define RCC_SR_IWDGRSTF RCC_RSR_IWDGRSTF
|
||||
#define RCC_SR_WWDGRSTF RCC_RSR_WWDGRSTF
|
||||
@@ -135,7 +135,7 @@ void machine_init(void) {
|
||||
reset_cause = PYB_RESET_DEEPSLEEP;
|
||||
PWR->PMCR |= PWR_PMCR_CSSF;
|
||||
} else
|
||||
#elif defined(STM32H7)
|
||||
#elif defined(STM32H7) || defined(STM32N6)
|
||||
if (PWR->CPUCR & PWR_CPUCR_SBF || PWR->CPUCR & PWR_CPUCR_STOPF) {
|
||||
// came out of standby or stop mode
|
||||
reset_cause = PYB_RESET_DEEPSLEEP;
|
||||
@@ -323,6 +323,19 @@ MP_NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args) {
|
||||
|
||||
// get or set the MCU frequencies
|
||||
static mp_obj_t mp_machine_get_freq(void) {
|
||||
#if defined(STM32N6)
|
||||
LL_RCC_ClocksTypeDef clocks;
|
||||
LL_RCC_GetSystemClocksFreq(&clocks);
|
||||
mp_obj_t tuple[] = {
|
||||
mp_obj_new_int(clocks.CPUCLK_Frequency),
|
||||
mp_obj_new_int(clocks.SYSCLK_Frequency),
|
||||
mp_obj_new_int(clocks.HCLK_Frequency),
|
||||
mp_obj_new_int(clocks.PCLK1_Frequency),
|
||||
mp_obj_new_int(clocks.PCLK2_Frequency),
|
||||
mp_obj_new_int(clocks.PCLK4_Frequency),
|
||||
mp_obj_new_int(clocks.PCLK5_Frequency),
|
||||
};
|
||||
#else
|
||||
mp_obj_t tuple[] = {
|
||||
mp_obj_new_int(HAL_RCC_GetSysClockFreq()),
|
||||
mp_obj_new_int(HAL_RCC_GetHCLKFreq()),
|
||||
@@ -331,11 +344,12 @@ static mp_obj_t mp_machine_get_freq(void) {
|
||||
mp_obj_new_int(HAL_RCC_GetPCLK2Freq()),
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple);
|
||||
}
|
||||
|
||||
static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) {
|
||||
#if defined(STM32F0) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32G0)
|
||||
#if defined(STM32F0) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32G0) || defined(STM32N6)
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("machine.freq set not supported yet"));
|
||||
#else
|
||||
mp_int_t sysclk = mp_obj_get_int(args[0]);
|
||||
|
||||
@@ -64,8 +64,12 @@
|
||||
|
||||
// Whether machine.bootloader() will enter the bootloader via reset, or direct jump.
|
||||
#ifndef MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
|
||||
#if defined(STM32N6)
|
||||
#define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (0)
|
||||
#else
|
||||
#define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Whether to enable ROMFS on the internal flash.
|
||||
#ifndef MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH
|
||||
@@ -77,6 +81,11 @@
|
||||
#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable ROMFS on external XSPI flash.
|
||||
#ifndef MICROPY_HW_ROMFS_ENABLE_EXTERNAL_XSPI
|
||||
#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_XSPI (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable ROMFS partition 0.
|
||||
#ifndef MICROPY_HW_ROMFS_ENABLE_PART0
|
||||
#define MICROPY_HW_ROMFS_ENABLE_PART0 (0)
|
||||
@@ -465,6 +474,16 @@
|
||||
#define MICROPY_HW_MAX_UART (5)
|
||||
#define MICROPY_HW_MAX_LPUART (1)
|
||||
|
||||
// Configuration for STM32N6 series
|
||||
#elif defined(STM32N6)
|
||||
|
||||
#define MP_HAL_UNIQUE_ID_ADDRESS (UID_BASE)
|
||||
#define PYB_EXTI_NUM_VECTORS (20) // only EXTI[15:0], RTC and TAMP currently supported
|
||||
#define MICROPY_HW_MAX_I2C (4)
|
||||
#define MICROPY_HW_MAX_TIMER (18)
|
||||
#define MICROPY_HW_MAX_UART (10)
|
||||
#define MICROPY_HW_MAX_LPUART (1)
|
||||
|
||||
// Configuration for STM32WB series
|
||||
#elif defined(STM32WB)
|
||||
|
||||
@@ -589,8 +608,16 @@
|
||||
(op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(MICROPY_HW_BDEV_SPIFLASH, (op), (uint32_t)MICROPY_HW_BDEV_SPIFLASH_CONFIG) : \
|
||||
spi_bdev_ioctl(MICROPY_HW_BDEV_SPIFLASH, (op), (arg)) \
|
||||
)
|
||||
#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(MICROPY_HW_BDEV_SPIFLASH, (dest), (bl), (n))
|
||||
#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(MICROPY_HW_BDEV_SPIFLASH, (src), (bl), (n))
|
||||
#ifndef MICROPY_HW_BDEV_SPIFLASH_OFFSET_BYTES
|
||||
#define MICROPY_HW_BDEV_SPIFLASH_OFFSET_BYTES (0)
|
||||
#endif
|
||||
#define MICROPY_HW_BDEV_SPIFLASH_OFFSET_BLOCKS (MICROPY_HW_BDEV_SPIFLASH_OFFSET_BYTES / FLASH_BLOCK_SIZE)
|
||||
#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(MICROPY_HW_BDEV_SPIFLASH, (dest), MICROPY_HW_BDEV_SPIFLASH_OFFSET_BLOCKS + (bl), (n))
|
||||
#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(MICROPY_HW_BDEV_SPIFLASH, (src), MICROPY_HW_BDEV_SPIFLASH_OFFSET_BLOCKS + (bl), (n))
|
||||
#endif
|
||||
|
||||
#if defined(STM32N6)
|
||||
#define MICROPY_FATFS_MAX_SS (4096)
|
||||
#endif
|
||||
|
||||
// Whether to enable caching for external SPI flash, to allow block writes that are
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
#define MICROPY_SCHEDULER_DEPTH (8)
|
||||
#define MICROPY_VFS (1)
|
||||
#ifndef MICROPY_VFS_ROM
|
||||
#define MICROPY_VFS_ROM (MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH || MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI)
|
||||
#define MICROPY_VFS_ROM (MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH || MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI || MICROPY_HW_ROMFS_ENABLE_EXTERNAL_XSPI)
|
||||
#endif
|
||||
|
||||
// control over Python builtins
|
||||
|
||||
@@ -105,7 +105,7 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) {
|
||||
#elif defined(STM32F4) || defined(STM32F7)
|
||||
#define AHBxENR AHB1ENR
|
||||
#define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos
|
||||
#elif defined(STM32H7)
|
||||
#elif defined(STM32H7) || defined(STM32N6)
|
||||
#define AHBxENR AHB4ENR
|
||||
#define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos
|
||||
#elif defined(STM32L0)
|
||||
|
||||
@@ -137,18 +137,26 @@ static inline void mpu_config_end(uint32_t irq_state) {
|
||||
enable_irq(irq_state);
|
||||
}
|
||||
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
|
||||
#define MPU_REGION_SIG (MPU_REGION_NUMBER0)
|
||||
#define MPU_REGION_ETH (MPU_REGION_NUMBER1)
|
||||
#define MPU_REGION_LAST_USED (MPU_REGION_NUMBER1)
|
||||
#define MPU_REGION_DMA_UNCACHED_1 (MPU_REGION_NUMBER2)
|
||||
#define MPU_REGION_DMA_UNCACHED_2 (MPU_REGION_NUMBER3)
|
||||
#define MPU_REGION_LAST_USED (MPU_REGION_NUMBER3)
|
||||
|
||||
#define ST_DEVICE_SIGNATURE_BASE (0x08fff800)
|
||||
#define ST_DEVICE_SIGNATURE_LIMIT (0x08ffffff)
|
||||
|
||||
// STM32H5 Cortex-M33 MPU works differently from older cores.
|
||||
// Macro only takes region size in bytes, Attributes are coded in mpu_config_region().
|
||||
#define MPU_CONFIG_DISABLE (0)
|
||||
#define MPU_CONFIG_ETH(size) (size)
|
||||
#define MPU_CONFIG_UNCACHED(size) (size)
|
||||
|
||||
#if defined(STM32N6)
|
||||
#define MPU_REGION_SIZE_32B (32)
|
||||
#endif
|
||||
|
||||
static inline void mpu_init(void) {
|
||||
// Configure attribute 0, inner-outer non-cacheable (=0x44).
|
||||
@@ -180,8 +188,12 @@ static inline uint32_t mpu_config_start(void) {
|
||||
}
|
||||
|
||||
static inline void mpu_config_region(uint32_t region, uint32_t base_addr, uint32_t size) {
|
||||
if (region == MPU_REGION_ETH) {
|
||||
// Configure region 1 to make DMA memory non-cacheable.
|
||||
if (size == 0) {
|
||||
// Disable MPU for this region.
|
||||
MPU->RNR = region;
|
||||
MPU->RLAR &= ~MPU_RLAR_EN_Msk;
|
||||
} else if (region == MPU_REGION_ETH || region == MPU_REGION_DMA_UNCACHED_1 || region == MPU_REGION_DMA_UNCACHED_2) {
|
||||
// Configure region to make DMA memory non-cacheable.
|
||||
|
||||
__DMB();
|
||||
// Configure attribute 1, inner-outer non-cacheable (=0x44).
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "boardctrl.h"
|
||||
#include "powerctrl.h"
|
||||
#include "rtc.h"
|
||||
#include "extmod/modbluetooth.h"
|
||||
#include "py/mpconfig.h"
|
||||
#ifndef NO_QSTR
|
||||
#include "genhdr/pllfreqtable.h"
|
||||
#endif
|
||||
@@ -46,7 +46,7 @@ static uint32_t __attribute__((unused)) micropy_hw_hse_value = HSE_VALUE;
|
||||
static uint32_t __attribute__((unused)) micropy_hw_clk_pllm = MICROPY_HW_CLK_PLLM;
|
||||
#endif
|
||||
|
||||
#if defined(STM32H5) || defined(STM32H7)
|
||||
#if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
|
||||
#define RCC_SR RSR
|
||||
#if defined(STM32H747xx)
|
||||
#define RCC_SR_SFTRSTF RCC_RSR_SFT2RSTF
|
||||
@@ -63,7 +63,7 @@ static uint32_t __attribute__((unused)) micropy_hw_clk_pllm = MICROPY_HW_CLK_PLL
|
||||
#define POWERCTRL_GET_VOLTAGE_SCALING() PWR_REGULATOR_VOLTAGE_SCALE0
|
||||
#elif defined(STM32H723xx)
|
||||
#define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling()
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
#define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling()
|
||||
#else
|
||||
#define POWERCTRL_GET_VOLTAGE_SCALING() \
|
||||
@@ -136,6 +136,12 @@ MP_NORETURN static __attribute__((naked)) void branch_to_bootloader(uint32_t r0,
|
||||
}
|
||||
|
||||
MP_NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
|
||||
#if defined(STM32N6)
|
||||
LL_PWR_EnableBkUpAccess();
|
||||
TAMP_S->BKP31R = r0;
|
||||
NVIC_SystemReset();
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
|
||||
|
||||
// Enter the bootloader via a reset, so everything is reset (including WDT).
|
||||
@@ -169,6 +175,8 @@ void powerctrl_check_enter_bootloader(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(STM32N6)
|
||||
|
||||
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB) && !defined(STM32WL)
|
||||
|
||||
typedef struct _sysclk_scaling_table_entry_t {
|
||||
@@ -781,6 +789,8 @@ static void powerctrl_low_power_exit_wb55() {
|
||||
|
||||
#endif // !defined(STM32F0) && !defined(STM32G0) && !defined(STM32L0) && !defined(STM32L1) && !defined(STM32L4)
|
||||
|
||||
#endif
|
||||
|
||||
void powerctrl_enter_stop_mode(void) {
|
||||
// Disable IRQs so that the IRQ that wakes the device from stop mode is not
|
||||
// executed until after the clocks are reconfigured
|
||||
@@ -809,7 +819,7 @@ void powerctrl_enter_stop_mode(void) {
|
||||
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
|
||||
#endif
|
||||
|
||||
#if !defined(STM32F0) && !defined(STM32G0) && !defined(STM32G4) && !defined(STM32L0) && !defined(STM32L1) && !defined(STM32L4) && !defined(STM32WB) && !defined(STM32WL)
|
||||
#if !defined(STM32F0) && !defined(STM32G0) && !defined(STM32G4) && !defined(STM32L0) && !defined(STM32L1) && !defined(STM32L4) && !defined(STM32N6) && !defined(STM32WB) && !defined(STM32WL)
|
||||
// takes longer to wake but reduces stop current
|
||||
HAL_PWREx_EnableFlashPowerDown();
|
||||
#endif
|
||||
@@ -848,6 +858,8 @@ void powerctrl_enter_stop_mode(void) {
|
||||
|
||||
#if defined(STM32F7)
|
||||
HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI);
|
||||
#elif defined(STM32N6)
|
||||
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
|
||||
#else
|
||||
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
|
||||
#endif
|
||||
@@ -912,6 +924,19 @@ void powerctrl_enter_stop_mode(void) {
|
||||
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) {
|
||||
}
|
||||
|
||||
#elif defined(STM32N6)
|
||||
|
||||
// Enable PLL1, and switch the CPU and system clock source to use PLL1.
|
||||
LL_RCC_PLL1_Enable();
|
||||
while (!LL_RCC_PLL1_IsReady()) {
|
||||
}
|
||||
LL_RCC_SetCpuClkSource(LL_RCC_CPU_CLKSOURCE_IC1);
|
||||
while (LL_RCC_GetCpuClkSource() != LL_RCC_CPU_CLKSOURCE_STATUS_IC1) {
|
||||
}
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_IC2_IC6_IC11);
|
||||
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_IC2_IC6_IC11) {
|
||||
}
|
||||
|
||||
#else // defined(STM32H5)
|
||||
|
||||
// enable PLL
|
||||
@@ -1016,9 +1041,47 @@ void powerctrl_enter_stop_mode(void) {
|
||||
enable_irq(irq_state);
|
||||
}
|
||||
|
||||
#if defined(STM32N6)
|
||||
|
||||
// Upon wake from standby, STM32N6 can resume execution from retained SRAM1.
|
||||
// Place a small bootloader there which initialises XSPI in memory-mapped mode
|
||||
// and jumps to the main application entry point.
|
||||
|
||||
#include "xspi.h"
|
||||
|
||||
extern uint32_t _estack;
|
||||
|
||||
void Reset_Handler(void);
|
||||
|
||||
void iram_bootloader_reset(void) {
|
||||
#if defined(MICROPY_BOARD_LEAVE_STANDBY)
|
||||
MICROPY_BOARD_LEAVE_STANDBY;
|
||||
#endif
|
||||
xspi_init();
|
||||
Reset_Handler();
|
||||
}
|
||||
|
||||
// Very simple ARM vector table.
|
||||
const uint32_t iram_bootloader_isr_vector[] = {
|
||||
(uint32_t)&_estack,
|
||||
(uint32_t)&iram_bootloader_reset,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
MP_NORETURN void powerctrl_enter_standby_mode(void) {
|
||||
rtc_init_finalise();
|
||||
|
||||
#if defined(STM32N6)
|
||||
// Upon wake from standby, jump to the code at SRAM1.
|
||||
// A board can reconfigure this in MICROPY_BOARD_ENTER_STANDBY if needed.
|
||||
LL_PWR_EnableTCMSBRetention();
|
||||
LL_PWR_EnableTCMFLXSBRetention();
|
||||
LL_APB4_GRP2_EnableClock(LL_APB4_GRP2_PERIPH_SYSCFG);
|
||||
SCB_CleanDCache();
|
||||
SYSCFG->INITSVTORCR = (uint32_t)&iram_bootloader_isr_vector[0];
|
||||
#endif
|
||||
|
||||
#if defined(MICROPY_BOARD_ENTER_STANDBY)
|
||||
MICROPY_BOARD_ENTER_STANDBY
|
||||
#endif
|
||||
@@ -1039,6 +1102,13 @@ MP_NORETURN void powerctrl_enter_standby_mode(void) {
|
||||
mp_bluetooth_deinit();
|
||||
#endif
|
||||
|
||||
#if defined(STM32N6)
|
||||
|
||||
// Clear all WKUPx flags.
|
||||
LL_PWR_ClearFlag_WU();
|
||||
|
||||
#else
|
||||
|
||||
// We need to clear the PWR wake-up-flag before entering standby, since
|
||||
// the flag may have been set by a previous wake-up event. Furthermore,
|
||||
// we need to disable the wake-up sources while clearing this flag, so
|
||||
@@ -1135,6 +1205,8 @@ MP_NORETURN void powerctrl_enter_standby_mode(void) {
|
||||
powerctrl_low_power_prep_wb55();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// enter standby mode
|
||||
HAL_PWR_EnterSTANDBYMode();
|
||||
|
||||
|
||||
@@ -34,6 +34,12 @@ void stm32_system_init(void);
|
||||
#else
|
||||
static inline void stm32_system_init(void) {
|
||||
SystemInit();
|
||||
|
||||
#if defined(STM32N6)
|
||||
// The ROM bootloader uses PLL1 to set the CPU to 400MHz, so update
|
||||
// the value of SystemCoreClock to reflect the hardware state.
|
||||
SystemCoreClockUpdate();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -47,9 +47,15 @@ void stm32_system_init(void) {
|
||||
#endif
|
||||
|
||||
void powerctrl_config_systick(void) {
|
||||
#if defined(STM32N6)
|
||||
uint32_t systick_source_freq = HAL_RCC_GetCpuClockFreq();
|
||||
#else
|
||||
uint32_t systick_source_freq = HAL_RCC_GetHCLKFreq();
|
||||
#endif
|
||||
|
||||
// Configure SYSTICK to run at 1kHz (1ms interval)
|
||||
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
|
||||
SysTick_Config(HAL_RCC_GetHCLKFreq() / 1000);
|
||||
SysTick_Config(systick_source_freq / 1000);
|
||||
NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK);
|
||||
|
||||
#if !BUILDING_MBOOT && (defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB))
|
||||
@@ -410,6 +416,124 @@ void SystemClock_Config(void) {
|
||||
DBGMCU->CR &= ~(DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STOP | DBGMCU_CR_DBG_STANDBY);
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(STM32N6)
|
||||
|
||||
void SystemClock_Config(void) {
|
||||
// Enable HSI.
|
||||
LL_RCC_HSI_Enable();
|
||||
while (!LL_RCC_HSI_IsReady()) {
|
||||
}
|
||||
|
||||
// Switch the CPU clock source to HSI.
|
||||
LL_RCC_SetCpuClkSource(LL_RCC_CPU_CLKSOURCE_HSI);
|
||||
while (LL_RCC_GetCpuClkSource() != LL_RCC_CPU_CLKSOURCE_STATUS_HSI) {
|
||||
}
|
||||
|
||||
// Switch the system clock source to HSI.
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
|
||||
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) {
|
||||
}
|
||||
|
||||
// Disable all ICx clocks.
|
||||
RCC->DIVENCR = 0x000fffff;
|
||||
|
||||
// This doesn't work, VOSRDY never becomes active.
|
||||
#if 0
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE0);
|
||||
while (!LL_PWR_IsActiveFlag_VOSRDY()) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Enable HSE.
|
||||
LL_RCC_HSE_Enable();
|
||||
while (!LL_RCC_HSE_IsReady()) {
|
||||
}
|
||||
|
||||
// Disable PLL1.
|
||||
LL_RCC_PLL1_Disable();
|
||||
while (LL_RCC_PLL1_IsReady()) {
|
||||
}
|
||||
|
||||
// Configure PLL1 for use as system clock.
|
||||
LL_RCC_PLL1_SetSource(LL_RCC_PLLSOURCE_HSE);
|
||||
LL_RCC_PLL1_DisableBypass();
|
||||
LL_RCC_PLL1_DisableFractionalModulationSpreadSpectrum();
|
||||
LL_RCC_PLL1_SetM(MICROPY_HW_CLK_PLLM);
|
||||
LL_RCC_PLL1_SetN(MICROPY_HW_CLK_PLLN);
|
||||
LL_RCC_PLL1_SetP1(MICROPY_HW_CLK_PLLP1);
|
||||
LL_RCC_PLL1_SetP2(MICROPY_HW_CLK_PLLP2);
|
||||
LL_RCC_PLL1_SetFRACN(MICROPY_HW_CLK_PLLFRAC);
|
||||
LL_RCC_PLL1P_Enable();
|
||||
|
||||
// Enable PLL1.
|
||||
LL_RCC_PLL1_Enable();
|
||||
while (!LL_RCC_PLL1_IsReady()) {
|
||||
}
|
||||
|
||||
// Configure IC1, IC2, IC6, IC11.
|
||||
LL_RCC_IC1_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
|
||||
LL_RCC_IC1_SetDivider(1);
|
||||
LL_RCC_IC1_Enable();
|
||||
LL_RCC_IC2_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
|
||||
LL_RCC_IC2_SetDivider(2);
|
||||
LL_RCC_IC2_Enable();
|
||||
LL_RCC_IC6_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
|
||||
LL_RCC_IC6_SetDivider(1);
|
||||
LL_RCC_IC6_Enable();
|
||||
LL_RCC_IC11_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
|
||||
LL_RCC_IC11_SetDivider(1);
|
||||
LL_RCC_IC11_Enable();
|
||||
|
||||
// Configure IC14 at 100MHz for slower peripherals.
|
||||
LL_RCC_IC14_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
|
||||
LL_RCC_IC14_SetDivider(8);
|
||||
LL_RCC_IC14_Enable();
|
||||
|
||||
// Enable buses.
|
||||
LL_BUS_EnableClock(LL_APB5 | LL_APB4 | LL_APB3 | LL_APB2 | LL_APB1 | LL_AHB5 | LL_AHB4 | LL_AHB3 | LL_AHB2 | LL_AHB1);
|
||||
LL_MISC_EnableClock(LL_PER);
|
||||
|
||||
// Configure bus dividers.
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2);
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
|
||||
LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_1);
|
||||
LL_RCC_SetAPB5Prescaler(LL_RCC_APB5_DIV_1);
|
||||
|
||||
// Switch the CPU clock source to IC1 (connected to PLL1).
|
||||
LL_RCC_SetCpuClkSource(LL_RCC_CPU_CLKSOURCE_IC1);
|
||||
while (LL_RCC_GetCpuClkSource() != LL_RCC_CPU_CLKSOURCE_STATUS_IC1) {
|
||||
}
|
||||
|
||||
// Switch the system clock source to IC2/IC6/IC11 (connected to PLL1).
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_IC2_IC6_IC11);
|
||||
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_IC2_IC6_IC11) {
|
||||
}
|
||||
|
||||
// ADC clock configuration, HCLK/2.
|
||||
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_HCLK);
|
||||
LL_RCC_SetADCPrescaler(2 - 1);
|
||||
|
||||
// USB clock configuration.
|
||||
#if MICROPY_HW_ENABLE_USB
|
||||
|
||||
// Select HSE/2 as output of direct HSE signal.
|
||||
LL_RCC_HSE_SelectHSEDiv2AsDiv2Clock();
|
||||
|
||||
// Select HSE/2 for OTG1 clock source.
|
||||
LL_RCC_SetClockSource(LL_RCC_OTGPHY1_CLKSOURCE_HSE_DIV_2_OSC);
|
||||
LL_RCC_SetClockSource(LL_RCC_OTGPHY1CKREF_CLKSOURCE_HSE_DIV_2_OSC);
|
||||
LL_RCC_SetOTGPHYClockSource(LL_RCC_OTGPHY1_CLKSOURCE_HSE_DIV_2_OSC);
|
||||
LL_RCC_SetOTGPHYCKREFClockSource(LL_RCC_OTGPHY1CKREF_CLKSOURCE_HSE_DIV_2_OSC);
|
||||
|
||||
#endif
|
||||
|
||||
// Reconfigure clock state and SysTick.
|
||||
SystemCoreClockUpdate();
|
||||
powerctrl_config_systick();
|
||||
}
|
||||
|
||||
#elif defined(STM32WB)
|
||||
|
||||
void SystemClock_Config(void) {
|
||||
|
||||
82
ports/stm32/resethandler_iram.s
Normal file
82
ports/stm32/resethandler_iram.s
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018-2025 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m4
|
||||
.thumb
|
||||
|
||||
.section .text.Reset_Handler
|
||||
.global Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
|
||||
Reset_Handler:
|
||||
/* Save the first argument to pass through to stm32_main */
|
||||
mov r4, r0
|
||||
|
||||
/* Load the stack pointer */
|
||||
ldr sp, =_estack
|
||||
|
||||
/* Initialise the iram section */
|
||||
ldr r1, =_siiram
|
||||
ldr r2, =_siram
|
||||
ldr r3, =_eiram
|
||||
b .iram_copy_entry
|
||||
nop
|
||||
.iram_copy_loop:
|
||||
ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
|
||||
str r0, [r2], #4
|
||||
.iram_copy_entry:
|
||||
cmp r2, r3
|
||||
bcc .iram_copy_loop
|
||||
|
||||
/* Initialise the data section */
|
||||
ldr r1, =_sidata
|
||||
ldr r2, =_sdata
|
||||
ldr r3, =_edata
|
||||
b .data_copy_entry
|
||||
.data_copy_loop:
|
||||
ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
|
||||
str r0, [r2], #4
|
||||
.data_copy_entry:
|
||||
cmp r2, r3
|
||||
bcc .data_copy_loop
|
||||
|
||||
/* Zero out the BSS section */
|
||||
movs r0, #0
|
||||
ldr r1, =_sbss
|
||||
ldr r2, =_ebss
|
||||
b .bss_zero_entry
|
||||
.bss_zero_loop:
|
||||
str r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
|
||||
.bss_zero_entry:
|
||||
cmp r1, r2
|
||||
bcc .bss_zero_loop
|
||||
|
||||
/* Jump to the main code */
|
||||
mov r0, r4
|
||||
b stm32_main
|
||||
|
||||
.size Reset_Handler, .-Reset_Handler
|
||||
@@ -100,6 +100,10 @@ static bool rtc_need_init_finalise = false;
|
||||
#define RCC_BDCR_LSEBYP RCC_CSR_LSEBYP
|
||||
#endif
|
||||
|
||||
#if defined(STM32N6)
|
||||
#define RCC_DBP_TIMEOUT_VALUE (5)
|
||||
#endif
|
||||
|
||||
void rtc_init_start(bool force_init) {
|
||||
// Enable the RTC APB bus clock, to communicate with the RTC.
|
||||
#if defined(STM32H5)
|
||||
@@ -129,6 +133,32 @@ void rtc_init_start(bool force_init) {
|
||||
|
||||
if (!force_init) {
|
||||
bool rtc_running = false;
|
||||
#if defined(STM32N6)
|
||||
if (LL_RCC_IsEnabledRTC()
|
||||
&& LL_RCC_GetRTCClockSource() == LL_RCC_RTC_CLKSOURCE_LSE
|
||||
&& LL_RCC_LSE_IsReady()) {
|
||||
// LSE is enabled & ready --> no need to (re-)init RTC
|
||||
rtc_running = true;
|
||||
// remove Backup Domain write protection
|
||||
HAL_PWR_EnableBkUpAccess();
|
||||
// Clear source Reset Flag
|
||||
__HAL_RCC_CLEAR_RESET_FLAGS();
|
||||
// provide some status information
|
||||
rtc_info |= 0x40000;
|
||||
} else if (LL_RCC_IsEnabledRTC()
|
||||
&& LL_RCC_GetRTCClockSource() == LL_RCC_RTC_CLKSOURCE_LSI) {
|
||||
// LSI configured as the RTC clock source --> no need to (re-)init RTC
|
||||
rtc_running = true;
|
||||
// remove Backup Domain write protection
|
||||
HAL_PWR_EnableBkUpAccess();
|
||||
// Clear source Reset Flag
|
||||
__HAL_RCC_CLEAR_RESET_FLAGS();
|
||||
// Turn the LSI on (it may need this even if the RTC is running)
|
||||
LL_RCC_LSI_Enable();
|
||||
// provide some status information
|
||||
rtc_info |= 0x80000;
|
||||
}
|
||||
#else
|
||||
uint32_t bdcr = RCC->BDCR;
|
||||
if ((bdcr & (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL | RCC_BDCR_LSEON | RCC_BDCR_LSERDY))
|
||||
== (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_0 | RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) {
|
||||
@@ -157,6 +187,7 @@ void rtc_init_start(bool force_init) {
|
||||
// provide some status information
|
||||
rtc_info |= 0x80000;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rtc_running) {
|
||||
// Provide information about the registers that indicated the RTC is running.
|
||||
@@ -296,7 +327,7 @@ static HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct
|
||||
return HAL_TIMEOUT;
|
||||
}
|
||||
}
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
// Wait for Backup domain Write protection disable
|
||||
while (!LL_PWR_IsEnabledBkUpAccess()) {
|
||||
if (HAL_GetTick() - tickstart > RCC_DBP_TIMEOUT_VALUE) {
|
||||
@@ -381,7 +412,7 @@ static HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) {
|
||||
#elif defined(STM32F7)
|
||||
hrtc->Instance->OR &= (uint32_t) ~RTC_OR_ALARMTYPE;
|
||||
hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32WL)
|
||||
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32N6) || defined(STM32WL)
|
||||
hrtc->Instance->CR &= (uint32_t) ~RTC_CR_TAMPALRM_TYPE_Msk;
|
||||
hrtc->Instance->CR |= (uint32_t)(hrtc->Init.OutPutType);
|
||||
#else
|
||||
@@ -413,7 +444,14 @@ static void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse, bool
|
||||
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct;
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
|
||||
#if defined(STM32N6)
|
||||
RCC_OscInitStruct.PLL1.PLLState = RCC_PLL_NONE;
|
||||
RCC_OscInitStruct.PLL2.PLLState = RCC_PLL_NONE;
|
||||
RCC_OscInitStruct.PLL3.PLLState = RCC_PLL_NONE;
|
||||
RCC_OscInitStruct.PLL4.PLLState = RCC_PLL_NONE;
|
||||
#else
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
|
||||
#endif
|
||||
#if MICROPY_HW_RTC_USE_BYPASS
|
||||
if (rtc_use_byp) {
|
||||
RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS;
|
||||
@@ -651,6 +689,8 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime
|
||||
#define RTC_WKUP_IRQn RTC_IRQn
|
||||
#elif defined(STM32G0)
|
||||
#define RTC_WKUP_IRQn RTC_TAMP_IRQn
|
||||
#elif defined(STM32N6)
|
||||
#define RTC_WKUP_IRQn RTC_S_IRQn
|
||||
#endif
|
||||
|
||||
// wakeup(None)
|
||||
@@ -759,8 +799,9 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
EXTI->IMR1 |= 1 << EXTI_RTC_WAKEUP;
|
||||
EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP;
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
EXTI->IMR1 |= 1 << EXTI_RTC_WAKEUP;
|
||||
EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP;
|
||||
#elif defined(STM32H7)
|
||||
EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP;
|
||||
EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP;
|
||||
@@ -772,8 +813,8 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
|
||||
// clear interrupt flags
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32WL)
|
||||
RTC->ICSR &= ~RTC_ICSR_WUTWF;
|
||||
#elif defined(STM32H5)
|
||||
RTC->SCR = RTC_SCR_CWUTF;
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
LL_RTC_ClearFlag_WUT(RTC);
|
||||
#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
|
||||
RTC->SR &= ~RTC_SR_WUTF;
|
||||
#else
|
||||
@@ -783,7 +824,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
|
||||
EXTI->PR1 = 1 << EXTI_RTC_WAKEUP;
|
||||
#elif defined(STM32H7)
|
||||
EXTI_D1->PR1 = 1 << EXTI_RTC_WAKEUP;
|
||||
#elif defined(STM32G0) || defined(STM32H5)
|
||||
#elif defined(STM32G0) || defined(STM32H5) || defined(STM32N6)
|
||||
// Do nothing
|
||||
#else
|
||||
EXTI->PR = 1 << EXTI_RTC_WAKEUP;
|
||||
@@ -799,7 +840,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
|
||||
RTC->WPR = 0xff;
|
||||
|
||||
// disable external interrupts on line EXTI_RTC_WAKEUP
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
EXTI->IMR1 &= ~(1 << EXTI_RTC_WAKEUP);
|
||||
#elif defined(STM32H7)
|
||||
EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
#if MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD
|
||||
|
||||
#if defined(STM32F7) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4)
|
||||
#if defined(STM32F7) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6)
|
||||
|
||||
// The H7/F7/L4 have 2 SDMMC peripherals, but at the moment this driver only supports
|
||||
// using one of them in a given build, selected by MICROPY_HW_SDCARD_SDMMC.
|
||||
@@ -104,7 +104,7 @@
|
||||
#define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE
|
||||
#define SDIO_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_HARDWARE_FLOW_CONTROL_ENABLE
|
||||
|
||||
#if defined(STM32H5) || defined(STM32H7)
|
||||
#if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
|
||||
#define SDIO_TRANSFER_CLK_DIV SDMMC_NSpeed_CLK_DIV
|
||||
#define SDIO_USE_GPDMA 0
|
||||
#else
|
||||
@@ -214,7 +214,7 @@ static void sdmmc_msp_init(void) {
|
||||
// enable SDIO clock
|
||||
SDMMC_CLK_ENABLE();
|
||||
|
||||
#if defined(STM32H7)
|
||||
#if defined(STM32H7) || defined(STM32N6)
|
||||
// Reset SDMMC
|
||||
SDMMC_FORCE_RESET();
|
||||
SDMMC_RELEASE_RESET();
|
||||
@@ -270,7 +270,7 @@ static HAL_StatusTypeDef sdmmc_init_sd(void) {
|
||||
// SD device interface configuration
|
||||
sdmmc_handle.sd.Instance = SDIO;
|
||||
sdmmc_handle.sd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
|
||||
#if !defined(STM32H5) && !defined(STM32H7)
|
||||
#if !defined(STM32H5) && !defined(STM32H7) && !defined(STM32N6)
|
||||
sdmmc_handle.sd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
|
||||
#endif
|
||||
sdmmc_handle.sd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE;
|
||||
|
||||
@@ -77,7 +77,11 @@ static volatile uint8_t *sdmmc_buf_top;
|
||||
#define SDMMC_IRQHandler SDMMC2_IRQHandler
|
||||
#define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC2_CLK_ENABLE()
|
||||
#define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC2_CLK_DISABLE()
|
||||
#if defined(STM32N6)
|
||||
#define SDMMC_IS_CLK_DISABLED() (!__HAL_RCC_SDMMC2_IS_CLK_ENABLED())
|
||||
#else
|
||||
#define SDMMC_IS_CLK_DISABLED() __HAL_RCC_SDMMC2_IS_CLK_DISABLED()
|
||||
#endif
|
||||
#define STATIC_AF_SDMMC_CK STATIC_AF_SDMMC2_CK
|
||||
#define STATIC_AF_SDMMC_CMD STATIC_AF_SDMMC2_CMD
|
||||
#define STATIC_AF_SDMMC_D0 STATIC_AF_SDMMC2_D0
|
||||
@@ -96,9 +100,17 @@ static volatile uint8_t *sdmmc_buf_top;
|
||||
#define MICROPY_HW_SDIO_CMD (pin_D2)
|
||||
#endif
|
||||
|
||||
#if defined(STM32H7)
|
||||
#if defined(STM32H7) || defined(STM32N6)
|
||||
static uint32_t safe_divide(uint32_t denom) {
|
||||
#if defined(STM32N6)
|
||||
#if MICROPY_HW_SDIO_SDMMC == 1
|
||||
uint32_t num = LL_RCC_GetSDMMCClockFreq(LL_RCC_SDMMC1_CLKSOURCE);
|
||||
#else
|
||||
uint32_t num = LL_RCC_GetSDMMCClockFreq(LL_RCC_SDMMC2_CLKSOURCE);
|
||||
#endif
|
||||
#else
|
||||
uint32_t num = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC);
|
||||
#endif
|
||||
uint32_t divres;
|
||||
|
||||
divres = num / (2U * denom);
|
||||
@@ -119,11 +131,15 @@ void sdio_init(uint32_t irq_pri) {
|
||||
mp_hal_pin_config_alt_static(MICROPY_HW_SDIO_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_CMD);
|
||||
|
||||
SDMMC_CLK_ENABLE(); // enable SDIO peripheral
|
||||
#if defined(STM32N6)
|
||||
LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_SDMMC1);
|
||||
LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_SDMMC2);
|
||||
#endif
|
||||
|
||||
SDMMC_TypeDef *SDIO = SDMMC;
|
||||
#if defined(STM32F7)
|
||||
SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | (120 - 2); // 1-bit, 400kHz
|
||||
#elif defined(STM32H7)
|
||||
#elif defined(STM32H7) || defined(STM32N6)
|
||||
SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | safe_divide(400000U); // 1-bit, 400kHz
|
||||
#else
|
||||
SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | (120 / 2); // 1-bit, 400kHz
|
||||
@@ -172,7 +188,7 @@ void sdio_enable_high_speed_4bit(void) {
|
||||
mp_hal_delay_us(10);
|
||||
#if defined(STM32F7)
|
||||
SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_WIDBUS_0 | SDMMC_CLKCR_BYPASS /*| SDMMC_CLKCR_PWRSAV*/; // 4-bit, 48MHz
|
||||
#elif defined(STM32H7)
|
||||
#elif defined(STM32H7) || defined(STM32N6)
|
||||
SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_WIDBUS_0 | safe_divide(48000000U); // 4-bit, 48MHz
|
||||
#else
|
||||
SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_WIDBUS_0; // 4-bit, 48MHz
|
||||
@@ -199,7 +215,7 @@ void SDMMC_IRQHandler(void) {
|
||||
sdmmc_irq_state = SDMMC_IRQ_STATE_DONE;
|
||||
return;
|
||||
}
|
||||
#if defined(STM32H7)
|
||||
#if defined(STM32H7) || defined(STM32N6)
|
||||
if (!sdmmc_dma) {
|
||||
while (sdmmc_buf_cur < sdmmc_buf_top && (SDMMC->STA & SDMMC_STA_DPSMACT) && !(SDMMC->STA & SDMMC_STA_RXFIFOE)) {
|
||||
*(uint32_t *)sdmmc_buf_cur = SDMMC->FIFO;
|
||||
@@ -413,11 +429,15 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le
|
||||
dma_nohal_init(&dma_SDIO_0, dma_config);
|
||||
dma_nohal_start(&dma_SDIO_0, dma_src, dma_dest, dma_len);
|
||||
#else
|
||||
#if defined(STM32N6)
|
||||
SDMMC->IDMABASER = (uint32_t)buf;
|
||||
#else
|
||||
SDMMC->IDMABASE0 = (uint32_t)buf;
|
||||
#endif
|
||||
SDMMC->IDMACTRL = SDMMC_IDMA_IDMAEN;
|
||||
#endif
|
||||
} else {
|
||||
#if defined(STM32H7)
|
||||
#if defined(STM32H7) || defined(STM32N6)
|
||||
SDMMC->IDMACTRL = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ const spi_t spi_obj[6] = {
|
||||
#error "spi_obj needs updating for new value of MICROPY_HW_SUBGHZSPI_ID"
|
||||
#endif
|
||||
|
||||
#if defined(STM32H5) || defined(STM32H7)
|
||||
#if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
|
||||
// STM32H5/H7 HAL requires SPI IRQs to be enabled and handled.
|
||||
#if defined(MICROPY_HW_SPI1_SCK)
|
||||
void SPI1_IRQHandler(void) {
|
||||
@@ -176,6 +176,18 @@ void spi_init0(void) {
|
||||
#if defined(MICROPY_HW_SUBGHZSPI_ID)
|
||||
SPIHandleSubGhz.Instance = SUBGHZSPI;
|
||||
#endif
|
||||
|
||||
#if defined(STM32N6)
|
||||
// SPI1/2/3/6 clock configuration, PCLKx (max 200MHz).
|
||||
LL_RCC_SetSPIClockSource(LL_RCC_SPI1_CLKSOURCE_PCLK2);
|
||||
LL_RCC_SetSPIClockSource(LL_RCC_SPI2_CLKSOURCE_PCLK1);
|
||||
LL_RCC_SetSPIClockSource(LL_RCC_SPI3_CLKSOURCE_PCLK1);
|
||||
LL_RCC_SetSPIClockSource(LL_RCC_SPI6_CLKSOURCE_PCLK4);
|
||||
|
||||
// SPI4/5 clock configuration, IC14 (max 100MHz).
|
||||
LL_RCC_SetSPIClockSource(LL_RCC_SPI4_CLKSOURCE_IC14);
|
||||
LL_RCC_SetSPIClockSource(LL_RCC_SPI5_CLKSOURCE_IC14);
|
||||
#endif
|
||||
}
|
||||
|
||||
int spi_find_index(mp_obj_t id) {
|
||||
@@ -256,6 +268,20 @@ static uint32_t spi_get_source_freq(SPI_HandleTypeDef *spi) {
|
||||
} else {
|
||||
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6);
|
||||
}
|
||||
#elif defined(STM32N6)
|
||||
if (spi->Instance == SPI1) {
|
||||
return LL_RCC_GetSPIClockFreq(LL_RCC_SPI1_CLKSOURCE);
|
||||
} else if (spi->Instance == SPI2) {
|
||||
return LL_RCC_GetSPIClockFreq(LL_RCC_SPI2_CLKSOURCE);
|
||||
} else if (spi->Instance == SPI3) {
|
||||
return LL_RCC_GetSPIClockFreq(LL_RCC_SPI3_CLKSOURCE);
|
||||
} else if (spi->Instance == SPI4) {
|
||||
return LL_RCC_GetSPIClockFreq(LL_RCC_SPI4_CLKSOURCE);
|
||||
} else if (spi->Instance == SPI5) {
|
||||
return LL_RCC_GetSPIClockFreq(LL_RCC_SPI5_CLKSOURCE);
|
||||
} else {
|
||||
return LL_RCC_GetSPIClockFreq(LL_RCC_SPI6_CLKSOURCE);
|
||||
}
|
||||
#else // !STM32F0, !STM32G0, !STM32H
|
||||
#if defined(SPI2)
|
||||
if (spi->Instance == SPI2) {
|
||||
@@ -470,7 +496,7 @@ int spi_init(const spi_t *self, bool enable_nss_pin) {
|
||||
dma_invalidate_channel(self->tx_dma_descr);
|
||||
dma_invalidate_channel(self->rx_dma_descr);
|
||||
|
||||
#if defined(STM32H5) || defined(STM32H7)
|
||||
#if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
|
||||
NVIC_SetPriority(irqn, IRQ_PRI_SPI);
|
||||
HAL_NVIC_EnableIRQ(irqn);
|
||||
#else
|
||||
@@ -724,7 +750,7 @@ void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) {
|
||||
if (spi->State != HAL_SPI_STATE_RESET) {
|
||||
if (spi->Init.Mode == SPI_MODE_MASTER) {
|
||||
// compute baudrate
|
||||
#if defined(STM32H5) || defined(STM32H7)
|
||||
#if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
|
||||
uint log_prescaler = (spi->Init.BaudRatePrescaler >> 28) + 1;
|
||||
#else
|
||||
uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1;
|
||||
|
||||
@@ -32,6 +32,16 @@
|
||||
|
||||
#if MICROPY_HW_ENABLE_STORAGE
|
||||
|
||||
#if MICROPY_HW_RUNS_FROM_EXT_FLASH
|
||||
// Disable all interrupts.
|
||||
#define FLASH_WRITE_ENTER uint32_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION()
|
||||
#define FLASH_WRITE_EXIT MICROPY_END_ATOMIC_SECTION(atomic_state)
|
||||
#else
|
||||
// Prevent cache flushing and USB access.
|
||||
#define FLASH_WRITE_ENTER uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH)
|
||||
#define FLASH_WRITE_EXIT restore_irq_pri(basepri)
|
||||
#endif
|
||||
|
||||
int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) {
|
||||
switch (op) {
|
||||
case BDEV_IOCTL_INIT:
|
||||
@@ -68,6 +78,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) {
|
||||
}
|
||||
|
||||
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
|
||||
|
||||
int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
|
||||
int ret = mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest);
|
||||
@@ -87,20 +98,36 @@ int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_nu
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#elif FLASH_BLOCK_SIZE == MP_SPIFLASH_ERASE_BLOCK_SIZE
|
||||
|
||||
int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
||||
int ret = spi_bdev_readblocks_raw(bdev, dest, block_num, 0, num_blocks * FLASH_BLOCK_SIZE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
|
||||
int ret = spi_bdev_eraseblocks_raw(bdev, block_num, num_blocks * FLASH_BLOCK_SIZE);
|
||||
if (ret == 0) {
|
||||
ret = spi_bdev_writeblocks_raw(bdev, src, block_num, 0, num_blocks * FLASH_BLOCK_SIZE);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // MICROPY_HW_SPIFLASH_ENABLE_CACHE
|
||||
|
||||
int spi_bdev_readblocks_raw(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes) {
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
|
||||
FLASH_WRITE_ENTER;
|
||||
int ret = mp_spiflash_read(&bdev->spiflash, block_num * MP_SPIFLASH_ERASE_BLOCK_SIZE + block_offset, num_bytes, dest);
|
||||
restore_irq_pri(basepri);
|
||||
FLASH_WRITE_EXIT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spi_bdev_writeblocks_raw(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes) {
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
|
||||
FLASH_WRITE_ENTER;
|
||||
int ret = mp_spiflash_write(&bdev->spiflash, block_num * MP_SPIFLASH_ERASE_BLOCK_SIZE + block_offset, num_bytes, src);
|
||||
restore_irq_pri(basepri);
|
||||
FLASH_WRITE_EXIT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -108,9 +135,9 @@ int spi_bdev_writeblocks_raw(spi_bdev_t *bdev, const uint8_t *src, uint32_t bloc
|
||||
int spi_bdev_eraseblocks_raw(spi_bdev_t *bdev, uint32_t block_num, uint32_t num_bytes) {
|
||||
int ret = 0;
|
||||
while (num_bytes >= MP_SPIFLASH_ERASE_BLOCK_SIZE) {
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
|
||||
FLASH_WRITE_ENTER;
|
||||
ret = mp_spiflash_erase_block(&bdev->spiflash, block_num * MP_SPIFLASH_ERASE_BLOCK_SIZE);
|
||||
restore_irq_pri(basepri);
|
||||
FLASH_WRITE_EXIT;
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -43,19 +43,17 @@ ifneq ($(BUILDING_MBOOT),1)
|
||||
# Select hardware floating-point support.
|
||||
SUPPORTS_HARDWARE_FP_SINGLE = 0
|
||||
SUPPORTS_HARDWARE_FP_DOUBLE = 0
|
||||
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx STM32H747xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ))
|
||||
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx STM32H747xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ STM32N657xx))
|
||||
CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard -mfp16-format=ieee
|
||||
SUPPORTS_HARDWARE_FP_SINGLE = 1
|
||||
SUPPORTS_HARDWARE_FP_DOUBLE = 1
|
||||
else
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 g0 l0 l1 wl))
|
||||
else ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 g0 l0 l1 wl))
|
||||
CFLAGS_CORTEX_M += -msoft-float
|
||||
else
|
||||
CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mfp16-format=ieee
|
||||
SUPPORTS_HARDWARE_FP_SINGLE = 1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Options for particular MCU series.
|
||||
CFLAGS_MCU_f0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0 -mcpu=cortex-m0
|
||||
@@ -68,6 +66,7 @@ CFLAGS_MCU_l1 = $(CFLAGS_CORTEX_M) -mtune=cortex-m3 -mcpu=cortex-m3
|
||||
CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
|
||||
CFLAGS_MCU_h5 = $(CFLAGS_CORTEX_M) -mtune=cortex-m33 -mcpu=cortex-m33
|
||||
CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
|
||||
CFLAGS_MCU_n6 = $(CFLAGS_CORTEX_M) -mtune=cortex-m55 -mcpu=cortex-m55 -mcmse
|
||||
CFLAGS_MCU_wb = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
|
||||
CFLAGS_MCU_wl = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
|
||||
|
||||
@@ -81,5 +80,6 @@ MPY_CROSS_MCU_ARCH_l1 = armv7m
|
||||
MPY_CROSS_MCU_ARCH_l4 = armv7m
|
||||
MPY_CROSS_MCU_ARCH_h5 = armv7m
|
||||
MPY_CROSS_MCU_ARCH_h7 = armv7m
|
||||
MPY_CROSS_MCU_ARCH_n6 = armv7m # really armv8m
|
||||
MPY_CROSS_MCU_ARCH_wb = armv7m
|
||||
MPY_CROSS_MCU_ARCH_wl = armv7m
|
||||
|
||||
@@ -343,14 +343,22 @@ void OTG_FS_IRQHandler(void) {
|
||||
}
|
||||
#endif
|
||||
#if MICROPY_HW_USB_HS
|
||||
#if defined(STM32N6)
|
||||
void USB1_OTG_HS_IRQHandler(void) {
|
||||
IRQ_ENTER(USB1_OTG_HS_IRQn);
|
||||
HAL_PCD_IRQHandler(&pcd_hs_handle);
|
||||
IRQ_EXIT(USB1_OTG_HS_IRQn);
|
||||
}
|
||||
#else
|
||||
void OTG_HS_IRQHandler(void) {
|
||||
IRQ_ENTER(OTG_HS_IRQn);
|
||||
HAL_PCD_IRQHandler(&pcd_hs_handle);
|
||||
IRQ_EXIT(OTG_HS_IRQn);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS
|
||||
#if (MICROPY_HW_USB_FS || MICROPY_HW_USB_HS) && !defined(STM32N6)
|
||||
/**
|
||||
* @brief This function handles USB OTG Common FS/HS Wakeup functions.
|
||||
* @param *pcd_handle for FS or HS
|
||||
@@ -421,7 +429,7 @@ void OTG_FS_WKUP_IRQHandler(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_USB_HS
|
||||
#if MICROPY_HW_USB_HS && !defined(STM32N6)
|
||||
/**
|
||||
* @brief This function handles USB OTG HS Wakeup IRQ Handler.
|
||||
* @param None
|
||||
@@ -480,7 +488,7 @@ void ETH_WKUP_IRQHandler(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
void TAMP_IRQHandler(void) {
|
||||
IRQ_ENTER(TAMP_IRQn);
|
||||
Handle_EXTI_Irq(EXTI_RTC_TAMP);
|
||||
@@ -502,6 +510,9 @@ void TAMP_STAMP_IRQHandler(void) {
|
||||
|
||||
#if defined(STM32H5)
|
||||
void RTC_IRQHandler(void)
|
||||
#elif defined(STM32N6)
|
||||
#define RTC_WKUP_IRQn RTC_S_IRQn
|
||||
void RTC_S_IRQHandler(void)
|
||||
#else
|
||||
void RTC_WKUP_IRQHandler(void)
|
||||
#endif
|
||||
@@ -509,8 +520,8 @@ void RTC_WKUP_IRQHandler(void)
|
||||
IRQ_ENTER(RTC_WKUP_IRQn);
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32WL)
|
||||
RTC->MISR &= ~RTC_MISR_WUTMF; // clear wakeup interrupt flag
|
||||
#elif defined(STM32H5)
|
||||
RTC->SCR = RTC_SCR_CWUTF; // clear wakeup interrupt flag
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
LL_RTC_ClearFlag_WUT(RTC);
|
||||
#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
|
||||
RTC->SR &= ~RTC_SR_WUTF; // clear wakeup interrupt flag
|
||||
#else
|
||||
@@ -520,6 +531,12 @@ void RTC_WKUP_IRQHandler(void)
|
||||
IRQ_EXIT(RTC_WKUP_IRQn);
|
||||
}
|
||||
|
||||
#if defined(STM32N6)
|
||||
void RTC_IRQHandler(void) {
|
||||
RTC_S_IRQHandler();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32L0)
|
||||
|
||||
#if defined(STM32G0)
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "led.h"
|
||||
#include "storage.h"
|
||||
#include "irq.h"
|
||||
#include "xspi.h"
|
||||
|
||||
#if MICROPY_HW_ENABLE_STORAGE
|
||||
|
||||
@@ -44,13 +45,17 @@
|
||||
|
||||
static bool storage_is_initialised = false;
|
||||
|
||||
#if !defined(STM32N6)
|
||||
static void storage_systick_callback(uint32_t ticks_ms);
|
||||
#endif
|
||||
|
||||
void storage_init(void) {
|
||||
if (!storage_is_initialised) {
|
||||
storage_is_initialised = true;
|
||||
|
||||
#if !defined(STM32N6)
|
||||
systick_enable_dispatch(SYSTICK_DISPATCH_STORAGE, storage_systick_callback);
|
||||
#endif
|
||||
|
||||
MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0);
|
||||
|
||||
@@ -58,10 +63,12 @@ void storage_init(void) {
|
||||
MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0);
|
||||
#endif
|
||||
|
||||
#if !defined(STM32N6)
|
||||
// Enable the flash IRQ, which is used to also call our storage IRQ handler
|
||||
// It must go at the same priority as USB (see comment in irq.h).
|
||||
NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH);
|
||||
HAL_NVIC_EnableIRQ(FLASH_IRQn);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +84,7 @@ uint32_t storage_get_block_count(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(STM32N6)
|
||||
static void storage_systick_callback(uint32_t ticks_ms) {
|
||||
if (STORAGE_IDLE_TICK(ticks_ms)) {
|
||||
// Trigger a FLASH IRQ to execute at a lower priority
|
||||
@@ -96,6 +104,7 @@ void FLASH_IRQHandler(void) {
|
||||
#endif
|
||||
IRQ_EXIT(FLASH_IRQn);
|
||||
}
|
||||
#endif
|
||||
|
||||
void storage_flush(void) {
|
||||
MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_SYNC, 0);
|
||||
@@ -235,11 +244,11 @@ int storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_bl
|
||||
// Board defined an external SPI flash for use with extended block protocol
|
||||
#define MICROPY_HW_BDEV_BLOCKSIZE_EXT (MP_SPIFLASH_ERASE_BLOCK_SIZE)
|
||||
#define MICROPY_HW_BDEV_READBLOCKS_EXT(dest, bl, off, len) \
|
||||
(spi_bdev_readblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, (dest), (bl), (off), (len)))
|
||||
(spi_bdev_readblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, (dest), MICROPY_HW_BDEV_SPIFLASH_OFFSET_BYTES / MP_SPIFLASH_ERASE_BLOCK_SIZE + (bl), (off), (len)))
|
||||
#define MICROPY_HW_BDEV_WRITEBLOCKS_EXT(src, bl, off, len) \
|
||||
(spi_bdev_writeblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, (src), (bl), (off), (len)))
|
||||
(spi_bdev_writeblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, (src), MICROPY_HW_BDEV_SPIFLASH_OFFSET_BYTES / MP_SPIFLASH_ERASE_BLOCK_SIZE + (bl), (off), (len)))
|
||||
#define MICROPY_HW_BDEV_ERASEBLOCKS_EXT(bl, len) \
|
||||
(spi_bdev_eraseblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, (bl), (len)))
|
||||
(spi_bdev_eraseblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, MICROPY_HW_BDEV_SPIFLASH_OFFSET_BYTES / MP_SPIFLASH_ERASE_BLOCK_SIZE + (bl), (len)))
|
||||
|
||||
#elif (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2) && MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
|
||||
// Board uses littlefs and internal flash, so enable extended block protocol on internal flash
|
||||
|
||||
@@ -28,7 +28,11 @@
|
||||
|
||||
#include "drivers/memory/spiflash.h"
|
||||
|
||||
#if defined(STM32N6)
|
||||
#define FLASH_BLOCK_SIZE (4096)
|
||||
#else
|
||||
#define FLASH_BLOCK_SIZE (512)
|
||||
#endif
|
||||
#define FLASH_PART1_START_BLOCK (0x100)
|
||||
|
||||
// Try to match Python-level VFS block protocol where possible for these constants
|
||||
|
||||
@@ -261,6 +261,12 @@ uint32_t timer_get_source_freq(uint32_t tim_id) {
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(STM32N6)
|
||||
|
||||
// Timers are clocked either by ck_timg1 or ck_timg2.
|
||||
// Both of those have the same frequency: sys_bus_ck / prescaler(TIMPRE)
|
||||
return LL_RCC_GetSystemClockFreq() / (1 << LL_RCC_GetTIMPrescaler());
|
||||
|
||||
#else
|
||||
|
||||
uint32_t source, clk_div;
|
||||
@@ -846,7 +852,9 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
TIM_ENTRY(1, TIM1_UP_TIM16_IRQn),
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TIM_ENTRY(2, TIM2_IRQn),
|
||||
|
||||
#if defined(TIM3)
|
||||
#if defined(STM32G0B1xx) || defined(STM32G0C1xx)
|
||||
TIM_ENTRY(3, TIM3_TIM4_IRQn),
|
||||
@@ -854,6 +862,7 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
TIM_ENTRY(3, TIM3_IRQn),
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TIM4)
|
||||
#if defined(STM32G0B1xx) || defined(STM32G0C1xx)
|
||||
TIM_ENTRY(3, TIM3_TIM4_IRQn),
|
||||
@@ -861,20 +870,23 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
TIM_ENTRY(4, TIM4_IRQn),
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TIM5)
|
||||
TIM_ENTRY(5, TIM5_IRQn),
|
||||
#endif
|
||||
|
||||
#if defined(TIM6)
|
||||
#if defined(STM32F412Zx) || defined(STM32L1)
|
||||
TIM_ENTRY(6, TIM6_IRQn),
|
||||
#elif defined(STM32G0)
|
||||
TIM_ENTRY(6, TIM6_DAC_LPTIM1_IRQn),
|
||||
#elif defined(STM32H5)
|
||||
#elif defined(STM32H5) || defined(STM32N6)
|
||||
TIM_ENTRY(6, TIM6_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(6, TIM6_DAC_IRQn),
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TIM7)
|
||||
#if defined(STM32G0)
|
||||
TIM_ENTRY(7, TIM7_LPTIM2_IRQn),
|
||||
@@ -894,7 +906,7 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
#endif
|
||||
|
||||
#if defined(TIM9)
|
||||
#if defined(STM32L1)
|
||||
#if defined(STM32L1) || defined(STM32N6)
|
||||
TIM_ENTRY(9, TIM9_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(9, TIM1_BRK_TIM9_IRQn),
|
||||
@@ -902,7 +914,7 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
#endif
|
||||
|
||||
#if defined(TIM10)
|
||||
#if defined(STM32L1)
|
||||
#if defined(STM32L1) || defined(STM32N6)
|
||||
TIM_ENTRY(10, TIM10_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(10, TIM1_UP_TIM10_IRQn),
|
||||
@@ -910,7 +922,7 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
#endif
|
||||
|
||||
#if defined(TIM11)
|
||||
#if defined(STM32L1)
|
||||
#if defined(STM32L1) || defined(STM32N6)
|
||||
TIM_ENTRY(11, TIM11_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(11, TIM1_TRG_COM_TIM11_IRQn),
|
||||
@@ -918,7 +930,7 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
#endif
|
||||
|
||||
#if defined(TIM12)
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
TIM_ENTRY(12, TIM12_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(12, TIM8_BRK_TIM12_IRQn),
|
||||
@@ -926,21 +938,21 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
#endif
|
||||
|
||||
#if defined(TIM13)
|
||||
#if defined(STM32H5)
|
||||
#if defined(STM32H5) || defined(STM32N6)
|
||||
TIM_ENTRY(13, TIM13_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(13, TIM8_UP_TIM13_IRQn),
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32H5)
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32H5) || defined(STM32N6)
|
||||
TIM_ENTRY(14, TIM14_IRQn),
|
||||
#elif defined(TIM14)
|
||||
TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn),
|
||||
#endif
|
||||
|
||||
#if defined(TIM15)
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32H5) || defined(STM32H7)
|
||||
#if defined(STM32F0) || defined(STM32G0) || defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
|
||||
TIM_ENTRY(15, TIM15_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn),
|
||||
@@ -950,7 +962,7 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
#if defined(TIM16)
|
||||
#if defined(STM32G0B1xx) || defined(STM32G0C1xx)
|
||||
TIM_ENTRY(16, TIM16_FDCAN_IT0_IRQn),
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32H5) || defined(STM32H7) || defined(STM32WL)
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32H5) || defined(STM32H7) || defined(STM32N6) || defined(STM32WL)
|
||||
TIM_ENTRY(16, TIM16_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(16, TIM1_UP_TIM16_IRQn),
|
||||
@@ -960,7 +972,7 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
#if defined(TIM17)
|
||||
#if defined(STM32G0B1xx) || defined(STM32G0C1xx)
|
||||
TIM_ENTRY(17, TIM17_FDCAN_IT1_IRQn),
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32H5) || defined(STM32H7) || defined(STM32WL)
|
||||
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32H5) || defined(STM32H7) || defined(STM32N6) || defined(STM32WL)
|
||||
TIM_ENTRY(17, TIM17_IRQn),
|
||||
#else
|
||||
TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn),
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
#define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_WUFIE)
|
||||
#endif
|
||||
|
||||
#elif defined(STM32H7)
|
||||
#elif defined(STM32H7) || defined(STM32N6)
|
||||
#define USART_CR1_IE_ALL (USART_CR1_IE_BASE | USART_CR1_RXFFIE | USART_CR1_TXFEIE | USART_CR1_EOBIE | USART_CR1_RTOIE | USART_CR1_CMIE)
|
||||
#define USART_CR2_IE_ALL (USART_CR2_IE_BASE)
|
||||
#define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_RXFTIE | USART_CR3_TCBGTIE | USART_CR3_TXFTIE | USART_CR3_WUFIE)
|
||||
@@ -157,6 +157,18 @@ void uart_init0(void) {
|
||||
if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) {
|
||||
MICROPY_BOARD_FATAL_ERROR("HAL_RCCEx_PeriphCLKConfig");
|
||||
}
|
||||
#elif defined(STM32N6)
|
||||
// UART clock configuration, IC14 (max 100MHz).
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART2_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART3_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUARTClockSource(LL_RCC_UART4_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUARTClockSource(LL_RCC_UART5_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART6_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUARTClockSource(LL_RCC_UART7_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUARTClockSource(LL_RCC_UART8_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUARTClockSource(LL_RCC_UART9_CLKSOURCE_IC14);
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART10_CLKSOURCE_IC14);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -661,7 +673,7 @@ bool uart_init(machine_uart_obj_t *uart_obj,
|
||||
huart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
|
||||
#endif
|
||||
|
||||
#if defined(STM32H7) || defined(STM32WB)
|
||||
#if defined(STM32H7) || defined(STM32N6) || defined(STM32WB)
|
||||
// Compute the smallest prescaler that will allow the given baudrate.
|
||||
uint32_t presc = UART_PRESCALER_DIV1;
|
||||
if (uart_obj->uart_id == PYB_LPUART_1) {
|
||||
@@ -976,6 +988,29 @@ uint32_t uart_get_source_freq(machine_uart_obj_t *self) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#elif defined(STM32N6)
|
||||
|
||||
static const uint16_t is_usart = 1 << 10 | 1 << 6 | 1 << 3 | 1 << 2 | 1 << 1;
|
||||
static const uint32_t clksource[] = {
|
||||
LL_RCC_USART1_CLKSOURCE,
|
||||
LL_RCC_USART2_CLKSOURCE,
|
||||
LL_RCC_USART3_CLKSOURCE,
|
||||
LL_RCC_UART4_CLKSOURCE,
|
||||
LL_RCC_UART5_CLKSOURCE,
|
||||
LL_RCC_USART6_CLKSOURCE,
|
||||
LL_RCC_UART7_CLKSOURCE,
|
||||
LL_RCC_UART8_CLKSOURCE,
|
||||
LL_RCC_UART9_CLKSOURCE,
|
||||
LL_RCC_USART10_CLKSOURCE,
|
||||
};
|
||||
|
||||
if (is_usart & (1 << self->uart_id)) {
|
||||
uart_clk = LL_RCC_GetUSARTClockFreq(clksource[self->uart_id - 1]);
|
||||
} else {
|
||||
uart_clk = LL_RCC_GetUARTClockFreq(clksource[self->uart_id - 1]);
|
||||
}
|
||||
|
||||
#else
|
||||
if (self->uart_id == 1
|
||||
#if defined(USART6)
|
||||
@@ -1001,14 +1036,14 @@ uint32_t uart_get_baudrate(machine_uart_obj_t *self) {
|
||||
#if defined(LPUART1)
|
||||
if (self->uart_id == PYB_LPUART_1) {
|
||||
return LL_LPUART_GetBaudRate(self->uartx, uart_get_source_freq(self)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
, self->uartx->PRESC
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif
|
||||
return LL_USART_GetBaudRate(self->uartx, uart_get_source_freq(self),
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
self->uartx->PRESC,
|
||||
#endif
|
||||
LL_USART_OVERSAMPLING_16);
|
||||
@@ -1018,7 +1053,7 @@ void uart_set_baudrate(machine_uart_obj_t *self, uint32_t baudrate) {
|
||||
#if defined(LPUART1)
|
||||
if (self->uart_id == PYB_LPUART_1) {
|
||||
LL_LPUART_SetBaudRate(self->uartx, uart_get_source_freq(self),
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
LL_LPUART_PRESCALER_DIV1,
|
||||
#endif
|
||||
baudrate);
|
||||
@@ -1026,7 +1061,7 @@ void uart_set_baudrate(machine_uart_obj_t *self, uint32_t baudrate) {
|
||||
}
|
||||
#endif
|
||||
LL_USART_SetBaudRate(self->uartx, uart_get_source_freq(self),
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
LL_USART_PRESCALER_DIV1,
|
||||
#endif
|
||||
LL_USART_OVERSAMPLING_16, baudrate);
|
||||
@@ -1077,7 +1112,7 @@ int uart_rx_char(machine_uart_obj_t *self) {
|
||||
return data;
|
||||
} else {
|
||||
// no buffering
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
int data = self->uartx->RDR & self->char_mask;
|
||||
self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set
|
||||
return data;
|
||||
@@ -1232,7 +1267,7 @@ void uart_irq_handler(mp_uint_t uart_id) {
|
||||
uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
|
||||
if (next_head != self->read_buf_tail) {
|
||||
// only read data if room in buf
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB) || defined(STM32WL)
|
||||
int data = self->uartx->RDR; // clears UART_FLAG_RXNE
|
||||
#else
|
||||
self->mp_irq_flags = self->uartx->SR; // resample to get any new flags since next read of DR will clear SR
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
#define MAX_ENDPOINT(dev_id) ((dev_id) == USB_PHY_FS_ID ? 3 : 5)
|
||||
#elif defined(STM32F7)
|
||||
#define MAX_ENDPOINT(dev_id) ((dev_id) == USB_PHY_FS_ID ? 5 : 8)
|
||||
#elif defined(STM32H7)
|
||||
#elif defined(STM32H7) || defined(STM32N6)
|
||||
#define MAX_ENDPOINT(dev_id) (8)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -51,6 +51,11 @@ PCD_HandleTypeDef pcd_hs_handle;
|
||||
#define USB_OTG_FS USB
|
||||
#endif
|
||||
|
||||
#if defined(STM32N6)
|
||||
#define USB_OTG_HS USB1_OTG_HS
|
||||
#define OTG_HS_IRQn USB1_OTG_HS_IRQn
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
PCD BSP Routines
|
||||
*******************************************************************************/
|
||||
@@ -191,6 +196,10 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
|
||||
mp_hal_pin_config(pin_A12, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
|
||||
mp_hal_pin_config_speed(pin_A12, GPIO_SPEED_FREQ_VERY_HIGH);
|
||||
|
||||
#elif defined(STM32N6)
|
||||
|
||||
// These MCUs have dedicated USB pins.
|
||||
|
||||
#else
|
||||
|
||||
// Other MCUs have an alternate function for GPIO's to be in USB mode.
|
||||
@@ -220,6 +229,23 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
|
||||
mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, otg_alt);
|
||||
#endif
|
||||
|
||||
#if defined(STM32N6)
|
||||
|
||||
__HAL_RCC_USB1_OTG_HS_FORCE_RESET();
|
||||
__HAL_RCC_USB1_OTG_HS_PHY_FORCE_RESET();
|
||||
__HAL_RCC_USB1_OTG_HS_PHY_RELEASE_RESET();
|
||||
__HAL_RCC_USB1_OTG_HS_RELEASE_RESET();
|
||||
|
||||
LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_OTG1);
|
||||
LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_OTGPHY1);
|
||||
LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_OTG1);
|
||||
LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_OTGPHY1);
|
||||
|
||||
// Select 24MHz clock.
|
||||
MODIFY_REG(USB1_HS_PHYC->USBPHYC_CR, USB_USBPHYC_CR_FSEL, 2 << USB_USBPHYC_CR_FSEL_Pos);
|
||||
|
||||
#else
|
||||
|
||||
// Enable calling WFI and correct function of the embedded USB_FS_IN_HS phy
|
||||
__HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_DISABLE();
|
||||
__HAL_RCC_USB_OTG_HS_CLK_SLEEP_ENABLE();
|
||||
@@ -235,6 +261,8 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
|
||||
|
||||
__HAL_RCC_USB_OTG_HS_CLK_ENABLE();
|
||||
|
||||
#endif
|
||||
|
||||
#else // !MICROPY_HW_USB_HS_IN_FS
|
||||
|
||||
// Configure USB HS GPIOs
|
||||
@@ -283,7 +311,12 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) {
|
||||
#if MICROPY_HW_USB_HS
|
||||
if (hpcd->Instance == USB_OTG_HS) {
|
||||
/* Disable USB FS Clocks */
|
||||
#if defined(STM32N6)
|
||||
LL_AHB5_GRP1_DisableClock(LL_AHB5_GRP1_PERIPH_OTG1);
|
||||
LL_AHB5_GRP1_DisableClock(LL_AHB5_GRP1_PERIPH_OTGPHY1);
|
||||
#else
|
||||
__USB_OTG_HS_CLK_DISABLE();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -517,7 +550,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed, const
|
||||
|
||||
#if MICROPY_HW_USB_HS_IN_FS
|
||||
|
||||
#if defined(STM32F723xx) || defined(STM32F733xx)
|
||||
#if defined(STM32F723xx) || defined(STM32F733xx) || defined(STM32N6)
|
||||
pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY;
|
||||
#else
|
||||
pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
// Work out if we should support USB high-speed device mode
|
||||
#if MICROPY_HW_USB_HS \
|
||||
&& (!MICROPY_HW_USB_HS_IN_FS || defined(STM32F723xx) || defined(STM32F733xx))
|
||||
&& (!MICROPY_HW_USB_HS_IN_FS || defined(STM32F723xx) || defined(STM32F733xx) || defined(STM32N6))
|
||||
#define USBD_SUPPORT_HS_MODE (1)
|
||||
#else
|
||||
#define USBD_SUPPORT_HS_MODE (0)
|
||||
@@ -31,7 +31,11 @@
|
||||
#else
|
||||
#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE
|
||||
#endif
|
||||
#if defined(STM32N6)
|
||||
#define MSC_MEDIA_PACKET (4096) // must be at least the SPI flash erase size
|
||||
#else
|
||||
#define MSC_MEDIA_PACKET (2048) // was 8192; how low can it go whilst still working?
|
||||
#endif
|
||||
#define HID_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
|
||||
|
||||
// Maximum number of LUN that can be exposed on the MSC interface
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "flash.h"
|
||||
#include "qspi.h"
|
||||
#include "storage.h"
|
||||
#include "xspi.h"
|
||||
|
||||
#if MICROPY_VFS_ROM_IOCTL
|
||||
|
||||
@@ -142,6 +143,18 @@ mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) {
|
||||
return MP_OBJ_NEW_SMALL_INT(4);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_ROMFS_ENABLE_EXTERNAL_XSPI
|
||||
if (xspi_is_valid_addr(&xspi_flash2, dest)) {
|
||||
dest -= xspi_get_xip_base(&xspi_flash2);
|
||||
dest_max -= xspi_get_xip_base(&xspi_flash2);
|
||||
int ret = spi_bdev_eraseblocks_raw(MICROPY_HW_ROMFS_XSPI_SPIBDEV_OBJ, dest / MP_SPIFLASH_ERASE_BLOCK_SIZE, dest_max - dest + MP_SPIFLASH_ERASE_BLOCK_SIZE - 1);
|
||||
if (ret < 0) {
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
return MP_OBJ_NEW_SMALL_INT(4);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cmd == MP_VFS_ROM_IOCTL_WRITE) {
|
||||
@@ -170,6 +183,14 @@ mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) {
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_ROMFS_ENABLE_EXTERNAL_XSPI
|
||||
if (xspi_is_valid_addr(&xspi_flash2, dest)) {
|
||||
dest -= xspi_get_xip_base(&xspi_flash2);
|
||||
int ret = spi_bdev_writeblocks_raw(MICROPY_HW_ROMFS_XSPI_SPIBDEV_OBJ, bufinfo.buf, 0, dest, bufinfo.len);
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL);
|
||||
|
||||
599
ports/stm32/xspi.c
Normal file
599
ports/stm32/xspi.c
Normal file
@@ -0,0 +1,599 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024-2025 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// This XSPI driver is currently configured to run in 1-line (SPI) mode.
|
||||
// It uses the mp_qspi_proto_t QSPI protocol and translates quad-commands
|
||||
// into 1-line commands.
|
||||
|
||||
#include <string.h>
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "xspi.h"
|
||||
|
||||
#if defined(MICROPY_HW_XSPIFLASH_SIZE_BITS_LOG2)
|
||||
|
||||
#ifndef MICROPY_HW_XSPI_PRESCALER
|
||||
#define MICROPY_HW_XSPI_PRESCALER (4) // F_CLK = F_AHB/4
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_HW_XSPI_CS_HIGH_CYCLES
|
||||
#define MICROPY_HW_XSPI_CS_HIGH_CYCLES (2) // nCS stays high for 4 cycles
|
||||
#endif
|
||||
|
||||
// Currently hard-coded to use XSPI2 instance.
|
||||
#define XSPIx (XSPI2)
|
||||
|
||||
// For XSPI2, PN0 through PN12.
|
||||
#define XSPI2_AF (9)
|
||||
|
||||
typedef struct _xspi_flash_t {
|
||||
XSPI_TypeDef *xspi;
|
||||
uintptr_t xip_base;
|
||||
} xspi_flash_t;
|
||||
|
||||
const xspi_flash_t xspi_flash1 = {
|
||||
.xspi = XSPI1,
|
||||
.xip_base = 0x90000000,
|
||||
};
|
||||
|
||||
const xspi_flash_t xspi_flash2 = {
|
||||
.xspi = XSPI2,
|
||||
.xip_base = 0x70000000,
|
||||
};
|
||||
|
||||
static bool xspi_dtr_enabled = false;
|
||||
|
||||
#ifdef pyb_pin_FLASH_RESET
|
||||
// Can't rely on SysTick being available, so use a busy loop for delays.
|
||||
// The timing here is approximate and assumes a CPU frequency of 800MHz.
|
||||
static void xspi_delay_us(unsigned int us) {
|
||||
while (us--) {
|
||||
for (unsigned int i = 0; i < 800; ++i) {
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void mp_hal_pin_config_alt_speed(mp_hal_pin_obj_t pin, uint32_t pull, uint32_t alt, uint32_t speed) {
|
||||
mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ALT, pull, alt);
|
||||
mp_hal_pin_config_speed(pin, speed);
|
||||
}
|
||||
|
||||
static int xspi_read_111_ext(uint8_t cmd, bool addr_enabled, uint32_t addr, size_t len, uint8_t *dest);
|
||||
static int xspi_write_111_ext(uint8_t cmd, bool addr_enabled, uint32_t addr, size_t len, const uint8_t *src);
|
||||
static int xspi_read_888_dtr_ext(uint16_t cmd, bool addr_enabled, uint32_t addr, uint32_t num_dummy, size_t len, uint8_t *dest);
|
||||
static int xspi_write_888_dtr_ext(uint16_t cmd, bool addr_enabled, uint32_t addr, size_t len, const uint8_t *src);
|
||||
static void xspi_memory_map_111(void);
|
||||
static void xspi_memory_map_888(void);
|
||||
static void xspi_memory_map_exit(void);
|
||||
|
||||
void xspi_init(void) {
|
||||
// Configure XSPI pins.
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_CS, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_SCK, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_DQS, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_IO0, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_IO1, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_IO2, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_IO3, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_IO4, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_IO5, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_IO6, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
mp_hal_pin_config_alt_speed(pyb_pin_XSPIM_P2_IO7, MP_HAL_PIN_PULL_NONE, XSPI2_AF, MP_HAL_PIN_SPEED_VERY_HIGH);
|
||||
|
||||
LL_AHB5_GRP1_ForceReset(LL_AHB5_GRP1_PERIPH_XSPIM);
|
||||
LL_AHB5_GRP1_ForceReset(LL_AHB5_GRP1_PERIPH_XSPI1);
|
||||
LL_AHB5_GRP1_ForceReset(LL_AHB5_GRP1_PERIPH_XSPI2);
|
||||
LL_AHB5_GRP1_ForceReset(LL_AHB5_GRP1_PERIPH_XSPI3);
|
||||
|
||||
LL_AHB5_GRP1_ReleaseReset(LL_AHB5_GRP1_PERIPH_XSPIM);
|
||||
LL_AHB5_GRP1_ReleaseReset(LL_AHB5_GRP1_PERIPH_XSPI1);
|
||||
LL_AHB5_GRP1_ReleaseReset(LL_AHB5_GRP1_PERIPH_XSPI2);
|
||||
LL_AHB5_GRP1_ReleaseReset(LL_AHB5_GRP1_PERIPH_XSPI3);
|
||||
|
||||
LL_RCC_SetXSPIClockSource(LL_RCC_XSPI1_CLKSOURCE_HCLK);
|
||||
LL_RCC_SetXSPIClockSource(LL_RCC_XSPI2_CLKSOURCE_HCLK);
|
||||
|
||||
LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_XSPIM);
|
||||
LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_XSPI1);
|
||||
LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_XSPI2);
|
||||
|
||||
// Configure XSPIM in direct mode.
|
||||
XSPI1->CR &= ~XSPI_CR_EN;
|
||||
XSPI2->CR &= ~XSPI_CR_EN;
|
||||
XSPIM->CR = 0;
|
||||
|
||||
// Configure the XSPIx peripheral.
|
||||
|
||||
XSPIx->CR =
|
||||
3 << XSPI_CR_FTHRES_Pos // 4 byte must be available to read/write
|
||||
| 0 << XSPI_CR_MSEL_Pos // FLASH 0 selected
|
||||
| 0 << XSPI_CR_CSSEL_Pos // use NCS1 as chip select
|
||||
| 0 << XSPI_CR_DMM_Pos // dual-memory mode disabled
|
||||
| 1 << XSPI_CR_TCEN_Pos // time-out counter enabled
|
||||
| 0 << XSPI_CR_DMAEN_Pos // DMA disabled
|
||||
| 0 << XSPI_CR_ABORT_Pos // no abort request
|
||||
| 0 << XSPI_CR_EN_Pos // disabled
|
||||
;
|
||||
|
||||
XSPIx->DCR1 =
|
||||
1 << XSPI_DCR1_MTYP_Pos // Macronix mode
|
||||
| (MICROPY_HW_XSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) << XSPI_DCR1_DEVSIZE_Pos
|
||||
| (MICROPY_HW_XSPI_CS_HIGH_CYCLES - 1) << XSPI_DCR1_CSHT_Pos
|
||||
| 0 << XSPI_DCR1_FRCK_Pos // CLK is not free running
|
||||
| 0 << XSPI_DCR1_CKMODE_Pos // CLK idles at low state
|
||||
;
|
||||
|
||||
XSPIx->DCR2 =
|
||||
0 << XSPI_DCR2_WRAPSIZE_Pos // separate wrap reads are not supported by the memory
|
||||
| (MICROPY_HW_XSPI_PRESCALER - 1) << XSPI_DCR2_PRESCALER_Pos
|
||||
;
|
||||
|
||||
XSPIx->DCR3 =
|
||||
0
|
||||
// 10 << XSPI_DCR3_CSBOUND_Pos // transaction boundary at 1024
|
||||
;
|
||||
|
||||
XSPIx->DCR4 =
|
||||
0 << XSPI_DCR4_REFRESH_Pos // refresh disabled (it's non-volatile memory)
|
||||
;
|
||||
|
||||
XSPIx->TCR = 0;
|
||||
|
||||
// Enable the XSPI peripheral.
|
||||
XSPIx->CR |= XSPI_CR_EN;
|
||||
|
||||
// XSPIM init
|
||||
XSPI1->CR &= ~(1 << XSPI_CR_EN_Pos);
|
||||
XSPI2->CR &= ~(1 << XSPI_CR_EN_Pos);
|
||||
XSPIM->CR = 0; // can also be (1 << 4) to pass through CS signal
|
||||
XSPIx->CR |= 1 << XSPI_CR_EN_Pos;
|
||||
|
||||
#ifdef pyb_pin_FLASH_RESET
|
||||
// Reset SPI flash to make sure it's in a known state (SPI mode).
|
||||
mp_hal_pin_output(pyb_pin_FLASH_RESET);
|
||||
mp_hal_pin_low(pyb_pin_FLASH_RESET);
|
||||
xspi_delay_us(1000);
|
||||
mp_hal_pin_high(pyb_pin_FLASH_RESET);
|
||||
xspi_delay_us(10000);
|
||||
#endif
|
||||
|
||||
// Enable memory-mapped mode.
|
||||
// Can select either SPI or DTR mode.
|
||||
if (1) {
|
||||
xspi_switch_to_dtr();
|
||||
xspi_memory_map_888();
|
||||
} else {
|
||||
xspi_memory_map_111();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t xspi_get_xip_base(const xspi_flash_t *self) {
|
||||
return self->xip_base;
|
||||
}
|
||||
|
||||
bool xspi_is_valid_addr(const xspi_flash_t *self, uint32_t addr) {
|
||||
return self->xip_base <= addr && addr < self->xip_base + 256 * 1024 * 1024;
|
||||
}
|
||||
|
||||
static int xspi_read_111_ext(uint8_t cmd, bool addr_enabled, uint32_t addr, size_t len, uint8_t *dest) {
|
||||
uint32_t admode = addr_enabled ? 1 : 0;
|
||||
XSPIx->CR = (XSPIx->CR & ~XSPI_CR_FMODE_Msk) | 1 << XSPI_CR_FMODE_Pos; // indirect read mode
|
||||
XSPIx->CCR =
|
||||
1 << XSPI_CCR_DMODE_Pos // data on 1 line
|
||||
| 3 << XSPI_CCR_ADSIZE_Pos // 32-bit address size
|
||||
| admode << XSPI_CCR_ADMODE_Pos // address on 1 line, or disabled
|
||||
| 1 << XSPI_CCR_IMODE_Pos // instruction on 1 line
|
||||
;
|
||||
XSPIx->TCR = 0 << XSPI_TCR_DCYC_Pos; // 0 dummy cycles
|
||||
XSPIx->DLR = len - 1; // number of bytes to read
|
||||
XSPIx->IR = cmd; // read opcode (triggers the start of the transaction if address disabled)
|
||||
if (addr_enabled) {
|
||||
XSPIx->AR = addr; // triggers the start of the transaction
|
||||
}
|
||||
|
||||
#if 0 // untested code
|
||||
// Read in the data 4 bytes at a time if dest is aligned.
|
||||
if (((uintptr_t)dest & 3) == 0) {
|
||||
while (len >= 4) {
|
||||
while (!(XSPIx->SR & XSPI_SR_FTF)) {
|
||||
if (XSPIx->SR & XSPI_SR_TEF) {
|
||||
return -MP_EIO;
|
||||
}
|
||||
}
|
||||
*(uint32_t *)dest = XSPIx->DR;
|
||||
dest += 4;
|
||||
len -= 4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Read in data 1 byte at a time.
|
||||
while (len--) {
|
||||
while (!((XSPIx->SR >> XSPI_SR_FLEVEL_Pos) & 0x3f)) {
|
||||
if (XSPIx->SR & XSPI_SR_TEF) {
|
||||
return -MP_EIO;
|
||||
}
|
||||
}
|
||||
*dest++ = *(volatile uint8_t *)&XSPIx->DR;
|
||||
}
|
||||
|
||||
XSPIx->FCR = XSPI_FCR_CTCF; // clear TC flag
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xspi_write_111_ext(uint8_t cmd, bool addr_enabled, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
uint32_t dmode = len == 0 ? 0 : 1;
|
||||
uint32_t admode = addr_enabled ? 1 : 0;
|
||||
|
||||
// Configure and start the transfer.
|
||||
// Transfer starts with IR write if no address or data, with AR write if no data,
|
||||
// otherwise with DR write.
|
||||
|
||||
XSPIx->CR = (XSPIx->CR & ~XSPI_CR_FMODE_Msk) | 0 << XSPI_CR_FMODE_Pos; // indirect write mode
|
||||
XSPIx->CCR =
|
||||
dmode << XSPI_CCR_DMODE_Pos // data on 1 line, or disabled
|
||||
| 3 << XSPI_CCR_ADSIZE_Pos // 32-bit address size
|
||||
| admode << XSPI_CCR_ADMODE_Pos // address on 1 line, or disabled
|
||||
| 1 << XSPI_CCR_IMODE_Pos // instruction on 1 line
|
||||
;
|
||||
XSPIx->TCR = 0 << XSPI_TCR_DCYC_Pos; // 0 dummy cycles
|
||||
if (len != 0) {
|
||||
XSPIx->DLR = len - 1;
|
||||
}
|
||||
XSPIx->IR = cmd; // write opcode
|
||||
if (addr_enabled) {
|
||||
XSPIx->AR = addr; // address
|
||||
}
|
||||
|
||||
// Write out the data one byte at a time
|
||||
while (len--) {
|
||||
while (!(XSPIx->SR & XSPI_SR_FTF)) {
|
||||
if (XSPIx->SR & XSPI_SR_TEF) {
|
||||
return -MP_EIO;
|
||||
}
|
||||
}
|
||||
*(volatile uint8_t *)&XSPIx->DR = *src++;
|
||||
}
|
||||
|
||||
// Wait for write to finish
|
||||
while (!(XSPIx->SR & XSPI_SR_TCF)) {
|
||||
if (XSPIx->SR & XSPI_SR_TEF) {
|
||||
return -MP_EIO;
|
||||
}
|
||||
}
|
||||
|
||||
XSPIx->FCR = XSPI_FCR_CTCF; // clear TC flag
|
||||
|
||||
// Wait for peripheral to return to idle.
|
||||
while (XSPIx->SR & XSPI_SR_BUSY) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xspi_read_888_dtr_ext(uint16_t cmd, bool addr_enabled, uint32_t addr, uint32_t num_dummy, size_t len, uint8_t *dest) {
|
||||
uint32_t admode = addr_enabled ? 4 : 0;
|
||||
|
||||
// Configure and start the transfer.
|
||||
// Transfer starts with IR write if no address, otherwise with AR write.
|
||||
|
||||
XSPIx->CR = (XSPIx->CR & ~XSPI_CR_FMODE_Msk) | 1 << XSPI_CR_FMODE_Pos; // indirect read mode
|
||||
XSPIx->CCR =
|
||||
1 << XSPI_CCR_DQSE_Pos // DQS enabled
|
||||
| 1 << XSPI_CCR_DDTR_Pos // data DTR enabled
|
||||
| 4 << XSPI_CCR_DMODE_Pos // data on 8 lines
|
||||
| 3 << XSPI_CCR_ADSIZE_Pos // 32-bit address size
|
||||
| 1 << XSPI_CCR_ADDTR_Pos // address DTR enabled
|
||||
| admode << XSPI_CCR_ADMODE_Pos // address on 8 lines, or disabled
|
||||
| 1 << XSPI_CCR_ISIZE_Pos // 16-bit instruction
|
||||
| 1 << XSPI_CCR_IDTR_Pos // instruction DTR enabled
|
||||
| 4 << XSPI_CCR_IMODE_Pos // instruction on 8 lines
|
||||
;
|
||||
XSPIx->TCR = num_dummy << XSPI_TCR_DCYC_Pos; // N dummy cycles
|
||||
XSPIx->DLR = len - 1;
|
||||
XSPIx->IR = cmd; // read opcode
|
||||
if (addr_enabled) {
|
||||
XSPIx->AR = addr; // address
|
||||
}
|
||||
|
||||
// Read in data 1 byte at a time.
|
||||
while (len--) {
|
||||
while (!((XSPIx->SR >> XSPI_SR_FLEVEL_Pos) & 0x3f)) {
|
||||
if (XSPIx->SR & XSPI_SR_TEF) {
|
||||
return -MP_EIO;
|
||||
}
|
||||
}
|
||||
*dest++ = *(volatile uint8_t *)&XSPIx->DR;
|
||||
}
|
||||
|
||||
XSPIx->FCR = XSPI_FCR_CTCF; // clear TC flag
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xspi_write_888_dtr_ext(uint16_t cmd, bool addr_enabled, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
uint32_t dmode = len == 0 ? 0 : 4;
|
||||
uint32_t admode = addr_enabled ? 4 : 0;
|
||||
|
||||
// Configure and start the transfer.
|
||||
// Transfer starts with IR write if no address or data, with AR write if no data,
|
||||
// otherwise with DR write.
|
||||
|
||||
XSPIx->CR = (XSPIx->CR & ~XSPI_CR_FMODE_Msk) | 0 << XSPI_CR_FMODE_Pos; // indirect write mode
|
||||
XSPIx->CCR =
|
||||
1 << XSPI_CCR_DDTR_Pos // data DTR enabled
|
||||
| dmode << XSPI_CCR_DMODE_Pos // data on 8 lines, or disabled
|
||||
| 3 << XSPI_CCR_ADSIZE_Pos // 32-bit address size
|
||||
| 1 << XSPI_CCR_ADDTR_Pos // address DTR enabled
|
||||
| admode << XSPI_CCR_ADMODE_Pos // address on 8 lines, or disabled
|
||||
| 1 << XSPI_CCR_ISIZE_Pos // 16-bit instruction
|
||||
| 1 << XSPI_CCR_IDTR_Pos // instruction DTR enabled
|
||||
| 4 << XSPI_CCR_IMODE_Pos // instruction on 8 lines
|
||||
;
|
||||
XSPIx->TCR = 0 << XSPI_TCR_DCYC_Pos; // 0 dummy cycles
|
||||
if (len != 0) {
|
||||
XSPIx->DLR = len - 1;
|
||||
}
|
||||
XSPIx->IR = cmd; // write opcode
|
||||
if (addr_enabled) {
|
||||
XSPIx->AR = addr; // address
|
||||
}
|
||||
|
||||
// Write out the data one byte at a time
|
||||
while (len--) {
|
||||
while (!(XSPIx->SR & XSPI_SR_FTF)) {
|
||||
if (XSPIx->SR & XSPI_SR_TEF) {
|
||||
return -MP_EIO;
|
||||
}
|
||||
}
|
||||
*(volatile uint8_t *)&XSPIx->DR = *src++;
|
||||
}
|
||||
|
||||
// Wait for write to finish
|
||||
while (!(XSPIx->SR & XSPI_SR_TCF)) {
|
||||
if (XSPIx->SR & XSPI_SR_TEF) {
|
||||
return -MP_EIO;
|
||||
}
|
||||
}
|
||||
|
||||
XSPIx->FCR = XSPI_FCR_CTCF; // clear TC flag
|
||||
|
||||
// Wait for peripheral to return to idle.
|
||||
while (XSPIx->SR & XSPI_SR_BUSY) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xspi_memory_map_111(void) {
|
||||
XSPIx->CCR =
|
||||
1 << XSPI_CCR_DMODE_Pos // data on 1 line
|
||||
| 3 << XSPI_CCR_ADSIZE_Pos // 32-bit address
|
||||
| 1 << XSPI_CCR_ADMODE_Pos // address on 1 line
|
||||
| 1 << XSPI_CCR_IMODE_Pos // instruction on 1 line
|
||||
;
|
||||
|
||||
XSPIx->TCR = 0 << XSPI_TCR_DCYC_Pos; // no dummy cycles
|
||||
XSPIx->IR = 0x13; // READ4B
|
||||
XSPIx->LPTR = 1024; // timeout period in number of CLK cycles
|
||||
|
||||
// Enable the XSPI peripheral in memory-mapped mode.
|
||||
XSPIx->CR = (XSPIx->CR & ~XSPI_CR_FMODE_Msk) | 3 << XSPI_CR_FMODE_Pos;
|
||||
}
|
||||
|
||||
static void xspi_memory_map_888(void) {
|
||||
XSPIx->CCR =
|
||||
1 << XSPI_CCR_DQSE_Pos // DQS enabled
|
||||
| 1 << XSPI_CCR_DDTR_Pos // data DTR enabled
|
||||
| 4 << XSPI_CCR_DMODE_Pos // data on 8 lines
|
||||
| 3 << XSPI_CCR_ADSIZE_Pos // 32-bit address
|
||||
| 1 << XSPI_CCR_ADDTR_Pos // address DTR enabled
|
||||
| 4 << XSPI_CCR_ADMODE_Pos // address on 8 lines
|
||||
| 1 << XSPI_CCR_ISIZE_Pos // 16-bit instruction
|
||||
| 1 << XSPI_CCR_IDTR_Pos // instruction DTR enabled
|
||||
| 4 << XSPI_CCR_IMODE_Pos // instruction on 8 lines
|
||||
;
|
||||
|
||||
XSPIx->TCR = 20 << XSPI_TCR_DCYC_Pos; // 20 dummy cycles for reading (minimum, flash may insert more by holding DQS low)
|
||||
XSPIx->IR = 0xee11; // octal DTR read mode (8DTRD)
|
||||
XSPIx->LPTR = 1024; // timeout period in number of CLK cycles
|
||||
|
||||
// Enable the XSPI peripheral in memory-mapped mode.
|
||||
XSPIx->CR = (XSPIx->CR & ~XSPI_CR_FMODE_Msk) | 3 << XSPI_CR_FMODE_Pos;
|
||||
}
|
||||
|
||||
static void xspi_memory_map_exit(void) {
|
||||
// Abort any ongoing transfer if peripheral is busy.
|
||||
if (XSPIx->SR & XSPI_SR_BUSY) {
|
||||
XSPIx->CR |= XSPI_CR_ABORT;
|
||||
while (!(XSPIx->SR & XSPI_SR_TCF)) {
|
||||
}
|
||||
XSPIx->FCR = XSPI_FCR_CTCF; // clear TC flag
|
||||
while (XSPIx->SR & XSPI_SR_BUSY) {
|
||||
}
|
||||
}
|
||||
XSPIx->CR = (XSPIx->CR & ~XSPI_CR_FMODE_Msk) | 0 << XSPI_CR_FMODE_Pos; // indirect write mode
|
||||
}
|
||||
|
||||
void xspi_switch_to_dtr(void) {
|
||||
uint8_t buf[4];
|
||||
|
||||
// WREN.
|
||||
xspi_write_111_ext(0x06, false, 0, 0, NULL);
|
||||
|
||||
// Wait WEL=1, with small timeout.
|
||||
for (unsigned int i = 0; i < 100; ++i) {
|
||||
xspi_read_111_ext(0x05, false, 0, 1, buf);
|
||||
if (buf[0] & 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Switch to DOPI DTR mode.
|
||||
buf[0] = 2;
|
||||
xspi_write_111_ext(0x72, true, 0x00000000, 1, buf);
|
||||
|
||||
xspi_dtr_enabled = true;
|
||||
}
|
||||
|
||||
void xspi_switch_to_spi(void) {
|
||||
uint8_t buf[4];
|
||||
|
||||
// WREN.
|
||||
xspi_write_888_dtr_ext(0x06f9, false, 0, 0, NULL);
|
||||
|
||||
// Wait WEL=1, with small timeout.
|
||||
for (unsigned int i = 0; i < 100; ++i) {
|
||||
xspi_read_111_ext(0x05, false, 0, 1, buf);
|
||||
if (buf[0] & 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Switch to SPI mode.
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
xspi_write_888_dtr_ext(0x728d, true, 0x00000000, 2, buf);
|
||||
|
||||
xspi_dtr_enabled = false;
|
||||
}
|
||||
|
||||
static int xspi_ioctl(void *self_in, uint32_t cmd, uintptr_t arg) {
|
||||
xspi_flash_t *self = self_in;
|
||||
switch (cmd) {
|
||||
case MP_QSPI_IOCTL_INIT:
|
||||
// XSPI must be manually initialise by calling `xspi_init()` at boot.
|
||||
// Here, just determine if it's in SPI or DTR mode.
|
||||
xspi_dtr_enabled = XSPIx->IR == 0xee11;
|
||||
break;
|
||||
case MP_QSPI_IOCTL_BUS_ACQUIRE:
|
||||
xspi_memory_map_exit();
|
||||
break;
|
||||
case MP_QSPI_IOCTL_BUS_RELEASE:
|
||||
if (xspi_dtr_enabled) {
|
||||
xspi_memory_map_888();
|
||||
} else {
|
||||
xspi_memory_map_111();
|
||||
}
|
||||
break;
|
||||
case MP_QSPI_IOCTL_MEMORY_MODIFIED: {
|
||||
uintptr_t *addr_len = (uintptr_t *)arg;
|
||||
volatile void *addr = (volatile void *)(self->xip_base + addr_len[0]);
|
||||
size_t len = addr_len[1];
|
||||
SCB_InvalidateICache_by_Addr(addr, len);
|
||||
SCB_InvalidateDCache_by_Addr(addr, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// These commands may be passed to this function.
|
||||
#define CMD_WREN (0x06)
|
||||
#define CMD_RSTEN (0x66)
|
||||
#define CMD_RESET (0x99)
|
||||
#define CMD_SLEEP (0xb9)
|
||||
#define CMD_AWAKE (0xab)
|
||||
static int xspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
|
||||
if (xspi_dtr_enabled) {
|
||||
uint16_t cmd16 = 0;
|
||||
if (cmd == CMD_WREN) {
|
||||
cmd16 = 0x06f9;
|
||||
} else if (cmd == CMD_SLEEP) {
|
||||
cmd16 = 0xb946;
|
||||
} else if (cmd == CMD_AWAKE) {
|
||||
cmd16 = 0xab54;
|
||||
}
|
||||
return xspi_write_888_dtr_ext(cmd16, false, 0, len, (const uint8_t *)&data);
|
||||
}
|
||||
return xspi_write_111_ext(cmd, false, 0, len, (const uint8_t *)&data);
|
||||
}
|
||||
|
||||
// These commands may be passed to this function.
|
||||
#define CMD_WRITE (0x02)
|
||||
#define CMD_WRITE_32 (0x12)
|
||||
#define CMD_SEC_ERASE (0x20)
|
||||
#define CMD_SEC_ERASE_32 (0x21)
|
||||
static int xspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
// Convert 24-bit address commands to 32-bit address commands.
|
||||
if (cmd == CMD_WRITE) {
|
||||
cmd = CMD_WRITE_32;
|
||||
} else if (cmd == CMD_SEC_ERASE) {
|
||||
cmd = CMD_SEC_ERASE_32;
|
||||
}
|
||||
if (xspi_dtr_enabled) {
|
||||
uint16_t cmd16 = 0;
|
||||
if (cmd == CMD_WRITE_32) {
|
||||
cmd16 = 0x12ed;
|
||||
} else if (cmd == CMD_SEC_ERASE_32) {
|
||||
cmd16 = 0x21de;
|
||||
}
|
||||
return xspi_write_888_dtr_ext(cmd16, true, addr, len, src);
|
||||
}
|
||||
return xspi_write_111_ext(cmd, true, addr, len, src);
|
||||
}
|
||||
|
||||
// These commands may be passed to this function.
|
||||
#define CMD_RDSR (0x05)
|
||||
#define CMD_RD_DEVID (0x9f)
|
||||
static int xspi_read_cmd(void *self_in, uint8_t cmd, size_t len, uint32_t *dest) {
|
||||
(void)self_in;
|
||||
if (xspi_dtr_enabled) {
|
||||
uint16_t cmd16 = 0;
|
||||
uint32_t num_dummy = 0;
|
||||
if (cmd == CMD_RDSR) {
|
||||
cmd16 = 0x05fa;
|
||||
num_dummy = 4;
|
||||
len = 2;
|
||||
} else if (cmd == CMD_RD_DEVID) {
|
||||
// TODO this doesn't really work, because result is in STR format.
|
||||
cmd16 = 0x9f60;
|
||||
num_dummy = 4;
|
||||
}
|
||||
return xspi_read_888_dtr_ext(cmd16, true, 0, num_dummy, len, (uint8_t *)dest);
|
||||
}
|
||||
return xspi_read_111_ext(cmd, false, 0, len, (uint8_t *)dest);
|
||||
}
|
||||
|
||||
static int xspi_direct_read(void *self_in, uint32_t addr, size_t len, uint8_t *dest) {
|
||||
xspi_flash_t *self = self_in;
|
||||
memcpy(dest, (const void *)(self->xip_base + addr), len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const mp_qspi_proto_t xspi_proto = {
|
||||
.ioctl = xspi_ioctl,
|
||||
.write_cmd_data = xspi_write_cmd_data,
|
||||
.write_cmd_addr_data = xspi_write_cmd_addr_data,
|
||||
.read_cmd = xspi_read_cmd,
|
||||
.read_cmd_qaddr_qdata = NULL, // unused because .direct_read is set below, and caching is disabled
|
||||
.direct_read = xspi_direct_read,
|
||||
};
|
||||
|
||||
#endif // defined(MICROPY_HW_XSPIFLASH_SIZE_BITS_LOG2)
|
||||
43
ports/stm32/xspi.h
Normal file
43
ports/stm32/xspi.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024-2025 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_STM32_XSPI_H
|
||||
#define MICROPY_INCLUDED_STM32_XSPI_H
|
||||
|
||||
#include "drivers/bus/qspi.h"
|
||||
|
||||
typedef struct _xspi_flash_t xspi_flash_t;
|
||||
|
||||
extern const mp_qspi_proto_t xspi_proto;
|
||||
extern const xspi_flash_t xspi_flash1;
|
||||
extern const xspi_flash_t xspi_flash2;
|
||||
|
||||
void xspi_init(void);
|
||||
uint32_t xspi_get_xip_base(const xspi_flash_t *self);
|
||||
bool xspi_is_valid_addr(const xspi_flash_t *self, uint32_t addr);
|
||||
void xspi_switch_to_spi(void);
|
||||
void xspi_switch_to_dtr(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_XSPI_H
|
||||
Reference in New Issue
Block a user