8000 WIP: stm32: Add support for STM32N6xx MCUs and three N6 boards by dpgeorge · Pull Request #17171 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

WIP: stm32: Add support for STM32N6xx MCUs and three N6 boards #17171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

dpgeorge
Copy link
Member
@dpgeorge dpgeorge commented Apr 23, 2025

Summary

This PR 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
  • mboot support (required, because there's no internal flash)
  • XSPI in memory-mapped mode
  • machine.Pin
  • machine.UART
  • filesystem

Supported boards:

  • NUCLEO_N657X0
  • STM32N6570_DK
  • OPENMV_N6

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.

The ST CMSIS and HAL files are added verbatim here, but will eventually be moved into stm32lib. Edit: N6 CMSIS and HAL files are now in stm32lib.

OpenMV have generously sponsored the development of this port.

Testing

This PR has been tested on the three N6 boards that are added here.

Copy link
github-actions bot commented Apr 23, 2025

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32: -1704 -0.435% PYBV10[incl -176(bss)]
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

Copy link
codecov bot commented Apr 23, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.54%. Comparing base (f5d10c3) to head (5c6c893).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #17171   +/-   ##
=======================================
  Coverage   98.54%   98.54%           
=======================================
  Files         169      169           
  Lines       21898    21898           
=======================================
  Hits        21579    21579           
  Misses        319      319           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

// TODO: if (HAL_PWREx_ConfigSupply(PWR_EXTERNAL_SOURCE_SUPPLY ) != HAL_OK)
//xspi_flash_init();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define OMV_BOOT_MAGIC_ADDR (0x3401FFFCU)
#define OMV_BOOT_MAGIC_VALUE (0xB00710ADU)
void board_enter_bootloader(void) {
*((uint32_t *) OMV_BOOT_MAGIC_ADDR) = OMV_BOOT_MAGIC_VALUE;
SCB_CleanDCache();
NVIC_SystemReset();
}

To enter our bootloader.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to have the OPENMV_N6 board definition included in MicroPython's stm32 port (like with the OPENMV_AE3)? If so, it should work with mboot. But probably also a good idea to work with the OpenMV bootloader, which means adding this code.

Related: how did you choose address 0x3401FFFC? That's part way through SRAM1, in the FLEXRAM area. You'd need to make sure that isn't cleared on reset like the rest of SRAM1/2, and also make sure it's not overwritten by the bootloader.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to have the OPENMV_N6 board definition included in MicroPython's stm32 port (like with the OPENMV_AE3)? If so, it should work with mboot. But probably also a good idea to work with the OpenMV bootloader, which means adding this code.

Either way is fine with me. If mboot support is kept, I can always use MP_CONFIGFILE to override and not build mboot when building our firmware.

Related: how did you choose address 0x3401FFFC? That's part way through SRAM1, in the FLEXRAM area. You'd need to make sure that isn't cleared on reset like the rest of SRAM1/2, and also make sure it's not overwritten by the bootloader.

Good point. The bootloader uses the 128K (or 64K) DTCM for its memory (heap, stack etc..), so this address is typically 0x2001FFFCU (last word of bootloader's memory) and it's the same for almost all boards. However, for some reason, this doesn't work on the N6, so I just used SRAM1. Note that SRAM1 and SRAM2 don't seem to get erased on reset, otherwise this wouldn't work, but it would still be better to use DTCM for this, but it's not working.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I think I just needed a DSB, seems the write might be buffered. The following works too:

#define OMV_BOOT_MAGIC_ADDR   (0x3001FFFCU)
#define OMV_BOOT_MAGIC_VALUE  (0xB00710ADU)

void board_enter_bootloader(void) {
    *((uint32_t *) OMV_BOOT_MAGIC_ADDR) = OMV_BOOT_MAGIC_VALUE;
    __DSB();
    NVIC_SystemReset();
}

Copy link
Contributor
@iabdalkader iabdalkader Apr 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dpgeorge There seems to be some issue with DTCM, I can't access any address above ~0x1000. This causes a fault on boot when it tries accesses the magic number address (oddly enough, it doesn't always happen). Perhaps it has something to do with security config, flexram, clocks or something else that gets enabled by the main firmware, but even from the main firmware I still can't access this memory from gdb. Anyway let's please keep the original boot address (with cache clean).

@dpgeorge dpgeorge force-pushed the stm32-add-n6-support branch 2 times, most recently from 562ed7c to 6cb319e Compare April 30, 2025 15:25
MICROPY_PY_NETWORK_CYW43 = 1
MICROPY_PY_SSL = 1
MICROPY_SSL_MBEDTLS = 1
MICROPY_VFS_LFS2 = 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to be able to disable mboot USE_MBOOT ?= 1 and also we never use LFS2, just fat.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made all these options use ?=.

But note that the way it's configured you'll probably want to enable USE_MBOOT because that puts the firmware in external flash. Otherwise MicroPython runs from RAM.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to build a flash-based image just without mboot? Like an option to do so, that gets forced to one if mboot is enabled, otherwise is user-defined?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's just USE_MBOOT=1. I guess it should be called USE_BOOTLOADER=1 but for consistency it's the mboot option.

That option is anyway local to the board (nothing outside the board uses this config option, except mboot itself). The option controls:

  1. which ld scripts to use
  2. location of .text

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what if you don't want to build mboot, yet still want a flash-based image? Can USE_MBOOT=1 define something like MICROPY_FLASH_BASED=1? For example:

USE_MBOOT ?= 1
MICROPY_FLASH_BASED ?= $(USE_MBOOT)

This way I can define USE_MBOOT=0 MICROPY_FLASH_BASED=1 to get a flash-based image without mboot.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mboot is not built unless you explicitly do make in the ports/stm32/mboot directory.

But, I can do what you suggest, it makes sense.

#define MICROPY_HW_ENABLE_RNG (0)
#define MICROPY_HW_ENABLE_RTC (0)
#define MICROPY_HW_ENABLE_RTC (1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For our bootloader, we need the following:

#define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET   (0)

extern void board_early_init(void);
#define MICROPY_BOARD_EARLY_INIT    board_early_init

extern void board_enter_bootloader(void);
#define MICROPY_BOARD_ENTER_BOOTLOADER(nargs, args) board_enter_bootloader()

With the following code in board.c (which could be gated if mboot is enabled):

#include STM32_HAL_H
#include "py/mphal.h"

#define OMV_BOOT_MAGIC_ADDR   (0x3401FFFCU)
#define OMV_BOOT_MAGIC_VALUE  (0xB00710ADU)

void board_early_init(void) {

}

void board_enter_bootloader(void) {
    *((uint32_t *) OMV_BOOT_MAGIC_ADDR) = OMV_BOOT_MAGIC_VALUE;
    SCB_CleanDCache();
    NVIC_SystemReset();
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now made the board work with both the OpenMV bootloader and mboot.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a proper init sequence for this in the examples in the HAL, if you want to take a look. I think it's more or less the same, but there were some delays, more force_reset/release etc...

Also, could you please add this? I use it in HS mode.

diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
index 3a87896b4..5906f95e0 100644
--- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
+++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
@@ -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)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the USBD_SUPPORT_HS_MODE option as above.

But testing it with #15909 shows that there is data corruption when HS is enabled. That needs investigation.

@dpgeorge dpgeorge force-pushed the stm32-add-n6-support branch from 43eb2ba to 653f480 Compare May 16, 2025 06:34
@dpgeorge dpgeorge force-pushed the stm32-add-n6-support branch 3 times, most recently from 32f5690 to 5fb6eff Compare May 23, 2025 14:02
@iabdalkader
Copy link
Contributor

The N6 is missing from the FPU filter list in micropython/ports/stm32/stm32.mk.

@dpgeorge dpgeorge force-pushed the stm32-add-n6-support branch from 75dc026 to 5522b3b Compare May 28, 2025 07:37
@dpgeorge
Copy link
Member Author

The N6 is missing from the FPU filter list

OK, now fixed.

@dpgeorge dpgeorge force-pushed the stm32-add-n6-support branch from 5522b3b to dbb5086 Compare May 28, 2025 16:08
dpgeorge and others added 13 commits May 29, 2025 16:27
Signed-off-by: Damien George <damien@micropython.org>
That's almost the same as FLT_EVAL_METHOD == 0, but indicates the
presence of _Float16_t support.

Signed-off-by: Damien George <damien@micropython.org>
Changes in this new library version are:
- Add N6 HAL at v1.1.0.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
See ST Errata ES0620 - Rev 0.2 section 2.1.2.

Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
@dpgeorge dpgeorge force-pushed the stm32-add-n6-support branch from dbb5086 to 5c6c893 Compare May 30, 2025 03:53
@dpgeorge
Copy link
Member Author

I finally got the filesystem working. Needed to make sure all relevant code and data structures to erase/write SPI flash is in RAM, and that interrupts are fully disabled during erase/write (obvious but tricky to do).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0