diff --git a/tutorials/stm32/nucleo_f756zg/cubemx/README.md b/tutorials/stm32/nucleo_f756zg/cubemx/README.md new file mode 100644 index 00000000..2ef1fe35 --- /dev/null +++ b/tutorials/stm32/nucleo_f756zg/cubemx/README.md @@ -0,0 +1,98 @@ +# Mongoose CubeMX integration + +This is a step-by-step guide on how to bring up a production-grade Web UI +dashboard on STM32 Nucleo-F756ZG development board. + +A pre-configured project .zip is available for download at https://mongoose.ws. +However for those who want to configure the project from scratch, follow the steps +below. + +## Generate project code +- Open the .ioc file in your CubeMX +- Click on "Project Manager" + - If you're using CubeIDE, select "CubeIDE" in the toolchain/IDE dropdown + - If you're using VSCode, select "Cmake" in the toolchain/IDE dropdown + - If you're using Makefile, select "Makefile" in the toolchain/IDE dropdown +- Click "Generate Code" button on the top right + +This should generate project code in this directory the directory where .ioc file lives. +Open this directory in your IDE. + +## Configure .bin generation + +Normally, IDEs generate .elf firmware file, cause it is easier for a debugger +to load it to a device. However, for the firmware OTA update, the .bin file +is required. The .bin file is the firmware image that gets copied to the +beginning of the microcontroller's flash memory and gets executed after the +system boot. + +So, we need to tell the IDE to generate .bin firmware flash image file. + +- If you're using CubeIDE, select Project / Properties / C/C++ build / Settings + / MCU/MPU Post build outputs, enable "Convert to binary file (-O binary)" +- If you're using VSCode, add a section to the end of the top-level `CMakeLists.txt`: +```cmake +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary + ${PROJECT_NAME}.elf + ${PROJECT_NAME}.bin +) +``` + +## Call Mongoose from main.c + + +Edit `Core/Src/main.c` and update the following snippets - notice the `USER CODE BEGIN` / `USER CODE END` placeholders. At the top of the file: + +```c +/* USER CODE BEGIN Includes */ +#include "mongoose_glue.h" +/* USER CODE END Includes */ +``` + +Before the `main()` function: +```c +/* USER CODE BEGIN 0 */ +int _write(int fd, unsigned char *buf, int len) { + HAL_UART_Transmit(&huart3, buf, len, HAL_MAX_DELAY); + return len; +} + +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_GetTick()); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", HAL_GetTick()); + } + } +} + +// This blocks forever. Call it at the end of main(), or in a +// separate RTOS task. Give that task 8k stack space. +void run_mongoose(void) { + 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); + } +} +/* USER CODE END 0 */ +``` + +Inside the `main()` function: +```c +/* USER CODE BEGIN WHILE */ +run_mongoose(); // <----------------- Add this line +while (1) +{ + /* USER CODE END WHILE */ +``` + +## Build, flash, test + +Start serial console. +Use STM32CubeProgrammer to flash the firmware. diff --git a/tutorials/stm32/nucleo_f756zg/cubemx/nucleo_f756zg.ioc b/tutorials/stm32/nucleo_f756zg/cubemx/nucleo_f756zg.ioc new file mode 100644 index 00000000..1538131e --- /dev/null +++ b/tutorials/stm32/nucleo_f756zg/cubemx/nucleo_f756zg.ioc @@ -0,0 +1,210 @@ +#MicroXplorer Configuration settings - do not modify +CAD.formats= +CAD.pinconfig= +CAD.provider= +CORTEX_M7.IPParameters=default_mode_Activation +CORTEX_M7.default_mode_Activation=1 +Cesanta.I-CUBE-Mongoose.7.21.7.IPParameters=MongooseJjNetworkingOoCore,MongooseJjWebOoDeviceOoDashboard +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjNetworkingOoCore=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjNetworkingOoCore_Checked=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjWebOoDeviceOoDashboard=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjWebOoDeviceOoDashboard_Checked=true +Cesanta.I-CUBE-Mongoose.7.21.7_SwParameter=MongooseJjNetworkingOoCore\:true;MongooseJjWebOoDeviceOoDashboard\:true;MongooseJjMQTTOoClient\:true; +ETH.IPParameters=MediaInterface +ETH.MediaInterface=HAL_ETH_RMII_MODE +File.Version=6 +GPIO.groupedBy= +KeepUserPlacement=false +Mcu.CPN=STM32F756ZGT6 +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=STM32F756ZGTx +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.Pin16=VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7 +Mcu.Pin17=VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7 +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=18 +Mcu.ThirdParty0=Cesanta.I-CUBE-Mongoose.7.21.7 +Mcu.ThirdPartyNb=1 +Mcu.UserConstants= +Mcu.UserName=STM32F756ZGTx +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.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=STM32F756ZGTx +PCC.PartNumber=STM32F756ZGTx +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=STM32F756ZGTx +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= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=nucleo_f756zg.ioc +ProjectManager.ProjectName=nucleo_f756zg +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.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.I2SFreq_Value=192000000 +RCC.IPParameters=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,I2SFreq_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,PLLSAIoutputFreq_Value,RNGFreq_Value,SAI1Freq_Value,SAI2Freq_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 +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.PLLSAIoutputFreq_Value=192000000 +RCC.RNGFreq_Value=48000000 +RCC.SAI1Freq_Value=192000000 +RCC.SAI2Freq_Value=192000000 +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 +USART3.IPParameters=VirtualMode-Asynchronous +USART3.VirtualMode-Asynchronous=VM_ASYNC +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7.Mode=MongooseJjNetworkingOoCore +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7.Signal=Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7 +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7.Mode=MongooseJjWebOoDeviceOoDashboard +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7.Signal=Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7 +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_f756zg/minimal/Makefile b/tutorials/stm32/nucleo_f756zg/minimal/Makefile new file mode 100644 index 00000000..224649a1 --- /dev/null +++ b/tutorials/stm32/nucleo_f756zg/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_stm32f756xx.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.10 https://github.com/STMicroelectronics/cmsis_device_f7 $@ + +clean: + rm -rf firmware.* diff --git a/tutorials/stm32/nucleo_f756zg/minimal/hal.c b/tutorials/stm32/nucleo_f756zg/minimal/hal.c new file mode 100644 index 00000000..e519bff3 --- /dev/null +++ b/tutorials/stm32/nucleo_f756zg/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 = 160000000; +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_f756zg/minimal/hal.h b/tutorials/stm32/nucleo_f756zg/minimal/hal.h new file mode 100644 index 00000000..9c9c65a7 --- /dev/null +++ b/tutorials/stm32/nucleo_f756zg/minimal/hal.h @@ -0,0 +1,196 @@ +// 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 + +#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) + +#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('B', 13), /* ETH_TXD1 */ \ + PIN('G', 11), /* ETH_TX_EN */ \ + PIN('G', 13) /* ETH_TXD0 */ + +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; + +/* 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 + SystemCoreClock = SYS_FREQUENCY; // Update SystemCoreClock global var + SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms +} + +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_f756zg/minimal/link.ld b/tutorials/stm32/nucleo_f756zg/minimal/link.ld new file mode 100644 index 00000000..4232d046 --- /dev/null +++ b/tutorials/stm32/nucleo_f756zg/minimal/link.ld @@ -0,0 +1,21 @@ +ENTRY(Reset_Handler); +MEMORY { + flash(rx) : ORIGIN = 0x08000000, LENGTH = 1024k + sram(rwx) : ORIGIN = 0x20000000, LENGTH = 320k +} +_estack = ORIGIN(sram) + LENGTH(sram); + +SECTIONS { + .vectors : { KEEP(*(.isr_vector)) } > flash + .text : { *(.text* .text.*) } > flash + .rodata : { *(.rodata*) } > flash + + /* Note the .iram section, for functions copied to RAM. Required for MG_IRAM OTA support */ + .data : { _sdata = .; *(.first_data) *(.iram .iram* .iram.*) *(.data SORT(.data.*)) _edata = .; } > sram AT > flash + _sidata = LOADADDR(.data); + + .bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram + + . = ALIGN(8); + _end = .; +} diff --git a/tutorials/stm32/nucleo_f756zg/minimal/main.c b/tutorials/stm32/nucleo_f756zg/minimal/main.c new file mode 100644 index 00000000..2f3e99e5 --- /dev/null +++ b/tutorials/stm32/nucleo_f756zg/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_f756zg/minimal/mongoose_config.h b/tutorials/stm32/nucleo_f756zg/minimal/mongoose_config.h new file mode 100644 index 00000000..f7dd4eab --- /dev/null +++ b/tutorials/stm32/nucleo_f756zg/minimal/mongoose_config.h @@ -0,0 +1,34 @@ +#pragma once + +// See https://mongoose.ws/docs/getting-started/build-options/ +#define MG_ARCH MG_ARCH_ARMGCC +#define MG_TLS MG_TLS_BUILTIN +#define MG_OTA MG_OTA_STM32F + +#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_ENABLE_PACKED_FS 1 + +// #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) // IP +// #define MG_TCPIP_GW MG_IPV4(192, 168, 0, 1) // Gateway +// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0) // Netmask + +// Construct MAC address from the MCU unique ID +#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_h563zi/cubemx/README.md b/tutorials/stm32/nucleo_h563zi/cubemx/README.md new file mode 100644 index 00000000..d3e60b1e --- /dev/null +++ b/tutorials/stm32/nucleo_h563zi/cubemx/README.md @@ -0,0 +1,98 @@ +# Mongoose CubeMX integration + +This is a step-by-step guide on how to bring up a production-grade Web UI +dashboard on STM32 Nucleo-H563ZI development board. + +A pre-configured project .zip is available for download at https://mongoose.ws. +However for those who want to configure the project from scratch, follow the steps +below. + + +## Generate project code +- Open the .ioc file in your CubeMX +- Click on "Project Manager" + - If you're using CubeIDE, select "CubeIDE" in the toolchain/IDE dropdown + - If you're using VSCode, select "Cmake" in the toolchain/IDE dropdown + - If you're using Makefile, select "Makefile" in the toolchain/IDE dropdown +- Click "Generate Code" button on the top right + +This should generate project code in this directory the directory where .ioc file lives. +Open this directory in your IDE. + +## Configure .bin generation + +Normally, IDEs generate .elf firmware file, cause it is easier for a debugger +to load it to a device. However, for the firmware OTA update, the .bin file +is required. The .bin file is the firmware image that gets copied to the +beginning of the microcontroller's flash memory and gets executed after the +system boot. + +So, we need to tell the IDE to generate .bin firmware flash image file. + +- If you're using CubeIDE, select Project / Properties / C/C++ build / Settings + / MCU/MPU Post build outputs, enable "Convert to binary file (-O binary)" +- If you're using VSCode, add a section to the end of the top-level `CMakeLists.txt`: +```cmake +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary + ${PROJECT_NAME}.elf + ${PROJECT_NAME}.bin +) +``` + +## Call Mongoose from main.c + +Edit `Core/Src/main.c` and update the following snippets - notice the `USER CODE BEGIN` / `USER CODE END` placeholders. At the top of the file: + +```c +/* USER CODE BEGIN Includes */ +#include "mongoose_glue.h" +/* USER CODE END Includes */ +``` + +Before the `main()` function: +```c +/* USER CODE BEGIN 0 */ +int _write(int fd, unsigned char *buf, int len) { + HAL_UART_Transmit(&huart3, buf, len, HAL_MAX_DELAY); + return len; +} + +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_GetTick()); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", HAL_GetTick()); + } + } +} + +// This blocks forever. Call it at the end of main(), or in a +// separate RTOS task. Give that task 8k stack space. +void run_mongoose(void) { + 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); + } +} +/* USER CODE END 0 */ +``` + +Inside the `main()` function: +```c +/* USER CODE BEGIN WHILE */ +run_mongoose(); // <----------------- Add this line +while (1) +{ + /* USER CODE END WHILE */ +``` + +## Build, flash, test + +Start serial console. +Use STM32CubeProgrammer to flash the firmware. diff --git a/tutorials/stm32/nucleo_h563zi/cubemx/nucleo_h563zi.ioc b/tutorials/stm32/nucleo_h563zi/cubemx/nucleo_h563zi.ioc new file mode 100644 index 00000000..89418b61 --- /dev/null +++ b/tutorials/stm32/nucleo_h563zi/cubemx/nucleo_h563zi.ioc @@ -0,0 +1,268 @@ +#MicroXplorer Configuration settings - do not modify +BOOTPATH.BootPathName=LEGACY +BOOTPATH.IPParameters=BootPathName +BOOTPATH.UserSelectedBootPath=LEGACY +CAD.formats= +CAD.pinconfig= +CAD.provider= +CORTEX_M33_NS.IPParameters=default_mode_Activation,Number-Cortex_Memory_Protection_Unit_Region0_OTP_RO_AREAS_Settings +CORTEX_M33_NS.Number-Cortex_Memory_Protection_Unit_Region0_OTP_RO_AREAS_Settings=MPU_REGION_NUMBER0 +CORTEX_M33_NS.default_mode_Activation=1 +CORTEX_M33_NS.userName=CORTEX_M33 +Cesanta.I-CUBE-Mongoose.7.21.7.IPParameters=MongooseJjNetworkingOoCore,MongooseJjWebOoDeviceOoDashboard +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjNetworkingOoCore=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjNetworkingOoCore_Checked=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjWebOoDeviceOoDashboard=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjWebOoDeviceOoDashboard_Checked=true +Cesanta.I-CUBE-Mongoose.7.21.7_SwParameter=MongooseJjNetworkingOoCore\:true;MongooseJjWebOoDeviceOoDashboard\:true; +ETH.IPParameters=MediaInterface +ETH.MediaInterface=HAL_ETH_RMII_MODE +File.Version=6 +GPIO.groupedBy= +KeepUserPlacement=false +MMTAppRegionsCount=0 +MMTConfigApplied=false +MMTSectionSuffix= +Mcu.CPN=STM32H563ZIT6 +Mcu.ContextProject=TrustZoneDisabled +Mcu.Family=STM32H5 +Mcu.IP0=BOOTPATH +Mcu.IP1=CORTEX_M33_NS +Mcu.IP10=USART3 +Mcu.IP2=ETH +Mcu.IP3=ICACHE +Mcu.IP4=MEMORYMAP +Mcu.IP5=NVIC +Mcu.IP6=PWR +Mcu.IP7=RCC +Mcu.IP8=RNG +Mcu.IP9=SYS +Mcu.IPNb=11 +Mcu.Name=STM32H563ZITx +Mcu.Package=LQFP144 +Mcu.Pin0=PF4 +Mcu.Pin1=PC1 +Mcu.Pin10=PD9 +Mcu.Pin11=PG4 +Mcu.Pin12=PG11 +Mcu.Pin13=PG13 +Mcu.Pin14=VP_CORTEX_M33_NS_VS_Hclk +Mcu.Pin15=VP_ICACHE_VS_ICACHE +Mcu.Pin16=VP_PWR_VS_SECSignals +Mcu.Pin17=VP_PWR_VS_LPOM +Mcu.Pin18=VP_RNG_VS_RNG +Mcu.Pin19=VP_SYS_VS_Systick +Mcu.Pin2=PA1 +Mcu.Pin20=VP_BOOTPATH_VS_BOOTPATH +Mcu.Pin21=VP_MEMORYMAP_VS_MEMORYMAP +Mcu.Pin22=VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7 +Mcu.Pin23=VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7 +Mcu.Pin3=PA2 +Mcu.Pin4=PA7 +Mcu.Pin5=PC4 +Mcu.Pin6=PC5 +Mcu.Pin7=PB0 +Mcu.Pin8=PB15 +Mcu.Pin9=PD8 +Mcu.PinsNb=24 +Mcu.ThirdParty0=Cesanta.I-CUBE-Mongoose.7.21.7 +Mcu.ThirdPartyNb=1 +Mcu.UserConstants= +Mcu.UserName=STM32H563ZITx +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.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 +PB15.Mode=RMII +PB15.Signal=ETH_TXD1 +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=STM32H563/H573 +PCC.MCU=STM32H563ZITx +PCC.PartNumber=STM32H563ZITx +PCC.Series=STM32H5 +PCC.Temperature=25 +PCC.Vdd=3.0 +PD8.Locked=true +PD8.Mode=Asynchronous +PD8.Signal=USART3_TX +PD9.Locked=true +PD9.Mode=Asynchronous +PD9.Signal=USART3_RX +PF4.Locked=true +PF4.Signal=GPIO_Output +PG11.Locked=true +PG11.Mode=RMII +PG11.Signal=ETH_TX_EN +PG13.Locked=true +PG13.Mode=RMII +PG13.Signal=ETH_TXD0 +PG4.Locked=true +PG4.Signal=GPIO_Output +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=STM32H563ZITx +ProjectManager.FirmwarePackage=STM32Cube FW_H5 V1.6.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= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=nucleo_h563zi.ioc +ProjectManager.ProjectName=nucleo_h563zi +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_ICACHE_Init-ICACHE-false-HAL-true,5-MX_RNG_Init-RNG-false-HAL-true,6-MX_USART3_UART_Init-USART3-false-HAL-true,0-MX_CORTEX_M33_NS_Init-CORTEX_M33_NS-false-HAL-true,0-MX_PWR_Init-PWR-false-HAL-true +RCC.ADCFreq_Value=250000000 +RCC.AHBFreq_Value=250000000 +RCC.APB1Freq_Value=250000000 +RCC.APB1TimFreq_Value=250000000 +RCC.APB2Freq_Value=250000000 +RCC.APB2TimFreq_Value=250000000 +RCC.APB3Freq_Value=250000000 +RCC.CECFreq_Value=32000 +RCC.CKPERFreq_Value=32000000 +RCC.CRSFreq_Value=48000000 +RCC.CSI_VALUE=4000000 +RCC.CortexFreq_Value=250000000 +RCC.DACFreq_Value=32768 +RCC.EPOD_VALUE=4000000 +RCC.ETHFreq_Value=250000000 +RCC.FCLKCortexFreq_Value=250000000 +RCC.FDCANFreq_Value=25000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=250000000 +RCC.HSE_VALUE=25000000 +RCC.HSI48_VALUE=48000000 +RCC.HSI_VALUE=64000000 +RCC.I2C1Freq_Value=250000000 +RCC.I2C2Freq_Value=250000000 +RCC.I2C3Freq_Value=250000000 +RCC.I2C4Freq_Value=250000000 +RCC.I3C1Freq_Value=250000000 +RCC.IPParameters=ADCFreq_Value,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,APB3Freq_Value,CECFreq_Value,CKPERFreq_Value,CRSFreq_Value,CSI_VALUE,CortexFreq_Value,DACFreq_Value,EPOD_VALUE,ETHFreq_Value,FCLKCortexFreq_Value,FDCANFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I3C1Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM3Freq_Value,LPTIM4Freq_Value,LPTIM5Freq_Value,LPTIM6Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_VALUE,LSIRC_VALUE,MCO1PinFreq_Value,MCO2PinFreq_Value,OCTOSPIMFreq_Value,PLL2FRACN,PLL2PoutputFreq_Value,PLL2QoutputFreq_Value,PLL2RoutputFreq_Value,PLL3FRACN,PLL3PoutputFreq_Value,PLL3QoutputFreq_Value,PLL3RoutputFreq_Value,PLLFRACN,PLLN,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PWRFreq_Value,RNGFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMC1Freq_Value,SDMMC2Freq_Value,SPI1Freq_Value,SPI2Freq_Value,SPI3Freq_Value,SPI4Freq_Value,SPI5Freq_Value,SPI6Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART12Freq_Value,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,UART9Freq_Value,UCPD1outputFreq_Value,USART10Freq_Value,USART11Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBFreq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOPLL2OutputFreq_Value,VCOPLL3OutputFreq_Value +RCC.LPTIM1Freq_Value=250000000 +RCC.LPTIM2Freq_Value=250000000 +RCC.LPTIM3Freq_Value=250000000 +RCC.LPTIM4Freq_Value=250000000 +RCC.LPTIM5Freq_Value=250000000 +RCC.LPTIM6Freq_Value=250000000 +RCC.LPUART1Freq_Value=250000000 +RCC.LSCOPinFreq_Value=32000 +RCC.LSE_VALUE=32768 +RCC.LSIRC_VALUE=32000 +RCC.MCO1PinFreq_Value=32000000 +RCC.MCO2PinFreq_Value=250000000 +RCC.OCTOSPIMFreq_Value=250000000 +RCC.PLL2FRACN=0 +RCC.PLL2PoutputFreq_Value=258000000 +RCC.PLL2QoutputFreq_Value=258000000 +RCC.PLL2RoutputFreq_Value=258000000 +RCC.PLL3FRACN=0 +RCC.PLL3PoutputFreq_Value=258000000 +RCC.PLL3QoutputFreq_Value=258000000 +RCC.PLL3RoutputFreq_Value=258000000 +RCC.PLLFRACN=0 +RCC.PLLN=125 +RCC.PLLPoutputFreq_Value=250000000 +RCC.PLLQoutputFreq_Value=250000000 +RCC.PWRFreq_Value=250000000 +RCC.RNGFreq_Value=48000000 +RCC.SAI1Freq_Value=258000000 +RCC.SAI2Freq_Value=258000000 +RCC.SDMMC1Freq_Value=250000000 +RCC.SDMMC2Freq_Value=250000000 +RCC.SPI1Freq_Value=250000000 +RCC.SPI2Freq_Value=250000000 +RCC.SPI3Freq_Value=250000000 +RCC.SPI4Freq_Value=250000000 +RCC.SPI5Freq_Value=250000000 +RCC.SPI6Freq_Value=250000000 +RCC.SYSCLKFreq_VALUE=250000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.UART12Freq_Value=250000000 +RCC.UART4Freq_Value=250000000 +RCC.UART5Freq_Value=250000000 +RCC.UART7Freq_Value=250000000 +RCC.UART8Freq_Value=250000000 +RCC.UART9Freq_Value=250000000 +RCC.UCPD1outputFreq_Value=8000000 +RCC.USART10Freq_Value=250000000 +RCC.USART11Freq_Value=250000000 +RCC.USART1Freq_Value=250000000 +RCC.USART2Freq_Value=250000000 +RCC.USART3Freq_Value=250000000 +RCC.USART6Freq_Value=250000000 +RCC.USBFreq_Value=48000000 +RCC.VCOInput2Freq_Value=4000000 +RCC.VCOInput3Freq_Value=4000000 +RCC.VCOInputFreq_Value=4000000 +RCC.VCOOutputFreq_Value=500000000 +RCC.VCOPLL2OutputFreq_Value=516000000 +RCC.VCOPLL3OutputFreq_Value=516000000 +USART3.IPParameters=VirtualMode-Asynchronous +USART3.VirtualMode-Asynchronous=VM_ASYNC +VP_BOOTPATH_VS_BOOTPATH.Mode=BP_Activate +VP_BOOTPATH_VS_BOOTPATH.Signal=BOOTPATH_VS_BOOTPATH +VP_CORTEX_M33_NS_VS_Hclk.Mode=Hclk_Mode +VP_CORTEX_M33_NS_VS_Hclk.Signal=CORTEX_M33_NS_VS_Hclk +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7.Mode=MongooseJjNetworkingOoCore +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7.Signal=Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7 +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7.Mode=MongooseJjWebOoDeviceOoDashboard +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7.Signal=Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7 +VP_ICACHE_VS_ICACHE.Mode=DirectMappedCache +VP_ICACHE_VS_ICACHE.Signal=ICACHE_VS_ICACHE +VP_MEMORYMAP_VS_MEMORYMAP.Mode=CurAppReg +VP_MEMORYMAP_VS_MEMORYMAP.Signal=MEMORYMAP_VS_MEMORYMAP +VP_PWR_VS_LPOM.Mode=PowerOptimisation +VP_PWR_VS_LPOM.Signal=PWR_VS_LPOM +VP_PWR_VS_SECSignals.Mode=Security/Privilege +VP_PWR_VS_SECSignals.Signal=PWR_VS_SECSignals +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_h563zi/minimal/Makefile b/tutorials/stm32/nucleo_h563zi/minimal/Makefile new file mode 100644 index 00000000..7b0c37f9 --- /dev/null +++ b/tutorials/stm32/nucleo_h563zi/minimal/Makefile @@ -0,0 +1,47 @@ +# 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_h5/Include +CFLAGS += -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard $(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_h5/Source/Templates/gcc/startup_stm32h563xx.s + +TOP = ../../../.. +CFLAGS += -I$(TOP) +SOURCES += $(TOP)/mongoose.c + +all: firmware.bin + +firmware.elf: cmsis_core cmsis_h5 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 mode=UR -w firmware.elf -hardRst + +gdb: firmware.elf + arm-none-eabi-gdb -q $^ -ex='set confirm off' -ex 'target remote :61234' + +# Directory where STM32_Programmer_CLI binary lives +CUBEPROG_DIR ?= $(dir $(shell which STM32_Programmer_CLI)) +gdb_server: + ST-LINK_gdbserver --port-number 61234 --log-level 1 --swd --verify --stm32cubeprogrammer-path $(CUBEPROG_DIR) --apid 1 --initialize-reset + + +cmsis_core: + git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@ + +cmsis_h5: + git clone -q -c advice.detachedHead=false --depth 1 -b v1.6.0 https://github.com/STMicroelectronics/cmsis-device-h5 $@ + +clean: + rm -rf firmware.* diff --git a/tutorials/stm32/nucleo_h563zi/minimal/hal.c b/tutorials/stm32/nucleo_h563zi/minimal/hal.c new file mode 100644 index 00000000..e519bff3 --- /dev/null +++ b/tutorials/stm32/nucleo_h563zi/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 = 160000000; +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_h563zi/minimal/hal.h b/tutorials/stm32/nucleo_h563zi/minimal/hal.h new file mode 100644 index 00000000..d66a7620 --- /dev/null +++ b/tutorials/stm32/nucleo_h563zi/minimal/hal.h @@ -0,0 +1,212 @@ +// Copyright (c) 2022-2026 Cesanta Software Limited +// All rights reserved +// +// Datasheet: RM0481, devboard manual: UM3115 +// https://www.st.com/resource/en/reference_manual/rm0481-stm32h563h573-and-stm32h562-armbased-32bit-mcus-stmicroelectronics.pdf +// Alternate functions: https://www.st.com/resource/en/datasheet/stm32h563vi.pdf + +#pragma once + +#include + +#include +#include +#include +#include +#include + +void hal_init(void); +size_t hal_ram_free(void); +size_t hal_ram_used(void); +bool hal_timer_expired(volatile uint64_t *t, uint64_t prd, uint64_t now); +uint64_t hal_get_tick(void); + +#define BIT(x) (1UL << (x)) +#define CLRSET(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK) +#define PIN(bank, num) ((((bank) - 'A') << 8) | (num)) +#define PINNO(pin) (pin & 255) +#define PINBANK(pin) (pin >> 8) + +#define HAL_ETH_PINS \ + PIN('A', 1), /* ETH_REF_CLK */ \ + PIN('A', 2), /* ETH_MDIO */ \ + PIN('A', 7), /* ETH_CRS_DV */ \ + PIN('B', 15), /* 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 */ + +// System clock (11.4, Figure 48; 11.4.5, Figure 51; 11.4.8 +// SYS_FREQUENCY <= 250 MHz; (CLOCK_FREQUENCY / HPRE) ; hclk = SYS_FREQUENCY +// APB clocks <= 250 MHz. Configure flash latency (WS) in accordance to hclk +// freq (7.3.4, Table 37) +enum { + HAL_HPRE = 7, // register value, divisor value = BIT(value - 7) = / 1 + HAL_PPRE1 = 4, // register values, divisor value = BIT(value - 3) = / 2 + HAL_PPRE2 = 4, + HAL_PPRE3 = 4, +}; +// Make sure your chip package uses the internal LDO, otherwise set PLL1_N = 200 +enum { PLL1_HSI = 64, PLL1_M = 32, PLL1_N = 250, PLL1_P = 2 }; +#define SYS_FREQUENCY \ + ((PLL1_HSI * PLL1_N / PLL1_M / PLL1_P / (BIT(HAL_HPRE - 7))) * 1000000) +#define AHB_FREQUENCY SYS_FREQUENCY +#define APB2_FREQUENCY (AHB_FREQUENCY / (BIT(HAL_PPRE2 - 3))) +#define APB1_FREQUENCY (AHB_FREQUENCY / (BIT(HAL_PPRE1 - 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 *) ((GPIOA_BASE_NS) + 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->AHB2ENR |= 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 bool hal_uart_init(USART_TypeDef *uart, uint16_t tx_pin, + uint16_t rx_pin, unsigned long baud) { + uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1 + + if (uart == USART1) { + freq = APB2_FREQUENCY, RCC->APB2ENR |= RCC_APB2ENR_USART1EN; + } else if (uart == USART2) { + freq = APB1_FREQUENCY, RCC->APB1LENR |= RCC_APB1LENR_USART2EN; + } else if (uart == USART3) { + freq = APB1_FREQUENCY, RCC->APB1LENR |= RCC_APB1LENR_USART3EN; + } else { + return false; + } + hal_gpio_init(tx_pin, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, 7U); + hal_gpio_init(rx_pin, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, 7U); + uart->CR1 = 0; // Disable UART + uart->BRR = freq / baud; // Set baud rate + uart->CR1 = USART_CR1_RE | USART_CR1_TE; // Set mode to TX & RX + uart->CR1 |= USART_CR1_UE; // Enable UART + return true; +} +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->CCIPR5 |= RCC_CCIPR5_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) spin(1); + return RNG->DR; +} + +static inline bool hal_ldo_is_on(void) { + return (PWR->SCCR & PWR_SCCR_LDOEN) == PWR_SCCR_LDOEN; +} + +// 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 UM3115 section 10.7 + 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 + RCC->APB3ENR |= RCC_APB3ENR_SBSEN; // Enable SBS clock + CLRSET(SBS->PMCR, SBS_PMCR_ETH_SEL_PHY, SBS_PMCR_ETH_SEL_PHY_2); // RMII + RCC->AHB1ENR |= RCC_AHB1ENR_ETHEN | RCC_AHB1ENR_ETHRXEN | RCC_AHB1ENR_ETHTXEN; +} + +#define UUID ((uint32_t *) UID_BASE) // Unique 96-bit chip ID. TRM 59.1 + +// Helper macro for MAC generation, byte reads not allowed +#define GENERATE_LOCALLY_ADMINISTERED_MAC() \ + { \ + 2, UUID[0] & 255, (UUID[0] >> 10) & 255, (UUID[0] >> 19) & 255, \ + UUID[1] & 255, UUID[2] & 255 \ + } + +static inline void hal_system_init(void) { + SCB->CPACR |= ((3UL << 20U) | (3UL << 22U)); // Enable FPU + __DSB(); + __ISB(); +} + +static inline void hal_clock_init(void) { + // Set flash latency. RM0481, section 7.11.1, section 7.3.4 table 37 + CLRSET(FLASH->ACR, (FLASH_ACR_WRHIGHFREQ_Msk | FLASH_ACR_LATENCY_Msk), + FLASH_ACR_LATENCY_5WS | FLASH_ACR_WRHIGHFREQ_1); + + if (hal_ldo_is_on()) { + PWR->VOSCR = PWR_VOSCR_VOS_0 | PWR_VOSCR_VOS_1; // Select VOS0 + } else { + PWR->VOSCR = PWR_VOSCR_VOS_1; // Select VOS1 + } + uint32_t f = PWR->VOSCR; // fake read to wait for bus clocking + while ((PWR->VOSSR & PWR_VOSSR_ACTVOSRDY) == 0) spin(1); + (void) f; + RCC->CR = RCC_CR_HSION; // Clear HSI clock divisor + while ((RCC->CR & RCC_CR_HSIRDY) == 0) spin(1); // Wait until done + RCC->CFGR2 = (HAL_PPRE3 << 12) | (HAL_PPRE2 << 8) | (HAL_PPRE1 << 4) | (HAL_HPRE << 0); + RCC->PLL1DIVR = + ((PLL1_P - 1) << 9) | ((PLL1_N - 1) << 0); // Set PLL1_P PLL1_N + // Enable P and Q divider outputs; set PLL1_M, select HSI as source, + // !PLL1VCOSEL, PLL1RGE=0 + RCC->PLL1CFGR = + RCC_PLL1CFGR_PLL1QEN | RCC_PLL1CFGR_PLL1PEN | (PLL1_M << 8) | (1 << 0); + RCC->CR |= RCC_CR_PLL1ON; // Enable PLL1 + while ((RCC->CR & RCC_CR_PLL1RDY) == 0) spin(1); // Wait until done + RCC->CFGR1 |= (3 << 0); // Set clock source to PLL1 + while ((RCC->CFGR1 & (7 << 3)) != (3 << 3)) spin(1); // Wait until done + + SystemCoreClock = SYS_FREQUENCY; +} diff --git a/tutorials/stm32/nucleo_h563zi/minimal/link.ld b/tutorials/stm32/nucleo_h563zi/minimal/link.ld new file mode 100644 index 00000000..fac73050 --- /dev/null +++ b/tutorials/stm32/nucleo_h563zi/minimal/link.ld @@ -0,0 +1,31 @@ +ENTRY(Reset_Handler); +MEMORY { + flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k + sram(rwx) : ORIGIN = 0x20000000, LENGTH = 640k +} +_estack = ORIGIN(sram) + LENGTH(sram); /* End of RAM. stack points here */ +_sstack = _estack - 4098; + +SECTIONS { + .vectors : { KEEP(*(.isr_vector)) } > flash + .text : { *(.text* .text.*) } > flash + .rodata : { *(.rodata*) } > flash + + .data : { + _sdata = .; + *(.first_data) + *(.ram) + *(.data SORT(.data.*)) + _edata = .; + } > sram AT > flash + _sidata = LOADADDR(.data); + + .bss : { + _sbss = .; + *(.bss SORT(.bss.*) COMMON) + _ebss = .; + } > sram + + . = ALIGN(8); + _end = .; +} diff --git a/tutorials/stm32/nucleo_h563zi/minimal/main.c b/tutorials/stm32/nucleo_h563zi/minimal/main.c new file mode 100644 index 00000000..a64d0205 --- /dev/null +++ b/tutorials/stm32/nucleo_h563zi/minimal/main.c @@ -0,0 +1,71 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "hal.h" +#include "mongoose.h" + +#define DEBUG_UART USART3 +#define DEBUG_UART_TX_PIN PIN('D', 8) +#define DEBUG_UART_RX_PIN PIN('D', 9) + +#define LED_1 PIN('B', 0) // On-board LED pin (green) +#define LED_2 PIN('F', 4) // On-board LED pin (yellow) +#define LED_3 PIN('G', 4) // 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(LED_1); + } +} + +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_uart_init(DEBUG_UART, DEBUG_UART_TX_PIN, DEBUG_UART_RX_PIN, 115200); + hal_rng_init(); + hal_gpio_output(LED_1); + hal_gpio_output(LED_2); + hal_gpio_output(LED_3); + + 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_h563zi/minimal/mongoose_config.h b/tutorials/stm32/nucleo_h563zi/minimal/mongoose_config.h new file mode 100644 index 00000000..dc0ca30b --- /dev/null +++ b/tutorials/stm32/nucleo_h563zi/minimal/mongoose_config.h @@ -0,0 +1,44 @@ +#pragma once + +// See https://mongoose.ws/documentation/#build-options +#define MG_ARCH MG_ARCH_ARMGCC +#define MG_OTA MG_OTA_STM32H5 +#define MG_TLS MG_TLS_BUILTIN +#define MG_IO_SIZE 2048 + +#define MG_ENABLE_TCPIP 1 +#define MG_ENABLE_CUSTOM_MILLIS 1 +#define MG_ENABLE_CUSTOM_RANDOM 1 +#define MG_ENABLE_PACKED_FS 1 +#define MG_ENABLE_DRIVER_STM32H 1 + +// #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 *) 0x08fff800) // 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_h723zg/cubemx/README.md b/tutorials/stm32/nucleo_h723zg/cubemx/README.md new file mode 100644 index 00000000..adce66c2 --- /dev/null +++ b/tutorials/stm32/nucleo_h723zg/cubemx/README.md @@ -0,0 +1,105 @@ +# Mongoose CubeMX integration + +This is a step-by-step guide on how to bring up a production-grade Web UI +dashboard on STM32 Nucleo-H723ZG development board. + +A pre-configured project .zip is available for download at https://mongoose.ws. +However for those who want to configure the project from scratch, follow the steps +below. + + +## Generate project code +- Open the .ioc file in your CubeMX +- Click on "Project Manager" + - If you're using CubeIDE, select "CubeIDE" in the toolchain/IDE dropdown + - If you're using VSCode, select "Cmake" in the toolchain/IDE dropdown + - If you're using Makefile, select "Makefile" in the toolchain/IDE dropdown +- Click "Generate Code" button on the top right + +This should generate project code in this directory the directory where .ioc file lives. +Open this directory in your IDE. + +## Configure .bin generation + +Normally, IDEs generate .elf firmware file, cause it is easier for a debugger +to load it to a device. However, for the firmware OTA update, the .bin file +is required. The .bin file is the firmware image that gets copied to the +beginning of the microcontroller's flash memory and gets executed after the +system boot. + +So, we need to tell the IDE to generate .bin firmware flash image file. + +- If you're using CubeIDE, select Project / Properties / C/C++ build / Settings + / MCU/MPU Post build outputs, enable "Convert to binary file (-O binary)" +- If you're using VSCode, add a section to the end of the top-level `CMakeLists.txt`: +```cmake +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary + ${PROJECT_NAME}.elf + ${PROJECT_NAME}.bin +) +``` + +## Call Mongoose from main.c + +Edit `Core/Src/main.c` and update the following snippets - notice the `USER CODE BEGIN` / `USER CODE END` placeholders. At the top of the file: + +```c +/* USER CODE BEGIN Includes */ +#include "mongoose_glue.h" +/* USER CODE END Includes */ +``` +Before the `main()` function: +```c +/* USER CODE BEGIN 0 */ +int _write(int fd, unsigned char *buf, int len) { + HAL_UART_Transmit(&huart3, buf, len, HAL_MAX_DELAY); + return len; +} + +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_GetTick()); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", HAL_GetTick()); + } + } +} + +// This blocks forever. Call it at the end of main(), or in a +// separate RTOS task. Give that task 8k stack space. +void run_mongoose(void) { + 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); + } +} +/* USER CODE END 0 */ +``` + +Inside the `main()` function: +```c +/* USER CODE BEGIN WHILE */ +run_mongoose(); // <----------------- Add this line +while (1) +{ + /* USER CODE END WHILE */ +``` + + +## Edit linker script + +Edit `STM32H723XG_FLASH.ld`, add the following line before the `.bss (NOLOAD)` line: +```text +.eth_ram : { *(.eth_ram .eth_ram*) } > RAM_D2 AT > FLASH +``` + +## Build, flash, test + +Start serial console. +Use STM32CubeProgrammer to flash the firmware. diff --git a/tutorials/stm32/nucleo_h723zg/cubemx/nucleo_h723zg.ioc b/tutorials/stm32/nucleo_h723zg/cubemx/nucleo_h723zg.ioc new file mode 100644 index 00000000..cbeee74c --- /dev/null +++ b/tutorials/stm32/nucleo_h723zg/cubemx/nucleo_h723zg.ioc @@ -0,0 +1,225 @@ +#MicroXplorer Configuration settings - do not modify +CAD.formats= +CAD.pinconfig= +CAD.provider= +CORTEX_M7.IPParameters=default_mode_Activation +CORTEX_M7.default_mode_Activation=1 +Cesanta.I-CUBE-Mongoose.7.21.7.IPParameters=MongooseJjNetworkingOoCore,MongooseJjWebOoDeviceOoDashboard +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjNetworkingOoCore=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjNetworkingOoCore_Checked=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjWebOoDeviceOoDashboard=true +Cesanta.I-CUBE-Mongoose.7.21.7.MongooseJjWebOoDeviceOoDashboard_Checked=true +Cesanta.I-CUBE-Mongoose.7.21.7_SwParameter=MongooseJjNetworkingOoCore\:true;MongooseJjWebOoDeviceOoDashboard\:true;MongooseJjMQTTOoClient\:true; +ETH.IPParameters=MediaInterface +ETH.MediaInterface=HAL_ETH_RMII_MODE +File.Version=6 +GPIO.groupedBy= +KeepUserPlacement=false +MMTAppRegionsCount=0 +MMTConfigApplied=false +MMTSectionSuffix= +Mcu.CPN=STM32H723ZGT6 +Mcu.Family=STM32H7 +Mcu.IP0=CORTEX_M7 +Mcu.IP1=ETH +Mcu.IP2=MEMORYMAP +Mcu.IP3=NVIC +Mcu.IP4=RCC +Mcu.IP5=RNG +Mcu.IP6=SYS +Mcu.IP7=USART3 +Mcu.IPNb=8 +Mcu.Name=STM32H723ZGTx +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.Pin16=VP_MEMORYMAP_VS_MEMORYMAP +Mcu.Pin17=VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7 +Mcu.Pin18=VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7 +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=19 +Mcu.ThirdParty0=Cesanta.I-CUBE-Mongoose.7.21.7 +Mcu.ThirdPartyNb=1 +Mcu.UserConstants= +Mcu.UserName=STM32H723ZGTx +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.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=STM32H723ZGTx +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= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=h723.ioc +ProjectManager.ProjectName=h723 +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=275000000 +RCC.AHB4Freq_Value=275000000 +RCC.APB1Freq_Value=137500000 +RCC.APB2Freq_Value=137500000 +RCC.APB3Freq_Value=137500000 +RCC.APB4Freq_Value=137500000 +RCC.AXIClockFreq_Value=275000000 +RCC.CECFreq_Value=32000 +RCC.CKPERFreq_Value=64000000 +RCC.CortexFreq_Value=550000000 +RCC.CpuClockFreq_Value=550000000 +RCC.D1CPREFreq_Value=550000000 +RCC.D1PPRE=RCC_APB3_DIV2 +RCC.D2PPRE1=RCC_APB1_DIV2 +RCC.D2PPRE2=RCC_APB2_DIV2 +RCC.D3PPRE=RCC_APB4_DIV2 +RCC.DFSDMACLkFreq_Value=275000000 +RCC.DFSDMFreq_Value=137500000 +RCC.DIVM1=4 +RCC.DIVN1=34 +RCC.DIVP1=1 +RCC.DIVP1Freq_Value=550000000 +RCC.DIVP2Freq_Value=129000000 +RCC.DIVP3Freq_Value=129000000 +RCC.DIVQ1Freq_Value=275000000 +RCC.DIVQ2Freq_Value=129000000 +RCC.DIVQ3Freq_Value=129000000 +RCC.DIVR1Freq_Value=275000000 +RCC.DIVR2Freq_Value=129000000 +RCC.DIVR3Freq_Value=129000000 +RCC.FDCANFreq_Value=275000000 +RCC.FMCFreq_Value=275000000 +RCC.FamilyName=M +RCC.HCLK3ClockFreq_Value=275000000 +RCC.HCLKFreq_Value=275000000 +RCC.HPRE=RCC_HCLK_DIV2 +RCC.I2C123Freq_Value=137500000 +RCC.I2C4Freq_Value=137500000 +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,DIVP1,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,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,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=137500000 +RCC.LPTIM2Freq_Value=137500000 +RCC.LPTIM345Freq_Value=137500000 +RCC.LPUART1Freq_Value=137500000 +RCC.LTDCFreq_Value=129000000 +RCC.MCO1PinFreq_Value=64000000 +RCC.MCO2PinFreq_Value=550000000 +RCC.PLL2FRACN=0 +RCC.PLL3FRACN=0 +RCC.PLLFRACN=3072 +RCC.QSPIFreq_Value=275000000 +RCC.RNGFreq_Value=48000000 +RCC.RTCFreq_Value=32000 +RCC.SAI1Freq_Value=275000000 +RCC.SAI4AFreq_Value=275000000 +RCC.SAI4BFreq_Value=275000000 +RCC.SDMMCFreq_Value=275000000 +RCC.SPDIFRXFreq_Value=275000000 +RCC.SPI123Freq_Value=275000000 +RCC.SPI45Freq_Value=137500000 +RCC.SPI6Freq_Value=137500000 +RCC.SWPMI1Freq_Value=137500000 +RCC.SYSCLKFreq_VALUE=550000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.Tim1OutputFreq_Value=275000000 +RCC.Tim2OutputFreq_Value=275000000 +RCC.TraceFreq_Value=64000000 +RCC.USART16Freq_Value=137500000 +RCC.USART234578Freq_Value=137500000 +RCC.USBFreq_Value=275000000 +RCC.VCO1OutputFreq_Value=550000000 +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_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7.Mode=MongooseJjNetworkingOoCore +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7.Signal=Cesanta.I-CUBE-Mongoose_VS_MongooseJjNetworkingOoCore_7.21.7_7.21.7 +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7.Mode=MongooseJjWebOoDeviceOoDashboard +VP_Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7.Signal=Cesanta.I-CUBE-Mongoose_VS_MongooseJjWebOoDeviceOoDashboard_7.21.7_7.21.7 +VP_MEMORYMAP_VS_MEMORYMAP.Mode=CurAppReg +VP_MEMORYMAP_VS_MEMORYMAP.Signal=MEMORYMAP_VS_MEMORYMAP +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_h723zg/minimal/Makefile b/tutorials/stm32/nucleo_h723zg/minimal/Makefile new file mode 100644 index 00000000..9ed5f162 --- /dev/null +++ b/tutorials/stm32/nucleo_h723zg/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_stm32h723xx.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.6 https://github.com/STMicroelectronics/cmsis_device_h7 $@ + +clean: + rm -rf firmware.* diff --git a/tutorials/stm32/nucleo_h723zg/minimal/hal.c b/tutorials/stm32/nucleo_h723zg/minimal/hal.c new file mode 100644 index 00000000..e519bff3 --- /dev/null +++ b/tutorials/stm32/nucleo_h723zg/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 = 160000000; +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_h723zg/minimal/hal.h b/tutorials/stm32/nucleo_h723zg/minimal/hal.h new file mode 100644 index 00000000..19667f52 --- /dev/null +++ b/tutorials/stm32/nucleo_h723zg/minimal/hal.h @@ -0,0 +1,223 @@ +// Copyright (c) 2022-2026 Cesanta Software Limited +// Datasheet: RM0468, devboard manual: UM2407 +// https://www.st.com/resource/en/reference_manual/rm0468-stm32h723733-stm32h725735-and-stm32h730-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf +// https://www.st.com/resource/en/user_manual/um2407-stm32h7-nucleo144-boards-mb1364-stmicroelectronics.pdf +// Alternate functions: https://www.st.com/resource/en/datasheet/stm32h723.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 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) + +#define HAL_ETH_PINS PIN('A', 1), PIN('A', 2), PIN('A', 7), \ + PIN('B', 13), PIN('C', 1), PIN('C', 4), \ + PIN('C', 5), PIN('G', 11), PIN('G', 13) + +// System clock (2.1, Figure 1; 8.5, Figure 45; 8.5.5, Figure 47; 8.5.6, Figure +// 49; 8.5.8 Table 56; datasheet) CPU_FREQUENCY <= 550 MHz; hclk = CPU_FREQUENCY +// / HAL_HPRE ; hclk <= 275 MHz; APB clocks <= 137.5 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 16) 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.12) (except for '1') +enum { PLL1_HSI = 64, PLL1_M = 32, PLL1_N = 225, PLL1_P = 1 }; +#define HAL_FLASH_LATENCY 0x33 // WRHIGHFREQ LATENCY +#define SYS_FREQUENCY ((PLL1_HSI * PLL1_N / PLL1_M / PLL1_P / 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 hal_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) hal_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); +} + +// RNG clock (rng_clk) defaults to HSI48 and is characterized at this frequency. +// Enable at SystemInit. (STM32CubeMX) It won't work with a 275MHz (AHB) +static inline void hal_rng_init(void) { + RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; // Enable RNG AHB clock (hal_rng_hclk) + // 39.6.2 Table 320 init + RNG->CR = RNG_CR_CONDRST | (0x0F << RNG_CR_RNG_CONFIG1_Pos) | + (0 << RNG_CR_RNG_CONFIG2_Pos) | (0xD << RNG_CR_RNG_CONFIG3_Pos); + RNG->HTCR = 0x17590abc; + RNG->HTCR = 0xaa74; + RNG->CR &= ~RNG_CR_CONDRST ; + while(RNG->CR & RNG_CR_CONDRST) hal_spin(1); // 39.7.1 + 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 + } + NVIC_EnableIRQ(ETH_IRQn); // Setup Ethernet IRQ handler + CLRSET(SYSCFG->PMCR, 7 << 21, 4 << 21); // Use RMII (12.3.1) + RCC->AHB1ENR |= BIT(15) | BIT(16) | BIT(17); // Enable Ethernet clocks +} + +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) hal_spin(1); // ACTVOSRDY + PWR->D3CR &= ~(BIT(15) | BIT(14)); // Select VOS0 + while ((PWR->D3CR & BIT(13)) == 0) hal_spin(1); // VOSRDY + 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) | BIT(12); // Enable PLL1 and HSI48 (for RNG) + while ((RCC->CR & BIT(25)) == 0) hal_spin(1); // Wait until done + RCC->CFGR |= (3 << 0); // Set clock source to PLL1 + while ((RCC->CFGR & (7 << 3)) != (3 << 3)) hal_spin(1); // Wait until done + FLASH->ACR = HAL_FLASH_LATENCY; // default is larger + RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN; // Enable SYSCFG + while ((RCC->CR & BIT(13)) == 0) hal_spin(1); // Make sure HSI48 is ready + SystemCoreClock = SYS_FREQUENCY; // Update SystemCoreClock global var + SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms +} + +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_h723zg/minimal/link.ld b/tutorials/stm32/nucleo_h723zg/minimal/link.ld new file mode 100644 index 00000000..a62749dc --- /dev/null +++ b/tutorials/stm32/nucleo_h723zg/minimal/link.ld @@ -0,0 +1,28 @@ +ENTRY(Reset_Handler); +MEMORY { + flash(rx) : ORIGIN = 0x08000000, LENGTH = 1024k + + dtcmram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + ram_d1 (rwx) : ORIGIN = 0x24000000, LENGTH = 320K + ram_d2 (rwx) : ORIGIN = 0x30000000, LENGTH = 32K + ram_d3 (rwx) : ORIGIN = 0x38000000, LENGTH = 16K + itcmram (rwx) : ORIGIN = 0x00000000, LENGTH = 64K +} +_estack = ORIGIN(ram_d1) + LENGTH(ram_d1); + +SECTIONS { + .vectors : { KEEP(*(.isr_vector)) } > flash + .text : { *(.text* .text.*) } > flash + .rodata : { *(.rodata*) } > flash + + /* Note the .iram section, for functions copied to RAM. Required for MG_IRAM OTA support */ + .data : { _sdata = .; *(.first_data) *(.iram .iram* .iram.*) *(.data SORT(.data.*)) _edata = .; } > ram_d1 AT > flash + _sidata = LOADADDR(.data); + + .bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > ram_d1 + + .eth_ram : { *(.eth_ram .eth_ram*) } > ram_d1 AT > flash + + . = ALIGN(8); + _end = .; +} diff --git a/tutorials/stm32/nucleo_h723zg/minimal/main.c b/tutorials/stm32/nucleo_h723zg/minimal/main.c new file mode 100644 index 00000000..38f16d68 --- /dev/null +++ b/tutorials/stm32/nucleo_h723zg/minimal/main.c @@ -0,0 +1,70 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "hal.h" +#include "mongoose.h" + +#define DEBUG_UART USART3 +#define LED1 PIN('B', 0) +#define LED2 PIN('E', 1) +#define LED3 PIN('B', 14) + +// Redirect stdout debug output to UART +int _write(int fd, char *ptr, int len) { + if (fd == 1) 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_uart_init(DEBUG_UART, 115200); + hal_rng_init(); + hal_ethernet_init(); + hal_gpio_output(LED1); + hal_gpio_output(LED2); + hal_gpio_output(LED3); + + printf("Initialised. CPU clock: %lu MHz\r\n", SystemCoreClock / 1000000); + + // 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_h723zg/minimal/mongoose_config.h b/tutorials/stm32/nucleo_h723zg/minimal/mongoose_config.h new file mode 100644 index 00000000..a9513324 --- /dev/null +++ b/tutorials/stm32/nucleo_h723zg/minimal/mongoose_config.h @@ -0,0 +1,35 @@ +#pragma once + +// See https://mongoose.ws/docs/getting-started/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_ENABLE_PACKED_FS 1 +#define MG_ETH_RAM __attribute__((section(".eth_ram"))) + +// #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 + +// Construct MAC address from the MCU unique ID +#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/nucleo_n657x0_q/cubemx/README.md b/tutorials/stm32/nucleo_n657x0_q/cubemx/README.md new file mode 100644 index 00000000..14cf1253 --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/cubemx/README.md @@ -0,0 +1,122 @@ +# Mongoose CubeMX integration + +This is a step-by-step guide on how to bring up a production-grade Web UI +dashboard on STM32 Nucleo-N657X0-Q development board. + +A pre-configured project .zip is available for download at https://mongoose.ws. +However for those who want to configure the project from scratch, follow the steps +below. + +## Generate .ioc file + +This directory already has a pre-configured `.ioc` file so you can just open it +in your CubeMX and skip this step. However for those who want to create the +project from scratch, here are the steps: + +- Open CubeMX, File / New project, type "STM32N657X0H3Q" in the part number, select + it from the list, click "Start project" on the top right, choose "Secure domain only" +- Project Manager: Project name: "n657". Project location: path to this directory. + Project strucure: "FSBL" only. Toolchain/IDE: pick ether Cmake or CubeIDE. +- Clock configuration: Find SYSB, enter 400 MHz, Resolve clock issues +- MCU pinout view: set PG0, PG8, PG10 to GPIO_Output mode +- Pinout & Configuration / System Core: click on "GPIO", then click on each + of the PG0, PG8, PG10 pins and select Pin Context Assignment / First Stage Boot Loader +- Pinout & Configuration / Security: Enable RIF and RNG for FSBL, click on RNG, check Activate +- Pinout & Configuration / Connectivity: enable USART1 for FSBL, mode asynchronous, + configure pins PE5 and PE6 for USART1 function +- Pinout & Configuration / Connectivity: enable ETH1 for FSBL, mode RMII, + pins PF4, PF5, PF7, PF10, PF11, PF12, PF13, PF14, PF15, PG11 for Ethernet function +- RIF: + - Peripherals (RISUP), enable "Privilege" on ETH1 + - Domains (RIMU): for ETH1, enable SECURE and PRIVILEGE +- Clock configuration: resolve clocks if required. Find "To ETH1" and make sure it has 100 MHz + +## Generate project code +- Clone this repo to your workstation. Open the .ioc file in your CubeMX +- Click on "Project Manager" + - If you're using CubeIDE, select "CubeIDE" in the toolchain/IDE dropdown + - If you're using VSCode, select "Cmake" in the toolchain/IDE dropdown + - If you're using Makefile, select "Makefile" in the toolchain/IDE dropdown +- Click "Generate Code" button on the top right + +## Configure .bin generation + +Normally, IDEs generate .elf firmware file, cause it is easier for a debugger +to load it to a device. However, for the firmware OTA update, the .bin file +is required. The .bin file is the firmware image that gets copied to the +beginning of the microcontroller's flash memory and gets executed after the +system boot. + +So, we need to tell the IDE to generate .bin firmware flash image file. + +- If you're using CubeIDE, select Project / Properties / C/C++ build / Settings + / MCU/MPU Post build outputs, enable "Convert to binary file (-O binary)" +- If you're using VSCode, add a section to the end of the top-level `CMakeLists.txt`: +```cmake +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary + ${PROJECT_NAME}.elf + ${PROJECT_NAME}.bin +) +``` + +## Call Mongoose from main.c + +Edit `Core/Src/main.c` and update the following snippets - notice the `USER CODE BEGIN` / `USER CODE END` placeholders. At the top of the file: + +```c +/* USER CODE BEGIN Includes */ +#include "mongoose_glue.h" +/* USER CODE END Includes */ +``` + +Before the `main()` function: +```c +/* USER CODE BEGIN 0 */ +int _write(int fd, unsigned char *buf, int len) { + HAL_UART_Transmit(&huart1, buf, len, HAL_MAX_DELAY); + return len; +} + +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_GetTick()); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", HAL_GetTick()); + } + } +} + +// This blocks forever. Call it at the end of main(), or in a +// separate RTOS task. Give that task 8k stack space. +void run_mongoose(void) { + 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); + } +} +/* USER CODE END 0 */ +``` + +Inside the `main()` function: +```c +/* USER CODE BEGIN WHILE */ +HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, 1); +HAL_GPIO_WritePin(GPIOG, GPIO_PIN_8, 1); +HAL_GPIO_WritePin(GPIOG, GPIO_PIN_10, 1); +run_mongoose(); +while (1) +{ + /* USER CODE END WHILE */ +``` + +## Build, flash, test + +Start serial console. +Use STM32CubeProgrammer to flash the firmware. Don't forget to specify +the `MX25UM51245G_STM32N6570-NUCLEO.stldr` external loader for this board. diff --git a/tutorials/stm32/nucleo_n657x0_q/cubemx/nucleo_n657x0_q.ioc b/tutorials/stm32/nucleo_n657x0_q/cubemx/nucleo_n657x0_q.ioc new file mode 100644 index 00000000..dfc17da2 --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/cubemx/nucleo_n657x0_q.ioc @@ -0,0 +1,880 @@ +#MicroXplorer Configuration settings - do not modify +Appli.IPs=CORTEX_M55_S,GPDMA1,HPDMA1,LINKEDLIST,RCC,SAU,GPIO,NVIC1\:I +CAD.formats= +CAD.pinconfig= +CAD.provider= +ETH1.IPParameters=MediaInterface +ETH1.MediaInterface=HAL_ETH_RMII_MODE +ExtMemLoader.IPs=EXTMEM_LOADER,EXTMEM_MANAGER,RCC\:I,GPIO +FSBL.IPs=CORTEX_M55_FSBL,GPDMA1\:I,HDP,HPDMA1\:I,LINKEDLIST,RCC,GPIO\:I,NVIC\:I,RIF,RNG,USART1,ETH1 +FSBL.Pins=PG0,PG10,PG8 +File.Version=6 +GPIO.groupedBy= +KeepUserPlacement=false +Mcu.CPN=STM32N657X0H3Q +Mcu.Context0=FSBL +Mcu.Context1=Appli +Mcu.Context2=ExtMemLoader +Mcu.ContextNb=3 +Mcu.ContextProject=FullSecure +Mcu.Family=STM32N6 +Mcu.IP0=CORTEX_M55_FSBL +Mcu.IP1=CORTEX_M55_S +Mcu.IP2=ETH1 +Mcu.IP3=NVIC1 +Mcu.IP4=NVIC +Mcu.IP5=RCC +Mcu.IP6=RIF +Mcu.IP7=RNG +Mcu.IP8=USART1 +Mcu.IPNb=9 +Mcu.Name=STM32N657X0HxQ +Mcu.Package=VFBGA264 +Mcu.Pin0=PE5 +Mcu.Pin1=PE6 +Mcu.Pin10=PG0 +Mcu.Pin11=PF12 +Mcu.Pin12=PG10 +Mcu.Pin13=PG8 +Mcu.Pin14=PG11 +Mcu.Pin15=VP_RIF_VS_RIF1 +Mcu.Pin16=VP_RNG_VS_RNG +Mcu.Pin2=PF4 +Mcu.Pin3=PF10 +Mcu.Pin4=PF7 +Mcu.Pin5=PF5 +Mcu.Pin6=PF15 +Mcu.Pin7=PF14 +Mcu.Pin8=PF11 +Mcu.Pin9=PF13 +Mcu.PinsNb=17 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32N657X0HxQ +MxCube.Version=6.17.0 +MxDb.Version=DB.6.0.170 +NVIC.BFHFNMINS=0 +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.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.PRIS=0 +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.SecureFault_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 +NVIC1.BFHFNMINS=0 +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.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.PRIS=0 +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.SecureFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC1.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false +NVIC1.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PCC.Checker=false +PCC.Display=Plot\: All Steps +PCC.Line=STM32N6x7 +PCC.MCU=STM32N657X0HxQ +PCC.PartNumber=STM32N657X0HxQ +PCC.Series=STM32N6 +PCC.Temperature=25 +PCC.Vdd=1.8 +PE5.GPIOParameters=PinAttribute +PE5.Locked=true +PE5.Mode=Asynchronous +PE5.PinAttribute=FSBL +PE5.Signal=USART1_TX +PE6.GPIOParameters=PinAttribute +PE6.Mode=Asynchronous +PE6.PinAttribute=FSBL +PE6.Signal=USART1_RX +PF10.GPIOParameters=PinAttribute +PF10.Mode=RMII +PF10.PinAttribute=FSBL +PF10.Signal=ETH1_RMII_CRS_DV +PF11.GPIOParameters=PinAttribute +PF11.Mode=RMII +PF11.PinAttribute=FSBL +PF11.Signal=ETH1_RMII_TX_EN +PF12.GPIOParameters=PinAttribute +PF12.Mode=RMII +PF12.PinAttribute=FSBL +PF12.Signal=ETH1_RMII_TXD0 +PF13.GPIOParameters=PinAttribute +PF13.Mode=RMII +PF13.PinAttribute=FSBL +PF13.Signal=ETH1_RMII_TXD1 +PF14.GPIOParameters=PinAttribute +PF14.Mode=RMII +PF14.PinAttribute=FSBL +PF14.Signal=ETH1_RMII_RXD0 +PF15.GPIOParameters=PinAttribute +PF15.Mode=RMII +PF15.PinAttribute=FSBL +PF15.Signal=ETH1_RMII_RXD1 +PF4.GPIOParameters=PinAttribute +PF4.Locked=true +PF4.Mode=RMII +PF4.PinAttribute=FSBL +PF4.Signal=ETH1_MDIO +PF5.GPIOParameters=PinAttribute +PF5.Mode=RMII +PF5.PinAttribute=FSBL +PF5.Signal=ETH1_CLK +PF7.GPIOParameters=PinAttribute +PF7.Mode=RMII +PF7.PinAttribute=FSBL +PF7.Signal=ETH1_RMII_REF_CLK +PG0.ContextOwner=FSBL +PG0.GPIOParameters=PinAttribute +PG0.Locked=true +PG0.PinAttribute=FSBL +PG0.Signal=GPIO_Output +PG10.ContextOwner=FSBL +PG10.GPIOParameters=PinAttribute +PG10.Locked=true +PG10.PinAttribute=FSBL +PG10.Signal=GPIO_Output +PG11.GPIOParameters=PinAttribute +PG11.Locked=true +PG11.Mode=RMII +PG11.PinAttribute=FSBL +PG11.Signal=ETH1_MDC +PG8.ContextOwner=FSBL +PG8.GPIOParameters=PinAttribute +PG8.Locked=true +PG8.PinAttribute=FSBL +PG8.Signal=GPIO_Output +PinOutPanel.CurrentBGAView=Top +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=STM32N657X0HxQ +ProjectManager.FirmwarePackage=STM32Cube FW_N6 V1.3.0 +ProjectManager.FreePins=false +ProjectManager.FreePinsContext=FSBL +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=FSBL-0x200,Appli-0x200,ExtMemLoader-0x200 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=1 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain=STM32CubeIDE +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=n567.ioc +ProjectManager.ProjectName=n567 +ProjectManager.ProjectStructure=FSBL\:FSBL\:true;Appli\:Appli\:false;ExtMemLoader\:ExtMemLoader\:false; +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=FSBL-0x800,Appli-0x800,ExtMemLoader-0x800 +ProjectManager.TargetToolchain=STM32CubeIDE +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false-FSBL,2-MX_GPIO_Init-GPIO-false-HAL-true-FSBL,3-MX_ETH1_Init-ETH1-false-HAL-true-FSBL,4-MX_RNG_Init-RNG-false-HAL-true-FSBL,5-MX_USART1_UART_Init-USART1-false-HAL-true-FSBL,6-SystemIsolation_Config-RIF-false-HAL-true-FSBL,0-MX_CORTEX_M55_FSBL_Init-CORTEX_M55_FSBL-false-HAL-true-FSBL,0-MX_CORTEX_M55_S_Init-CORTEX_M55_S-false-HAL-true-Appli +RCC.ADC12Freq_Value=100000000 +RCC.ADFFreq_Value=100000000 +RCC.AHB1234Freq_Value=100000000 +RCC.AHBFreq_Value=8000000 +RCC.APB1Freq_Value=100000000 +RCC.APB2Freq_Value=100000000 +RCC.APB4Freq_Value=100000000 +RCC.APB5Freq_Value=100000000 +RCC.AXIClockFreq_Value=400000000 +RCC.CKPERFreq_Value=64000000 +RCC.CortexFreq_Value=8000000 +RCC.CpuClockFreq_Value=64000000 +RCC.DCMIPPFreq_Value=100000000 +RCC.ETH1Freq_Value=100000000 +RCC.FDCANFreq_Value=100000000 +RCC.FMCFreq_Value=100000000 +RCC.FOUTPOSTDIV1Freq_Value=1600000000 +RCC.FOUTPOSTDIV2Freq_Value=1600000000 +RCC.FOUTPOSTDIV3Freq_Value=1600000000 +RCC.FOUTPOSTDIV4Freq_Value=1600000000 +RCC.FamilyName=M +RCC.HPRE_Div=RCC_HCLK_DIV4 +RCC.HSE_VALUE=48000000 +RCC.HSI_VALUE=64000000 +RCC.I2C1Freq_Value=100000000 +RCC.I2C2Freq_Value=100000000 +RCC.I2C3Freq_Value=100000000 +RCC.I2C4Freq_Value=100000000 +RCC.I3C1Freq_Value=100000000 +RCC.I3C2Freq_Value=100000000 +RCC.IC10Freq_VALUE=1600000000 +RCC.IC11Freq_VALUE=400000000 +RCC.IC12Freq_VALUE=1600000000 +RCC.IC13Freq_VALUE=1600000000 +RCC.IC14Freq_VALUE=1600000000 +RCC.IC15Freq_VALUE=1600000000 +RCC.IC16Freq_VALUE=1600000000 +RCC.IC17Freq_VALUE=1600000000 +RCC.IC18Freq_VALUE=1600000000 +RCC.IC19Freq_VALUE=1600000000 +RCC.IC1Freq_VALUE=533333333.3333333 +RCC.IC20Freq_VALUE=1600000000 +RCC.IC2Freq_VALUE=400000000 +RCC.IC3Freq_VALUE=1600000000 +RCC.IC4Freq_VALUE=1600000000 +RCC.IC5Freq_VALUE=1600000000 +RCC.IC6Freq_VALUE=400000000 +RCC.IC7Freq_VALUE=1600000000 +RCC.IC8Freq_VALUE=1600000000 +RCC.IC9Freq_VALUE=1600000000 +RCC.IPParameters=ADC12Freq_Value,ADFFreq_Value,AHB1234Freq_Value,AHBFreq_Value,APB1Freq_Value,APB2Freq_Value,APB4Freq_Value,APB5Freq_Value,AXIClockFreq_Value,CKPERFreq_Value,CortexFreq_Value,CpuClockFreq_Value,DCMIPPFreq_Value,ETH1Freq_Value,FDCANFreq_Value,FMCFreq_Value,FOUTPOSTDIV1Freq_Value,FOUTPOSTDIV2Freq_Value,FOUTPOSTDIV3Freq_Value,FOUTPOSTDIV4Freq_Value,FamilyName,HPRE_Div,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I3C1Freq_Value,I3C2Freq_Value,IC10Freq_VALUE,IC11Freq_VALUE,IC12Freq_VALUE,IC13Freq_VALUE,IC14Freq_VALUE,IC15Freq_VALUE,IC16Freq_VALUE,IC17Freq_VALUE,IC18Freq_VALUE,IC19Freq_VALUE,IC1Freq_VALUE,IC20Freq_VALUE,IC2Freq_VALUE,IC3Freq_VALUE,IC4Freq_VALUE,IC5Freq_VALUE,IC6Freq_VALUE,IC7Freq_VALUE,IC8Freq_VALUE,IC9Freq_VALUE,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM3Freq_Value,LPTIM4Freq_Value,LPTIM5Freq_Value,LPUART1Freq_Value,LSE_VALUE,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MDFFreq_Value,MSI_VALUE,OTGHS1Freq_Value,OTGHS2Freq_Value,OTGPHY1Freq_Value,OTGPHY2Freq_Value,PLL1FRACV,PLL2FRACV,PLL3FRACV,PLL4FRACV,PSSIFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMC1Freq_Value,SDMMC2Freq_Value,SPDIFRX1Freq_Value,SPI1Freq_Value,SPI2Freq_Value,SPI3Freq_Value,SPI4Freq_Value,SPI5Freq_Value,SPI6Freq_Value,SYSBCLKFreq_VALUE,SYSBCLKSource,SYSCCLKFreq_VALUE,SYSDCLKFreq_VALUE,TIMGFreq_Value,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,UART9Freq_Value,USART10Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value,XSPI1Freq_Value,XSPI2Freq_Value,XSPI3Freq_Value +RCC.LPTIM1Freq_Value=100000000 +RCC.LPTIM2Freq_Value=100000000 +RCC.LPTIM3Freq_Value=100000000 +RCC.LPTIM4Freq_Value=100000000 +RCC.LPTIM5Freq_Value=100000000 +RCC.LPUART1Freq_Value=100000000 +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.LTDCFreq_Value=100000000 +RCC.MCO1PinFreq_Value=64000000 +RCC.MCO2PinFreq_Value=64000000 +RCC.MDFFreq_Value=100000000 +RCC.MSI_VALUE=16000000 +RCC.OTGHS1Freq_Value=24000000 +RCC.OTGHS2Freq_Value=24000000 +RCC.OTGPHY1Freq_Value=24000000 +RCC.OTGPHY2Freq_Value=24000000 +RCC.PLL1FRACV=0 +RCC.PLL2FRACV=0 +RCC.PLL3FRACV=0 +RCC.PLL4FRACV=0 +RCC.PSSIFreq_Value=100000000 +RCC.RTCFreq_Value=32000 +RCC.SAI1Freq_Value=100000000 +RCC.SAI2Freq_Value=100000000 +RCC.SDMMC1Freq_Value=100000000 +RCC.SDMMC2Freq_Value=100000000 +RCC.SPDIFRX1Freq_Value=100000000 +RCC.SPI1Freq_Value=100000000 +RCC.SPI2Freq_Value=100000000 +RCC.SPI3Freq_Value=100000000 +RCC.SPI4Freq_Value=100000000 +RCC.SPI5Freq_Value=100000000 +RCC.SPI6Freq_Value=100000000 +RCC.SYSBCLKFreq_VALUE=400000000 +RCC.SYSBCLKSource=RCC_SYSCLKSOURCE_IC2_IC6_IC11 +RCC.SYSCCLKFreq_VALUE=400000000 +RCC.SYSDCLKFreq_VALUE=400000000 +RCC.TIMGFreq_Value=400000000 +RCC.UART4Freq_Value=100000000 +RCC.UART5Freq_Value=100000000 +RCC.UART7Freq_Value=100000000 +RCC.UART8Freq_Value=100000000 +RCC.UART9Freq_Value=100000000 +RCC.USART10Freq_Value=100000000 +RCC.USART1Freq_Value=100000000 +RCC.USART2Freq_Value=100000000 +RCC.USART3Freq_Value=100000000 +RCC.USART6Freq_Value=100000000 +RCC.VCO1OutputFreq_Value=1600000000 +RCC.VCO2OutputFreq_Value=1600000000 +RCC.VCO3OutputFreq_Value=1600000000 +RCC.VCO4OutputFreq_Value=1600000000 +RCC.VCOInput1Freq_Value=64000000 +RCC.VCOInput2Freq_Value=64000000 +RCC.VCOInput3Freq_Value=64000000 +RCC.VCOInput4Freq_Value=64000000 +RCC.XSPI1Freq_Value=100000000 +RCC.XSPI2Freq_Value=100000000 +RCC.XSPI3Freq_Value=100000000 +RIF.DCMIPP_CID_RIMU=0 +RIF.DMA2D_CID_RIMU=0 +RIF.ETH1_CID_RIMU=1 +RIF.ETR_CID_RIMU=0 +RIF.GPU_CID_RIMU=0 +RIF.IPParameters=ETR_CID_RIMU,SDMMC1_CID_RIMU,SDMMC2_CID_RIMU,OTG1_CID_RIMU,OTG2_CID_RIMU,ETH1_CID_RIMU,GPU_CID_RIMU,DMA2D_CID_RIMU,DCMIPP_CID_RIMU,LTDC_L1_CID_RIMU,LTDC_L2_CID_RIMU,VENC_CID_RIMU +RIF.LTDC_L1_CID_RIMU=0 +RIF.LTDC_L2_CID_RIMU=0 +RIF.OTG1_CID_RIMU=0 +RIF.OTG2_CID_RIMU=0 +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 0\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 0\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 0\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 1\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 1\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 1\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 10\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 10\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 10\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 11\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 11\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 11\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 12\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 12\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 12\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 13\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 13\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 13\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 14\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 14\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 14\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 15\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 15\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 15\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 2\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 2\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 2\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 3\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 3\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 3\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 4\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 4\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 4\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 5\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 5\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 5\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 6\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 6\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 6\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 7\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 7\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 7\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 8\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 8\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 8\ Secure=false +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 9\ Cid=- +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 9\ Privilege=true +RIF.RIFAWARE.GPDMA1\ Feature\ GPDMA1\ channel\ 9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA10\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA10\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA11\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA11\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA12\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA12\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PA9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PA9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB10\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB10\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB11\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB11\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB12\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB12\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB13\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB13\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB14\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB14\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB15\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB15\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PB9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PB9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC10\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC10\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC11\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC11\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC12\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC12\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC13\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC13\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PC9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PC9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD10\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD10\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD11\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD11\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD12\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD12\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD13\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD13\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD14\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD14\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD15\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD15\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PD9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PD9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE10\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE10\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE11\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE11\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE12\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE12\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE13\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE13\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE14\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE14\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE15\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE15\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE5\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PE5\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PE5\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PE6\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PE6\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PE6\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PE7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PE9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PE9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PF0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PF0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PF1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PF1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PF10\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF10\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF10\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF11\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF11\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF11\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF12\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF12\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF12\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF13\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF13\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF13\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF14\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF14\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF14\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF15\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF15\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF15\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PF2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PF3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PF3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PF4\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF4\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF4\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF5\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF5\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF5\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PF6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PF7\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PF7\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PF7\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PF8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PF8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PF9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PF9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG0\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PG0\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PG0\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PG1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG10\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PG10\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PG10\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PG11\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PG11\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PG11\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PG12\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG12\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG13\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG13\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG14\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG14\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG15\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG15\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PG8\ Cid=1 +RIF.RIFAWARE.GPIO\ Feature\ PG8\ FSBL=true +RIF.RIFAWARE.GPIO\ Feature\ PG8\ Secure=true +RIF.RIFAWARE.GPIO\ Feature\ PG9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PG9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PH2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PH2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PH3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PH3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PH4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PH4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PH5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PH5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PH6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PH6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PH7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PH7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PH8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PH8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PH9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PH9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN10\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN10\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN11\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN11\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN12\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN12\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PN9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PN9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PO0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PO0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PO1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PO1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PO2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PO2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PO3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PO3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PO4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PO4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PO5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PO5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP10\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP10\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP11\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP11\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP12\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP12\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP13\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP13\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP14\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP14\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP15\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP15\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP7\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP8\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP8\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PP9\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PP9\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PQ0\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PQ0\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PQ1\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PQ1\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PQ2\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PQ2\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PQ3\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PQ3\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PQ4\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PQ4\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PQ5\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PQ5\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PQ6\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PQ6\ Secure=false +RIF.RIFAWARE.GPIO\ Feature\ PQ7\ Cid=- +RIF.RIFAWARE.GPIO\ Feature\ PQ7\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 0\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 0\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 0\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 1\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 1\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 1\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 10\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 10\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 10\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 11\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 11\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 11\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 12\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 12\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 12\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 13\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 13\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 13\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 14\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 14\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 14\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 15\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 15\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 15\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 2\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 2\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 2\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 3\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 3\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 3\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 4\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 4\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 4\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 5\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 5\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 5\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 6\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 6\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 6\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 7\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 7\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 7\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 8\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 8\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 8\ Secure=false +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 9\ Cid=- +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 9\ Privilege=true +RIF.RIFAWARE.HPDMA1\ Feature\ HPDMA1\ channel\ 9\ Secure=false +RIF.RIFAWARE.LTDC\ Feature\ LTDC_L1\ Cid=- +RIF.RIFAWARE.LTDC\ Feature\ LTDC_L1\ Secure=false +RIF.RIFAWARE.LTDC\ Feature\ LTDC_L2\ Cid=- +RIF.RIFAWARE.LTDC\ Feature\ LTDC_L2\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ Backup\ domain\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ Backup\ domain\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ CPU\ power\ control\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ CPU\ power\ control\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ I-TCM,\ D-TCM,\ and\ I-TCM\ FLEXMEM\ low\ power\ control\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ I-TCM,\ D-TCM,\ and\ I-TCM\ FLEXMEM\ low\ power\ control\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ Peripheral\ voltage\ monitor\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ Peripheral\ voltage\ monitor\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ Programmable\ voltage\ detector\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ Programmable\ voltage\ detector\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ System\ supply\ configuration\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ System\ supply\ configuration\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ VDDCORE\ monitor\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ VDDCORE\ monitor\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ Voltage\ scaling\ selection\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ Voltage\ scaling\ selection\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ WKUP1\ pin\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ WKUP1\ pin\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ WKUP2\ pin\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ WKUP2\ pin\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ WKUP3\ pin\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ WKUP3\ pin\ protection\ Secure=false +RIF.RIFAWARE.PWR\ Feature\ WKUP4\ pin\ protection\ Cid=- +RIF.RIFAWARE.PWR\ Feature\ WKUP4\ pin\ protection\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ BUS\ system\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ BUS\ system\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ DFT\ system\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ DFT\ system\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC1\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC1\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC10\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC10\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC11\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC11\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC12\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC12\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC13\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC13\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC14\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC14\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC15\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC15\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC16\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC16\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC17\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC17\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC18\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC18\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC19\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC19\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC2\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC2\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC20\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC20\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC3\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC3\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC4\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC4\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC5\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC5\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC6\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC6\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC7\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC7\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC8\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC8\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC9\ divider\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ IC9\ divider\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ INT\ system\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ INT\ system\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ MOD\ system\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ MOD\ system\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PER\ system\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PER\ system\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PLL1\ configuration\ bits\u200B\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PLL1\ configuration\ bits\u200B\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PLL2\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PLL2\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PLL3\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PLL3\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PLL4\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ PLL4\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ RST\ system\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ RST\ system\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ SYS\ system\ configuration\ bit\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ Protection\ of\ SYS\ system\ configuration\ bit\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ ACLKN\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ ACLKN\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ ACLKNC\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ ACLKNC\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB1\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB1\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB2\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB2\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB3\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB3\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB4\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB4\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB5\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHB5\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHBM\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ AHBM\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB1\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB1\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB2\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB2\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB3\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB3\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB4\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB4\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB5\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ APB5\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ NOC\ bus\ configuration\ bits\ Cid=- +RIF.RIFAWARE.RCC\ Feature\ protection\ of\ NOC\ bus\ configuration\ bits\ Secure=false +RIF.RIFAWARE.RTC\ Feature\ Alarm\ A\ and\ SSR\ underflow\ protection\u200B\ Cid=- +RIF.RIFAWARE.RTC\ Feature\ Alarm\ A\ and\ SSR\ underflow\ protection\u200B\ Secure=false +RIF.RIFAWARE.RTC\ Feature\ Alarm\ B\ protection\ Cid=- +RIF.RIFAWARE.RTC\ Feature\ Alarm\ B\ protection\ Secure=false +RIF.RIFAWARE.RTC\ Feature\ Initialization\ protection\ Cid=- +RIF.RIFAWARE.RTC\ Feature\ Initialization\ protection\ Secure=false +RIF.RIFAWARE.RTC\ Feature\ RTC\ global\ protection\ Cid=- +RIF.RIFAWARE.RTC\ Feature\ RTC\ global\ protection\ Secure=false +RIF.RIFAWARE.RTC\ Feature\ Shift\ register,\ daylight\ saving,\ calibration\ and\ reference\ clock\ protection\ Cid=- +RIF.RIFAWARE.RTC\ Feature\ Shift\ register,\ daylight\ saving,\ calibration\ and\ reference\ clock\ protection\ Secure=false +RIF.RIFAWARE.RTC\ Feature\ Timestamp\ protection\ Cid=- +RIF.RIFAWARE.RTC\ Feature\ Timestamp\ protection\ Secure=false +RIF.RIFAWARE.RTC\ Feature\ Wake-up\ timer\ protection\ Cid=- +RIF.RIFAWARE.RTC\ Feature\ Wake-up\ timer\ protection\ Secure=false +RIF.RISUP.ETH1.Privilege=true +RIF.SDMMC1_CID_RIMU=0 +RIF.SDMMC2_CID_RIMU=0 +RIF.VENC_CID_RIMU=0 +RIF.default_config=false +USART1.IPParameters=VirtualMode-Asynchronous +USART1.VirtualMode-Asynchronous=VM_ASYNC +VP_RIF_VS_RIF1.Mode=RISUP +VP_RIF_VS_RIF1.Signal=RIF_VS_RIF1 +VP_RNG_VS_RNG.Mode=RNG_Activate +VP_RNG_VS_RNG.Signal=RNG_VS_RNG +board=custom diff --git a/tutorials/stm32/nucleo_n657x0_q/minimal/MX25UM51245G_STM32N6570-NUCLEO.stldr b/tutorials/stm32/nucleo_n657x0_q/minimal/MX25UM51245G_STM32N6570-NUCLEO.stldr new file mode 100755 index 00000000..b6a533da Binary files /dev/null and b/tutorials/stm32/nucleo_n657x0_q/minimal/MX25UM51245G_STM32N6570-NUCLEO.stldr differ diff --git a/tutorials/stm32/nucleo_n657x0_q/minimal/Makefile b/tutorials/stm32/nucleo_n657x0_q/minimal/Makefile new file mode 100644 index 00000000..bd3c9a4c --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/minimal/Makefile @@ -0,0 +1,61 @@ +# 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_n6/Include +CFLAGS += -mcpu=cortex-m55 -mthumb -mfloat-abi=soft -mfpu=fpv5-d16 -mcmse +CFLAGS += $(CFLAGS_EXTRA) +LDFLAGS ?= -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections + +SOURCES = cmsis_n6/Source/Templates/gcc/startup_stm32n657xx.s +SOURCES += main.c hal.c + +FSBL_SOURCES = cmsis_n6/Source/Templates/gcc/startup_stm32n657xx_fsbl.s +FSBL_SOURCES += fsbl.c + +TOP = ../../../.. +CFLAGS += -I$(TOP) +SOURCES += $(TOP)/mongoose.c + +all: fsbl.signed.bin firmware.bin + +firmware.elf: cmsis_core cmsis_n6 hal.h link.ld Makefile $(SOURCES) + arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -Tlink.ld -o $@ + +fsbl.elf: cmsis_core cmsis_n6 hal.h fsbl.ld Makefile $(FSBL_SOURCES) + arm-none-eabi-gcc $(FSBL_SOURCES) $(CFLAGS) $(LDFLAGS) -Tfsbl.ld -o $@ + +%.bin: %.elf + arm-none-eabi-objcopy -O binary $< $@ + @echo + @echo "To flash:" + @echo " 1. set the BOOT1 jumper to position 1, click reset button" + @echo " 2. run 'make flash'" + @echo " 3. set the BOOT1 jumper to position 0, click reset button" + @echo " NOTE: STM32_Programmer_CLI and STM32_SigningTool_CLI should be in your PATH" + +fsbl.signed.bin: fsbl.bin + STM32_SigningTool_CLI -s -nk -of 0x80000000 -t fsbl -hv 2.3 -align -bin $^ -o $@ + +flash: fsbl.signed.bin firmware.bin + STM32_Programmer_CLI -c port=swd mode=HOTPLUG -el MX25UM51245G_STM32N6570-NUCLEO.stldr -d firmware.bin 0x70100000 -hardRst + STM32_Programmer_CLI -c port=swd mode=HOTPLUG -el MX25UM51245G_STM32N6570-NUCLEO.stldr -d fsbl.signed.bin 0x70000000 -hardRst + +gdb: fsbl.elf + arm-none-eabi-gdb -q -ex='set confirm off' -ex 'target remote :61234' -ex 'load' $^ + +# Directory where STM32_Programmer_CLI binary lives +CUBEPROG_DIR ?= $(dir $(shell which STM32_Programmer_CLI)) +gdb_server: + ST-LINK_gdbserver --port-number 61234 --log-level 1 --swd --verify --stm32cubeprogrammer-path $(CUBEPROG_DIR) --apid 1 --initialize-reset + +cmsis_core: + git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@ + +cmsis_n6: + git clone -q -c advice.detachedHead=false --depth 1 -b v1.3.0 https://github.com/STMicroelectronics/cmsis-device-n6 $@ + +clean: + rm -rf *.bin *.map *.elf diff --git a/tutorials/stm32/nucleo_n657x0_q/minimal/fsbl.c b/tutorials/stm32/nucleo_n657x0_q/minimal/fsbl.c new file mode 100644 index 00000000..0214527a --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/minimal/fsbl.c @@ -0,0 +1,132 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved +#include "hal.h" + +#define APP_BASE 0x70100000U // Should match link.ld + +uint32_t SystemCoreClock; +void SystemInit(void) { + hal_system_init(); + if (!hal_clock_init(HAL_SYS_FREQUENCY)) { + for (;;) (void) 0; + } +} + +static void xip_init(void) { + enum { + XSPI_AF = 9U, + XSPI_FLASH_SIZE_BITS = 26U, // 64 MiB MX25UM51245G + XSPI_KERNEL_DIV = HAL_XSPI_IC3_DIV, // PLL1 / div, capped at 50 MHz + XSPI_CSHT_CYCLES = 3U, + XSPI_REQ2ACK_CYCLES = 1U, + XSPI_READ_OPCODE = 0x0CU, // JEDEC 4-byte fast read + XSPI_READ_DUMMY_CYCLES = 8U, + }; + static const uint16_t xspi_pins[] = { + PIN('N', 4), PIN('N', 6), PIN('N', 8), PIN('N', 0), + PIN('N', 3), PIN('N', 5), PIN('N', 1), PIN('N', 9), + PIN('N', 2), PIN('N', 10), PIN('N', 11), + }; + const uint32_t clear_flags = + XSPI_FCR_CTCF | XSPI_FCR_CTEF | XSPI_FCR_CSMF | XSPI_FCR_CTOF; + + // Explicitly enable every clock this XIP path depends on. + RCC->AHB4ENSR = RCC_AHB4ENSR_PWRENS | RCC_AHB4ENSR_GPIONENS; + RCC->APB4ENSR2 = RCC_APB4ENSR2_SYSCFGENS; + (void) RCC->AHB4ENR; + (void) RCC->APB4ENR2; + + RCC->AHB5RSTSR = RCC_AHB5RSTSR_XSPIMRSTS | RCC_AHB5RSTSR_XSPI2RSTS; + RCC->AHB5RSTCR = RCC_AHB5RSTCR_XSPIMRSTC | RCC_AHB5RSTCR_XSPI2RSTC; + RCC->AHB4RSTSR = RCC_AHB4RSTSR_GPIONRSTS; + RCC->AHB4RSTCR = RCC_AHB4RSTCR_GPIONRSTC; + + PWR->SVMCR1 |= PWR_SVMCR1_VDDIO4SV; + PWR->SVMCR2 |= PWR_SVMCR2_VDDIO5SV; + PWR->SVMCR3 |= PWR_SVMCR3_VDDIO2SV | PWR_SVMCR3_VDDIO3SV; + + SYSCFG->VDDIO2CCCR = SYSCFG_VDDIO2CCCR_CS | SYSCFG_VDDIO2CCCR_RAPSRC_3 | + SYSCFG_VDDIO2CCCR_RANSRC_0 | SYSCFG_VDDIO2CCCR_RANSRC_1 | + SYSCFG_VDDIO2CCCR_RANSRC_2; + SYSCFG->VDDIO3CCCR = SYSCFG_VDDIO3CCCR_CS | SYSCFG_VDDIO3CCCR_RAPSRC_3 | + SYSCFG_VDDIO3CCCR_RANSRC_0 | SYSCFG_VDDIO3CCCR_RANSRC_1 | + SYSCFG_VDDIO3CCCR_RANSRC_2; + SYSCFG->VDDIO4CCCR = SYSCFG_VDDIO4CCCR_CS | SYSCFG_VDDIO4CCCR_RAPSRC_3 | + SYSCFG_VDDIO4CCCR_RANSRC_0 | SYSCFG_VDDIO4CCCR_RANSRC_1 | + SYSCFG_VDDIO4CCCR_RANSRC_2; + SYSCFG->VDDIO5CCCR = SYSCFG_VDDIO5CCCR_CS | SYSCFG_VDDIO5CCCR_RAPSRC_3 | + SYSCFG_VDDIO5CCCR_RANSRC_0 | SYSCFG_VDDIO5CCCR_RANSRC_1 | + SYSCFG_VDDIO5CCCR_RANSRC_2; + SYSCFG->VDDCCCR = SYSCFG_VDDCCCR_CS | SYSCFG_VDDCCCR_RAPSRC_3 | + SYSCFG_VDDCCCR_RANSRC_0 | SYSCFG_VDDCCCR_RANSRC_1 | + SYSCFG_VDDCCCR_RANSRC_2; + + // Mirror the Cube FSBL topology: XSPI2 kernel clock is IC3 fed from PLL1. + CLRSET(RCC->IC3CFGR, RCC_IC3CFGR_IC3SEL | RCC_IC3CFGR_IC3INT, + (((uint32_t) (XSPI_KERNEL_DIV - 1U) << RCC_IC3CFGR_IC3INT_Pos) & + RCC_IC3CFGR_IC3INT)); + RCC->DIVENSR = RCC_DIVENSR_IC3ENS; + CLRSET(RCC->CCIPR6, RCC_CCIPR6_XSPI2SEL, RCC_CCIPR6_XSPI2SEL_1); + + RCC->AHB5ENSR = RCC_AHB5ENSR_XSPIMENS | RCC_AHB5ENSR_XSPI2ENS; + (void) RCC->AHB5ENR; + + for (size_t i = 0; i < sizeof(xspi_pins) / sizeof(xspi_pins[0]); i++) { + hal_gpio_init(xspi_pins[i], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, + HAL_GPIO_SPEED_VERY_HIGH, HAL_GPIO_PULL_NONE, XSPI_AF); + } + + // Keep XIP bring-up small and predictable: fixed 1-1-1 JEDEC 4-byte read. + XSPI2->CR = (uint32_t) ((4U - 1U) << XSPI_CR_FTHRES_Pos); + XSPI2->DCR1 = ((uint32_t) XSPI_CSHT_CYCLES << XSPI_DCR1_CSHT_Pos) | + XSPI_DCR1_MTYP_0 | + ((uint32_t) XSPI_FLASH_SIZE_BITS << XSPI_DCR1_DEVSIZE_Pos); + XSPI2->DCR2 = 0U; + XSPI2->DCR3 = 0U; + XSPI2->DCR4 = 0U; + XSPIM->CR = XSPIM_CR_CSSEL_OVR_EN | + ((uint32_t) XSPI_REQ2ACK_CYCLES << XSPIM_CR_REQ2ACK_TIME_Pos); + XSPI2->CR |= XSPI_CR_EN; + XSPI2->TCR = XSPI_READ_DUMMY_CYCLES | XSPI_TCR_SSHIFT; + XSPI2->DLR = 0U; + XSPI2->CCR = + XSPI_CCR_IMODE_0 | XSPI_CCR_ADMODE_0 | XSPI_CCR_ADSIZE | XSPI_CCR_DMODE_0; + XSPI2->IR = XSPI_READ_OPCODE; + XSPI2->AR = 0U; + XSPI2->FCR = clear_flags; + + // In reset topology XSPI2 is wired to XSPIM port 2 already. + CLRSET(XSPI2->CR, XSPI_CR_FMODE, XSPI_CR_FMODE); +} + +static void jump_to_app(void) { + // Lit blue pin + hal_gpio_output(PIN('G', 8)); + hal_gpio_write(PIN('G', 8), false); + + // Read stack and app entry point from the app vector table + uint32_t sp = *(volatile uint32_t *) (APP_BASE + 0U); + uint32_t pc = *(volatile uint32_t *) (APP_BASE + 4U); + + // Switch to the app's vector table only after the first XIP reads succeed. + SCB->VTOR = APP_BASE; + __DSB(); + __ISB(); + + // Lit green pin + hal_gpio_output(PIN('G', 0)); + hal_gpio_write(PIN('G', 0), false); + + __set_MSP(sp); + ((void (*)(void)) pc)(); // Jump to the application entry point + for (;;) (void) 0; // Hang +} + +int main(void) { + xip_init(); + jump_to_app(); + return 0; +} + +void _init(void) { +} diff --git a/tutorials/stm32/nucleo_n657x0_q/minimal/fsbl.ld b/tutorials/stm32/nucleo_n657x0_q/minimal/fsbl.ld new file mode 100644 index 00000000..71e71505 --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/minimal/fsbl.ld @@ -0,0 +1,20 @@ +ENTRY(Reset_Handler); +MEMORY { + ROM (xrw) : ORIGIN = 0x34180400, LENGTH = 255K + RAM (xrw) : ORIGIN = 0x341C0000, LENGTH = 256K +} +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sstack = _estack - 4096; + +SECTIONS { + .vectors : { KEEP(*(.isr_vector)) } > ROM + .text : { *(.text* .text.*) } > ROM + .rodata : { *(.rodata*) } > ROM + + .data : { _sdata = .; *(.first_data) *(.data SORT(.data.*)) _edata = .; } > RAM AT > ROM + _sidata = LOADADDR(.data); + + .bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > RAM + . = ALIGN(8); + _end = .; +} diff --git a/tutorials/stm32/nucleo_n657x0_q/minimal/hal.c b/tutorials/stm32/nucleo_n657x0_q/minimal/hal.c new file mode 100644 index 00000000..bd09d907 --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/minimal/hal.c @@ -0,0 +1,124 @@ +// 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 = HAL_SYS_FREQUENCY; +void SystemInit(void) { + SystemCoreClock = HAL_SYS_FREQUENCY; // FSBL intitialised the clock for us + SysTick_Config(SystemCoreClock / 1000U); +} + +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_n657x0_q/minimal/hal.h b/tutorials/stm32/nucleo_n657x0_q/minimal/hal.h new file mode 100644 index 00000000..4fe25647 --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/minimal/hal.h @@ -0,0 +1,427 @@ +// Copyright (c) 2022-2026 Cesanta Software Limited + +#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 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) + +// UM3417 7.12 +#ifndef HAL_ETH_PINS +#define HAL_ETH_PINS \ + PIN('F', 4), PIN('F', 5), PIN('F', 7), PIN('F', 10), PIN('F', 11), \ + PIN('F', 12), PIN('F', 13), PIN('F', 14), PIN('F', 15), PIN('G', 11), +#endif + +#ifndef HAL_SYS_FREQUENCY +#define HAL_SYS_FREQUENCY (600U * 1000U * 1000U) +#endif + +#if ((HAL_SYS_FREQUENCY % (8U * 1000U * 1000U)) != 0U) +#error "HAL_SYS_FREQUENCY must be a multiple of 8 MHz" +#endif + +#if (HAL_SYS_FREQUENCY == 0U || HAL_SYS_FREQUENCY > (1600U * 1000U * 1000U)) +#error "HAL_SYS_FREQUENCY must be between 8 MHz and 1600 MHz" +#endif + +enum { + HAL_HSI_FREQUENCY = 64000000U, + HAL_PLL1_MAX_FREQUENCY = 1600000000U, + HAL_PLL1_M = 1U, + HAL_PLL1_P1 = 1U, + HAL_PLL1_P2 = 1U, + HAL_ETH_TARGET_FREQUENCY = 100000000U, + HAL_XSPI_TARGET_FREQUENCY = 50000000U, + HAL_HPRE = 4U, + HAL_PPRE1 = 1U, + HAL_PPRE2 = 1U, + HAL_PPRE4 = 1U, + HAL_PPRE5 = 1U, +}; + +#define HAL_SYSCLK_IC_DIV (HAL_PLL1_MAX_FREQUENCY / HAL_SYS_FREQUENCY) +#define HAL_PLL1_FREQUENCY (HAL_SYS_FREQUENCY * HAL_SYSCLK_IC_DIV) +#define HAL_PLL1_N (HAL_PLL1_FREQUENCY / HAL_HSI_FREQUENCY) +#define HAL_PLL1_N_FRAC \ + ((uint32_t) (((((uint64_t) HAL_PLL1_FREQUENCY) % HAL_HSI_FREQUENCY) << 24) / \ + HAL_HSI_FREQUENCY)) +#define HAL_AHB_FREQUENCY (HAL_SYS_FREQUENCY / HAL_HPRE) +#define HAL_APB1_FREQUENCY (HAL_AHB_FREQUENCY / HAL_PPRE1) +#define HAL_APB2_FREQUENCY (HAL_AHB_FREQUENCY / HAL_PPRE2) +#define HAL_ETH_IC12_DIV \ + ((HAL_PLL1_FREQUENCY + HAL_ETH_TARGET_FREQUENCY - 1U) / \ + HAL_ETH_TARGET_FREQUENCY) +#define HAL_ETH_KERNEL_FREQUENCY (HAL_PLL1_FREQUENCY / HAL_ETH_IC12_DIV) +#define HAL_XSPI_IC3_DIV \ + ((HAL_PLL1_FREQUENCY + HAL_XSPI_TARGET_FREQUENCY - 1U) / \ + HAL_XSPI_TARGET_FREQUENCY) +#define HAL_XSPI_KERNEL_FREQUENCY (HAL_PLL1_FREQUENCY / HAL_XSPI_IC3_DIV) + +enum { + HAL_GPIO_MODE_INPUT = 0U, + HAL_GPIO_MODE_OUTPUT = 1U, + HAL_GPIO_MODE_AF = 2U, + HAL_GPIO_MODE_ANALOG = 3U, +}; +enum { + HAL_GPIO_OTYPE_PUSH_PULL = 0U, + HAL_GPIO_OTYPE_OPEN_DRAIN = 1U, +}; +enum { + HAL_GPIO_SPEED_LOW = 0U, + HAL_GPIO_SPEED_MEDIUM = 1U, + HAL_GPIO_SPEED_HIGH = 2U, + HAL_GPIO_SPEED_VERY_HIGH = 3U, +}; +enum { + HAL_GPIO_PULL_NONE = 0U, + HAL_GPIO_PULL_UP = 1U, + HAL_GPIO_PULL_DOWN = 2U, +}; + +static inline GPIO_TypeDef *hal_gpio_bank(uint16_t pin) { + uint8_t bank = (uint8_t) PINBANK(pin); + return (GPIO_TypeDef *) (GPIOA_BASE + 0x400 * bank); // Using secure base +} + +static inline void hal_gpio_enable_clock(uint16_t pin) { + const uint32_t bank = (uint32_t) PINBANK(pin); + RCC->AHB4ENR |= BIT(bank); + (void) RCC->AHB4ENR; // Read back to ensure the write completes before access +} + +static inline void hal_gpio_set_secure_nonpriv(uint16_t pin) { + const uint32_t mask = BIT((uint32_t) PINNO(pin)); + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + gpio->SECCFGR |= mask; // Secure + gpio->PRIVCFGR &= ~mask; // Clear privileged-only protection +} + +static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t otype, + uint8_t speed, uint8_t pull, uint8_t af) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + const uint32_t n = (uint32_t) PINNO(pin); + const uint32_t shift2 = n * 2U; + const uint32_t shift4 = (n & 7U) * 4U; + if (gpio == NULL || n > 15U) return; + hal_gpio_enable_clock(pin); + CLRSET(gpio->OTYPER, BIT(n), ((uint32_t) (otype & 0x1U)) << n); + CLRSET(gpio->OSPEEDR, 3UL << shift2, ((uint32_t) (speed & 0x3U)) << shift2); + CLRSET(gpio->PUPDR, 3UL << shift2, ((uint32_t) (pull & 0x3U)) << shift2); + if (mode == HAL_GPIO_MODE_AF) { + CLRSET(gpio->AFR[n >> 3], 0xFUL << shift4, + ((uint32_t) (af & 0xFU)) << shift4); + } + CLRSET(gpio->MODER, 3UL << shift2, ((uint32_t) (mode & 0x3U)) << shift2); +} + +static inline void hal_gpio_toggle(uint16_t pin) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + const uint32_t mask = BIT(PINNO(pin)); + if (gpio == NULL) return; + gpio->BSRR = mask << ((gpio->ODR & mask) ? 16U : 0U); +} + +static inline int hal_gpio_read(uint16_t pin) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + if (gpio == NULL) return 0; + return (gpio->IDR & BIT(PINNO(pin))) ? 1 : 0; +} + +static inline void hal_gpio_write(uint16_t pin, bool val) { + GPIO_TypeDef *gpio = hal_gpio_bank(pin); + if (gpio == NULL) return; + gpio->BSRR = BIT(PINNO(pin)) << (val ? 0U : 16U); +} + +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, 0U); +} + +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, 0U); +} + +static inline void hal_gpio_af(uint16_t pin, uint8_t af, uint8_t pull) { + hal_gpio_init(pin, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, + HAL_GPIO_SPEED_HIGH, pull, af); +} + +static inline void hal_gpio_analog(uint16_t pin) { + hal_gpio_init(pin, HAL_GPIO_MODE_ANALOG, HAL_GPIO_OTYPE_PUSH_PULL, + HAL_GPIO_SPEED_LOW, HAL_GPIO_PULL_NONE, 0U); +} + +static inline bool hal_uart_init(USART_TypeDef *uart, uint16_t tx, uint16_t rx, + unsigned long baud) { + uint32_t freq = 0U; + // uint32_t ready = USART_ISR_TEACK | USART_ISR_REACK; + + if (baud == 0U) return false; + + if (uart == USART1) { + RCC->APB2ENSR = RCC_APB2ENSR_USART1ENS; + (void) RCC->APB2ENR; + CLRSET(RCC->CCIPR13, RCC_CCIPR13_USART1SEL, 0U); + RCC->APB2RSTSR = RCC_APB2RSTSR_USART1RSTS; + RCC->APB2RSTCR = RCC_APB2RSTCR_USART1RSTC; + freq = HAL_APB2_FREQUENCY; + } else if (uart == USART2) { + RCC->APB1ENSR1 = RCC_APB1ENSR1_USART2ENS; + (void) RCC->APB1ENR1; + CLRSET(RCC->CCIPR13, RCC_CCIPR13_USART2SEL, 0U); + RCC->APB1RSTSR1 = RCC_APB1RSTSR1_USART2RSTS; + RCC->APB1RSTCR1 = RCC_APB1RSTCR1_USART2RSTC; + freq = HAL_APB1_FREQUENCY; + } else if (uart == USART3) { + RCC->APB1ENSR1 = RCC_APB1ENSR1_USART3ENS; + (void) RCC->APB1ENR1; + CLRSET(RCC->CCIPR13, RCC_CCIPR13_USART3SEL, 0U); + RCC->APB1RSTSR1 = RCC_APB1RSTSR1_USART3RSTS; + RCC->APB1RSTCR1 = RCC_APB1RSTCR1_USART3RSTC; + freq = HAL_APB1_FREQUENCY; + } else { + return false; + } + + hal_gpio_init(tx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, + HAL_GPIO_SPEED_HIGH, 0, 7u); + hal_gpio_init(rx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, + HAL_GPIO_SPEED_HIGH, 0, 7u); + + uart->CR1 = uart->CR2 = uart->CR3 = uart->PRESC = 0; + uart->BRR = (uint32_t) ((freq + baud / 2U) / baud); + uart->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; + + return false; +} + +static inline bool hal_uart_write_byte(USART_TypeDef *uart, uint8_t byte) { + uart->TDR = byte; + for (volatile uint32_t n = 0; n < 999U; n++) { + if ((uart->ISR & USART_ISR_TXE_TXFNF) != 0U) return true; + } + return false; +} + +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 & USART_ISR_RXNE_RXFNE) ? 1 : 0; +} + +static inline uint8_t hal_uart_read_byte(USART_TypeDef *uart) { + return (uint8_t) (uart->RDR); +} + +static inline unsigned int hal_div2prescval(unsigned int div) { + // STM32N6 encodes AHB/APB prescalers as log2(divider): 0 -> /1, 1 -> /2 ... + unsigned int val = 0; + while (div > 1U) { + div >>= 1U; + val++; + } + return val; +} + +static inline bool hal_rng_init(void) { + RCC->AHB3ENR |= RCC_AHB3ENR_RNGEN; + RNG->CR &= ~RNG_CR_RNGEN; + CLRSET(RNG->CR, RNG_CR_CED | RNG_CR_CONDRST, RNG_CR_CONDRST); + RNG->CR &= ~RNG_CR_CONDRST; + while (RNG->CR & RNG_CR_CONDRST) (void) 0; + RNG->CR |= RNG_CR_RNGEN; + if (RNG->SR & RNG_SR_SEIS) return false; + while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0; + return true; +} + +static inline uint32_t hal_rng_read(void) { + while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0; + return RNG->DR; +} + +static inline void hal_eth_set_secure(uint32_t cid, uint32_t master_index, + uint32_t slave_index, bool priv) { + const uint32_t slave_reg = (slave_index >> 28) & 0xFU; + const uint32_t slave_mask = BIT(slave_index & 0x1FU); + + RIFSC->RIMC_ATTRx[master_index] = + ((cid & 0x7U) << RIFSC_RIMC_ATTRx_MCID_Pos) | RIFSC_RIMC_ATTRx_MSEC | + (priv ? RIFSC_RIMC_ATTRx_MPRIV : 0); + + RIFSC->RISC_SECCFGRx[slave_reg] |= slave_mask; + if (priv) { + RIFSC->RISC_PRIVCFGRx[slave_reg] |= slave_mask; + } else { + RIFSC->RISC_PRIVCFGRx[slave_reg] &= ~slave_mask; + } +} + +static inline void hal_ethernet_init(void) { + uint16_t pins[] = {HAL_ETH_PINS}; + + // Hold ETH1 in reset while clock path is configured + RCC->AHB5RSTSR = RCC_AHB5RSTSR_ETH1RSTS; + (void) RCC->AHB5RSTSR; + + // IC12 from the PLL1-based clock tree used by hal_clock_init() + CLRSET(RCC->IC12CFGR, RCC_IC12CFGR_IC12SEL | RCC_IC12CFGR_IC12INT, + RCC_IC12CFGR_IC12SEL_1 | ((((uint32_t) (HAL_ETH_IC12_DIV - 1U)) + << RCC_IC12CFGR_IC12INT_Pos) & + RCC_IC12CFGR_IC12INT)); + RCC->DIVENSR = RCC_DIVENSR_IC12ENS; + (void) RCC->DIVENR; + + // Keep ETH1SEL_2, ETH1CLKSEL_1. Clear ETH1REFCLKSEL ETH1GTXCLKSEL + CLRSET(RCC->CCIPR2, + RCC_CCIPR2_ETH1CLKSEL | RCC_CCIPR2_ETH1SEL | RCC_CCIPR2_ETH1REFCLKSEL | + RCC_CCIPR2_ETH1GTXCLKSEL, + RCC_CCIPR2_ETH1CLKSEL_1 | RCC_CCIPR2_ETH1SEL_2); + (void) RCC->CCIPR2; + + // Enable ETH1 clocks + RCC->AHB5ENSR = RCC_AHB5ENSR_ETH1MACENS | RCC_AHB5ENSR_ETH1TXENS | + RCC_AHB5ENSR_ETH1RXENS | RCC_AHB5ENSR_ETH1ENS; + (void) RCC->AHB5ENR; + + // Release reset + RCC->AHB5RSTCR = RCC_AHB5RSTCR_ETH1RSTC; + (void) RCC->AHB5RSTSR; + + // Set ETH1 in secure privileged mode + hal_eth_set_secure(1U, 6U, 0x1000001CU, true); + + // Configure pins in RMII AF + 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_VERY_HIGH, HAL_GPIO_PULL_NONE, 11); + } + + NVIC_EnableIRQ(ETH1_IRQn); +} + +static inline bool hal_clock_init(uint32_t cpu_freq) { + uint32_t cpu_divider = 0U; + + // Keep the PLL high enough for the SYS/XSPI tree, then derive CPUCLK from + // IC1. HAL_SYS_FREQUENCY is restricted to 8 MHz steps so PLL1 DIVNFRAC stays + // exact. + if (cpu_freq == 0U || (cpu_freq % 8000000U) != 0U) return false; + if ((HAL_PLL1_FREQUENCY % cpu_freq) != 0U) return false; + cpu_divider = HAL_PLL1_FREQUENCY / cpu_freq; + if (cpu_divider == 0U || cpu_divider > 256U) return false; + + RCC->AHB4ENSR = RCC_AHB4ENSR_PWRENS; + (void) RCC->AHB4ENR; + + PWR->CR1 &= ~(PWR_CR1_SDEN | PWR_CR1_VDD18SMPSVMEN); + CLRSET(PWR->VOSCR, PWR_VOSCR_VOS, PWR_VOSCR_VOS); + for (volatile uint32_t n = 0; n < 1000000U; n++) { + const uint32_t voscr = PWR->VOSCR; + const uint32_t requested = (voscr & PWR_VOSCR_VOS) >> PWR_VOSCR_VOS_Pos; + const uint32_t applied = (voscr & PWR_VOSCR_ACTVOS) >> PWR_VOSCR_ACTVOS_Pos; + if ((voscr & PWR_VOSCR_VOSRDY) != 0U || requested == applied) break; + } + + CLRSET(RCC->HSICFGR, RCC_HSICFGR_HSIDIV, 0U); + RCC->CR |= RCC_CR_HSION; + while ((RCC->SR & RCC_SR_HSIRDY) == 0U) (void) 0; + + if ((RCC->CFGR1 & RCC_CFGR1_CPUSWS) == RCC_CFGR1_CPUSWS || + (RCC->CFGR1 & RCC_CFGR1_SYSSWS) == RCC_CFGR1_SYSSWS) { + CLRSET(RCC->CFGR1, RCC_CFGR1_CPUSW | RCC_CFGR1_SYSSW, 0U); + while ((RCC->CFGR1 & RCC_CFGR1_CPUSWS) != 0U) (void) 0; + while ((RCC->CFGR1 & RCC_CFGR1_SYSSWS) != 0U) (void) 0; + } + + RCC->CR &= ~RCC_CR_PLL1ON; + while ((RCC->SR & RCC_SR_PLL1RDY) != 0U) (void) 0; + CLRSET( + RCC->PLL1CFGR1, + RCC_PLL1CFGR1_PLL1SEL | RCC_PLL1CFGR1_PLL1DIVM | RCC_PLL1CFGR1_PLL1DIVN, + (((uint32_t) HAL_PLL1_M << RCC_PLL1CFGR1_PLL1DIVM_Pos) & + RCC_PLL1CFGR1_PLL1DIVM) | + (((uint32_t) HAL_PLL1_N << RCC_PLL1CFGR1_PLL1DIVN_Pos) & + RCC_PLL1CFGR1_PLL1DIVN)); + RCC->PLL1CFGR3 |= RCC_PLL1CFGR3_PLL1MODSSDIS; + RCC->PLL1CFGR3 &= ~(RCC_PLL1CFGR3_PLL1MODDSEN | RCC_PLL1CFGR3_PLL1DACEN); + CLRSET(RCC->PLL1CFGR2, RCC_PLL1CFGR2_PLL1DIVNFRAC, + ((uint32_t) HAL_PLL1_N_FRAC << RCC_PLL1CFGR2_PLL1DIVNFRAC_Pos) & + RCC_PLL1CFGR2_PLL1DIVNFRAC); + CLRSET(RCC->PLL1CFGR3, + RCC_PLL1CFGR3_PLL1MODSSRST | RCC_PLL1CFGR3_PLL1DACEN | + RCC_PLL1CFGR3_PLL1MODDSEN | RCC_PLL1CFGR3_PLL1PDIV1 | + RCC_PLL1CFGR3_PLL1PDIV2 | RCC_PLL1CFGR3_PLL1PDIVEN, + (((uint32_t) HAL_PLL1_P1 << RCC_PLL1CFGR3_PLL1PDIV1_Pos) & + RCC_PLL1CFGR3_PLL1PDIV1) | + (((uint32_t) HAL_PLL1_P2 << RCC_PLL1CFGR3_PLL1PDIV2_Pos) & + RCC_PLL1CFGR3_PLL1PDIV2) | + RCC_PLL1CFGR3_PLL1MODSSRST | RCC_PLL1CFGR3_PLL1PDIVEN | + (HAL_PLL1_N_FRAC != 0U + ? RCC_PLL1CFGR3_PLL1MODDSEN | RCC_PLL1CFGR3_PLL1DACEN + : 0U)); + RCC->CR |= RCC_CR_PLL1ON; + while ((RCC->SR & RCC_SR_PLL1RDY) == 0U) (void) 0; + + CLRSET(RCC->CFGR2, + RCC_CFGR2_HPRE | RCC_CFGR2_PPRE1 | RCC_CFGR2_PPRE2 | RCC_CFGR2_PPRE4 | + RCC_CFGR2_PPRE5, + ((uint32_t) hal_div2prescval(HAL_HPRE) << RCC_CFGR2_HPRE_Pos) | + ((uint32_t) hal_div2prescval(HAL_PPRE1) << RCC_CFGR2_PPRE1_Pos) | + ((uint32_t) hal_div2prescval(HAL_PPRE2) << RCC_CFGR2_PPRE2_Pos) | + ((uint32_t) hal_div2prescval(HAL_PPRE4) << RCC_CFGR2_PPRE4_Pos) | + ((uint32_t) hal_div2prescval(HAL_PPRE5) << RCC_CFGR2_PPRE5_Pos)); + CLRSET(RCC->IC2CFGR, RCC_IC2CFGR_IC2SEL | RCC_IC2CFGR_IC2INT, + (((uint32_t) (HAL_SYSCLK_IC_DIV - 1U) << RCC_IC2CFGR_IC2INT_Pos) & + RCC_IC2CFGR_IC2INT)); + CLRSET(RCC->IC1CFGR, RCC_IC1CFGR_IC1SEL | RCC_IC1CFGR_IC1INT, + (((uint32_t) (cpu_divider - 1U) << RCC_IC1CFGR_IC1INT_Pos) & + RCC_IC1CFGR_IC1INT)); + CLRSET(RCC->IC6CFGR, RCC_IC6CFGR_IC6SEL | RCC_IC6CFGR_IC6INT, + (((uint32_t) (HAL_SYSCLK_IC_DIV - 1U) << RCC_IC6CFGR_IC6INT_Pos) & + RCC_IC6CFGR_IC6INT)); + CLRSET(RCC->IC11CFGR, RCC_IC11CFGR_IC11SEL | RCC_IC11CFGR_IC11INT, + (((uint32_t) (HAL_SYSCLK_IC_DIV - 1U) << RCC_IC11CFGR_IC11INT_Pos) & + RCC_IC11CFGR_IC11INT)); + RCC->DIVENSR = RCC_DIVENSR_IC1ENS | RCC_DIVENSR_IC2ENS | RCC_DIVENSR_IC6ENS | + RCC_DIVENSR_IC11ENS; + + // Keep the system buses on the Cube-compatible IC2/IC6/IC11 path so XIP + // timings stay unchanged, and drive only CPUCLK from IC1. + CLRSET(RCC->CFGR1, RCC_CFGR1_CPUSW | RCC_CFGR1_SYSSW, + RCC_CFGR1_CPUSW | RCC_CFGR1_SYSSW); + while ((RCC->CFGR1 & RCC_CFGR1_CPUSWS) != RCC_CFGR1_CPUSWS) (void) 0; + while ((RCC->CFGR1 & RCC_CFGR1_SYSSWS) != RCC_CFGR1_SYSSWS) (void) 0; + + SystemCoreClock = cpu_freq; + return true; +} + +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_n657x0_q/minimal/link.ld b/tutorials/stm32/nucleo_n657x0_q/minimal/link.ld new file mode 100644 index 00000000..b8976094 --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/minimal/link.ld @@ -0,0 +1,21 @@ +ENTRY(Reset_Handler); +MEMORY { + flash (rx) : ORIGIN = 0x70100000, LENGTH = 64M - 1M + sram (rwx) : ORIGIN = 0x34000000, LENGTH = 2048K +} +_estack = ORIGIN(sram) + LENGTH(sram); +_sstack = _estack - 4096; + +SECTIONS { + .vectors : { KEEP(*(.isr_vector)) } > flash + .text : { *(.text* .text.*) } > flash + .rodata : { *(.rodata*) } > flash + + /* Note the .iram section, for functions copied to RAM */ + .data : { _sdata = .; *(.first_data) *(.iram .iram* .iram.*) *(.data SORT(.data.*)) _edata = .; } > sram AT > flash + _sidata = LOADADDR(.data); + + .bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram + . = ALIGN(8); + _end = .; +} diff --git a/tutorials/stm32/nucleo_n657x0_q/minimal/main.c b/tutorials/stm32/nucleo_n657x0_q/minimal/main.c new file mode 100644 index 00000000..7ec52c91 --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/minimal/main.c @@ -0,0 +1,78 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "hal.h" +#include "mongoose.h" + +#define DEBUG_UART USART1 +#define UART_TX PIN('E', 5) +#define UART_RX PIN('E', 6) + +#define LED_1 PIN('G', 0) // Green LED +#define LED_2 PIN('G', 8) // Blue LED +#define LED_3 PIN('G', 10) // Red LED + +// Redirect stdout debug output to UART +int _write(int fd, char *ptr, int len) { + if (fd == 1) hal_uart_write_buf(DEBUG_UART, ptr, (size_t) len); + return len; +} + +// Blink green LED every 500ms +static void blink_task(void) { + static uint64_t blink_timer = 0; + if (hal_timer_expired(&blink_timer, 500, hal_get_tick())) { + hal_gpio_toggle(LED_1); + } +} + +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_uart_init(DEBUG_UART, UART_TX, UART_RX, 115200); + hal_rng_init(); + + // Initialise pins and turn them off: they are active high + hal_gpio_output(LED_1), hal_gpio_write(LED_1, true); + hal_gpio_output(LED_2), hal_gpio_write(LED_2, true); + hal_gpio_output(LED_3), hal_gpio_write(LED_3, true); + + printf("Initialised. CPU clock: %lu MHz\r\n", SystemCoreClock / 1000000); + printf("APB1: %u, APB2: %u\r\n", HAL_APB1_FREQUENCY, HAL_APB2_FREQUENCY); + + 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_n657x0_q/minimal/mongoose_config.h b/tutorials/stm32/nucleo_n657x0_q/minimal/mongoose_config.h new file mode 100644 index 00000000..a65f3cdd --- /dev/null +++ b/tutorials/stm32/nucleo_n657x0_q/minimal/mongoose_config.h @@ -0,0 +1,34 @@ +#pragma once + +// See https://mongoose.ws/docs/getting-started/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_STM32N 1 +#define MG_ENABLE_PACKED_FS 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 + +// Construct MAC address from the MCU unique ID +#define MGUID ((uint32_t *) 0x56009014UL) // 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)