Add tutorials

This commit is contained in:
cpq committed 2026-05-15 19:13:27 +01:00
1 parent a6f08e0576
commit 592d0e2790
35 files changed
+4436

No files matched your search

@@ -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.
@@ -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
@@ -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.*
+125
View File
@@ -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) {
}
+196
View File
@@ -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 <stm32f756xx.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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();
}
@@ -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 = .;
}
@@ -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;
}
@@ -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)
@@ -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.
@@ -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
@@ -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.*
+125
View File
@@ -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) {
}
+212
View File
@@ -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 <stm32h563xx.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}
@@ -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 = .;
}
@@ -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;
}
@@ -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)
@@ -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.
@@ -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
@@ -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.*
+125
View File
@@ -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) {
}
+223
View File
@@ -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 <stm32h723xx.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
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();
}
@@ -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 = .;
}
@@ -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;
}
@@ -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)
@@ -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.
@@ -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
@@ -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
@@ -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) {
}
@@ -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 = .;
}
@@ -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) {
}
@@ -0,0 +1,427 @@
// Copyright (c) 2022-2026 Cesanta Software Limited
#pragma once
#include <stm32n657xx.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
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();
}
@@ -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 = .;
}
@@ -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;
}
@@ -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)