From 91e9da00691b9553f9fe34eb0eddec5fd8c3cdfe Mon Sep 17 00:00:00 2001 From: robert Date: Thu, 21 May 2026 07:58:05 -0400 Subject: [PATCH] More STM32 examples --- .../downloads/integrate_mongoose_cubemx.sh | 13 +- .../stm32/nucleo_f746zg/cubemx/README.md | 30 + .../nucleo_f746zg/cubemx/nucleo_f746zg.ioc | 207 ++++ .../stm32/nucleo_f746zg/minimal/Makefile | 38 + tutorials/stm32/nucleo_f746zg/minimal/hal.c | 125 ++ tutorials/stm32/nucleo_f746zg/minimal/hal.h | 181 +++ tutorials/stm32/nucleo_f746zg/minimal/link.ld | 26 + tutorials/stm32/nucleo_f746zg/minimal/main.c | 70 ++ .../nucleo_f746zg/minimal/mongoose_config.h | 42 + .../stm32/nucleo_h743zi/cubemx/README.md | 30 + .../nucleo_h743zi/cubemx/nucleo_h743zi.ioc | 212 ++++ .../stm32/nucleo_h743zi/minimal/Makefile | 38 + tutorials/stm32/nucleo_h743zi/minimal/hal.c | 125 ++ tutorials/stm32/nucleo_h743zi/minimal/hal.h | 269 ++++ tutorials/stm32/nucleo_h743zi/minimal/link.ld | 32 + tutorials/stm32/nucleo_h743zi/minimal/main.c | 70 ++ .../nucleo_h743zi/minimal/mongoose_config.h | 42 + .../stm32/stm32h747i_disco/cubemx/README.md | 30 + .../cubemx/stm32h747i_disco.ioc | 1097 +++++++++++++++++ .../stm32/stm32h747i_disco/minimal/Makefile | 38 + .../stm32/stm32h747i_disco/minimal/hal.c | 125 ++ .../stm32/stm32h747i_disco/minimal/hal.h | 246 ++++ .../stm32/stm32h747i_disco/minimal/link.ld | 31 + .../stm32/stm32h747i_disco/minimal/main.c | 70 ++ .../minimal/mongoose_config.h | 42 + 25 files changed, 3228 insertions(+), 1 deletion(-) create mode 100644 tutorials/stm32/nucleo_f746zg/cubemx/README.md create mode 100644 tutorials/stm32/nucleo_f746zg/cubemx/nucleo_f746zg.ioc create mode 100644 tutorials/stm32/nucleo_f746zg/minimal/Makefile create mode 100644 tutorials/stm32/nucleo_f746zg/minimal/hal.c create mode 100644 tutorials/stm32/nucleo_f746zg/minimal/hal.h create mode 100644 tutorials/stm32/nucleo_f746zg/minimal/link.ld create mode 100644 tutorials/stm32/nucleo_f746zg/minimal/main.c create mode 100644 tutorials/stm32/nucleo_f746zg/minimal/mongoose_config.h create mode 100644 tutorials/stm32/nucleo_h743zi/cubemx/README.md create mode 100644 tutorials/stm32/nucleo_h743zi/cubemx/nucleo_h743zi.ioc create mode 100644 tutorials/stm32/nucleo_h743zi/minimal/Makefile create mode 100644 tutorials/stm32/nucleo_h743zi/minimal/hal.c create mode 100644 tutorials/stm32/nucleo_h743zi/minimal/hal.h create mode 100644 tutorials/stm32/nucleo_h743zi/minimal/link.ld create mode 100644 tutorials/stm32/nucleo_h743zi/minimal/main.c create mode 100644 tutorials/stm32/nucleo_h743zi/minimal/mongoose_config.h create mode 100644 tutorials/stm32/stm32h747i_disco/cubemx/README.md create mode 100644 tutorials/stm32/stm32h747i_disco/cubemx/stm32h747i_disco.ioc create mode 100644 tutorials/stm32/stm32h747i_disco/minimal/Makefile create mode 100644 tutorials/stm32/stm32h747i_disco/minimal/hal.c create mode 100644 tutorials/stm32/stm32h747i_disco/minimal/hal.h create mode 100644 tutorials/stm32/stm32h747i_disco/minimal/link.ld create mode 100644 tutorials/stm32/stm32h747i_disco/minimal/main.c create mode 100644 tutorials/stm32/stm32h747i_disco/minimal/mongoose_config.h diff --git a/resources/downloads/integrate_mongoose_cubemx.sh b/resources/downloads/integrate_mongoose_cubemx.sh index b9b70f5f..266fab0d 100755 --- a/resources/downloads/integrate_mongoose_cubemx.sh +++ b/resources/downloads/integrate_mongoose_cubemx.sh @@ -24,12 +24,23 @@ case $DIR in *_n657*) (grep -q MG_TLS_NONE $DIR/Mongoose/mongoose_config.h || ec # Patch main.c and linker script MAIN_C=$DIR/Core/Src/main.c +patch_linker_script() { + LD=$1 + test -f "$LD" || return + echo $LD + grep -q RAM_D2 "$LD" || perl -i -ne 'print; print " RAM_D2 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K\n" if /^\s*MEMORY\b.*\{/ || ($m && /\{/); $m = /^\s*MEMORY\b/ && !/\{/' "$LD" + grep -q eth_ram "$LD" || perl -i -ne 'print ; print "\n /* Mongoose Ethernet driver */\n .eth_ram : { *(.eth_ram .eth_ram*) } > RAM_D2 AT > FLASH\n" if /_sidata =/' "$LD" +} HUART=`perl -nle 'print \$1 if /^UART_HandleTypeDef (.+);/' $MAIN_C` grep -q mongoose.h $MAIN_C || perl -i -ne 'print; print "#include \"mongoose.h\"\n" if /BEGIN Includes/' $MAIN_C grep -q '^int _write' $MAIN_C || perl -i -ne "print; print \"int _write(int fd, unsigned char *buf, int len) {\n HAL_UART_Transmit(&${HUART}, buf, len, HAL_MAX_DELAY);\n return len;\n}\n\" if /USER CODE BEGIN 0/" $MAIN_C grep -q 'mg_mgr_init' $MAIN_C || perl -i -ne 'print; print " struct mg_mgr mgr;\n mg_mgr_init(&mgr);\n\n" if /USER CODE BEGIN WHILE/' $MAIN_C grep -q 'mg_mgr_poll' $MAIN_C || perl -i -ne 'print " mg_mgr_poll(&mgr, 0);\n" if /USER CODE END WHILE/; print;' $MAIN_C -test -f $DIR/STM32H723XG_FLASH.ld && (grep -q eth_ram $DIR/STM32H723XG_FLASH.ld || perl -i -ne 'print ; print "\n /* Mongoose Ethernet driver */\n .eth_ram : { *(.eth_ram .eth_ram*) } > RAM_D2 AT > FLASH\n" if /_sidata =/' $DIR/STM32H723XG_FLASH.ld) +patch_linker_script $DIR/STM32H723XG_FLASH.ld +patch_linker_script $DIR/STM32H743XX_FLASH.ld +patch_linker_script $DIR/STM32H743ZITX_FLASH.ld +patch_linker_script $DIR/STM32H747XIHX_FLASH.ld +patch_linker_script $DIR/stm32h747xx_flash_CM7.ld test -f $DIR/LICENSE || $CURL $RAW/LICENSE -o $DIR/LICENSE case $DIR in portenta*) ( grep -q 'void hwspecific_sdio_init(void);' "$MAIN_C" || \ diff --git a/tutorials/stm32/nucleo_f746zg/cubemx/README.md b/tutorials/stm32/nucleo_f746zg/cubemx/README.md new file mode 100644 index 00000000..5a400d27 --- /dev/null +++ b/tutorials/stm32/nucleo_f746zg/cubemx/README.md @@ -0,0 +1,30 @@ +# Nucleo-F746ZG Mongoose Integration + +This guide explains how to bring up a production-grade Web UI dashboard on the +STM32 Nucleo-F746ZG development board. + +A pre-configured, ready-to-run project zip is available for download at +https://mongoose.ws. + +To integrate the Web UI dashboard into an existing CubeMX project, or to create a +new project from scratch: + +1. Configure the peripherals (described below). +2. Regenerate your project code and integrate Mongoose core by following + https://mongoose.ws/docs/guides/stm32-tcpip-stack/. +3. Add the Web UI dashboard by following + https://mongoose.ws/docs/guides/web-dashboard-guide/. + +## Configure peripherals + +An `.ioc` file is included in this directory for your reference. It was created +using the following steps: + +- Open CubeMX. If you are starting a new project, select the STM32F746ZG + microcontroller and create a new project. +- In Clock Configuration, set the maximum clock frequency to 216 MHz. +- In the MCU pinout view, set pins PB0, PB7, and PB14 to GPIO_Output mode. +- In Pinout & Configuration / Connectivity, enable USART3 in asynchronous mode. + Configure pins PD8 and PD9 for USART. +- In Pinout & Configuration / Connectivity, enable ETH in RMII mode and set pins + PA1, PA2, PA7, PC1, PC4, PC5, PB13, PG11, and PG13 for Ethernet. diff --git a/tutorials/stm32/nucleo_f746zg/cubemx/nucleo_f746zg.ioc b/tutorials/stm32/nucleo_f746zg/cubemx/nucleo_f746zg.ioc new file mode 100644 index 00000000..e2071563 --- /dev/null +++ b/tutorials/stm32/nucleo_f746zg/cubemx/nucleo_f746zg.ioc @@ -0,0 +1,207 @@ +#MicroXplorer Configuration settings - do not modify +CAD.formats= +CAD.pinconfig= +CAD.provider= +ETH.IPParameters=MediaInterface +ETH.MediaInterface=HAL_ETH_RMII_MODE +File.Version=6 +GPIO.groupedBy= +KeepUserPlacement=false +Mcu.CPN=STM32F746ZGT6 +Mcu.Family=STM32F7 +Mcu.IP0=CORTEX_M7 +Mcu.IP1=ETH +Mcu.IP2=NVIC +Mcu.IP3=RCC +Mcu.IP4=RNG +Mcu.IP5=SYS +Mcu.IP6=USART3 +Mcu.IPNb=7 +Mcu.Name=STM32F746ZGTx +Mcu.Package=LQFP144 +Mcu.Pin0=PC1 +Mcu.Pin1=PA1 +Mcu.Pin10=PD9 +Mcu.Pin11=PG11 +Mcu.Pin12=PG13 +Mcu.Pin13=PB7 +Mcu.Pin14=VP_RNG_VS_RNG +Mcu.Pin15=VP_SYS_VS_Systick +Mcu.Pin2=PA2 +Mcu.Pin3=PA7 +Mcu.Pin4=PC4 +Mcu.Pin5=PC5 +Mcu.Pin6=PB0 +Mcu.Pin7=PB13 +Mcu.Pin8=PB14 +Mcu.Pin9=PD8 +Mcu.PinsNb=16 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32F746ZGTx +MxCube.Version=6.17.0 +MxDb.Version=DB.6.0.170 +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.ETH_IRQn=true\:0\:0\:false\:false\:false\:true\:false\:true +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PA1.Mode=RMII +PA1.Signal=ETH_REF_CLK +PA2.Mode=RMII +PA2.Signal=ETH_MDIO +PA7.Mode=RMII +PA7.Signal=ETH_CRS_DV +PB0.Locked=true +PB0.Signal=GPIO_Output +PB13.Mode=RMII +PB13.Signal=ETH_TXD1 +PB14.Locked=true +PB14.Signal=GPIO_Output +PB7.Locked=true +PB7.Signal=GPIO_Output +PC1.Mode=RMII +PC1.Signal=ETH_MDC +PC4.Mode=RMII +PC4.Signal=ETH_RXD0 +PC5.Mode=RMII +PC5.Signal=ETH_RXD1 +PCC.Checker=false +PCC.Display=Plot\: All Steps +PCC.Line=STM32F7x6 +PCC.MCU=STM32F746ZGTx +PCC.PartNumber=STM32F746ZGTx +PCC.Series=STM32F7 +PCC.Temperature=25 +PCC.Vdd=3.3 +PD8.Locked=true +PD8.Mode=Asynchronous +PD8.Signal=USART3_TX +PD9.Locked=true +PD9.Mode=Asynchronous +PD9.Signal=USART3_RX +PG11.Locked=true +PG11.Mode=RMII +PG11.Signal=ETH_TX_EN +PG13.Locked=true +PG13.Mode=RMII +PG13.Signal=ETH_TXD0 +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerLinker=GCC +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=false +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32F746ZGTx +ProjectManager.FirmwarePackage=STM32Cube FW_F7 V1.17.4 +ProjectManager.FreePins=false +ProjectManager.FreePinsContext= +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=0x10000 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=1 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain=STM32CubeIDE +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=nucleo_f746zg.ioc +ProjectManager.ProjectName=nucleo_f746zg +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x2000 +ProjectManager.TargetToolchain=CMake +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_ETH_Init-ETH-false-HAL-true,4-MX_RNG_Init-RNG-false-HAL-true,5-MX_USART3_UART_Init-USART3-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true +RCC.48MHZClocksFreq_Value=45000000 +RCC.AHBFreq_Value=216000000 +RCC.APB1CLKDivider=RCC_HCLK_DIV4 +RCC.APB1Freq_Value=54000000 +RCC.APB1TimFreq_Value=108000000 +RCC.APB2CLKDivider=RCC_HCLK_DIV2 +RCC.APB2Freq_Value=108000000 +RCC.APB2TimFreq_Value=216000000 +RCC.CECFreq_Value=32786.88524590164 +RCC.CortexFreq_Value=216000000 +RCC.EthernetFreq_Value=216000000 +RCC.FCLKCortexFreq_Value=216000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=216000000 +RCC.HSE_VALUE=25000000 +RCC.HSI_VALUE=16000000 +RCC.I2C1Freq_Value=54000000 +RCC.I2C2Freq_Value=54000000 +RCC.I2C3Freq_Value=54000000 +RCC.I2C4Freq_Value=54000000 +RCC.I2SClocksFreq_Value=192000000 +RCC.I2SFreq_Value=192000000 +RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CECFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SClocksFreq_Value,I2SFreq_Value,LCDTFTFreq_Value,LCDTFToutputFreq_Value,LPTIM1Freq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLI2SRoutputFreq_Value,PLLM,PLLN,PLLQ,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLSAIPCLKFreq_Value,PLLSAIQCLKFreq_Value,PLLSAIRCLKFreq_Value,RNGFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SAI_AClocksFreq_Value,SAI_BClocksFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAIOutputFreq_Value,VCOSAIOutputFreq_ValueQ,VCOSAIOutputFreq_ValueR,VcooutputI2S,VcooutputI2SQ +RCC.LCDTFTFreq_Value=24500000 +RCC.LCDTFToutputFreq_Value=96000000 +RCC.LPTIM1Freq_Value=54000000 +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.MCO2PinFreq_Value=216000000 +RCC.PLLCLKFreq_Value=216000000 +RCC.PLLI2SPCLKFreq_Value=192000000 +RCC.PLLI2SQCLKFreq_Value=192000000 +RCC.PLLI2SRCLKFreq_Value=192000000 +RCC.PLLI2SRoutputFreq_Value=192000000 +RCC.PLLM=8 +RCC.PLLN=216 +RCC.PLLQ=9 +RCC.PLLQCLKFreq_Value=48000000 +RCC.PLLQoutputFreq_Value=48000000 +RCC.PLLSAIPCLKFreq_Value=192000000 +RCC.PLLSAIQCLKFreq_Value=192000000 +RCC.PLLSAIRCLKFreq_Value=192000000 +RCC.RNGFreq_Value=48000000 +RCC.RTCFreq_Value=32000 +RCC.RTCHSEDivFreq_Value=12500000 +RCC.SAI1Freq_Value=192000000 +RCC.SAI2Freq_Value=192000000 +RCC.SAI_AClocksFreq_Value=24500000 +RCC.SAI_BClocksFreq_Value=24500000 +RCC.SDMMCFreq_Value=216000000 +RCC.SPDIFRXFreq_Value=192000000 +RCC.SYSCLKFreq_VALUE=216000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.UART4Freq_Value=54000000 +RCC.UART5Freq_Value=54000000 +RCC.UART7Freq_Value=54000000 +RCC.UART8Freq_Value=54000000 +RCC.USART1Freq_Value=108000000 +RCC.USART2Freq_Value=54000000 +RCC.USART3Freq_Value=54000000 +RCC.USART6Freq_Value=108000000 +RCC.USBFreq_Value=48000000 +RCC.VCOI2SOutputFreq_Value=384000000 +RCC.VCOInputFreq_Value=2000000 +RCC.VCOOutputFreq_Value=432000000 +RCC.VCOSAIOutputFreq_Value=384000000 +RCC.VCOSAIOutputFreq_ValueQ=24500000 +RCC.VCOSAIOutputFreq_ValueR=49000000 +RCC.VcooutputI2S=192000000 +RCC.VcooutputI2SQ=192000000 +USART3.IPParameters=VirtualMode,VirtualMode-Asynchronous +USART3.VirtualMode=VM_ASYNC +USART3.VirtualMode-Asynchronous=VM_ASYNC +VP_RNG_VS_RNG.Mode=RNG_Activate +VP_RNG_VS_RNG.Signal=RNG_VS_RNG +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +board=custom diff --git a/tutorials/stm32/nucleo_f746zg/minimal/Makefile b/tutorials/stm32/nucleo_f746zg/minimal/Makefile new file mode 100644 index 00000000..07d5f9f6 --- /dev/null +++ b/tutorials/stm32/nucleo_f746zg/minimal/Makefile @@ -0,0 +1,38 @@ +# Copyright (c) 2026 Cesanta Software Limited +# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/ + +CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion +CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion +CFLAGS += -g3 -Os -ffunction-sections -fdata-sections +CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_f7/Include +CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 $(CFLAGS_EXTRA) +LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map + +SOURCES = main.c hal.c +SOURCES += cmsis_f7/Source/Templates/gcc/startup_stm32f746xx.s + +TOP = ../../../.. +CFLAGS += -I$(TOP) +SOURCES += $(TOP)/mongoose.c + +all: firmware.bin + +firmware.elf: cmsis_core cmsis_f7 hal.h link.ld Makefile $(SOURCES) + arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@ + +firmware.bin: firmware.elf + arm-none-eabi-objcopy -O binary $< $@ + @echo + @echo "To flash, run 'make flash', or use STM32CubeProgrammer" + +flash: firmware.bin + STM32_Programmer_CLI -c port=swd -e all -w firmware.elf -hardRst + +cmsis_core: + git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@ + +cmsis_f7: + git clone -q -c advice.detachedHead=false --depth 1 -b v1.2.8 https://github.com/STMicroelectronics/cmsis_device_f7 $@ + +clean: + rm -rf firmware.* diff --git a/tutorials/stm32/nucleo_f746zg/minimal/hal.c b/tutorials/stm32/nucleo_f746zg/minimal/hal.c new file mode 100644 index 00000000..6dc65c9f --- /dev/null +++ b/tutorials/stm32/nucleo_f746zg/minimal/hal.c @@ -0,0 +1,125 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "hal.h" + +bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) { + uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry + if (period == 0) return false; // Avoid division by zero + if (diff < period) return false; // Period has not elapsed yet + *t += (diff / period) * period; // Preserve cadence, skip missed periods + return true; +} + +static volatile uint64_t s_ticks; // Milliseconds since boot +void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms + s_ticks++; +} + +uint64_t hal_get_tick(void) { + return s_ticks; +}; + +uint32_t SystemCoreClock = SYS_FREQUENCY; +void SystemInit(void) { // Called automatically by startup code + hal_system_init(); // Enable FPU + hal_clock_init(); + SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms +} + +void ExitRun0Mode(void) { +} + +struct stat; +__attribute__((weak)) int _fstat(int fd, struct stat *st) { + (void) fd, (void) st; + return -1; +} + +extern unsigned char _end[]; // End of data section, start of heap. See link.ld +static unsigned char *s_current_heap_end = _end; + +size_t hal_ram_used(void) { + return (size_t) (s_current_heap_end - _end); +} + +size_t hal_ram_free(void) { + unsigned char endofstack; + return (size_t) (&endofstack - s_current_heap_end); +} + +void *_sbrk(int incr) { + unsigned char *prev_heap; + unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256); + prev_heap = s_current_heap_end; + // Check how much space we got from the heap end to the stack end + if (s_current_heap_end + incr > heap_end) return (void *) -1; + s_current_heap_end += incr; + return prev_heap; +} + +__attribute__((weak)) int _open(const char *path) { + (void) path; + return -1; +} + +__attribute__((weak)) int _close(int fd) { + (void) fd; + return -1; +} + +__attribute__((weak)) int _isatty(int fd) { + (void) fd; + return 1; +} + +__attribute__((weak)) int _lseek(int fd, int ptr, int dir) { + (void) fd, (void) ptr, (void) dir; + return 0; +} + +__attribute__((weak)) void _exit(int status) { + (void) status; + for (;;) asm volatile("BKPT #0"); +} + +__attribute__((weak)) void _kill(int pid, int sig) { + (void) pid, (void) sig; +} + +__attribute__((weak)) int _getpid(void) { + return -1; +} + +__attribute__((weak)) int _write(int fd, char *ptr, int len) { + (void) fd, (void) ptr, (void) len; + return -1; +} + +__attribute__((weak)) int _read(int fd, char *ptr, int len) { + (void) fd, (void) ptr, (void) len; + return -1; +} + +__attribute__((weak)) int _link(const char *a, const char *b) { + (void) a, (void) b; + return -1; +} + +__attribute__((weak)) int _unlink(const char *a) { + (void) a; + return -1; +} + +__attribute__((weak)) int _stat(const char *path, struct stat *st) { + (void) path, (void) st; + return -1; +} + +__attribute__((weak)) int mkdir(const char *path, int mode) { + (void) path, (void) mode; + return -1; +} + +__attribute__((weak)) void _init(void) { +} diff --git a/tutorials/stm32/nucleo_f746zg/minimal/hal.h b/tutorials/stm32/nucleo_f746zg/minimal/hal.h new file mode 100644 index 00000000..7f20936f --- /dev/null +++ b/tutorials/stm32/nucleo_f746zg/minimal/hal.h @@ -0,0 +1,181 @@ +// Copyright (c) 2022-2024 Cesanta Software Limited +// https://www.st.com/resource/en/reference_manual/dm00124865-stm32f75xxx-and-stm32f74xxx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf +// https://www.st.com/resource/en/datasheet/stm32f746zg.pdf + +#pragma once + +#include + +#include +#include +#include +#include + +extern bool hal_timer_expired(volatile uint64_t *t, uint64_t prd, uint64_t now); +extern uint64_t hal_get_tick(void); +extern size_t hal_ram_free(void); +extern size_t hal_ram_used(void); +extern uint32_t SystemCoreClock; + +#define HAL_ETH_PINS \ + PIN('A', 1), /* ETH_REF_CLK */ \ + PIN('A', 2), /* ETH_MDIO */ \ + PIN('A', 7), /* ETH_CRS_DV */ \ + PIN('B', 13), /* ETH_TXD1 */ \ + PIN('C', 1), /* ETH_MDC */ \ + PIN('C', 4), /* ETH_RXD0 */ \ + PIN('C', 5), /* ETH_RXD1 */ \ + PIN('G', 11), /* ETH_TX_EN */ \ + PIN('G', 13) /* ETH_TXD0 */ + +#define BIT(x) (1UL << (x)) +#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set)) +#define PIN(bank, num) ((((bank) - 'A') << 8) | (num)) +#define PINNO(pin) (pin & 255) +#define PINBANK(pin) (pin >> 8) + +void hal_init(void); +size_t hal_ram_free(void); +size_t hal_ram_used(void); + +/* System clock +5.3.3: APB1 clock <= 54MHz; APB2 clock <= 108MHz +3.3.2, Table 5: configure flash latency (WS) in accordance to clock freq +38.4: The AHB clock frequency must be at least 25 MHz when the Ethernet +controller is used */ +enum { HAL_APB1_PRE = 5 /* AHB clock / 4 */, HAL_APB2_PRE = 4 /* AHB clock / 2 */ }; +enum { PLL_HSI = 16, PLL_M = 8, PLL_N = 216, PLL_P = 2 }; // Run at 216 Mhz +#define FLASH_LATENCY 7 +#define SYS_FREQUENCY ((PLL_HSI * PLL_N / PLL_M / PLL_P) * 1000000) +#define APB2_FREQUENCY (SYS_FREQUENCY / (BIT(HAL_APB2_PRE - 3))) +#define APB1_FREQUENCY (SYS_FREQUENCY / (BIT(HAL_APB1_PRE - 3))) + +enum { HAL_GPIO_MODE_INPUT, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_MODE_AF, HAL_GPIO_MODE_ANALOG }; +enum { HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_OTYPE_OPEN_DRAIN }; +enum { HAL_GPIO_SPEED_LOW, HAL_GPIO_SPEED_MEDIUM, HAL_GPIO_SPEED_HIGH, HAL_GPIO_SPEED_INSANE }; +enum { HAL_GPIO_PULL_NONE, HAL_GPIO_PULL_UP, HAL_GPIO_PULL_DOWN }; +#define HAL_GPIO(N) ((GPIO_TypeDef *) (0x40020000 + 0x400 * (N))) + +static GPIO_TypeDef *hal_gpio_bank(uint16_t pin) { + return HAL_GPIO(PINBANK(pin)); +} +static inline void hal_gpio_toggle(uint16_t pin) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + uint32_t mask = BIT(PINNO(pin)); + gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0); +} +static inline int hal_gpio_read(uint16_t pin) { + return hal_gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0; +} +static inline void hal_gpio_write(uint16_t pin, bool val) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16); +} +static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t type, + uint8_t speed, uint8_t pull, uint8_t af) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + uint8_t n = (uint8_t) (PINNO(pin)); + RCC->AHB1ENR |= BIT(PINBANK(pin)); // Enable GPIO clock + CLRSET(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n); + CLRSET(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2)); + CLRSET(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2)); + CLRSET(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4), + ((uint32_t) af) << ((n & 7) * 4)); + CLRSET(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2)); +} +static inline void hal_gpio_input(uint16_t pin) { + hal_gpio_init(pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, + HAL_GPIO_PULL_NONE, 0); +} +static inline void hal_gpio_output(uint16_t pin) { + hal_gpio_init(pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, + HAL_GPIO_PULL_NONE, 0); +} + +static inline void hal_irq_exti_attach(uint16_t pin) { + uint8_t bank = (uint8_t) (PINBANK(pin)), n = (uint8_t) (PINNO(pin)); + SYSCFG->EXTICR[n / 4] &= ~(15UL << ((n % 4) * 4)); + SYSCFG->EXTICR[n / 4] |= (uint32_t) (bank << ((n % 4) * 4)); + EXTI->IMR |= BIT(n); + EXTI->RTSR |= BIT(n); + EXTI->FTSR |= BIT(n); + int irqvec = n < 5 ? 6 + n : n < 10 ? 23 : 40; // IRQ vector index, 10.1.2 + NVIC_SetPriority(irqvec, 3); + NVIC_EnableIRQ(irqvec); +} + +static inline void hal_uart_init(USART_TypeDef *uart, unsigned long baud) { + uint8_t af = 7; // Alternate function + uint16_t rx = 0, tx = 0; // pins + uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1 + + if (uart == USART1) freq = APB2_FREQUENCY, RCC->APB2ENR |= BIT(4); + if (uart == USART2) freq = APB1_FREQUENCY, RCC->APB1ENR |= BIT(17); + if (uart == USART3) freq = APB1_FREQUENCY, RCC->APB1ENR |= BIT(18); + + if (uart == USART1) tx = PIN('A', 9), rx = PIN('A', 10); + if (uart == USART2) tx = PIN('A', 2), rx = PIN('A', 3); + if (uart == USART3) tx = PIN('D', 8), rx = PIN('D', 9); + + hal_gpio_init(tx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af); + hal_gpio_init(rx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af); + uart->CR1 = 0; // Disable this UART + uart->BRR = freq / baud; // Set baud rate + uart->CR1 |= BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE +} +static inline void hal_uart_write_byte(USART_TypeDef *uart, uint8_t byte) { + uart->TDR = byte; + while ((uart->ISR & BIT(7)) == 0) (void) 0; +} +static inline void hal_uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) { + while (len-- > 0) hal_uart_write_byte(uart, *(uint8_t *) buf++); +} +static inline int hal_uart_read_ready(USART_TypeDef *uart) { + return uart->ISR & BIT(5); // If RXNE bit is set, data is ready +} +static inline uint8_t hal_uart_read_byte(USART_TypeDef *uart) { + return (uint8_t) (uart->RDR & 255); +} + +static inline void hal_rng_init(void) { + RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; + RNG->CR |= RNG_CR_RNGEN; +} +static inline uint32_t hal_rng_read(void) { + while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0; + return RNG->DR; +} + +// Hw pull-ups on PHY RXD0,1,DV to enable autonegotiation +static inline void hal_ethernet_init(void) { + // Initialise Ethernet. Enable MAC GPIO pins, see + // https://www.farnell.com/datasheets/2014265.pdf section 6.10 + uint16_t pins[] = {HAL_ETH_PINS}; + for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) { + hal_gpio_init(pins[i], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_INSANE, + HAL_GPIO_PULL_NONE, 11); // 11 is the Ethernet function + } + NVIC_EnableIRQ(ETH_IRQn); // Setup Ethernet IRQ handler + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; // Use RMII. Goes first! + RCC->AHB1ENR |= + RCC_AHB1ENR_ETHMACEN | RCC_AHB1ENR_ETHMACTXEN | RCC_AHB1ENR_ETHMACRXEN; +} + +static inline void hal_clock_init(void) { + FLASH->ACR |= FLASH_LATENCY | BIT(8) | BIT(9); // Flash latency, prefetch + RCC->PLLCFGR &= ~((BIT(17) - 1)); // Clear PLL multipliers + RCC->PLLCFGR |= (((PLL_P - 2) / 2) & 3) << 16; // Set PLL_P + RCC->PLLCFGR |= PLL_M | (PLL_N << 6); // Set PLL_M and PLL_N + RCC->CR |= BIT(24); // Enable PLL + while ((RCC->CR & BIT(25)) == 0) (void) 0; // Wait until done + RCC->CFGR = (HAL_APB1_PRE << 10) | (HAL_APB2_PRE << 13); // Set prescalers + RCC->CFGR |= 2; // Set clock source to PLL + while ((RCC->CFGR & 12) == 0) (void) 0; // Wait until done + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // Enable SYSCFG +} + +static inline void hal_system_init(void) { + SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU + __DSB(); + __ISB(); +} diff --git a/tutorials/stm32/nucleo_f746zg/minimal/link.ld b/tutorials/stm32/nucleo_f746zg/minimal/link.ld new file mode 100644 index 00000000..0bc86d6d --- /dev/null +++ b/tutorials/stm32/nucleo_f746zg/minimal/link.ld @@ -0,0 +1,26 @@ +ENTRY(Reset_Handler); +MEMORY { + flash(rx) : ORIGIN = 0x08000000, LENGTH = 1024k + sram(rwx) : ORIGIN = 0x20000000, LENGTH = 320k +} +_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */ + +SECTIONS { + .vectors : { KEEP(*(.isr_vector)) } > flash + .text : { *(.text* .text.*) } > flash + .rodata : { *(.rodata*) } > flash + + .data : { + _sdata = .; + *(.first_data) + *(.data SORT(.data.*)) + *(.iram .iram* .iram.*) + _edata = .; + } > sram AT > flash + _sidata = LOADADDR(.data); + + .bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram + + . = ALIGN(8); + _end = .; +} diff --git a/tutorials/stm32/nucleo_f746zg/minimal/main.c b/tutorials/stm32/nucleo_f746zg/minimal/main.c new file mode 100644 index 00000000..2f3e99e5 --- /dev/null +++ b/tutorials/stm32/nucleo_f746zg/minimal/main.c @@ -0,0 +1,70 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "mongoose.h" +#include "hal.h" + +#define DEBUG_UART USART3 +#define LED1 PIN('B', 0) +#define LED2 PIN('B', 7) +#define LED3 PIN('B', 14) + +// Redirect stdout debug output to UART +int _write(int fd, char *ptr, int len) { + if (fd == 1 || fd == 2) hal_uart_write_buf(DEBUG_UART, ptr, (size_t) len); + return len; +} + +static void blink_task(void) { + static uint64_t blink_timer = 0; + if (hal_timer_expired(&blink_timer, 500, hal_get_tick())) { + hal_gpio_toggle(LED1); + } +} + +uint64_t mg_millis(void) { + return hal_get_tick(); +} + +bool mg_random(void *buf, size_t len) { + for (size_t n = 0; n < len; n += sizeof(uint32_t)) { + uint32_t r = hal_rng_read(); + memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r)); + } + return true; +} + +static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_HTTP_MSG) { // New HTTP request received + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { + mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick()); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", + hal_get_tick()); + } + } +} + +int main(void) { + hal_clock_init(); + hal_rng_init(); + hal_gpio_output(LED1); + hal_gpio_output(LED2); + hal_gpio_output(LED3); + hal_uart_init(DEBUG_UART, 115200); + + hal_ethernet_init(); + + // Start a minimal web server + struct mg_mgr mgr; + mg_mgr_init(&mgr); + mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL); + + for (;;) { + mg_mgr_poll(&mgr, 0); + blink_task(); + } + + return 0; +} diff --git a/tutorials/stm32/nucleo_f746zg/minimal/mongoose_config.h b/tutorials/stm32/nucleo_f746zg/minimal/mongoose_config.h new file mode 100644 index 00000000..08bf0665 --- /dev/null +++ b/tutorials/stm32/nucleo_f746zg/minimal/mongoose_config.h @@ -0,0 +1,42 @@ +#pragma once + +// See https://mongoose.ws/documentation/#build-options +#define MG_ARCH MG_ARCH_ARMGCC +#define MG_TLS MG_TLS_BUILTIN + +#define MG_ENABLE_TCPIP 1 +#define MG_ENABLE_CUSTOM_MILLIS 1 +#define MG_ENABLE_CUSTOM_RANDOM 1 +#define MG_ENABLE_DRIVER_STM32F 1 +#define MG_OTA MG_OTA_STM32F + +// #define MG_DRIVER_MDC_CR 4 // RMII MDC clock divider, from 0 to 4 +// #define MG_TCPIP_PHY_ADDR 0 // PHY address + +// For static IP configuration, define MG_TCPIP_{IP,MASK,GW} +// By default, those are set to zero, meaning that DHCP is used +// +// #define MG_TCPIP_IP MG_IPV4(192, 168, 0, 10) +// #define MG_TCPIP_GW MG_IPV4(192, 168, 0, 1) +// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0) + +// Set custom MAC address. By default, it is randomly generated +// Using a build-time constant: +// #define MG_SET_MAC_ADDRESS(mac) do { mac[0] = 2; mac[1] = 3; mac[2] = 4; mac[3] = 5; mac[4] = 6; mac[5] = 7; } while (0) +// +// Using custom function: +// extern void my_function(unsigned char *mac); +// #define MG_SET_MAC_ADDRESS(mac) my_function(mac) + +// Construct MAC address from the MCU unique ID. It is defined in the +// ST CMSIS header as UID_BASE +#define MGUID ((uint32_t *) 0x1ff0f420) // Unique 96-bit chip ID +#define MG_SET_MAC_ADDRESS(mac) \ + do { \ + mac[0] = 2; \ + mac[1] = MGUID[0] & 255; \ + mac[2] = (MGUID[0] >> 10) & 255; \ + mac[3] = (MGUID[0] >> 19) & 255; \ + mac[4] = MGUID[1] & 255; \ + mac[5] = MGUID[2] & 255; \ + } while (0) diff --git a/tutorials/stm32/nucleo_h743zi/cubemx/README.md b/tutorials/stm32/nucleo_h743zi/cubemx/README.md new file mode 100644 index 00000000..21bc08c4 --- /dev/null +++ b/tutorials/stm32/nucleo_h743zi/cubemx/README.md @@ -0,0 +1,30 @@ +# Nucleo-H743ZI Mongoose Integration + +This guide explains how to bring up a production-grade Web UI dashboard on the +STM32 Nucleo-H743ZI development board. + +A pre-configured, ready-to-run project zip is available for download at +https://mongoose.ws. + +To integrate the Web UI dashboard into an existing CubeMX project, or to create a +new project from scratch: + +1. Configure the peripherals (described below). +2. Regenerate your project code and integrate Mongoose core by following + https://mongoose.ws/docs/guides/stm32-tcpip-stack/. +3. Add the Web UI dashboard by following + https://mongoose.ws/docs/guides/web-dashboard-guide/. + +## Configure peripherals + +An `.ioc` file is included in this directory for your reference. It was created +using the following steps: + +- Open CubeMX. If you are starting a new project, select the STM32H743ZI + microcontroller and create a new project. +- In Clock Configuration, set the maximum clock frequency to 480 MHz. +- In the MCU pinout view, set pins PB0, PE1, and PB14 to GPIO_Output mode. +- In Pinout & Configuration / Connectivity, enable USART3 in asynchronous mode. + Configure pins PD8 and PD9 for USART. +- In Pinout & Configuration / Connectivity, enable ETH in RMII mode and set pins + PA1, PA2, PA7, PC1, PC4, PC5, PB13, PG11, and PG13 for Ethernet. diff --git a/tutorials/stm32/nucleo_h743zi/cubemx/nucleo_h743zi.ioc b/tutorials/stm32/nucleo_h743zi/cubemx/nucleo_h743zi.ioc new file mode 100644 index 00000000..aac36e61 --- /dev/null +++ b/tutorials/stm32/nucleo_h743zi/cubemx/nucleo_h743zi.ioc @@ -0,0 +1,212 @@ +#MicroXplorer Configuration settings - do not modify +CAD.formats= +CAD.pinconfig= +CAD.provider= +CORTEX_M7.DisableExec-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_INSTRUCTION_ACCESS_DISABLE +CORTEX_M7.Enable-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_REGION_ENABLE +CORTEX_M7.IPParameters=MPU_Control,Enable-Cortex_Memory_Protection_Unit_Region0_Settings,Size-Cortex_Memory_Protection_Unit_Region0_Settings,SubRegionDisable-Cortex_Memory_Protection_Unit_Region0_Settings,DisableExec-Cortex_Memory_Protection_Unit_Region0_Settings,IsShareable-Cortex_Memory_Protection_Unit_Region0_Settings +CORTEX_M7.IsShareable-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_ACCESS_SHAREABLE +CORTEX_M7.MPU_Control=MPU_PRIVILEGED_DEFAULT +CORTEX_M7.Size-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_REGION_SIZE_4GB +CORTEX_M7.SubRegionDisable-Cortex_Memory_Protection_Unit_Region0_Settings=0x87 +ETH.IPParameters=MediaInterface +ETH.MediaInterface=HAL_ETH_RMII_MODE +File.Version=6 +GPIO.groupedBy=Group By Peripherals +KeepUserPlacement=false +Mcu.CPN=STM32H743ZIT6 +Mcu.Family=STM32H7 +Mcu.IP0=CORTEX_M7 +Mcu.IP1=ETH +Mcu.IP2=NVIC +Mcu.IP3=RCC +Mcu.IP4=RNG +Mcu.IP5=SYS +Mcu.IP6=USART3 +Mcu.IPNb=7 +Mcu.Name=STM32H743ZITx +Mcu.Package=LQFP144 +Mcu.Pin0=PC1 +Mcu.Pin1=PA1 +Mcu.Pin10=PD9 +Mcu.Pin11=PG11 +Mcu.Pin12=PG13 +Mcu.Pin13=PE1 +Mcu.Pin14=VP_RNG_VS_RNG +Mcu.Pin15=VP_SYS_VS_Systick +Mcu.Pin2=PA2 +Mcu.Pin3=PA7 +Mcu.Pin4=PC4 +Mcu.Pin5=PC5 +Mcu.Pin6=PB0 +Mcu.Pin7=PB13 +Mcu.Pin8=PB14 +Mcu.Pin9=PD8 +Mcu.PinsNb=16 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32H743ZITx +MxCube.Version=6.17.0 +MxDb.Version=DB.6.0.170 +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.ETH_IRQn=true\:0\:0\:false\:false\:false\:true\:false\:true +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PA1.Mode=RMII +PA1.Signal=ETH_REF_CLK +PA2.Mode=RMII +PA2.Signal=ETH_MDIO +PA7.Mode=RMII +PA7.Signal=ETH_CRS_DV +PB0.Locked=true +PB0.Signal=GPIO_Output +PB13.Mode=RMII +PB13.Signal=ETH_TXD1 +PB14.Locked=true +PB14.Signal=GPIO_Output +PC1.Mode=RMII +PC1.Signal=ETH_MDC +PC4.Mode=RMII +PC4.Signal=ETH_RXD0 +PC5.Mode=RMII +PC5.Signal=ETH_RXD1 +PD8.Locked=true +PD8.Mode=Asynchronous +PD8.Signal=USART3_TX +PD9.Locked=true +PD9.Mode=Asynchronous +PD9.Signal=USART3_RX +PE1.Locked=true +PE1.Signal=GPIO_Output +PG11.Locked=true +PG11.Mode=RMII +PG11.Signal=ETH_TX_EN +PG13.Locked=true +PG13.Mode=RMII +PG13.Signal=ETH_TXD0 +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerLinker=GCC +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=false +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32H743ZITx +ProjectManager.FirmwarePackage=STM32Cube FW_H7 V1.13.0 +ProjectManager.FreePins=false +ProjectManager.FreePinsContext= +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=0x10000 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=1 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain=STM32CubeIDE +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=nucleo_h743zi.ioc +ProjectManager.ProjectName=nucleo_h743zi +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x2000 +ProjectManager.TargetToolchain=CMake +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_ETH_Init-ETH-false-HAL-true,4-MX_RNG_Init-RNG-false-HAL-true,5-MX_USART3_UART_Init-USART3-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true +RCC.ADCFreq_Value=129000000 +RCC.AHB12Freq_Value=240000000 +RCC.AHB4Freq_Value=240000000 +RCC.APB1Freq_Value=120000000 +RCC.APB2Freq_Value=120000000 +RCC.APB3Freq_Value=120000000 +RCC.APB4Freq_Value=120000000 +RCC.AXIClockFreq_Value=240000000 +RCC.CECFreq_Value=32000 +RCC.CKPERFreq_Value=64000000 +RCC.CortexFreq_Value=480000000 +RCC.CpuClockFreq_Value=480000000 +RCC.D1CPREFreq_Value=480000000 +RCC.D1PPRE=RCC_APB3_DIV2 +RCC.D2PPRE1=RCC_APB1_DIV2 +RCC.D2PPRE2=RCC_APB2_DIV2 +RCC.D3PPRE=RCC_APB4_DIV2 +RCC.DFSDMACLkFreq_Value=480000000 +RCC.DFSDMFreq_Value=120000000 +RCC.DIVM1=4 +RCC.DIVN1=60 +RCC.DIVP1Freq_Value=480000000 +RCC.DIVP2Freq_Value=129000000 +RCC.DIVP3Freq_Value=129000000 +RCC.DIVQ1Freq_Value=480000000 +RCC.DIVQ2Freq_Value=129000000 +RCC.DIVQ3Freq_Value=129000000 +RCC.DIVR1Freq_Value=480000000 +RCC.DIVR2Freq_Value=129000000 +RCC.DIVR3Freq_Value=129000000 +RCC.FDCANFreq_Value=480000000 +RCC.FMCFreq_Value=240000000 +RCC.FamilyName=M +RCC.HCLK3ClockFreq_Value=240000000 +RCC.HCLKFreq_Value=240000000 +RCC.HPRE=RCC_HCLK_DIV2 +RCC.HRTIMFreq_Value=240000000 +RCC.I2C123Freq_Value=120000000 +RCC.I2C4Freq_Value=120000000 +RCC.IPParameters=ADCFreq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1Freq_Value,APB2Freq_Value,APB3Freq_Value,APB4Freq_Value,AXIClockFreq_Value,CECFreq_Value,CKPERFreq_Value,CortexFreq_Value,CpuClockFreq_Value,D1CPREFreq_Value,D1PPRE,D2PPRE1,D2PPRE2,D3PPRE,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVN1,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVR1Freq_Value,DIVR2Freq_Value,DIVR3Freq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLKFreq_Value,HPRE,HRTIMFreq_Value,I2C123Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPUART1Freq_Value,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,PLL2FRACN,PLL3FRACN,PLLFRACN,QSPIFreq_Value,RNGFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI23Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SPI123Freq_Value,SPI45Freq_Value,SPI6Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,Tim1OutputFreq_Value,Tim2OutputFreq_Value,TraceFreq_Value,USART16Freq_Value,USART234578Freq_Value,USBFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value +RCC.LPTIM1Freq_Value=120000000 +RCC.LPTIM2Freq_Value=120000000 +RCC.LPTIM345Freq_Value=120000000 +RCC.LPUART1Freq_Value=120000000 +RCC.LTDCFreq_Value=129000000 +RCC.MCO1PinFreq_Value=64000000 +RCC.MCO2PinFreq_Value=480000000 +RCC.PLL2FRACN=0 +RCC.PLL3FRACN=0 +RCC.PLLFRACN=0 +RCC.QSPIFreq_Value=240000000 +RCC.RNGFreq_Value=48000000 +RCC.RTCFreq_Value=32000 +RCC.SAI1Freq_Value=480000000 +RCC.SAI23Freq_Value=480000000 +RCC.SAI4AFreq_Value=480000000 +RCC.SAI4BFreq_Value=480000000 +RCC.SDMMCFreq_Value=480000000 +RCC.SPDIFRXFreq_Value=480000000 +RCC.SPI123Freq_Value=480000000 +RCC.SPI45Freq_Value=120000000 +RCC.SPI6Freq_Value=120000000 +RCC.SWPMI1Freq_Value=120000000 +RCC.SYSCLKFreq_VALUE=480000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.Tim1OutputFreq_Value=240000000 +RCC.Tim2OutputFreq_Value=240000000 +RCC.TraceFreq_Value=64000000 +RCC.USART16Freq_Value=120000000 +RCC.USART234578Freq_Value=120000000 +RCC.USBFreq_Value=480000000 +RCC.VCO1OutputFreq_Value=960000000 +RCC.VCO2OutputFreq_Value=258000000 +RCC.VCO3OutputFreq_Value=258000000 +RCC.VCOInput1Freq_Value=16000000 +RCC.VCOInput2Freq_Value=2000000 +RCC.VCOInput3Freq_Value=2000000 +USART3.IPParameters=VirtualMode-Asynchronous +USART3.VirtualMode-Asynchronous=VM_ASYNC +VP_RNG_VS_RNG.Mode=RNG_Activate +VP_RNG_VS_RNG.Signal=RNG_VS_RNG +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +board=custom diff --git a/tutorials/stm32/nucleo_h743zi/minimal/Makefile b/tutorials/stm32/nucleo_h743zi/minimal/Makefile new file mode 100644 index 00000000..b2ade941 --- /dev/null +++ b/tutorials/stm32/nucleo_h743zi/minimal/Makefile @@ -0,0 +1,38 @@ +# Copyright (c) 2026 Cesanta Software Limited +# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/ + +CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion +CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion +CFLAGS += -g3 -Os -ffunction-sections -fdata-sections +CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include +CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA) +LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map + +SOURCES = main.c hal.c +SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h743xx.s + +TOP = ../../../.. +CFLAGS += -I$(TOP) +SOURCES += $(TOP)/mongoose.c + +all: firmware.bin + +firmware.elf: cmsis_core cmsis_h7 hal.h link.ld Makefile $(SOURCES) + arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@ + +firmware.bin: firmware.elf + arm-none-eabi-objcopy -O binary $< $@ + @echo + @echo "To flash, run 'make flash', or use STM32CubeProgrammer" + +flash: firmware.bin + STM32_Programmer_CLI -c port=swd -e all -w firmware.elf -hardRst + +cmsis_core: + git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@ + +cmsis_h7: + git clone -q -c advice.detachedHead=false --depth 1 -b v1.10.4 https://github.com/STMicroelectronics/cmsis_device_h7 $@ + +clean: + rm -rf firmware.* diff --git a/tutorials/stm32/nucleo_h743zi/minimal/hal.c b/tutorials/stm32/nucleo_h743zi/minimal/hal.c new file mode 100644 index 00000000..6dc65c9f --- /dev/null +++ b/tutorials/stm32/nucleo_h743zi/minimal/hal.c @@ -0,0 +1,125 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "hal.h" + +bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) { + uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry + if (period == 0) return false; // Avoid division by zero + if (diff < period) return false; // Period has not elapsed yet + *t += (diff / period) * period; // Preserve cadence, skip missed periods + return true; +} + +static volatile uint64_t s_ticks; // Milliseconds since boot +void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms + s_ticks++; +} + +uint64_t hal_get_tick(void) { + return s_ticks; +}; + +uint32_t SystemCoreClock = SYS_FREQUENCY; +void SystemInit(void) { // Called automatically by startup code + hal_system_init(); // Enable FPU + hal_clock_init(); + SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms +} + +void ExitRun0Mode(void) { +} + +struct stat; +__attribute__((weak)) int _fstat(int fd, struct stat *st) { + (void) fd, (void) st; + return -1; +} + +extern unsigned char _end[]; // End of data section, start of heap. See link.ld +static unsigned char *s_current_heap_end = _end; + +size_t hal_ram_used(void) { + return (size_t) (s_current_heap_end - _end); +} + +size_t hal_ram_free(void) { + unsigned char endofstack; + return (size_t) (&endofstack - s_current_heap_end); +} + +void *_sbrk(int incr) { + unsigned char *prev_heap; + unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256); + prev_heap = s_current_heap_end; + // Check how much space we got from the heap end to the stack end + if (s_current_heap_end + incr > heap_end) return (void *) -1; + s_current_heap_end += incr; + return prev_heap; +} + +__attribute__((weak)) int _open(const char *path) { + (void) path; + return -1; +} + +__attribute__((weak)) int _close(int fd) { + (void) fd; + return -1; +} + +__attribute__((weak)) int _isatty(int fd) { + (void) fd; + return 1; +} + +__attribute__((weak)) int _lseek(int fd, int ptr, int dir) { + (void) fd, (void) ptr, (void) dir; + return 0; +} + +__attribute__((weak)) void _exit(int status) { + (void) status; + for (;;) asm volatile("BKPT #0"); +} + +__attribute__((weak)) void _kill(int pid, int sig) { + (void) pid, (void) sig; +} + +__attribute__((weak)) int _getpid(void) { + return -1; +} + +__attribute__((weak)) int _write(int fd, char *ptr, int len) { + (void) fd, (void) ptr, (void) len; + return -1; +} + +__attribute__((weak)) int _read(int fd, char *ptr, int len) { + (void) fd, (void) ptr, (void) len; + return -1; +} + +__attribute__((weak)) int _link(const char *a, const char *b) { + (void) a, (void) b; + return -1; +} + +__attribute__((weak)) int _unlink(const char *a) { + (void) a; + return -1; +} + +__attribute__((weak)) int _stat(const char *path, struct stat *st) { + (void) path, (void) st; + return -1; +} + +__attribute__((weak)) int mkdir(const char *path, int mode) { + (void) path, (void) mode; + return -1; +} + +__attribute__((weak)) void _init(void) { +} diff --git a/tutorials/stm32/nucleo_h743zi/minimal/hal.h b/tutorials/stm32/nucleo_h743zi/minimal/hal.h new file mode 100644 index 00000000..79c1ef77 --- /dev/null +++ b/tutorials/stm32/nucleo_h743zi/minimal/hal.h @@ -0,0 +1,269 @@ +// Copyright (c) 2022-2024 Cesanta Software Limited +// All rights reserved +// +// Datasheet: RM0433, devboard manual: UM2407 +// https://www.st.com/resource/en/reference_manual/rm0433-stm32h742-stm32h743753-and-stm32h750-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf +// Alternate functions: https://www.st.com/resource/en/datasheet/stm32h743vi.pdf + +#pragma once + +#include + +#include +#include +#include +#include + +extern bool hal_timer_expired(volatile uint64_t *t, uint64_t prd, uint64_t now); +extern uint64_t hal_get_tick(void); +extern size_t hal_ram_free(void); +extern size_t hal_ram_used(void); +extern uint32_t SystemCoreClock; + +#define HAL_ETH_PINS \ + PIN('A', 1), /* ETH_REF_CLK */ \ + PIN('A', 2), /* ETH_MDIO */ \ + PIN('A', 7), /* ETH_CRS_DV */ \ + PIN('B', 13), /* ETH_TXD1 */ \ + PIN('C', 1), /* ETH_MDC */ \ + PIN('C', 4), /* ETH_RXD0 */ \ + PIN('C', 5), /* ETH_RXD1 */ \ + PIN('G', 11), /* ETH_TX_EN */ \ + PIN('G', 13) /* ETH_TXD0 */ + +#define BIT(x) (1UL << (x)) +#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set)) +#define PIN(bank, num) ((((bank) - 'A') << 8) | (num)) +#define PINNO(pin) (pin & 255) +#define PINBANK(pin) (pin >> 8) + +void hal_init(void); +size_t hal_ram_free(void); +size_t hal_ram_used(void); + +// System clock (2.1, Figure 1; 8.5, Figure 45; 8.5.5, Figure 47; 8.5.6, Figure +// 49) SYS_FREQUENCY <= 480 MHz; hclk = SYS_FREQUENCY / HAL_HPRE ; hclk <= 240 MHz; +// APB clocks <= 120 MHz. D1 domain bus matrix (and so flash) runs at hclk +// frequency. Configure flash latency (WS) in accordance to hclk freq (4.3.8, +// Table 17) The Ethernet controller is in D2 domain and runs at hclk frequency +enum { + HAL_D1CPRE = 1, // actual divisor value + HAL_HPRE = 2, // actual divisor value + HAL_D1PPRE = 4, // register values, divisor value = BIT(value - 3) = / 2 + HAL_D2PPRE1 = 4, + HAL_D2PPRE2 = 4, + HAL_D3PPRE = 4 +}; +// PLL1_P: odd division factors are not allowed (8.7.13) (according to Cube, '1' +// is also an "odd division factor"). +// Make sure your chip is revision 'V', otherwise set PLL1_N = 400 +enum { PLL1_HSI = 64, PLL1_M = 32, PLL1_N = 480, PLL1_P = 2 }; +#define FLASH_LATENCY 0x24 // WRHIGHFREQ LATENCY +#define SYS_FREQUENCY ((PLL1_HSI * PLL1_N / PLL1_M / PLL1_P / HAL_D1CPRE) * 1000000) +// #define SYS_FREQUENCY ((PLL1_HSI / HAL_D1CPRE) * 1000000) +#define AHB_FREQUENCY (SYS_FREQUENCY / HAL_HPRE) +#define APB2_FREQUENCY (AHB_FREQUENCY / (BIT(HAL_D2PPRE2 - 3))) +#define APB1_FREQUENCY (AHB_FREQUENCY / (BIT(HAL_D2PPRE1 - 3))) + +static inline void spin(volatile uint32_t n) { + while (n--) (void) 0; +} + +enum { HAL_GPIO_MODE_INPUT, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_MODE_AF, HAL_GPIO_MODE_ANALOG }; +enum { HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_OTYPE_OPEN_DRAIN }; +enum { HAL_GPIO_SPEED_LOW, HAL_GPIO_SPEED_MEDIUM, HAL_GPIO_SPEED_HIGH, HAL_GPIO_SPEED_INSANE }; +enum { HAL_GPIO_PULL_NONE, HAL_GPIO_PULL_UP, HAL_GPIO_PULL_DOWN }; + +#define HAL_GPIO(N) ((GPIO_TypeDef *) (0x40000000 + 0x18020000UL + 0x400 * (N))) + +static GPIO_TypeDef *hal_gpio_bank(uint16_t pin) { + return HAL_GPIO(PINBANK(pin)); +} +static inline void hal_gpio_toggle(uint16_t pin) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + uint32_t mask = BIT(PINNO(pin)); + gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0); +} +static inline int hal_gpio_read(uint16_t pin) { + return hal_gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0; +} +static inline void hal_gpio_write(uint16_t pin, bool val) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16); +} +static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t type, + uint8_t speed, uint8_t pull, uint8_t af) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + uint8_t n = (uint8_t) (PINNO(pin)); + RCC->AHB4ENR |= BIT(PINBANK(pin)); // Enable GPIO clock + CLRSET(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n); + CLRSET(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2)); + CLRSET(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2)); + CLRSET(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4), + ((uint32_t) af) << ((n & 7) * 4)); + CLRSET(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2)); +} +static inline void hal_gpio_input(uint16_t pin) { + hal_gpio_init(pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_OTYPE_PUSH_PULL, + HAL_GPIO_SPEED_HIGH, HAL_GPIO_PULL_NONE, 0); +} +static inline void hal_gpio_output(uint16_t pin) { + hal_gpio_init(pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_OTYPE_PUSH_PULL, + HAL_GPIO_SPEED_HIGH, HAL_GPIO_PULL_NONE, 0); +} + +static inline uint32_t hal_apb_freq(int bus) { // 1 for APB1 or 2 for APB2 + uint32_t sysclk = 0, pll_src_freq = 0; + uint32_t hsi_freq = 64000000UL, hse_freq = 8000000UL, csi_freq = 4000000UL; + uint32_t hclk, hpre_div, apb_div, pllm, plln, pllp, tmp; + + // 1. Determine system clock source + switch (RCC->CFGR & RCC_CFGR_SWS) { + case RCC_CFGR_SWS_HSI: sysclk = hsi_freq; break; + case RCC_CFGR_SWS_CSI: sysclk = csi_freq; break; + case RCC_CFGR_SWS_HSE: sysclk = hse_freq; break; + case RCC_CFGR_SWS_PLL1: + pllm = ((RCC->PLLCKSELR & RCC_PLLCKSELR_DIVM1_Msk) >> + RCC_PLLCKSELR_DIVM1_Pos); + plln = ((RCC->PLL1DIVR & RCC_PLL1DIVR_N1_Msk) >> RCC_PLL1DIVR_N1_Pos) + 1; + pllp = ((RCC->PLL1DIVR & RCC_PLL1DIVR_P1_Msk) >> RCC_PLL1DIVR_P1_Pos) + 1; + if (pllm == 0U) pllm = 1U; + + switch (RCC->PLLCKSELR & RCC_PLLCKSELR_PLLSRC) { + case RCC_PLLCKSELR_PLLSRC_HSI: pll_src_freq = hsi_freq; break; + case RCC_PLLCKSELR_PLLSRC_CSI: pll_src_freq = csi_freq; break; + case RCC_PLLCKSELR_PLLSRC_HSE: pll_src_freq = hse_freq; break; + default: pll_src_freq = 0U; break; + } + sysclk = (pll_src_freq / pllm) * plln / pllp; + break; + default: sysclk = hsi_freq; break; + } + + // 2. Compute HCLK (core bus clock) from HPRE prescaler + tmp = (RCC->D1CFGR & RCC_D1CFGR_HPRE_Msk) >> RCC_D1CFGR_HPRE_Pos; + hpre_div = tmp < 8U ? 1U : (1U << (tmp - 7U)); + hclk = sysclk / hpre_div; + + // 3. Select the appropriate APB prescaler (from D2CFGR) + if (bus == 1) + tmp = (RCC->D2CFGR & RCC_D2CFGR_D2PPRE1_Msk) >> RCC_D2CFGR_D2PPRE1_Pos; + else + tmp = (RCC->D2CFGR & RCC_D2CFGR_D2PPRE2_Msk) >> RCC_D2CFGR_D2PPRE2_Pos; + + apb_div = tmp < 4U ? 1U : (1U << (tmp - 3U)); + return hclk / apb_div; +} + +// D2 Kernel clock (8.7.21) USART1 defaults to pclk2 (APB2), while USART2,3 +// default to pclk1 (APB1). Even if using other kernel clocks, the APBx clocks +// must be enabled for CPU access, as the kernel clock drives the BRR, not the +// APB bus interface +static inline void hal_uart_init(USART_TypeDef *uart, unsigned long baud) { + uint8_t af = 7; // Alternate function + uint16_t rx = 0, tx = 0; // pins + uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1 + + if (uart == USART1) freq = hal_apb_freq(2), RCC->APB2ENR |= BIT(4); + if (uart == USART2) freq = hal_apb_freq(1), RCC->APB1LENR |= BIT(17); + if (uart == USART3) freq = hal_apb_freq(1), RCC->APB1LENR |= BIT(18); + + if (uart == USART1) tx = PIN('A', 9), rx = PIN('A', 10); + if (uart == USART2) tx = PIN('A', 2), rx = PIN('A', 3); + if (uart == USART3) tx = PIN('D', 8), rx = PIN('D', 9); + + hal_gpio_init(tx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af); + hal_gpio_init(rx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af); + uart->CR1 = 0; // Disable this UART + uart->BRR = freq / baud; // Set baud rate + uart->CR1 = BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE +} +static inline void hal_uart_write_byte(USART_TypeDef *uart, uint8_t byte) { + uart->TDR = byte; + while ((uart->ISR & BIT(7)) == 0) spin(1); +} +static inline void hal_uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) { + while (len-- > 0) hal_uart_write_byte(uart, *(uint8_t *) buf++); +} +static inline int hal_uart_read_ready(USART_TypeDef *uart) { + return uart->ISR & BIT(5); // If RXNE bit is set, data is ready +} +static inline uint8_t hal_uart_read_byte(USART_TypeDef *uart) { + return (uint8_t) (uart->RDR & 255); +} + +static inline void hal_rng_init(void) { + RCC->D2CCIP2R |= RCC_D2CCIP2R_RNGSEL_0; // RNG clock source pll1_q_ck + RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; // Enable RNG clock + RNG->CR = RNG_CR_RNGEN; // Enable RNG +} + +static inline uint32_t hal_rng_read(void) { + while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0; + return RNG->DR; +} + +// Hw pull-ups on PHY RXD0,1,DV to enable autonegotiation +static inline void hal_ethernet_init(void) { + // Initialise Ethernet. Enable MAC GPIO pins, see + // https://www.st.com/resource/en/user_manual/um2407-stm32h7-nucleo144-boards-mb1364-stmicroelectronics.pdf + uint16_t pins[] = {HAL_ETH_PINS}; + for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) { + hal_gpio_init(pins[i], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, + HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_NONE, 11); // 11 is the Ethernet function + } + RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN; // Enable SYSCFG + CLRSET(SYSCFG->PMCR, 7 << 21, 4 << 21); // Use RMII (12.3.1) + RCC->AHB1ENR |= BIT(15) | BIT(16) | BIT(17); // Enable Ethernet clocks + NVIC_EnableIRQ(ETH_IRQn); // Setup Ethernet IRQ handler +} + +static inline unsigned int hal_div2prescval(unsigned int div) { + // 0 --> /1; 8 --> /2 ... 11 --> /16; 12 --> /64 ... 15 --> /512 + if (div == 1) return 0; + if (div > 16) div /= 2; + unsigned int val = 7; + while (div >>= 1) ++val; + return val; +} + +static inline unsigned int hal_pllrge(unsigned int f) { + unsigned int val = 0; + while (f >>= 1) ++val; + return val - 1; +} + +static inline void hal_clock_init(void) { + PWR->CR3 |= BIT(1); // select LDO (reset value) + while ((PWR->CSR1 & BIT(13)) == 0) spin(1); // ACTVOSRDY + PWR->D3CR |= BIT(15) | BIT(14); // Select VOS1 + uint32_t f = PWR->D3CR; // fake read to wait for bus clocking + while ((PWR->CSR1 & BIT(13)) == 0) spin(1); // ACTVOSRDY + SYSCFG->PWRCR |= BIT(0); // ODEN + f = SYSCFG->PWRCR; + while ((PWR->CSR1 & BIT(13)) == 0) spin(1); // ACTVOSRDY + (void) f; + CLRSET( + RCC->D1CFGR, (0x0F << 8) | (7 << 4) | (0x0F << 0), + (hal_div2prescval(HAL_D1CPRE) << 8) | (HAL_D1PPRE << 4) | (hal_div2prescval(HAL_HPRE) << 0)); + RCC->D2CFGR = (HAL_D2PPRE2 << 8) | (HAL_D2PPRE1 << 4); + RCC->D3CFGR = (HAL_D3PPRE << 4); + CLRSET(RCC->PLLCFGR, 3 << 2, + hal_pllrge(PLL1_HSI / PLL1_M) + << 2); // keep reset config (DIVP1EN, !PLL1VCOSEL), PLL1RGE + CLRSET(RCC->PLL1DIVR, (0x7F << 9) | (0x1FF << 0), + ((PLL1_P - 1) << 9) | ((PLL1_N - 1) << 0)); // Set PLL1_P PLL1_N + CLRSET(RCC->PLLCKSELR, 0x3F << 4, + PLL1_M << 4); // Set PLL1_M (source defaults to HSI) + RCC->CR |= BIT(24); // Enable PLL1 + while ((RCC->CR & BIT(25)) == 0) spin(1); // Wait until done + RCC->CFGR |= (3 << 0); // Set clock source to PLL1 + while ((RCC->CFGR & (7 << 3)) != (3 << 3)) spin(1); // Wait until done + FLASH->ACR = FLASH_LATENCY; // default is larger +} + +static inline void hal_system_init(void) { + SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU + __DSB(); + __ISB(); +} diff --git a/tutorials/stm32/nucleo_h743zi/minimal/link.ld b/tutorials/stm32/nucleo_h743zi/minimal/link.ld new file mode 100644 index 00000000..715a6217 --- /dev/null +++ b/tutorials/stm32/nucleo_h743zi/minimal/link.ld @@ -0,0 +1,32 @@ +ENTRY(Reset_Handler); +MEMORY { + flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k + sram(rwx) : ORIGIN = 0x24000000, LENGTH = 512k /* AXI SRAM in domain D1 */ + /* 2.3.2: remaining SRAM is in other (non-contiguous) banks, + DTCM @0x20000000 is in domain D1 and not accessible by the ETH DMA controller in domain D2 + SRAM @0x30000000 is in domain D2 and not directly available at startup to be used as stack (8.5.9 page 366) */ +} +_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */ + +SECTIONS { + .vectors : { KEEP(*(.isr_vector)) } > flash + .text : { *(.text* .text.*) } > flash + .rodata : { *(.rodata*) } > flash + + .data : { + _sdata = .; /* for init_ram() */ + *(.first_data) + *(.data SORT(.data.*)) + _edata = .; /* for init_ram() */ + } > sram AT > flash + _sidata = LOADADDR(.data); + + .bss : { + _sbss = .; /* for init_ram() */ + *(.bss SORT(.bss.*) COMMON) + _ebss = .; /* for init_ram() */ + } > sram + + . = ALIGN(8); + _end = .; /* for cmsis_gcc.h and init_ram() */ +} diff --git a/tutorials/stm32/nucleo_h743zi/minimal/main.c b/tutorials/stm32/nucleo_h743zi/minimal/main.c new file mode 100644 index 00000000..ee637f98 --- /dev/null +++ b/tutorials/stm32/nucleo_h743zi/minimal/main.c @@ -0,0 +1,70 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "mongoose.h" +#include "hal.h" + +#define DEBUG_UART USART3 +#define LED1 PIN('B', 0) // On-board LED pin (green) +#define LED2 PIN('E', 1) // On-board LED pin (yellow) +#define LED3 PIN('B', 14) // On-board LED pin (red) + +// Redirect stdout debug output to UART +int _write(int fd, char *ptr, int len) { + if (fd == 1 || fd == 2) hal_uart_write_buf(DEBUG_UART, ptr, (size_t) len); + return len; +} + +static void blink_task(void) { + static uint64_t blink_timer = 0; + if (hal_timer_expired(&blink_timer, 500, hal_get_tick())) { + hal_gpio_toggle(LED1); + } +} + +uint64_t mg_millis(void) { + return hal_get_tick(); +} + +bool mg_random(void *buf, size_t len) { + for (size_t n = 0; n < len; n += sizeof(uint32_t)) { + uint32_t r = hal_rng_read(); + memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r)); + } + return true; +} + +static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_HTTP_MSG) { // New HTTP request received + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { + mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick()); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", + hal_get_tick()); + } + } +} + +int main(void) { + hal_clock_init(); + hal_rng_init(); + hal_gpio_output(LED1); + hal_gpio_output(LED2); + hal_gpio_output(LED3); + hal_uart_init(DEBUG_UART, 115200); + + hal_ethernet_init(); + + // Start a minimal web server + struct mg_mgr mgr; + mg_mgr_init(&mgr); + mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL); + + for (;;) { + mg_mgr_poll(&mgr, 0); + blink_task(); + } + + return 0; +} diff --git a/tutorials/stm32/nucleo_h743zi/minimal/mongoose_config.h b/tutorials/stm32/nucleo_h743zi/minimal/mongoose_config.h new file mode 100644 index 00000000..7ad8280d --- /dev/null +++ b/tutorials/stm32/nucleo_h743zi/minimal/mongoose_config.h @@ -0,0 +1,42 @@ +#pragma once + +// See https://mongoose.ws/documentation/#build-options +#define MG_ARCH MG_ARCH_ARMGCC +#define MG_TLS MG_TLS_BUILTIN +#define MG_OTA MG_OTA_STM32H7 + +#define MG_ENABLE_TCPIP 1 +#define MG_ENABLE_CUSTOM_MILLIS 1 +#define MG_ENABLE_CUSTOM_RANDOM 1 +#define MG_ENABLE_DRIVER_STM32H 1 + +// #define MG_DRIVER_MDC_CR 4 // RMII MDC clock divider, from 0 to 5 +// #define MG_TCPIP_PHY_ADDR 0 // PHY address + +// For static IP configuration, define MG_TCPIP_{IP,MASK,GW} +// By default, those are set to zero, meaning that DHCP is used +// +// #define MG_TCPIP_IP MG_IPV4(192, 168, 0, 10) // IP +// #define MG_TCPIP_GW MG_IPV4(192, 168, 0, 1) // Gateway +// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0) // Netmask + +// Set custom MAC address. By default, it is randomly generated +// Using a build-time constant: +// #define MG_SET_MAC_ADDRESS(mac) do { mac[0] = 2; mac[1] = 3; mac[2] = 4; mac[3] = 5; mac[4] = 6; mac[5] = 7; } while (0) +// +// Using custom function: +// extern void my_function(unsigned char *mac); +// #define MG_SET_MAC_ADDRESS(mac) my_function(mac) + +// Construct MAC address from the MCU unique ID. It is defined in the +// ST CMSIS header as UID_BASE +#define MGUID ((uint32_t *) 0x1ff1e800) // Unique 96-bit chip ID +#define MG_SET_MAC_ADDRESS(mac) \ + do { \ + mac[0] = 2; \ + mac[1] = MGUID[0] & 255; \ + mac[2] = (MGUID[0] >> 10) & 255; \ + mac[3] = (MGUID[0] >> 19) & 255; \ + mac[4] = MGUID[1] & 255; \ + mac[5] = MGUID[2] & 255; \ + } while (0) diff --git a/tutorials/stm32/stm32h747i_disco/cubemx/README.md b/tutorials/stm32/stm32h747i_disco/cubemx/README.md new file mode 100644 index 00000000..ca6af09c --- /dev/null +++ b/tutorials/stm32/stm32h747i_disco/cubemx/README.md @@ -0,0 +1,30 @@ +# STM32H747I-DISCO Mongoose Integration + +This guide explains how to bring up a production-grade Web UI dashboard on the +STM32H747I-DISCO development board. + +A pre-configured, ready-to-run project zip is available for download at +https://mongoose.ws. + +To integrate the Web UI dashboard into an existing CubeMX project, or to create a +new project from scratch: + +1. Configure the peripherals (described below). +2. Regenerate your project code and integrate Mongoose core by following + https://mongoose.ws/docs/guides/stm32-tcpip-stack/. +3. Add the Web UI dashboard by following + https://mongoose.ws/docs/guides/web-dashboard-guide/. + +## Configure peripherals + +An `.ioc` file is included in this directory for your reference. It was created +using the following steps: + +- Open CubeMX. If you are starting a new project, select the STM32H747I-DISCO + board and create a new project. +- In Clock Configuration, set the maximum clock frequency to 400 MHz. +- In the MCU pinout view, set pins PI11, PI12, and PI13 to GPIO_Output mode. +- In Pinout & Configuration / Connectivity, enable USART1 in asynchronous mode. + Configure pins PA9 and PA10 for USART. +- In Pinout & Configuration / Connectivity, enable ETH in RMII mode and set pins + PA1, PA2, PA7, PC1, PC4, PC5, PG11, PG12, and PG13 for Ethernet. diff --git a/tutorials/stm32/stm32h747i_disco/cubemx/stm32h747i_disco.ioc b/tutorials/stm32/stm32h747i_disco/cubemx/stm32h747i_disco.ioc new file mode 100644 index 00000000..94450b4a --- /dev/null +++ b/tutorials/stm32/stm32h747i_disco/cubemx/stm32h747i_disco.ioc @@ -0,0 +1,1097 @@ +#MicroXplorer Configuration settings - do not modify +ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_1 +ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag,master +ADC1.NbrOfConversionFlag=1 +ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE +ADC1.Rank-0\#ChannelRegularConversion=1 +ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5 +ADC1.master=1 +CAD.formats= +CAD.pinconfig= +CAD.provider= +CortexM4.IPs=BDMA,DMA,FATFS_M4\:I,FREERTOS_M4\:I,IWDG2\:I,MDMA,NVIC2\:I,RCC,USB_DEVICE_M4\:I,USB_HOST_M4\:I,WWDG2\:I,ADC1\:I,DCMI\:I,TIM3\:I,DEBUG,PDM2PCM_M4\:I,PWR,RESMGR_UTILITY,SYS_M4\:I,CORTEX_M4\:I,OPENAMP_M4\:I,VREFBUF,GPIO +CortexM7.IPs=BDMA\:I,DMA\:I,FATFS_M7\:I,FREERTOS_M7\:I,IWDG1\:I,MDMA\:I,NVIC1\:I,RCC\:I,USB_DEVICE_M7\:I,USB_HOST_M7\:I,WWDG1\:I,CORTEX_M7\:I,DEBUG\:I,PDM2PCM_M7\:I,PWR\:I,RESMGR_UTILITY\:I,SYS\:I,OPENAMP_M7\:I,VREFBUF\:I,GPIO\:I,RNG\:I,ETH\:I,USART1\:I +ETH.IPParameters=MediaInterface +ETH.MediaInterface=HAL_ETH_RMII_MODE +File.Version=6 +KeepUserPlacement=false +Mcu.CPN=STM32H747XIH6 +Mcu.Context0=CortexM7 +Mcu.Context1=CortexM4 +Mcu.ContextNb=2 +Mcu.Family=STM32H7 +Mcu.IP0=ADC1 +Mcu.IP1=CORTEX_M4 +Mcu.IP10=USART1 +Mcu.IP2=CORTEX_M7 +Mcu.IP3=ETH +Mcu.IP4=NVIC1 +Mcu.IP5=NVIC2 +Mcu.IP6=RCC +Mcu.IP7=RNG +Mcu.IP8=SYS +Mcu.IP9=SYS_M4 +Mcu.IPNb=11 +Mcu.Name=STM32H747XIHx +Mcu.Package=TFBGA240 +Mcu.Pin0=PI6 +Mcu.Pin1=PI5 +Mcu.Pin10=PE1 +Mcu.Pin100=PE11 +Mcu.Pin101=PB10 +Mcu.Pin102=PB11 +Mcu.Pin103=PH10 +Mcu.Pin104=PH11 +Mcu.Pin105=PD15 +Mcu.Pin106=PD14 +Mcu.Pin107=PC2_C +Mcu.Pin108=PC3_C +Mcu.Pin109=PA7 +Mcu.Pin11=PB6 +Mcu.Pin110=PB2 +Mcu.Pin111=PF12 +Mcu.Pin112=PF15 +Mcu.Pin113=PE12 +Mcu.Pin114=PE15 +Mcu.Pin115=PJ5 +Mcu.Pin116=PH9 +Mcu.Pin117=PH12 +Mcu.Pin118=PD11 +Mcu.Pin119=PA0_C +Mcu.Pin12=PK4 +Mcu.Pin120=PA1_C +Mcu.Pin121=PA5 +Mcu.Pin122=PC4 +Mcu.Pin123=PB1 +Mcu.Pin124=PF11 +Mcu.Pin125=PG0 +Mcu.Pin126=PE8 +Mcu.Pin127=PE13 +Mcu.Pin128=PH6 +Mcu.Pin129=PH8 +Mcu.Pin13=PG11 +Mcu.Pin130=PB12 +Mcu.Pin131=PB15 +Mcu.Pin132=PD10 +Mcu.Pin133=PD9 +Mcu.Pin134=PA3 +Mcu.Pin135=PC5 +Mcu.Pin136=PB0 +Mcu.Pin137=PJ3 +Mcu.Pin138=PJ4 +Mcu.Pin139=PG1 +Mcu.Pin14=PJ15 +Mcu.Pin140=PE7 +Mcu.Pin141=PE14 +Mcu.Pin142=PH7 +Mcu.Pin143=PB13 +Mcu.Pin144=PB14 +Mcu.Pin145=PD8 +Mcu.Pin146=VP_RNG_VS_RNG +Mcu.Pin147=VP_SYS_VS_Systick +Mcu.Pin148=VP_SYS_M4_VS_Systick +Mcu.Pin15=PI2 +Mcu.Pin16=PH15 +Mcu.Pin17=PH14 +Mcu.Pin18=PC15-OSC32_OUT (OSC32_OUT) +Mcu.Pin19=PC14-OSC32_IN (OSC32_IN) +Mcu.Pin2=PI4 +Mcu.Pin20=PE0 +Mcu.Pin21=PK6 +Mcu.Pin22=PK3 +Mcu.Pin23=PG12 +Mcu.Pin24=PD7 +Mcu.Pin25=PC12 +Mcu.Pin26=PI3 +Mcu.Pin27=PE5 +Mcu.Pin28=PE4 +Mcu.Pin29=PE3 +Mcu.Pin3=PB5 +Mcu.Pin30=PG15 +Mcu.Pin31=PK7 +Mcu.Pin32=PG14 +Mcu.Pin33=PG13 +Mcu.Pin34=PJ12 +Mcu.Pin35=PD2 +Mcu.Pin36=PD0 +Mcu.Pin37=PA10 +Mcu.Pin38=PA9 +Mcu.Pin39=PH13 +Mcu.Pin4=PK5 +Mcu.Pin40=PI9 +Mcu.Pin41=PC13 +Mcu.Pin42=PI8 +Mcu.Pin43=PE6 +Mcu.Pin44=PJ13 +Mcu.Pin45=PD1 +Mcu.Pin46=PC8 +Mcu.Pin47=PA8 +Mcu.Pin48=PA12 +Mcu.Pin49=PA11 +Mcu.Pin5=PG9 +Mcu.Pin50=PI10 +Mcu.Pin51=PI11 +Mcu.Pin52=PG8 +Mcu.Pin53=PG7 +Mcu.Pin54=PF2 +Mcu.Pin55=PF1 +Mcu.Pin56=PF0 +Mcu.Pin57=PG6 +Mcu.Pin58=PI12 +Mcu.Pin59=PI13 +Mcu.Pin6=PC10 +Mcu.Pin60=PI14 +Mcu.Pin61=PF3 +Mcu.Pin62=PG4 +Mcu.Pin63=PG3 +Mcu.Pin64=PG2 +Mcu.Pin65=PK2 +Mcu.Pin66=PH1-OSC_OUT (PH1) +Mcu.Pin67=PH0-OSC_IN (PH0) +Mcu.Pin68=PF5 +Mcu.Pin69=PF4 +Mcu.Pin7=PI1 +Mcu.Pin70=PK0 +Mcu.Pin71=PK1 +Mcu.Pin72=PF6 +Mcu.Pin73=PF7 +Mcu.Pin74=PF8 +Mcu.Pin75=PJ11 +Mcu.Pin76=PC0 +Mcu.Pin77=PF10 +Mcu.Pin78=PF9 +Mcu.Pin79=PJ10 +Mcu.Pin8=PI0 +Mcu.Pin80=PC1 +Mcu.Pin81=PC2 +Mcu.Pin82=PC3 +Mcu.Pin83=PJ9 +Mcu.Pin84=PH2 +Mcu.Pin85=PA2 +Mcu.Pin86=PA1 +Mcu.Pin87=PJ0 +Mcu.Pin88=PE10 +Mcu.Pin89=PJ8 +Mcu.Pin9=PI7 +Mcu.Pin90=PJ7 +Mcu.Pin91=PJ6 +Mcu.Pin92=PH3 +Mcu.Pin93=PH4 +Mcu.Pin94=PH5 +Mcu.Pin95=PI15 +Mcu.Pin96=PJ1 +Mcu.Pin97=PF13 +Mcu.Pin98=PF14 +Mcu.Pin99=PE9 +Mcu.PinsNb=149 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32H747XIHx +MxCube.Version=6.17.0 +MxDb.Version=DB.6.0.170 +NVIC1.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC1.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC1.ETH_IRQn=true\:0\:0\:false\:false\:false\:true\:false\:true +NVIC1.ForceEnableDMAVector=true +NVIC1.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC1.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC1.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC1.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC1.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC1.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC1.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false +NVIC1.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC2.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC2.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC2.ForceEnableDMAVector=true +NVIC2.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC2.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC2.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC2.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC2.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC2.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC2.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false +NVIC2.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PA0_C.GPIOParameters=GPIO_Label,PinAttribute +PA0_C.GPIO_Label=ARD_A2 +PA0_C.Locked=true +PA0_C.PinAttribute=CortexM4 +PA0_C.Signal=ADCx_INP0 +PA1.GPIOParameters=GPIO_Label,PinAttribute +PA1.GPIO_Label=ETH_REF_CLK +PA1.Locked=true +PA1.Mode=RMII +PA1.PinAttribute=CortexM7 +PA1.Signal=ETH_REF_CLK +PA10.GPIOParameters=GPIO_Label,PinAttribute +PA10.GPIO_Label=STLINK_TX +PA10.Locked=true +PA10.Mode=Asynchronous +PA10.PinAttribute=CortexM7 +PA10.Signal=USART1_RX +PA11.GPIOParameters=GPIO_Label +PA11.GPIO_Label=PMOD\#1 +PA11.Locked=true +PA11.Signal=SPI2_NSS +PA12.GPIOParameters=GPIO_Label +PA12.GPIO_Label=SPI2_SCK +PA12.Locked=true +PA12.Signal=SPI2_SCK +PA1_C.GPIOParameters=GPIO_Label,PinAttribute +PA1_C.GPIO_Label=ARD_A3 +PA1_C.Locked=true +PA1_C.PinAttribute=CortexM4 +PA1_C.Signal=ADCx_INP1 +PA2.GPIOParameters=GPIO_Label,PinAttribute +PA2.GPIO_Label=ETH_MDIO +PA2.Locked=true +PA2.Mode=RMII +PA2.PinAttribute=CortexM7 +PA2.Signal=ETH_MDIO +PA3.GPIOParameters=GPIO_Label +PA3.GPIO_Label=ULPI_D0 +PA3.Locked=true +PA3.Signal=USB_OTG_HS_ULPI_D0 +PA5.GPIOParameters=GPIO_Label +PA5.GPIO_Label=ULPI_CK +PA5.Locked=true +PA5.Signal=USB_OTG_HS_ULPI_CK +PA7.GPIOParameters=GPIO_Label,PinAttribute +PA7.GPIO_Label=ETH_CRS_DV +PA7.Locked=true +PA7.Mode=RMII +PA7.PinAttribute=CortexM7 +PA7.Signal=ETH_CRS_DV +PA8.GPIOParameters=GPIO_Label,PinAttribute +PA8.GPIO_Label=CEC_CK/MCO1 +PA8.Locked=true +PA8.Mode=Clock-out-1 +PA8.PinAttribute=CortexM7 +PA8.Signal=RCC_MCO_1 +PA9.GPIOParameters=GPIO_Label,PinAttribute +PA9.GPIO_Label=STLINK_RX +PA9.Locked=true +PA9.Mode=Asynchronous +PA9.PinAttribute=CortexM7 +PA9.Signal=USART1_TX +PB0.GPIOParameters=GPIO_Label +PB0.GPIO_Label=ULPI_D1 +PB0.Locked=true +PB0.Signal=USB_OTG_HS_ULPI_D1 +PB1.GPIOParameters=GPIO_Label +PB1.GPIO_Label=ULPI_D2 +PB1.Locked=true +PB1.Signal=USB_OTG_HS_ULPI_D2 +PB10.GPIOParameters=GPIO_Label +PB10.GPIO_Label=ULPI_D3 +PB10.Locked=true +PB10.Signal=USB_OTG_HS_ULPI_D3 +PB11.GPIOParameters=GPIO_Label +PB11.GPIO_Label=ULPI_D4 +PB11.Locked=true +PB11.Signal=USB_OTG_HS_ULPI_D4 +PB12.GPIOParameters=GPIO_Label +PB12.GPIO_Label=ULPI_D5 +PB12.Locked=true +PB12.Signal=USB_OTG_HS_ULPI_D5 +PB13.GPIOParameters=GPIO_Label +PB13.GPIO_Label=ULPI_D6 +PB13.Locked=true +PB13.Signal=USB_OTG_HS_ULPI_D6 +PB14.GPIOParameters=GPIO_Label,PinAttribute +PB14.GPIO_Label=PMOD\#9 +PB14.Locked=true +PB14.PinAttribute=Free +PB14.Signal=GPIO_Input +PB15.GPIOParameters=GPIO_Label,PinAttribute +PB15.GPIO_Label=PMOD\#8 +PB15.Locked=true +PB15.PinAttribute=Free +PB15.Signal=GPIO_Input +PB2.GPIOParameters=GPIO_Label +PB2.GPIO_Label=QSPI_CLK +PB2.Locked=true +PB2.Signal=QUADSPI_CLK +PB5.GPIOParameters=GPIO_Label +PB5.GPIO_Label=ULPI_D7 +PB5.Locked=true +PB5.Signal=USB_OTG_HS_ULPI_D7 +PB6.GPIOParameters=GPIO_Label +PB6.GPIO_Label=HDMI_CEC +PB6.Locked=true +PB6.Signal=CEC +PC0.GPIOParameters=GPIO_Label +PC0.GPIO_Label=ULPI_STP +PC0.Locked=true +PC0.Signal=USB_OTG_HS_ULPI_STP +PC1.GPIOParameters=GPIO_Label,PinAttribute +PC1.GPIO_Label=ETH_MDC/SAI4_D1 +PC1.Locked=true +PC1.Mode=RMII +PC1.PinAttribute=CortexM7 +PC1.Signal=ETH_MDC +PC10.GPIOParameters=GPIO_Label +PC10.GPIO_Label=SDIO1_D2 +PC10.Locked=true +PC10.Signal=SDMMC1_D2 +PC12.GPIOParameters=GPIO_Label +PC12.GPIO_Label=SDIO1_CK +PC12.Locked=true +PC12.Signal=SDMMC1_CK +PC13.GPIOParameters=GPIO_Label +PC13.GPIO_Label=B2 [Wakeup Button] +PC13.Locked=true +PC13.Signal=RTC_TAMP1 +PC14-OSC32_IN\ (OSC32_IN).GPIOParameters=GPIO_Label,PinAttribute +PC14-OSC32_IN\ (OSC32_IN).GPIO_Label=OSC32_IN +PC14-OSC32_IN\ (OSC32_IN).Locked=true +PC14-OSC32_IN\ (OSC32_IN).PinAttribute=CortexM7 +PC14-OSC32_IN\ (OSC32_IN).Signal=RCC_OSC32_IN +PC15-OSC32_OUT\ (OSC32_OUT).GPIOParameters=GPIO_Label,PinAttribute +PC15-OSC32_OUT\ (OSC32_OUT).GPIO_Label=OSC32_OUT +PC15-OSC32_OUT\ (OSC32_OUT).Locked=true +PC15-OSC32_OUT\ (OSC32_OUT).PinAttribute=CortexM7 +PC15-OSC32_OUT\ (OSC32_OUT).Signal=RCC_OSC32_OUT +PC2.GPIOParameters=GPIO_Label +PC2.GPIO_Label=PMOD\#3 +PC2.Locked=true +PC2.Signal=SPI2_MISO +PC2_C.GPIOParameters=GPIO_Label +PC2_C.GPIO_Label=ARD_A4 +PC2_C.Locked=true +PC2_C.Signal=ADC3_INP0 +PC3.GPIOParameters=GPIO_Label +PC3.GPIO_Label=PMOD\#2 +PC3.Locked=true +PC3.Signal=SPI2_MOSI +PC3_C.GPIOParameters=GPIO_Label +PC3_C.GPIO_Label=ARD_A5 +PC3_C.Locked=true +PC3_C.Signal=ADC3_INP1 +PC4.GPIOParameters=GPIO_Label,PinAttribute +PC4.GPIO_Label=ETH_RXD0 +PC4.Locked=true +PC4.Mode=RMII +PC4.PinAttribute=CortexM7 +PC4.Signal=ETH_RXD0 +PC5.GPIOParameters=GPIO_Label,PinAttribute +PC5.GPIO_Label=ETH_RXD1 +PC5.Locked=true +PC5.Mode=RMII +PC5.PinAttribute=CortexM7 +PC5.Signal=ETH_RXD1 +PC8.GPIOParameters=GPIO_Label +PC8.GPIO_Label=SDIO1_D0 +PC8.Locked=true +PC8.Signal=SDMMC1_D0 +PD0.GPIOParameters=GPIO_Label +PD0.GPIO_Label=FMC_D2 +PD0.Locked=true +PD0.Signal=FMC_D2_DA2 +PD1.GPIOParameters=GPIO_Label +PD1.GPIO_Label=FMC_D3 +PD1.Locked=true +PD1.Signal=FMC_D3_DA3 +PD10.GPIOParameters=GPIO_Label +PD10.GPIO_Label=FMC_D15 +PD10.Locked=true +PD10.Signal=FMC_D15_DA15 +PD11.GPIOParameters=GPIO_Label +PD11.GPIO_Label=QSPI_BK1_IO0 +PD11.Locked=true +PD11.Signal=QUADSPI_BK1_IO0 +PD14.GPIOParameters=GPIO_Label +PD14.GPIO_Label=FMC_D0 +PD14.Locked=true +PD14.Signal=FMC_D0_DA0 +PD15.GPIOParameters=GPIO_Label +PD15.GPIO_Label=FMC_D1 +PD15.Locked=true +PD15.Signal=FMC_D1_DA1 +PD2.GPIOParameters=GPIO_Label +PD2.GPIO_Label=SDIO1_CMD +PD2.Locked=true +PD2.Signal=SDMMC1_CMD +PD7.GPIOParameters=GPIO_Label +PD7.GPIO_Label=SPDIF_RX0 +PD7.Locked=true +PD7.Signal=SPDIFRX1_IN0 +PD8.GPIOParameters=GPIO_Label +PD8.GPIO_Label=FMC_D13 +PD8.Locked=true +PD8.Signal=FMC_D13_DA13 +PD9.GPIOParameters=GPIO_Label +PD9.GPIO_Label=FMC_D14 +PD9.Locked=true +PD9.Signal=FMC_D14_DA14 +PE0.GPIOParameters=GPIO_Label +PE0.GPIO_Label=FMC_NBL0 +PE0.Locked=true +PE0.Signal=FMC_NBL0 +PE1.GPIOParameters=GPIO_Label +PE1.GPIO_Label=FMC_NBL1 +PE1.Locked=true +PE1.Signal=FMC_NBL1 +PE10.GPIOParameters=GPIO_Label +PE10.GPIO_Label=FMC_D7 +PE10.Locked=true +PE10.Signal=FMC_D7_DA7 +PE11.GPIOParameters=GPIO_Label +PE11.GPIO_Label=FMC_D8 +PE11.Locked=true +PE11.Signal=FMC_D8_DA8 +PE12.GPIOParameters=GPIO_Label +PE12.GPIO_Label=FMC_D9 +PE12.Locked=true +PE12.Signal=FMC_D9_DA9 +PE13.GPIOParameters=GPIO_Label +PE13.GPIO_Label=FMC_D10 +PE13.Locked=true +PE13.Signal=FMC_D10_DA10 +PE14.GPIOParameters=GPIO_Label +PE14.GPIO_Label=FMC_D11 +PE14.Locked=true +PE14.Signal=FMC_D11_DA11 +PE15.GPIOParameters=GPIO_Label +PE15.GPIO_Label=FMC_D12 +PE15.Locked=true +PE15.Signal=FMC_D12_DA12 +PE3.GPIOParameters=GPIO_Label +PE3.GPIO_Label=SAI1_SD_B +PE3.Locked=true +PE3.Signal=SAI1_SD_B +PE4.GPIOParameters=GPIO_Label +PE4.GPIO_Label=SAI1_FS_A +PE4.Locked=true +PE4.Signal=SAI1_FS_A +PE5.GPIOParameters=GPIO_Label +PE5.GPIO_Label=SAI1_SCK_A +PE5.Locked=true +PE5.Signal=SAI1_SCK_A +PE6.GPIOParameters=GPIO_Label +PE6.GPIO_Label=SAI1_SD_A +PE6.Locked=true +PE6.Signal=SAI1_SD_A +PE7.GPIOParameters=GPIO_Label +PE7.GPIO_Label=FMC_D4 +PE7.Locked=true +PE7.Signal=FMC_D4_DA4 +PE8.GPIOParameters=GPIO_Label +PE8.GPIO_Label=FMC_D5 +PE8.Locked=true +PE8.Signal=FMC_D5_DA5 +PE9.GPIOParameters=GPIO_Label +PE9.GPIO_Label=FMC_D6 +PE9.Locked=true +PE9.Signal=FMC_D6_DA6 +PF0.GPIOParameters=GPIO_Label +PF0.GPIO_Label=FMC_A0 +PF0.Locked=true +PF0.Signal=FMC_A0 +PF1.GPIOParameters=GPIO_Label +PF1.GPIO_Label=FMC_A1 +PF1.Locked=true +PF1.Signal=FMC_A1 +PF10.GPIOParameters=GPIO_Label +PF10.GPIO_Label=ARD_A1 +PF10.Locked=true +PF10.Signal=ADC3_INP6 +PF11.GPIOParameters=GPIO_Label +PF11.GPIO_Label=FMC_SDRAS +PF11.Locked=true +PF11.Signal=FMC_SDNRAS +PF12.GPIOParameters=GPIO_Label +PF12.GPIO_Label=FMC_A6 +PF12.Locked=true +PF12.Signal=FMC_A6 +PF13.GPIOParameters=GPIO_Label +PF13.GPIO_Label=FMC_A7 +PF13.Locked=true +PF13.Signal=FMC_A7 +PF14.GPIOParameters=GPIO_Label +PF14.GPIO_Label=FMC_A8 +PF14.Locked=true +PF14.Signal=FMC_A8 +PF15.GPIOParameters=GPIO_Label +PF15.GPIO_Label=FMC_A9 +PF15.Locked=true +PF15.Signal=FMC_A9 +PF2.GPIOParameters=GPIO_Label +PF2.GPIO_Label=FMC_A2 +PF2.Locked=true +PF2.Signal=FMC_A2 +PF3.GPIOParameters=GPIO_Label +PF3.GPIO_Label=FMC_A3 +PF3.Locked=true +PF3.Signal=FMC_A3 +PF4.GPIOParameters=GPIO_Label +PF4.GPIO_Label=FMC_A4 +PF4.Locked=true +PF4.Signal=FMC_A4 +PF5.GPIOParameters=GPIO_Label +PF5.GPIO_Label=FMC_A5 +PF5.Locked=true +PF5.Signal=FMC_A5 +PF6.GPIOParameters=GPIO_Label +PF6.GPIO_Label=QSPI_BK1_IO3 +PF6.Locked=true +PF6.Signal=QUADSPI_BK1_IO3 +PF7.GPIOParameters=GPIO_Label +PF7.GPIO_Label=QSPI_BK1_IO2 +PF7.Locked=true +PF7.Signal=QUADSPI_BK1_IO2 +PF8.GPIOParameters=GPIO_Label +PF8.GPIO_Label=PMOD\#14/ARD_D3 +PF8.Locked=true +PF8.Signal=S_TIM13_CH1 +PF9.GPIOParameters=GPIO_Label +PF9.GPIO_Label=QSPI_BK1_IO1 +PF9.Locked=true +PF9.Signal=QUADSPI_BK1_IO1 +PG0.GPIOParameters=GPIO_Label +PG0.GPIO_Label=FMC_A10 +PG0.Locked=true +PG0.Signal=FMC_A10 +PG1.GPIOParameters=GPIO_Label +PG1.GPIO_Label=FMC_A11 +PG1.Locked=true +PG1.Signal=FMC_A11 +PG11.GPIOParameters=GPIO_Label,PinAttribute +PG11.GPIO_Label=ETH_TX_EN +PG11.Locked=true +PG11.Mode=RMII +PG11.PinAttribute=CortexM7 +PG11.Signal=ETH_TX_EN +PG12.GPIOParameters=GPIO_Label,PinAttribute +PG12.GPIO_Label=ETH_TXD1 +PG12.Locked=true +PG12.Mode=RMII +PG12.PinAttribute=CortexM7 +PG12.Signal=ETH_TXD1 +PG13.GPIOParameters=GPIO_Label,PinAttribute +PG13.GPIO_Label=ETH_TXD0 +PG13.Locked=true +PG13.Mode=RMII +PG13.PinAttribute=CortexM7 +PG13.Signal=ETH_TXD0 +PG14.GPIOParameters=GPIO_Label +PG14.GPIO_Label=QSPI_BK2_IO3 +PG14.Locked=true +PG14.Signal=QUADSPI_BK2_IO3 +PG15.GPIOParameters=GPIO_Label +PG15.GPIO_Label=FMC_SDCAS +PG15.Locked=true +PG15.Signal=FMC_SDNCAS +PG2.GPIOParameters=GPIO_Label +PG2.GPIO_Label=FMC_A12 +PG2.Locked=true +PG2.Signal=FMC_A12 +PG3.GPIOParameters=GPIO_Label,PinAttribute +PG3.GPIO_Label=DSI_Reset +PG3.Locked=true +PG3.PinAttribute=Free +PG3.Signal=GPIO_Output +PG4.GPIOParameters=GPIO_Label +PG4.GPIO_Label=FMC_BA0 +PG4.Locked=true +PG4.Signal=FMC_A14_BA0 +PG6.GPIOParameters=GPIO_Label +PG6.GPIO_Label=QSPI_BK1_NCS +PG6.Locked=true +PG6.Signal=QUADSPI_BK1_NCS +PG7.GPIOParameters=GPIO_Label +PG7.GPIO_Label=SAI1_MCLK_A +PG7.Locked=true +PG7.Signal=SAI1_MCLK_A +PG8.GPIOParameters=GPIO_Label +PG8.GPIO_Label=FMC_SDCLK +PG8.Locked=true +PG8.Signal=FMC_SDCLK +PG9.GPIOParameters=GPIO_Label +PG9.GPIO_Label=QSPI_BK2_IO2 +PG9.Locked=true +PG9.Signal=QUADSPI_BK2_IO2 +PH0-OSC_IN\ (PH0).GPIOParameters=GPIO_Label,PinAttribute +PH0-OSC_IN\ (PH0).GPIO_Label=OSC_IN +PH0-OSC_IN\ (PH0).Locked=true +PH0-OSC_IN\ (PH0).PinAttribute=CortexM7 +PH0-OSC_IN\ (PH0).Signal=RCC_OSC_IN +PH1-OSC_OUT\ (PH1).GPIOParameters=GPIO_Label,PinAttribute +PH1-OSC_OUT\ (PH1).GPIO_Label=OSC_OUT +PH1-OSC_OUT\ (PH1).Locked=true +PH1-OSC_OUT\ (PH1).PinAttribute=CortexM7 +PH1-OSC_OUT\ (PH1).Signal=RCC_OSC_OUT +PH10.GPIOParameters=GPIO_Label +PH10.GPIO_Label=FMC_D18 +PH10.Locked=true +PH10.Signal=FMC_D18 +PH11.GPIOParameters=GPIO_Label +PH11.GPIO_Label=FMC_D19 +PH11.Locked=true +PH11.Signal=FMC_D19 +PH12.GPIOParameters=GPIO_Label +PH12.GPIO_Label=FMC_D20 +PH12.Locked=true +PH12.Signal=FMC_D20 +PH13.GPIOParameters=GPIO_Label +PH13.GPIO_Label=FMC_D21 +PH13.Locked=true +PH13.Signal=FMC_D21 +PH14.GPIOParameters=GPIO_Label +PH14.GPIO_Label=FMC_D22 +PH14.Locked=true +PH14.Signal=FMC_D22 +PH15.GPIOParameters=GPIO_Label +PH15.GPIO_Label=FMC_D23 +PH15.Locked=true +PH15.Signal=FMC_D23 +PH2.GPIOParameters=GPIO_Label +PH2.GPIO_Label=QSPI_BK2_IO0 +PH2.Locked=true +PH2.Signal=QUADSPI_BK2_IO0 +PH3.GPIOParameters=GPIO_Label +PH3.GPIO_Label=QSPI_BK2_IO1 +PH3.Locked=true +PH3.Signal=QUADSPI_BK2_IO1 +PH4.GPIOParameters=GPIO_Label +PH4.GPIO_Label=ULPI_NXT +PH4.Locked=true +PH4.Signal=USB_OTG_HS_ULPI_NXT +PH5.GPIOParameters=GPIO_Label +PH5.GPIO_Label=FMC_SDNWE +PH5.Locked=true +PH5.Signal=FMC_SDNWE +PH6.GPIOParameters=GPIO_Label +PH6.GPIO_Label=FMC_SDNE1 +PH6.Locked=true +PH6.Signal=FMC_SDNE1 +PH7.GPIOParameters=GPIO_Label +PH7.GPIO_Label=FMC_SDCKE1 +PH7.Locked=true +PH7.Signal=FMC_SDCKE1 +PH8.GPIOParameters=GPIO_Label +PH8.GPIO_Label=FMC_D16 +PH8.Locked=true +PH8.Signal=FMC_D16 +PH9.GPIOParameters=GPIO_Label +PH9.GPIO_Label=FMC_D17 +PH9.Locked=true +PH9.Signal=FMC_D17 +PI0.GPIOParameters=GPIO_Label +PI0.GPIO_Label=FMC_D24 +PI0.Locked=true +PI0.Signal=FMC_D24 +PI1.GPIOParameters=GPIO_Label +PI1.GPIO_Label=FMC_D25 +PI1.Locked=true +PI1.Signal=FMC_D25 +PI10.GPIOParameters=GPIO_Label +PI10.GPIO_Label=FMC_D31 +PI10.Locked=true +PI10.Signal=FMC_D31 +PI11.GPIOParameters=GPIO_Label +PI11.GPIO_Label=ULPI_DIR +PI11.Locked=true +PI11.Signal=USB_OTG_HS_ULPI_DIR +PI12.GPIOParameters=GPIO_Label,PinAttribute +PI12.GPIO_Label=LED1 +PI12.Locked=true +PI12.PinAttribute=Free +PI12.Signal=GPIO_Output +PI13.GPIOParameters=GPIO_Label,PinAttribute +PI13.GPIO_Label=LED2 +PI13.Locked=true +PI13.PinAttribute=Free +PI13.Signal=GPIO_Output +PI14.GPIOParameters=GPIO_Label,PinAttribute +PI14.GPIO_Label=LED3 +PI14.Locked=true +PI14.PinAttribute=Free +PI14.Signal=GPIO_Output +PI15.GPIOParameters=GPIO_Label,PinAttribute +PI15.GPIO_Label=LED4 +PI15.Locked=true +PI15.PinAttribute=Free +PI15.Signal=GPIO_Output +PI2.GPIOParameters=GPIO_Label +PI2.GPIO_Label=FMC_D26 +PI2.Locked=true +PI2.Signal=FMC_D26 +PI3.GPIOParameters=GPIO_Label +PI3.GPIO_Label=FMC_D27 +PI3.Locked=true +PI3.Signal=FMC_D27 +PI4.GPIOParameters=GPIO_Label +PI4.GPIO_Label=FMC_NBL2 +PI4.Locked=true +PI4.Signal=FMC_NBL2 +PI5.GPIOParameters=GPIO_Label +PI5.GPIO_Label=FMC_NBL3 +PI5.Locked=true +PI5.Signal=FMC_NBL3 +PI6.GPIOParameters=GPIO_Label +PI6.GPIO_Label=FMC_D28 +PI6.Locked=true +PI6.Signal=FMC_D28 +PI7.GPIOParameters=GPIO_Label +PI7.GPIO_Label=FMC_D29 +PI7.Locked=true +PI7.Signal=FMC_D29 +PI8.GPIOParameters=GPIO_Label,PinAttribute +PI8.GPIO_Label=uSD_Detect +PI8.Locked=true +PI8.PinAttribute=Free +PI8.Signal=GPIO_Input +PI9.GPIOParameters=GPIO_Label +PI9.GPIO_Label=FMC_D30 +PI9.Locked=true +PI9.Signal=FMC_D30 +PJ0.GPIOParameters=GPIO_Label,PinAttribute +PJ0.GPIO_Label=ARD_D7 +PJ0.Locked=true +PJ0.PinAttribute=Free +PJ0.Signal=GPIO_Input +PJ1.GPIOParameters=GPIO_Label,PinAttribute +PJ1.GPIO_Label=OTG_HS_OverCurrent +PJ1.Locked=true +PJ1.PinAttribute=Free +PJ1.Signal=GPIO_Input +PJ10.GPIOParameters=GPIO_Label +PJ10.GPIO_Label=ARD_D11 +PJ10.Locked=true +PJ10.Signal=SPI5_MOSI +PJ11.GPIOParameters=GPIO_Label +PJ11.GPIO_Label=ARD_D12 +PJ11.Locked=true +PJ11.Signal=SPI5_MISO +PJ12.GPIOParameters=GPIO_Label,PinAttribute +PJ12.GPIO_Label=BL_CTRL +PJ12.Locked=true +PJ12.PinAttribute=Free +PJ12.Signal=GPIO_Output +PJ13.GPIOParameters=GPIO_Label,PinAttribute +PJ13.GPIO_Label=PMOD\#12 +PJ13.Locked=true +PJ13.PinAttribute=Free +PJ13.Signal=GPIO_Input +PJ15.GPIOParameters=GPIO_Label,PinAttribute +PJ15.GPIO_Label=Audio_INT +PJ15.Locked=true +PJ15.PinAttribute=Free +PJ15.Signal=GPIO_Input +PJ3.GPIOParameters=GPIO_Label,PinAttribute +PJ3.GPIO_Label=ARD_D2 +PJ3.Locked=true +PJ3.PinAttribute=Free +PJ3.Signal=GPIO_Input +PJ4.GPIOParameters=GPIO_Label,PinAttribute +PJ4.GPIO_Label=ARD_D4 +PJ4.Locked=true +PJ4.PinAttribute=Free +PJ4.Signal=GPIO_Input +PJ5.GPIOParameters=GPIO_Label,PinAttribute +PJ5.GPIO_Label=ARD_D8 +PJ5.Locked=true +PJ5.PinAttribute=Free +PJ5.Signal=GPIO_Input +PJ6.GPIOParameters=GPIO_Label +PJ6.GPIO_Label=ARD_D9 +PJ6.Locked=true +PJ6.Signal=S_TIM8_CH2 +PJ7.GPIOParameters=GPIO_Label +PJ7.GPIO_Label=ARD_D6 +PJ7.Locked=true +PJ7.Signal=TIM8_CH2N +PJ8.GPIOParameters=GPIO_Label +PJ8.GPIO_Label=ARD_D1 +PJ8.Locked=true +PJ8.Signal=UART8_TX +PJ9.GPIOParameters=GPIO_Label +PJ9.GPIO_Label=ARD_D0 +PJ9.Locked=true +PJ9.Signal=UART8_RX +PK0.GPIOParameters=GPIO_Label +PK0.GPIO_Label=ARD_D13 +PK0.Locked=true +PK0.Signal=SPI5_SCK +PK1.GPIOParameters=GPIO_Label +PK1.GPIO_Label=ARD_D10 +PK1.Locked=true +PK1.Signal=SPI5_NSS +PK2.GPIOParameters=GPIO_Label,PinAttribute +PK2.GPIO_Label=JOY_SEL +PK2.Locked=true +PK2.PinAttribute=Free +PK2.Signal=GPIO_Input +PK3.GPIOParameters=GPIO_Label,PinAttribute +PK3.GPIO_Label=JOY_DOWN +PK3.Locked=true +PK3.PinAttribute=Free +PK3.Signal=GPIO_Input +PK4.GPIOParameters=GPIO_Label,PinAttribute +PK4.GPIO_Label=JOY_LEFT +PK4.Locked=true +PK4.PinAttribute=Free +PK4.Signal=GPIO_Input +PK5.GPIOParameters=GPIO_Label,PinAttribute +PK5.GPIO_Label=JOY_RIGHT +PK5.Locked=true +PK5.PinAttribute=Free +PK5.Signal=GPIO_Input +PK6.GPIOParameters=GPIO_Label,PinAttribute +PK6.GPIO_Label=JOY_UP +PK6.Locked=true +PK6.PinAttribute=Free +PK6.Signal=GPIO_Input +PK7.GPIOParameters=GPIO_Label,PinAttribute +PK7.GPIO_Label=TOUCH_INT +PK7.Locked=true +PK7.PinAttribute=Free +PK7.Signal=GPIO_Input +PinOutPanel.CurrentBGAView=Top +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.BootMode=boot0 +ProjectManager.CompilerLinker=GCC +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=false +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32H747XIHx +ProjectManager.FirmwarePackage=STM32Cube FW_H7 V1.13.0 +ProjectManager.FreePins=false +ProjectManager.FreePinsContext=CortexM7 +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=M4-0x200,M7-0x10000 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=1 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain=STM32CubeIDE +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=stm32h747i_disco.ioc +ProjectManager.ProjectName=stm32h747i_disco +ProjectManager.ProjectStructure=M7\:CortexM7 Project\:true;M4\:CortexM4 Project\:true; +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=M4-0x400,M7-0x2000 +ProjectManager.TargetToolchain=CMake +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false-CortexM7,2-MX_GPIO_Init-GPIO-false-HAL-true-CortexM7,3-MX_ETH_Init-ETH-false-HAL-true-CortexM7,4-MX_USART1_UART_Init-USART1-false-HAL-true-CortexM7,5-MX_RNG_Init-RNG-false-HAL-true-CortexM7,1-MX_GPIO_Init-GPIO-false-HAL-true-CortexM4,2-MX_ADC1_Init-ADC1-false-HAL-true-CortexM4,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true-CortexM7,0-MX_CORTEX_M4_Init-CORTEX_M4-false-HAL-true-CortexM4 +RCC.ADCFreq_Value=80000000 +RCC.AHB12Freq_Value=200000000 +RCC.AHB4Freq_Value=200000000 +RCC.APB1Freq_Value=100000000 +RCC.APB2Freq_Value=100000000 +RCC.APB3Freq_Value=100000000 +RCC.APB4Freq_Value=100000000 +RCC.AXIClockFreq_Value=200000000 +RCC.CECFreq_Value=32000 +RCC.CKPERFreq_Value=64000000 +RCC.CPU2Freq_Value=200000000 +RCC.CPU2SystikFreq_Value=200000000 +RCC.CortexFreq_Value=400000000 +RCC.CpuClockFreq_Value=400000000 +RCC.D1CPREFreq_Value=400000000 +RCC.D1PPRE=RCC_APB3_DIV2 +RCC.D2PPRE1=RCC_APB1_DIV2 +RCC.D2PPRE2=RCC_APB2_DIV2 +RCC.D3PPRE=RCC_APB4_DIV2 +RCC.DFSDMACLkFreq_Value=400000000 +RCC.DFSDMFreq_Value=100000000 +RCC.DIVM1=4 +RCC.DIVM2=4 +RCC.DIVN1=50 +RCC.DIVN2=10 +RCC.DIVP1Freq_Value=400000000 +RCC.DIVP2Freq_Value=80000000 +RCC.DIVP3Freq_Value=129000000 +RCC.DIVQ1Freq_Value=400000000 +RCC.DIVQ2Freq_Value=80000000 +RCC.DIVQ3Freq_Value=129000000 +RCC.DIVR1Freq_Value=400000000 +RCC.DIVR2Freq_Value=80000000 +RCC.DIVR3Freq_Value=129000000 +RCC.DSIFreq_Value=62500000 +RCC.DSITXEscFreq_Value=15625000 +RCC.FDCANFreq_Value=400000000 +RCC.FMCFreq_Value=200000000 +RCC.FamilyName=M +RCC.HCLK3ClockFreq_Value=200000000 +RCC.HCLKFreq_Value=200000000 +RCC.HPRE=RCC_HCLK_DIV2 +RCC.HRTIMFreq_Value=200000000 +RCC.I2C123Freq_Value=100000000 +RCC.I2C4Freq_Value=100000000 +RCC.IPParameters=ADCFreq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1Freq_Value,APB2Freq_Value,APB3Freq_Value,APB4Freq_Value,AXIClockFreq_Value,CECFreq_Value,CKPERFreq_Value,CPU2Freq_Value,CPU2SystikFreq_Value,CortexFreq_Value,CpuClockFreq_Value,D1CPREFreq_Value,D1PPRE,D2PPRE1,D2PPRE2,D3PPRE,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVN1,DIVN2,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVR1Freq_Value,DIVR2Freq_Value,DIVR3Freq_Value,DSIFreq_Value,DSITXEscFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLKFreq_Value,HPRE,HRTIMFreq_Value,I2C123Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPUART1Freq_Value,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,PLL2FRACN,PLLDSIVCOFreq_Value,PLLFRACN,PWR_Regulator_Voltage_Scale,QSPIFreq_Value,RNGFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI23Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SPI123Freq_Value,SPI45Freq_Value,SPI6Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,SupplySource,Tim1OutputFreq_Value,Tim2OutputFreq_Value,TraceFreq_Value,USART16Freq_Value,USART234578Freq_Value,USBFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value +RCC.LPTIM1Freq_Value=100000000 +RCC.LPTIM2Freq_Value=100000000 +RCC.LPTIM345Freq_Value=100000000 +RCC.LPUART1Freq_Value=100000000 +RCC.LTDCFreq_Value=129000000 +RCC.MCO1PinFreq_Value=64000000 +RCC.MCO2PinFreq_Value=400000000 +RCC.PLL2FRACN=0 +RCC.PLLDSIVCOFreq_Value=1000000000 +RCC.PLLFRACN=0 +RCC.PWR_Regulator_Voltage_Scale=PWR_REGULATOR_VOLTAGE_SCALE1 +RCC.QSPIFreq_Value=200000000 +RCC.RNGFreq_Value=48000000 +RCC.RTCFreq_Value=32000 +RCC.SAI1Freq_Value=400000000 +RCC.SAI23Freq_Value=400000000 +RCC.SAI4AFreq_Value=400000000 +RCC.SAI4BFreq_Value=400000000 +RCC.SDMMCFreq_Value=400000000 +RCC.SPDIFRXFreq_Value=400000000 +RCC.SPI123Freq_Value=400000000 +RCC.SPI45Freq_Value=100000000 +RCC.SPI6Freq_Value=100000000 +RCC.SWPMI1Freq_Value=100000000 +RCC.SYSCLKFreq_VALUE=400000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.SupplySource=PWR_DIRECT_SMPS_SUPPLY +RCC.Tim1OutputFreq_Value=200000000 +RCC.Tim2OutputFreq_Value=200000000 +RCC.TraceFreq_Value=64000000 +RCC.USART16Freq_Value=100000000 +RCC.USART234578Freq_Value=100000000 +RCC.USBFreq_Value=400000000 +RCC.VCO1OutputFreq_Value=800000000 +RCC.VCO2OutputFreq_Value=160000000 +RCC.VCO3OutputFreq_Value=258000000 +RCC.VCOInput1Freq_Value=16000000 +RCC.VCOInput2Freq_Value=16000000 +RCC.VCOInput3Freq_Value=2000000 +SH.ADCx_INP0.0=ADC1_INP0,IN0-Single-Ended +SH.ADCx_INP0.ConfNb=1 +SH.ADCx_INP1.0=ADC1_INP1,IN1-Single-Ended +SH.ADCx_INP1.ConfNb=1 +SH.FMC_A0.0=FMC_A0 +SH.FMC_A0.ConfNb=1 +SH.FMC_A1.0=FMC_A1 +SH.FMC_A1.ConfNb=1 +SH.FMC_A10.0=FMC_A10 +SH.FMC_A10.ConfNb=1 +SH.FMC_A11.0=FMC_A11 +SH.FMC_A11.ConfNb=1 +SH.FMC_A12.0=FMC_A12 +SH.FMC_A12.ConfNb=1 +SH.FMC_A14_BA0.0=FMC_BA0 +SH.FMC_A14_BA0.ConfNb=1 +SH.FMC_A2.0=FMC_A2 +SH.FMC_A2.ConfNb=1 +SH.FMC_A3.0=FMC_A3 +SH.FMC_A3.ConfNb=1 +SH.FMC_A4.0=FMC_A4 +SH.FMC_A4.ConfNb=1 +SH.FMC_A5.0=FMC_A5 +SH.FMC_A5.ConfNb=1 +SH.FMC_A6.0=FMC_A6 +SH.FMC_A6.ConfNb=1 +SH.FMC_A7.0=FMC_A7 +SH.FMC_A7.ConfNb=1 +SH.FMC_A8.0=FMC_A8 +SH.FMC_A8.ConfNb=1 +SH.FMC_A9.0=FMC_A9 +SH.FMC_A9.ConfNb=1 +SH.FMC_D0_DA0.0=FMC_D0 +SH.FMC_D0_DA0.ConfNb=1 +SH.FMC_D10_DA10.0=FMC_D10 +SH.FMC_D10_DA10.ConfNb=1 +SH.FMC_D11_DA11.0=FMC_D11 +SH.FMC_D11_DA11.ConfNb=1 +SH.FMC_D12_DA12.0=FMC_D12 +SH.FMC_D12_DA12.ConfNb=1 +SH.FMC_D13_DA13.0=FMC_D13 +SH.FMC_D13_DA13.ConfNb=1 +SH.FMC_D14_DA14.0=FMC_D14 +SH.FMC_D14_DA14.ConfNb=1 +SH.FMC_D15_DA15.0=FMC_D15 +SH.FMC_D15_DA15.ConfNb=1 +SH.FMC_D16.0=FMC_D16 +SH.FMC_D16.ConfNb=1 +SH.FMC_D17.0=FMC_D17 +SH.FMC_D17.ConfNb=1 +SH.FMC_D18.0=FMC_D18 +SH.FMC_D18.ConfNb=1 +SH.FMC_D19.0=FMC_D19 +SH.FMC_D19.ConfNb=1 +SH.FMC_D1_DA1.0=FMC_D1 +SH.FMC_D1_DA1.ConfNb=1 +SH.FMC_D20.0=FMC_D20 +SH.FMC_D20.ConfNb=1 +SH.FMC_D21.0=FMC_D21 +SH.FMC_D21.ConfNb=1 +SH.FMC_D22.0=FMC_D22 +SH.FMC_D22.ConfNb=1 +SH.FMC_D23.0=FMC_D23 +SH.FMC_D23.ConfNb=1 +SH.FMC_D24.0=FMC_D24 +SH.FMC_D24.ConfNb=1 +SH.FMC_D25.0=FMC_D25 +SH.FMC_D25.ConfNb=1 +SH.FMC_D26.0=FMC_D26 +SH.FMC_D26.ConfNb=1 +SH.FMC_D27.0=FMC_D27 +SH.FMC_D27.ConfNb=1 +SH.FMC_D28.0=FMC_D28 +SH.FMC_D28.ConfNb=1 +SH.FMC_D29.0=FMC_D29 +SH.FMC_D29.ConfNb=1 +SH.FMC_D2_DA2.0=FMC_D2 +SH.FMC_D2_DA2.ConfNb=1 +SH.FMC_D30.0=FMC_D30 +SH.FMC_D30.ConfNb=1 +SH.FMC_D31.0=FMC_D31 +SH.FMC_D31.ConfNb=1 +SH.FMC_D3_DA3.0=FMC_D3 +SH.FMC_D3_DA3.ConfNb=1 +SH.FMC_D4_DA4.0=FMC_D4 +SH.FMC_D4_DA4.ConfNb=1 +SH.FMC_D5_DA5.0=FMC_D5 +SH.FMC_D5_DA5.ConfNb=1 +SH.FMC_D6_DA6.0=FMC_D6 +SH.FMC_D6_DA6.ConfNb=1 +SH.FMC_D7_DA7.0=FMC_D7 +SH.FMC_D7_DA7.ConfNb=1 +SH.FMC_D8_DA8.0=FMC_D8 +SH.FMC_D8_DA8.ConfNb=1 +SH.FMC_D9_DA9.0=FMC_D9 +SH.FMC_D9_DA9.ConfNb=1 +SH.FMC_NBL0.0=FMC_NBL0 +SH.FMC_NBL0.ConfNb=1 +SH.FMC_NBL1.0=FMC_NBL1 +SH.FMC_NBL1.ConfNb=1 +SH.FMC_NBL2.0=FMC_NBL2 +SH.FMC_NBL2.ConfNb=1 +SH.FMC_NBL3.0=FMC_NBL3 +SH.FMC_NBL3.ConfNb=1 +SH.FMC_SDCLK.0=FMC_SDCLK +SH.FMC_SDCLK.ConfNb=1 +SH.FMC_SDNCAS.0=FMC_SDNCAS +SH.FMC_SDNCAS.ConfNb=1 +SH.FMC_SDNRAS.0=FMC_SDNRAS +SH.FMC_SDNRAS.ConfNb=1 +SH.FMC_SDNWE.0=FMC_SDNWE +SH.FMC_SDNWE.ConfNb=1 +SH.S_TIM13_CH1.0=TIM13_CH1 +SH.S_TIM13_CH1.ConfNb=1 +SH.S_TIM8_CH2.0=TIM8_CH2 +SH.S_TIM8_CH2.ConfNb=1 +USART1.IPParameters=VirtualMode-Asynchronous +USART1.VirtualMode-Asynchronous=VM_ASYNC +VP_RNG_VS_RNG.Mode=RNG_Activate +VP_RNG_VS_RNG.Signal=RNG_VS_RNG +VP_SYS_M4_VS_Systick.Mode=SysTick +VP_SYS_M4_VS_Systick.Signal=SYS_M4_VS_Systick +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +board=STM32H747I-DISCO +boardIOC=true diff --git a/tutorials/stm32/stm32h747i_disco/minimal/Makefile b/tutorials/stm32/stm32h747i_disco/minimal/Makefile new file mode 100644 index 00000000..7bfdaab1 --- /dev/null +++ b/tutorials/stm32/stm32h747i_disco/minimal/Makefile @@ -0,0 +1,38 @@ +# Copyright (c) 2026 Cesanta Software Limited +# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/ + +CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion +CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion +CFLAGS += -g3 -Os -ffunction-sections -fdata-sections +CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include +CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA) -DCORE_CM7 +LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map + +SOURCES = main.c hal.c +SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h747xx.s + +TOP = ../../../.. +CFLAGS += -I$(TOP) +SOURCES += $(TOP)/mongoose.c + +all: firmware.bin + +firmware.elf: cmsis_core cmsis_h7 hal.h link.ld Makefile $(SOURCES) + arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@ + +firmware.bin: firmware.elf + arm-none-eabi-objcopy -O binary $< $@ + @echo + @echo "To flash, run 'make flash', or use STM32CubeProgrammer" + +flash: firmware.bin + STM32_Programmer_CLI -c port=swd -e all -w firmware.elf -hardRst + +cmsis_core: + git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@ + +cmsis_h7: + git clone -q -c advice.detachedHead=false --depth 1 -b v1.10.4 https://github.com/STMicroelectronics/cmsis_device_h7 $@ + +clean: + rm -rf firmware.* diff --git a/tutorials/stm32/stm32h747i_disco/minimal/hal.c b/tutorials/stm32/stm32h747i_disco/minimal/hal.c new file mode 100644 index 00000000..6dc65c9f --- /dev/null +++ b/tutorials/stm32/stm32h747i_disco/minimal/hal.c @@ -0,0 +1,125 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "hal.h" + +bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) { + uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry + if (period == 0) return false; // Avoid division by zero + if (diff < period) return false; // Period has not elapsed yet + *t += (diff / period) * period; // Preserve cadence, skip missed periods + return true; +} + +static volatile uint64_t s_ticks; // Milliseconds since boot +void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms + s_ticks++; +} + +uint64_t hal_get_tick(void) { + return s_ticks; +}; + +uint32_t SystemCoreClock = SYS_FREQUENCY; +void SystemInit(void) { // Called automatically by startup code + hal_system_init(); // Enable FPU + hal_clock_init(); + SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms +} + +void ExitRun0Mode(void) { +} + +struct stat; +__attribute__((weak)) int _fstat(int fd, struct stat *st) { + (void) fd, (void) st; + return -1; +} + +extern unsigned char _end[]; // End of data section, start of heap. See link.ld +static unsigned char *s_current_heap_end = _end; + +size_t hal_ram_used(void) { + return (size_t) (s_current_heap_end - _end); +} + +size_t hal_ram_free(void) { + unsigned char endofstack; + return (size_t) (&endofstack - s_current_heap_end); +} + +void *_sbrk(int incr) { + unsigned char *prev_heap; + unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256); + prev_heap = s_current_heap_end; + // Check how much space we got from the heap end to the stack end + if (s_current_heap_end + incr > heap_end) return (void *) -1; + s_current_heap_end += incr; + return prev_heap; +} + +__attribute__((weak)) int _open(const char *path) { + (void) path; + return -1; +} + +__attribute__((weak)) int _close(int fd) { + (void) fd; + return -1; +} + +__attribute__((weak)) int _isatty(int fd) { + (void) fd; + return 1; +} + +__attribute__((weak)) int _lseek(int fd, int ptr, int dir) { + (void) fd, (void) ptr, (void) dir; + return 0; +} + +__attribute__((weak)) void _exit(int status) { + (void) status; + for (;;) asm volatile("BKPT #0"); +} + +__attribute__((weak)) void _kill(int pid, int sig) { + (void) pid, (void) sig; +} + +__attribute__((weak)) int _getpid(void) { + return -1; +} + +__attribute__((weak)) int _write(int fd, char *ptr, int len) { + (void) fd, (void) ptr, (void) len; + return -1; +} + +__attribute__((weak)) int _read(int fd, char *ptr, int len) { + (void) fd, (void) ptr, (void) len; + return -1; +} + +__attribute__((weak)) int _link(const char *a, const char *b) { + (void) a, (void) b; + return -1; +} + +__attribute__((weak)) int _unlink(const char *a) { + (void) a; + return -1; +} + +__attribute__((weak)) int _stat(const char *path, struct stat *st) { + (void) path, (void) st; + return -1; +} + +__attribute__((weak)) int mkdir(const char *path, int mode) { + (void) path, (void) mode; + return -1; +} + +__attribute__((weak)) void _init(void) { +} diff --git a/tutorials/stm32/stm32h747i_disco/minimal/hal.h b/tutorials/stm32/stm32h747i_disco/minimal/hal.h new file mode 100644 index 00000000..5a55fb16 --- /dev/null +++ b/tutorials/stm32/stm32h747i_disco/minimal/hal.h @@ -0,0 +1,246 @@ +// Copyright (c) 2022-2023 Cesanta Software Limited +// All rights reserved +// +// RM0399 +// https://www.st.com/resource/en/reference_manual/rm0399-stm32h745755-and-stm32h747757-advanced-armbased-32bit-mcus-stmicroelectronics.pdf +// https://www.st.com/resource/en/datasheet/stm32h747xi.pdf +// UM2411 +// https://www.st.com/resource/en/user_manual/um2411-discovery-kit-with-stm32h747xi-mcu-stmicroelectronics.pdf + +#pragma once + +#include + +#include +#include +#include +#include + +extern bool hal_timer_expired(volatile uint64_t *t, uint64_t prd, uint64_t now); +extern uint64_t hal_get_tick(void); +extern size_t hal_ram_free(void); +extern size_t hal_ram_used(void); +extern uint32_t SystemCoreClock; + +#define HAL_ETH_PINS \ + PIN('A', 1), /* ETH_REF_CLK */ \ + PIN('A', 2), /* ETH_MDIO */ \ + PIN('A', 7), /* ETH_CRS_DV */ \ + PIN('C', 1), /* ETH_MDC */ \ + PIN('C', 4), /* ETH_RXD0 */ \ + PIN('C', 5), /* ETH_RXD1 */ \ + PIN('G', 11), /* ETH_TX_EN */ \ + PIN('G', 12), /* ETH_TXD1 */ \ + PIN('G', 13) /* ETH_TXD0 */ + +#define BIT(x) (1UL << (x)) +#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set)) +#define PIN(bank, num) ((((bank) - 'A') << 8) | (num)) +#define PINNO(pin) (pin & 255) +#define PINBANK(pin) (pin >> 8) + +void hal_init(void); +size_t hal_ram_free(void); +size_t hal_ram_used(void); + +// System clock (2.1, Figure 1; 8.5, Figure 45; 8.5.5, Figure 47; 8.5.6, Figure +// 49) +// - This board defaults to work with an SMPS regulator, so: +// - SYS_FREQUENCY <= 400 MHz; hclk = SYS_FREQUENCY / HPRE ; hclk <= 200 MHz; +// APB clocks <= 100 MHz. +// - D1 domain bus matrix (and so flash) runs at hclk frequency. Configure flash +// latency (WS) in accordance to hclk freq (4.3.8, Table 17) +// - The Ethernet controller is in D2 domain and runs at hclk frequency +enum { + HAL_D1CPRE = 1, // actual divisor value + HAL_HPRE = 2, // actual divisor value + HAL_D1PPRE = 4, // register values, divisor value = BIT(value - 3) = / 2 + HAL_D2PPRE1 = 4, + HAL_D2PPRE2 = 4, + HAL_D3PPRE = 4 +}; +// PLL1_P: odd division factors are not allowed (8.7.13) (according to Cube, '1' +// is also an "odd division factor"). +// Make sure your chip is revision 'V', otherwise set PLL1_N = 400 +enum { PLL1_HSI = 64, PLL1_M = 32, PLL1_N = 400, PLL1_P = 2 }; +#define SYS_FREQUENCY ((PLL1_HSI * PLL1_N / PLL1_M / PLL1_P / HAL_D1CPRE) * 1000000) +//#define SYS_FREQUENCY ((PLL1_HSI / HAL_D1CPRE) * 1000000) +//#define SYS_FREQUENCY 64000000 +#define AHB_FREQUENCY (SYS_FREQUENCY / HAL_HPRE) +#define APB2_FREQUENCY (AHB_FREQUENCY / (BIT(HAL_D2PPRE2 - 3))) +#define APB1_FREQUENCY (AHB_FREQUENCY / (BIT(HAL_D2PPRE1 - 3))) + +static inline void spin(volatile uint32_t n) { + while (n--) (void) 0; +} + +enum { HAL_GPIO_MODE_INPUT, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_MODE_AF, HAL_GPIO_MODE_ANALOG }; +enum { HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_OTYPE_OPEN_DRAIN }; +enum { HAL_GPIO_SPEED_LOW, HAL_GPIO_SPEED_MEDIUM, HAL_GPIO_SPEED_HIGH, HAL_GPIO_SPEED_INSANE }; +enum { HAL_GPIO_PULL_NONE, HAL_GPIO_PULL_UP, HAL_GPIO_PULL_DOWN }; + +#define HAL_GPIO(N) ((GPIO_TypeDef *) (0x40000000 + 0x18020000UL + 0x400 * (N))) + +static GPIO_TypeDef *hal_gpio_bank(uint16_t pin) { + return HAL_GPIO(PINBANK(pin)); +} +static inline void hal_gpio_toggle(uint16_t pin) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + uint32_t mask = BIT(PINNO(pin)); + gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0); +} +static inline int hal_gpio_read(uint16_t pin) { + return hal_gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0; +} +static inline void hal_gpio_write(uint16_t pin, bool val) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16); +} +static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t type, + uint8_t speed, uint8_t pull, uint8_t af) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + uint8_t n = (uint8_t) (PINNO(pin)); + RCC->AHB4ENR |= BIT(PINBANK(pin)); // Enable GPIO clock + CLRSET(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n); + CLRSET(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2)); + CLRSET(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2)); + CLRSET(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4), + ((uint32_t) af) << ((n & 7) * 4)); + CLRSET(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2)); +} +static inline void hal_gpio_input(uint16_t pin) { + hal_gpio_init(pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, + HAL_GPIO_PULL_NONE, 0); +} +static inline void hal_gpio_output(uint16_t pin) { + hal_gpio_init(pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, + HAL_GPIO_PULL_NONE, 0); +} + +// D2 Kernel clock (8.7.21) USART1 defaults to pclk2 (APB2), while USART2,3 +// default to pclk1 (APB1). Even if using other kernel clocks, the APBx clocks +// must be enabled for CPU access, as the kernel clock drives the BRR, not the +// APB bus interface +static inline void hal_uart_init(USART_TypeDef *uart, unsigned long baud) { + uint8_t af = 7; // Alternate function + uint16_t rx = 0, tx = 0; // pins + uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1 + + if (uart == USART1) freq = APB2_FREQUENCY, RCC->APB2ENR |= BIT(4); + if (uart == USART2) freq = APB1_FREQUENCY, RCC->APB1LENR |= BIT(17); + if (uart == USART3) freq = APB1_FREQUENCY, RCC->APB1LENR |= BIT(18); + + if (uart == USART1) tx = PIN('A', 9), rx = PIN('A', 10); + if (uart == USART2) tx = PIN('A', 2), rx = PIN('A', 3); + if (uart == USART3) tx = PIN('D', 8), rx = PIN('D', 9); + +#if 0 // CONSTANT BAUD RATE FOR REMOTE DEBUGGING WHILE SETTING THE PLL + CLRSET(RCC->D2CCIP2R, 7 << 3, 3 << 3); // use HSI for UART1 + freq = 64000000; +#endif + + hal_gpio_init(tx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af); + hal_gpio_init(rx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af); + uart->CR1 = 0; // Disable this UART + uart->BRR = freq / baud; // Set baud rate + uart->CR1 = BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE +} +static inline void hal_uart_write_byte(USART_TypeDef *uart, uint8_t byte) { + uart->TDR = byte; + while ((uart->ISR & BIT(7)) == 0) spin(1); +} +static inline void hal_uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) { + while (len-- > 0) hal_uart_write_byte(uart, *(uint8_t *) buf++); +} +static inline int hal_uart_read_ready(USART_TypeDef *uart) { + return uart->ISR & BIT(5); // If RXNE bit is set, data is ready +} +static inline uint8_t hal_uart_read_byte(USART_TypeDef *uart) { + return (uint8_t) (uart->RDR & 255); +} + +static inline void hal_rng_init(void) { + RCC->D2CCIP2R |= RCC_D2CCIP2R_RNGSEL_0; // RNG clock source pll1_q_ck + RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; // Enable RNG clock + RNG->CR = RNG_CR_RNGEN; // Enable RNG +} + +static inline uint32_t hal_rng_read(void) { + while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0; + return RNG->DR; +} + +// Hw pull-ups on PHY RXD0,1,DV to enable autonegotiation +static inline void hal_ethernet_init(void) { + // Initialise Ethernet. Enable MAC GPIO pins, see UM2411 + uint16_t pins[] = {HAL_ETH_PINS}; + for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) { + hal_gpio_init(pins[i], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_INSANE, + HAL_GPIO_PULL_NONE, 11); // 11 is the Ethernet function + } + NVIC_EnableIRQ(ETH_IRQn); // Setup Ethernet IRQ handler + CLRSET(SYSCFG->PMCR, 7 << 21, 4 << 21); // Use RMII (13.3.1) + RCC->AHB1ENR |= BIT(15) | BIT(16) | BIT(17); // Enable Ethernet clocks +} + +static inline char hal_chiprev(void) { + uint16_t rev = (uint16_t) (((uint32_t) DBGMCU->IDCODE) >> 16); + if (rev == 0x1003) return 'Y'; + if (rev == 0x2003) return 'V'; + return '?'; +} + +static inline unsigned int hal_div2prescval(unsigned int div) { + // 0 --> /1; 8 --> /2 ... 11 --> /16; 12 --> /64 ... 15 --> /512 + if (div == 1) return 0; + if (div > 16) div /= 2; + unsigned int val = 7; + while (div >>= 1) ++val; + return val; +} + +static inline unsigned int hal_pllrge(unsigned int f) { + unsigned int val = 0; + while (f >>= 1) ++val; + return val - 1; +} + +static inline void hal_clock_init(void) { // Called automatically by startup code + // Set flash latency. RM section 4.9.1, section 4.3.8 table 16 + CLRSET(FLASH->ACR, (FLASH_ACR_WRHIGHFREQ_Msk | FLASH_ACR_LATENCY_Msk), + FLASH_ACR_LATENCY_2WS | FLASH_ACR_WRHIGHFREQ_1); + CLRSET(PWR->CR3, BIT(1), BIT(2)); // select SMPS + while ((PWR->CSR1 & BIT(13)) == 0) spin(1); // ACTVOSRDY + PWR->D3CR |= BIT(15) | BIT(14); // Select VOS1 + uint32_t f = PWR->D3CR; // fake read to wait for bus clocking + while ((PWR->CSR1 & BIT(13)) == 0) spin(1); // ACTVOSRDY +#if 0 + SYSCFG->PWRCR |= BIT(0); // ODEN for LDO to go 480MHz + f = SYSCFG->PWRCR; + while ((PWR->CSR1 & BIT(13)) == 0) spin(1); // ACTVOSRDY +#endif + (void) f; + CLRSET(RCC->D1CFGR, (0x0F << 8) | (7 << 4) | (0x0F << 0), + (hal_div2prescval(HAL_D1CPRE) << 8) | (HAL_D1PPRE << 4) | + (hal_div2prescval(HAL_HPRE) << 0)); + RCC->D2CFGR = (HAL_D2PPRE2 << 8) | (HAL_D2PPRE1 << 4); + RCC->D3CFGR = (HAL_D3PPRE << 4); + CLRSET(RCC->PLLCFGR, 3 << 2, + hal_pllrge(PLL1_HSI / PLL1_M) + << 2); // keep reset config (DIVP1EN, !PLL1VCOSEL), PLL1RGE + CLRSET(RCC->PLL1DIVR, (0x7F << 9) | (0x1FF << 0), + ((PLL1_P - 1) << 9) | ((PLL1_N - 1) << 0)); // Set PLL1_P PLL1_N + CLRSET(RCC->PLLCKSELR, 0x3F << 4, + PLL1_M << 4); // Set PLL1_M (source defaults to HSI) + RCC->CR |= BIT(24); // Enable PLL1 + while ((RCC->CR & BIT(25)) == 0) spin(1); // Wait until done + RCC->CFGR |= (3 << 0); // Set clock source to PLL1 + while ((RCC->CFGR & (7 << 3)) != (3 << 3)) spin(1); // Wait until done + RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN; // Enable SYSCFG +} + +static inline void hal_system_init(void) { + SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU + __DSB(); + __ISB(); +} diff --git a/tutorials/stm32/stm32h747i_disco/minimal/link.ld b/tutorials/stm32/stm32h747i_disco/minimal/link.ld new file mode 100644 index 00000000..810cee21 --- /dev/null +++ b/tutorials/stm32/stm32h747i_disco/minimal/link.ld @@ -0,0 +1,31 @@ +ENTRY(Reset_Handler); +MEMORY { + flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k + sram(rwx) : ORIGIN = 0x24000000, LENGTH = 512k +} +_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */ + +SECTIONS { + .vectors : { KEEP(*(.isr_vector)) } > flash + .text : { *(.text* .text.*) } > flash + .rodata : { *(.rodata*) } > flash + + .data : { + _sdata = .; + *(.first_data) + *(.data SORT(.data.*)) + *(.iram .iram* .iram.*) + _edata = .; + } > sram AT > flash + _sidata = LOADADDR(.data); + + .bss : { + _sbss = .; + *(.bss SORT(.bss.*) COMMON) + _ebss = .; + } > sram + + . = ALIGN(8); + _end = .; +} + diff --git a/tutorials/stm32/stm32h747i_disco/minimal/main.c b/tutorials/stm32/stm32h747i_disco/minimal/main.c new file mode 100644 index 00000000..7060918d --- /dev/null +++ b/tutorials/stm32/stm32h747i_disco/minimal/main.c @@ -0,0 +1,70 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "mongoose.h" +#include "hal.h" + +#define DEBUG_UART USART1 +#define LED1 PIN('I', 12) // On-board LED pin (green) +#define LED2 PIN('I', 13) // On-board LED pin (yellow) +#define LED3 PIN('I', 14) // On-board LED pin (red) + +// Redirect stdout debug output to UART +int _write(int fd, char *ptr, int len) { + if (fd == 1 || fd == 2) hal_uart_write_buf(DEBUG_UART, ptr, (size_t) len); + return len; +} + +static void blink_task(void) { + static uint64_t blink_timer = 0; + if (hal_timer_expired(&blink_timer, 500, hal_get_tick())) { + hal_gpio_toggle(LED1); + } +} + +uint64_t mg_millis(void) { + return hal_get_tick(); +} + +bool mg_random(void *buf, size_t len) { + for (size_t n = 0; n < len; n += sizeof(uint32_t)) { + uint32_t r = hal_rng_read(); + memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r)); + } + return true; +} + +static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_HTTP_MSG) { // New HTTP request received + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { + mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick()); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", + hal_get_tick()); + } + } +} + +int main(void) { + hal_clock_init(); + hal_rng_init(); + hal_gpio_output(LED1); + hal_gpio_output(LED2); + hal_gpio_output(LED3); + hal_uart_init(DEBUG_UART, 115200); + + hal_ethernet_init(); + + // Start a minimal web server + struct mg_mgr mgr; + mg_mgr_init(&mgr); + mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL); + + for (;;) { + mg_mgr_poll(&mgr, 0); + blink_task(); + } + + return 0; +} diff --git a/tutorials/stm32/stm32h747i_disco/minimal/mongoose_config.h b/tutorials/stm32/stm32h747i_disco/minimal/mongoose_config.h new file mode 100644 index 00000000..ae8942ce --- /dev/null +++ b/tutorials/stm32/stm32h747i_disco/minimal/mongoose_config.h @@ -0,0 +1,42 @@ +#pragma once + +// See https://mongoose.ws/documentation/#build-options +#define MG_ARCH MG_ARCH_ARMGCC +#define MG_TLS MG_TLS_BUILTIN +#define MG_OTA MG_OTA_STM32H7_DUAL_CORE + +#define MG_ENABLE_TCPIP 1 +#define MG_ENABLE_CUSTOM_MILLIS 1 +#define MG_ENABLE_CUSTOM_RANDOM 1 +#define MG_ENABLE_DRIVER_STM32H 1 + +// #define MG_DRIVER_MDC_CR 4 // RMII MDC clock divider, from 0 to 5 +// #define MG_TCPIP_PHY_ADDR 0 // PHY address + +// For static IP configuration, define MG_TCPIP_{IP,MASK,GW} +// By default, those are set to zero, meaning that DHCP is used +// +// #define MG_TCPIP_IP MG_IPV4(192, 168, 0, 10) // IP +// #define MG_TCPIP_GW MG_IPV4(192, 168, 0, 1) // Gateway +// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0) // Netmask + +// Set custom MAC address. By default, it is randomly generated +// Using a build-time constant: +// #define MG_SET_MAC_ADDRESS(mac) do { mac[0] = 2; mac[1] = 3; mac[2] = 4; mac[3] = 5; mac[4] = 6; mac[5] = 7; } while (0) +// +// Using custom function: +// extern void my_function(unsigned char *mac); +// #define MG_SET_MAC_ADDRESS(mac) my_function(mac) + +// Construct MAC address from the MCU unique ID. It is defined in the +// ST CMSIS header as UID_BASE +#define MGUID ((uint32_t *) 0x1ff1e800) // Unique 96-bit chip ID +#define MG_SET_MAC_ADDRESS(mac) \ + do { \ + mac[0] = 2; \ + mac[1] = MGUID[0] & 255; \ + mac[2] = (MGUID[0] >> 10) & 255; \ + mac[3] = (MGUID[0] >> 19) & 255; \ + mac[4] = MGUID[1] & 255; \ + mac[5] = MGUID[2] & 255; \ + } while (0)