mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-14 10:20:01 +00:00
Merge pull request #3553 from cesanta/stm32-examples
Add STM32 examples
This commit is contained in:
33 files changed
+3428
-1
No files matched your search
@@ -44,7 +44,7 @@ pico2_w_dashboard_full pico2_w_dashboard_minimal: pico2_w_dashboard_%:
|
||||
define ST_DASHBOARD_RULE
|
||||
$(1)_dashboard_$(2): $(TOP)/tutorials/stm32/$(1)/cubemx/$(1).ioc
|
||||
mkdir -p $$@
|
||||
cp $$^ $$@
|
||||
cp $(TOP)/tutorials/stm32/$(1)/cubemx/* $$@ 2>/dev/null || true
|
||||
echo config load `realpath $$@/$(1).ioc` > gen.mx
|
||||
echo project generate >> gen.mx
|
||||
echo exit >> gen.mx
|
||||
|
||||
Regular → Executable
+44
@@ -2,6 +2,7 @@
|
||||
|
||||
# IOC="${1:-}"
|
||||
DIR="${1:-}"
|
||||
ROOT_DIR=$DIR
|
||||
DASH=${2:-}
|
||||
CURL="curl -fsSL"
|
||||
RAW="https://raw.githubusercontent.com/cesanta/mongoose/HEAD/"
|
||||
@@ -12,6 +13,7 @@ fail() { echo $@ >&2 ; exit 1 ; }
|
||||
test -d "$DIR" || fail "Usage: $0 DIRECTORY"
|
||||
|
||||
test -f $DIR/FSBL/Core/Src/main.c && DIR=$DIR/FSBL
|
||||
test -f $DIR/CM7/Core/Src/main.c && DIR=$DIR/CM7
|
||||
|
||||
# Add mongoose core files
|
||||
test -d $DIR/Mongoose || mkdir -p $DIR/Mongoose
|
||||
@@ -29,12 +31,54 @@ grep -q 'mg_mgr_init' $MAIN_C || perl -i -ne 'print; print " struct mg_mgr mgr;
|
||||
grep -q 'mg_mgr_poll' $MAIN_C || perl -i -ne 'print " mg_mgr_poll(&mgr, 0);\n" if /USER CODE END WHILE/; print;' $MAIN_C
|
||||
test -f $DIR/STM32H723XG_FLASH.ld && (grep -q eth_ram $DIR/STM32H723XG_FLASH.ld || perl -i -ne 'print ; print "\n /* Mongoose Ethernet driver */\n .eth_ram : { *(.eth_ram .eth_ram*) } > RAM_D2 AT > FLASH\n" if /_sidata =/' $DIR/STM32H723XG_FLASH.ld)
|
||||
test -f $DIR/LICENSE || $CURL $RAW/LICENSE -o $DIR/LICENSE
|
||||
case $DIR in portenta*) (
|
||||
grep -q 'void hwspecific_sdio_init(void);' "$MAIN_C" || \
|
||||
perl -i -ne 'print; print "void hwspecific_sdio_init(void);\n" if /USER CODE BEGIN 0/' "$MAIN_C"
|
||||
grep -q 'hwspecific_sdio_init();' "$MAIN_C" || \
|
||||
perl -i -ne 'print " hwspecific_sdio_init();\n" if /mg_mgr_init\(&mgr\);/; print;' "$MAIN_C"
|
||||
) ;; esac
|
||||
case $DIR in *u5a5*) (
|
||||
grep -q 'void hwspecific_spi_init(void);' "$MAIN_C" || \
|
||||
perl -i -ne 'print; print "void hwspecific_spi_init(void);\n" if /USER CODE BEGIN 0/' "$MAIN_C"
|
||||
grep -q 'hwspecific_spi_init();' "$MAIN_C" || \
|
||||
perl -i -ne 'print " hwspecific_spi_init();\n" if /mg_mgr_init\(&mgr\);/; print;' "$MAIN_C"
|
||||
) ;; esac
|
||||
|
||||
# Add Mongoose dir to the build
|
||||
test -f $DIR/CMakeLists.txt && (grep -q 'Mongoose/$' $DIR/CMakeLists.txt || perl -i -ne 'print; print " \${CMAKE_SOURCE_DIR}/Mongoose/\n" if /Add user defined include paths/' $DIR/CMakeLists.txt)
|
||||
test -f $DIR/CMakeLists.txt && (grep -q 'mongoose.c$' $DIR/CMakeLists.txt || perl -i -ne 'print; print " \${CMAKE_SOURCE_DIR}/Mongoose/mongoose.c\n" if /Add user sources here/' $DIR/CMakeLists.txt)
|
||||
case $DIR in portenta*) (
|
||||
test -f $ROOT_DIR/mongoose_config.h && mv $ROOT_DIR/mongoose_config.h $DIR/Mongoose
|
||||
test -f $ROOT_DIR/wifi.c && mv $ROOT_DIR/wifi.c $DIR/Mongoose
|
||||
test -f $ROOT_DIR/getfw.cmake && mv $ROOT_DIR/getfw.cmake $DIR/
|
||||
test -f $DIR/CMakeLists.txt && (grep -q 'Mongoose/wifi.c$' "$DIR/CMakeLists.txt" || \
|
||||
perl -i -ne 'print; print " \${CMAKE_SOURCE_DIR}/Mongoose/wifi.c\n" if /Add user sources here/' "$DIR/CMakeLists.txt")
|
||||
test -f $DIR/CMakeLists.txt && (grep -q '^[[:space:]]*\${CMAKE_SOURCE_DIR}[[:space:]]*$' "$DIR/CMakeLists.txt" || \
|
||||
perl -i -ne 'print; print " \${CMAKE_SOURCE_DIR}\n" if /Add user defined include paths/' "$DIR/CMakeLists.txt")
|
||||
test -f $DIR/CMakeLists.txt && (grep -q 'COMPONENT_WHD$' "$DIR/CMakeLists.txt" || \
|
||||
perl -i -ne 'print; print " \${CMAKE_SOURCE_DIR}/mbed/targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD\n" if /Add user defined include paths/' "$DIR/CMakeLists.txt")
|
||||
test -f $DIR/CMakeLists.txt && (grep -q '^add_custom_target(getfw' "$DIR/CMakeLists.txt" || \
|
||||
cat >> "$DIR/CMakeLists.txt" <<'EOF'
|
||||
|
||||
add_custom_target(getfw
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/getfw.cmake
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
|
||||
add_dependencies(${CMAKE_PROJECT_NAME} getfw)
|
||||
EOF
|
||||
)
|
||||
) ;; esac
|
||||
case $DIR in *u5a5*) (
|
||||
test -f $ROOT_DIR/mongoose_config.h && mv $ROOT_DIR/mongoose_config.h $DIR/Mongoose
|
||||
test -f $ROOT_DIR/wifi.c && mv $ROOT_DIR/wifi.c $DIR/Mongoose
|
||||
test -f $DIR/CMakeLists.txt && (grep -q 'Mongoose/wifi.c$' "$DIR/CMakeLists.txt" || \
|
||||
perl -i -ne 'print; print " \${CMAKE_SOURCE_DIR}/Mongoose/wifi.c\n" if /Add user sources here/' "$DIR/CMakeLists.txt")
|
||||
|
||||
) ;; esac
|
||||
|
||||
# If dashboard is specified, copy it to the project
|
||||
#if test "$DASH" = "full" -o "$DASH" = "minimal" ; then
|
||||
if test "$DASH" == "full" -o "$DASH" == "minimal" ; then
|
||||
test -f $DIR/Mongoose/dashboard.c || $CURL $RAW/tutorials/device-dashboard/$DASH/dashboard.c -o $DIR/Mongoose/dashboard.c
|
||||
test -f $DIR/Mongoose/dashboard.html || $CURL $RAW/tutorials/device-dashboard/$DASH/dashboard.html -o $DIR/Mongoose/dashboard.html
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# Nucleo-U5A5ZJ-Q Mongoose Integration
|
||||
|
||||
This guide explains how to bring up a production-grade Web UI dashboard on the
|
||||
Nucleo-U5A5ZJ-Q board with the X-NUCLEO-67W61M1 Wi-Fi
|
||||
expansion board for STM32 Nucleo boards, based on the ST67W611M1 Wi-Fi module.
|
||||
|
||||
A pre-configured, ready-to-run project zip is available for download at
|
||||
https://mongoose.ws.
|
||||
|
||||
To integrate the Web UI dashboard into an existing CubeMX project, or to create a
|
||||
new project from scratch:
|
||||
|
||||
1. Configure the peripherals (described below).
|
||||
2. Regenerate your project code and integrate Mongoose core by following
|
||||
https://mongoose.ws/docs/guides/stm32-tcpip-stack/.
|
||||
3. Add the Web UI dashboard by following
|
||||
https://mongoose.ws/docs/guides/web-dashboard-guide/.
|
||||
|
||||
Note: to setup your WiFi login credentials, open the `wifi.c` file located in the
|
||||
`Mongoose` directory and edit the `WIFI_NAME` and `WIFI_PASS` macros.
|
||||
|
||||
## Configure peripherals
|
||||
|
||||
An `.ioc` file is included in this directory for your reference. It was created
|
||||
using the following steps:
|
||||
|
||||
- Open CubeMX. If you are starting a new project, select the STM32U5A5ZJT6Q
|
||||
microcontroller and create a new project.
|
||||
- In Clock Configuration, set the maximum clock frequency to 160 MHz.
|
||||
- In Pinout & Configuration / Connectivity, enable USART1 in asynchronous mode.
|
||||
Configure pins PA9 and PA10 for USART.
|
||||
|
||||
## Wi-Fi module firmware setup
|
||||
|
||||
Before running this project, the correct firmware must be flashed onto the Wi-Fi board.
|
||||
|
||||
Steps:
|
||||
|
||||
1. Install the X-CUBE-ST67W61 package.
|
||||
|
||||
Open `STM32CubeMX`, then navigate to:
|
||||
`Help -> Manage embedded software packages`.
|
||||
|
||||
In the `STMicroelectronics` tab, locate `X-CUBE-ST67W61`.
|
||||
Select the latest version and click `Install`.
|
||||
|
||||
2. Connect the X-NUCLEO-67W61M1 board to the Nucleo-U5A5ZJ-Q board using the
|
||||
Arduino connectors CN7, CN8, CN9 and CN10.
|
||||
|
||||
See Figure 5 in the Wi-Fi board
|
||||
[user manual](https://www.st.com/resource/en/user_manual/um3475-getting-started-with-xcubest67w61-stmicroelectronics.pdf)
|
||||
for the connector layout.
|
||||
|
||||
3. Program the firmware to the ST67W61 module.
|
||||
|
||||
Connect the Nucleo board to your PC using a USB cable.
|
||||
|
||||
Navigate to the STM32Cube repository directory. The installed package is located at:
|
||||
|
||||
`Packs/STMicroelectronics/X-CUBE-ST67W61/<version>/`
|
||||
|
||||
Then navigate to:
|
||||
|
||||
`<version>/Projects/ST67W6X_Utilities/Binaries`
|
||||
|
||||
Run the appropriate script depending on your operating system:
|
||||
|
||||
- `NCP_update_mission_profile_t02.sh` (Linux)
|
||||
- `NCP_update_mission_profile_t02.bat` (Windows)
|
||||
|
||||
Ensure that `STM32CubeProgrammer` is installed and available in your system `PATH`.
|
||||
|
||||
For more details on the programming process, see Section 4.3 and Table 2 of the
|
||||
Wi-Fi board
|
||||
[user manual](https://www.st.com/resource/en/user_manual/um3475-getting-started-with-xcubest67w61-stmicroelectronics.pdf).
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#define MG_ARCH MG_ARCH_CUBE
|
||||
#define MG_ENABLE_DRIVER_ST67W6 1
|
||||
extern void wifi_setconfig(void *data);
|
||||
#define MG_SET_WIFI_CONFIG(data) wifi_setconfig(data)
|
||||
@@ -0,0 +1,252 @@
|
||||
#MicroXplorer Configuration settings - do not modify
|
||||
CAD.formats=
|
||||
CAD.pinconfig=
|
||||
CAD.provider=
|
||||
CORTEX_M33_NS.userName=CORTEX_M33
|
||||
File.Version=6
|
||||
GPIO.groupedBy=Group By Peripherals
|
||||
KeepUserPlacement=false
|
||||
MMTAppReg1.MEMORYMAP.AP=RW_priv_only
|
||||
MMTAppReg1.MEMORYMAP.AppRegionName=RAM
|
||||
MMTAppReg1.MEMORYMAP.ContextName=CortexM33
|
||||
MMTAppReg1.MEMORYMAP.CoreName=ARM Cortex-M33
|
||||
MMTAppReg1.MEMORYMAP.DefaultDataRegion=true
|
||||
MMTAppReg1.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,DefaultDataRegion,ContextName,Name,AP
|
||||
MMTAppReg1.MEMORYMAP.Name=RAM
|
||||
MMTAppReg1.MEMORYMAP.Size=2555904
|
||||
MMTAppReg1.MEMORYMAP.StartAddress=0x20000000
|
||||
MMTAppReg2.MEMORYMAP.AppRegionName=RAM Reserved Alias Region
|
||||
MMTAppReg2.MEMORYMAP.CoreName=ARM Cortex-M33
|
||||
MMTAppReg2.MEMORYMAP.DefaultDataRegion=false
|
||||
MMTAppReg2.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,DefaultDataRegion,ReservedRegion,Name
|
||||
MMTAppReg2.MEMORYMAP.Name=RAM Reserved Alias Region
|
||||
MMTAppReg2.MEMORYMAP.ReservedRegion=true
|
||||
MMTAppReg2.MEMORYMAP.Size=2555904
|
||||
MMTAppReg2.MEMORYMAP.StartAddress=0x0A000000
|
||||
MMTAppReg3.MEMORYMAP.AP=RO_priv_only
|
||||
MMTAppReg3.MEMORYMAP.AppRegionName=FLASH
|
||||
MMTAppReg3.MEMORYMAP.Cacheability=WTRA
|
||||
MMTAppReg3.MEMORYMAP.ContextName=CortexM33
|
||||
MMTAppReg3.MEMORYMAP.CoreName=ARM Cortex-M33
|
||||
MMTAppReg3.MEMORYMAP.DefaultCodeRegion=true
|
||||
MMTAppReg3.MEMORYMAP.DefaultDataRegion=false
|
||||
MMTAppReg3.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,DefaultDataRegion,MemType,ContextName,Name,AP,Cacheability,DefaultCodeRegion
|
||||
MMTAppReg3.MEMORYMAP.MemType=ROM
|
||||
MMTAppReg3.MEMORYMAP.Name=FLASH
|
||||
MMTAppReg3.MEMORYMAP.Size=4194304
|
||||
MMTAppReg3.MEMORYMAP.StartAddress=0x08000000
|
||||
MMTAppRegionsCount=3
|
||||
MMTConfigApplied=false
|
||||
MMTSectionSuffix=
|
||||
Mcu.CPN=STM32U5A5ZJT6Q
|
||||
Mcu.ContextProject=TrustZoneDisabled
|
||||
Mcu.Family=STM32U5
|
||||
Mcu.IP0=CORTEX_M33_NS
|
||||
Mcu.IP1=LPBAM
|
||||
Mcu.IP2=LPBAMQUEUE
|
||||
Mcu.IP3=MEMORYMAP
|
||||
Mcu.IP4=NVIC
|
||||
Mcu.IP5=PWR
|
||||
Mcu.IP6=RCC
|
||||
Mcu.IP7=RNG
|
||||
Mcu.IP8=SYS
|
||||
Mcu.IP9=USART1
|
||||
Mcu.IPNb=10
|
||||
Mcu.Name=STM32U5A5ZJTxQ
|
||||
Mcu.Package=LQFP144
|
||||
Mcu.Pin0=PA5
|
||||
Mcu.Pin1=PA6
|
||||
Mcu.Pin10=VP_RNG_VS_RNG
|
||||
Mcu.Pin11=VP_SYS_VS_Systick
|
||||
Mcu.Pin12=VP_LPBAM_VS_SIG1
|
||||
Mcu.Pin13=VP_LPBAM_VS_SIG4
|
||||
Mcu.Pin14=VP_MEMORYMAP_VS_MEMORYMAP
|
||||
Mcu.Pin2=PA7
|
||||
Mcu.Pin3=PE11
|
||||
Mcu.Pin4=PE13
|
||||
Mcu.Pin5=PD14
|
||||
Mcu.Pin6=PA9
|
||||
Mcu.Pin7=PA10
|
||||
Mcu.Pin8=VP_LPBAMQUEUE_VS_QUEUE
|
||||
Mcu.Pin9=VP_PWR_VS_SECSignals
|
||||
Mcu.PinsNb=15
|
||||
Mcu.ThirdPartyNb=0
|
||||
Mcu.UserConstants=
|
||||
Mcu.UserName=STM32U5A5ZJTxQ
|
||||
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
|
||||
PA10.Mode=Asynchronous
|
||||
PA10.Signal=USART1_RX
|
||||
PA5.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label
|
||||
PA5.GPIO_Label=SPI_SCK
|
||||
PA5.GPIO_PuPd=GPIO_PULLDOWN
|
||||
PA5.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PA5.Locked=true
|
||||
PA5.Signal=SPI1_SCK
|
||||
PA6.GPIOParameters=GPIO_Speed,GPIO_Label
|
||||
PA6.GPIO_Label=SPI_MISO
|
||||
PA6.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PA6.Locked=true
|
||||
PA6.Signal=SPI1_MISO
|
||||
PA7.GPIOParameters=GPIO_Speed,GPIO_Label
|
||||
PA7.GPIO_Label=SPI_MOSI
|
||||
PA7.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PA7.Locked=true
|
||||
PA7.Signal=SPI1_MOSI
|
||||
PA9.Mode=Asynchronous
|
||||
PA9.Signal=USART1_TX
|
||||
PD14.GPIOParameters=GPIO_Speed,GPIO_Label
|
||||
PD14.GPIO_Label=SPI_CS
|
||||
PD14.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PD14.Locked=true
|
||||
PD14.Signal=GPIO_Output
|
||||
PE11.GPIOParameters=GPIO_Speed,GPIO_Label
|
||||
PE11.GPIO_Label=SPI_CHIP_EN
|
||||
PE11.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PE11.Locked=true
|
||||
PE11.Signal=GPIO_Output
|
||||
PE13.GPIOParameters=GPIO_Label
|
||||
PE13.GPIO_Label=SPI_RDY
|
||||
PE13.Locked=true
|
||||
PE13.Signal=GPIO_Input
|
||||
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=STM32U5A5ZJTxQ
|
||||
ProjectManager.FirmwarePackage=STM32Cube FW_U5 V1.8.0
|
||||
ProjectManager.FreePins=false
|
||||
ProjectManager.FreePinsContext=
|
||||
ProjectManager.HalAssertFull=false
|
||||
ProjectManager.HeapSize=0x10000
|
||||
ProjectManager.KeepUserCode=true
|
||||
ProjectManager.LPBAM.generateCode=
|
||||
ProjectManager.LastFirmware=true
|
||||
ProjectManager.LibraryCopy=1
|
||||
ProjectManager.MainLocation=Core/Src
|
||||
ProjectManager.NoMain=false
|
||||
ProjectManager.PreviousToolchain=STM32CubeIDE
|
||||
ProjectManager.ProjectBuild=false
|
||||
ProjectManager.ProjectFileName=nucleo_u5a5zj_q.ioc
|
||||
ProjectManager.ProjectName=nucleo_u5a5zj_q
|
||||
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_RNG_Init-RNG-false-HAL-true,4-MX_USART1_UART_Init-USART1-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=16000000
|
||||
RCC.ADF1Freq_Value=160000000
|
||||
RCC.AHBFreq_Value=160000000
|
||||
RCC.APB1Freq_Value=160000000
|
||||
RCC.APB1TimFreq_Value=160000000
|
||||
RCC.APB2Freq_Value=160000000
|
||||
RCC.APB2TimFreq_Value=160000000
|
||||
RCC.APB3Freq_Value=160000000
|
||||
RCC.CK48Freq_Value=48000000
|
||||
RCC.CRSFreq_Value=48000000
|
||||
RCC.CortexFreq_Value=160000000
|
||||
RCC.DACFreq_Value=32000
|
||||
RCC.EPOD_VALUE=48000000
|
||||
RCC.FCLKCortexFreq_Value=160000000
|
||||
RCC.FDCANFreq_Value=80000000
|
||||
RCC.FamilyName=M
|
||||
RCC.HCLKFreq_Value=160000000
|
||||
RCC.HSE_VALUE=16000000
|
||||
RCC.HSI48_VALUE=48000000
|
||||
RCC.HSI_VALUE=16000000
|
||||
RCC.I2C1Freq_Value=160000000
|
||||
RCC.I2C2Freq_Value=160000000
|
||||
RCC.I2C3Freq_Value=160000000
|
||||
RCC.I2C4Freq_Value=160000000
|
||||
RCC.I2C5Freq_Value=160000000
|
||||
RCC.I2C6Freq_Value=160000000
|
||||
RCC.IPParameters=ADCFreq_Value,ADF1Freq_Value,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,APB3Freq_Value,CK48Freq_Value,CRSFreq_Value,CortexFreq_Value,DACFreq_Value,EPOD_VALUE,FCLKCortexFreq_Value,FDCANFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2C5Freq_Value,I2C6Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_VALUE,LSIDIV_VALUE,LSI_VALUE,MCO1PinFreq_Value,MDF1Freq_Value,MSIClockRange,MSI_VALUE,OCTOSPIMFreq_Value,PLL1R,PLL2FRACN,PLL2PoutputFreq_Value,PLL2QoutputFreq_Value,PLL2RoutputFreq_Value,PLL3FRACN,PLL3PoutputFreq_Value,PLL3QoutputFreq_Value,PLL3RoutputFreq_Value,PLLFRACN,PLLM,PLLN,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,RNGFreq_Value,SAESFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMCFreq_Value,SPI1Freq_Value,SPI2Freq_Value,SPI3Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBPHYFreq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOPLL2OutputFreq_Value,VCOPLL3OutputFreq_Value
|
||||
RCC.LPTIM2Freq_Value=160000000
|
||||
RCC.LPUART1Freq_Value=160000000
|
||||
RCC.LSCOPinFreq_Value=32000
|
||||
RCC.LSE_VALUE=32768
|
||||
RCC.LSIDIV_VALUE=32000
|
||||
RCC.LSI_VALUE=32000
|
||||
RCC.MCO1PinFreq_Value=160000000
|
||||
RCC.MDF1Freq_Value=160000000
|
||||
RCC.MSIClockRange=RCC_MSIRANGE_0
|
||||
RCC.MSI_VALUE=48000000
|
||||
RCC.OCTOSPIMFreq_Value=160000000
|
||||
RCC.PLL1R=1
|
||||
RCC.PLL2FRACN=0
|
||||
RCC.PLL2PoutputFreq_Value=3096000000
|
||||
RCC.PLL2QoutputFreq_Value=3096000000
|
||||
RCC.PLL2RoutputFreq_Value=3096000000
|
||||
RCC.PLL3FRACN=0
|
||||
RCC.PLL3PoutputFreq_Value=3096000000
|
||||
RCC.PLL3QoutputFreq_Value=3096000000
|
||||
RCC.PLL3RoutputFreq_Value=3096000000
|
||||
RCC.PLLFRACN=0
|
||||
RCC.PLLM=3
|
||||
RCC.PLLN=10
|
||||
RCC.PLLPoutputFreq_Value=80000000
|
||||
RCC.PLLQoutputFreq_Value=80000000
|
||||
RCC.PLLRCLKFreq_Value=160000000
|
||||
RCC.RNGFreq_Value=48000000
|
||||
RCC.SAESFreq_Value=48000000
|
||||
RCC.SAI1Freq_Value=3096000000
|
||||
RCC.SAI2Freq_Value=3096000000
|
||||
RCC.SDMMCFreq_Value=80000000
|
||||
RCC.SPI1Freq_Value=160000000
|
||||
RCC.SPI2Freq_Value=160000000
|
||||
RCC.SPI3Freq_Value=160000000
|
||||
RCC.SYSCLKFreq_VALUE=160000000
|
||||
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
|
||||
RCC.UART4Freq_Value=160000000
|
||||
RCC.UART5Freq_Value=160000000
|
||||
RCC.USART1Freq_Value=160000000
|
||||
RCC.USART2Freq_Value=160000000
|
||||
RCC.USART3Freq_Value=160000000
|
||||
RCC.USART6Freq_Value=160000000
|
||||
RCC.USBPHYFreq_Value=80000000
|
||||
RCC.VCOInput2Freq_Value=48000000
|
||||
RCC.VCOInput3Freq_Value=48000000
|
||||
RCC.VCOInputFreq_Value=16000000
|
||||
RCC.VCOOutputFreq_Value=160000000
|
||||
RCC.VCOPLL2OutputFreq_Value=6192000000
|
||||
RCC.VCOPLL3OutputFreq_Value=6192000000
|
||||
RNG.ClockErrorDetection=RNG_CED_DISABLE
|
||||
RNG.IPParameters=ClockErrorDetection
|
||||
USART1.IPParameters=VirtualMode-Asynchronous
|
||||
USART1.VirtualMode-Asynchronous=VM_ASYNC
|
||||
VP_LPBAMQUEUE_VS_QUEUE.Mode=QUEUEMODE
|
||||
VP_LPBAMQUEUE_VS_QUEUE.Signal=LPBAMQUEUE_VS_QUEUE
|
||||
VP_LPBAM_VS_SIG1.Mode=SmartRun
|
||||
VP_LPBAM_VS_SIG1.Signal=LPBAM_VS_SIG1
|
||||
VP_LPBAM_VS_SIG4.Mode=LPDMA1
|
||||
VP_LPBAM_VS_SIG4.Signal=LPBAM_VS_SIG4
|
||||
VP_MEMORYMAP_VS_MEMORYMAP.Mode=CurAppReg
|
||||
VP_MEMORYMAP_VS_MEMORYMAP.Signal=MEMORYMAP_VS_MEMORYMAP
|
||||
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,133 @@
|
||||
#include "mongoose.h"
|
||||
#include "main.h"
|
||||
|
||||
#define WIFISPI SPI1
|
||||
|
||||
#ifndef WIFI_NAME
|
||||
#define WIFI_NAME ""
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_PASS
|
||||
#define WIFI_PASS ""
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_AP_NAME
|
||||
#define WIFI_AP_NAME "Mongoose"
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_AP_PASS
|
||||
#define WIFI_AP_PASS "mongoose"
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_WIFI_AP
|
||||
#define ENABLE_WIFI_AP 0
|
||||
#endif
|
||||
|
||||
#define BIT(x) (1UL << (x))
|
||||
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
|
||||
|
||||
static inline void spin(volatile uint32_t n) {
|
||||
while (n--)
|
||||
(void)0;
|
||||
}
|
||||
|
||||
static inline void hal_spi_init(SPI_TypeDef *spi, uint16_t div) {
|
||||
(void)spi;
|
||||
uint32_t br = 0; // Baud rate prescaler: div = 2,4,8...256 -> MBR = 0..7
|
||||
while (div > 2)
|
||||
div >>= 1, br++;
|
||||
if (br > 7)
|
||||
br = 7;
|
||||
|
||||
|
||||
CLRSET(RCC->CCIPR1, 3 << 20, 1); // SYSCLK source
|
||||
RCC->APB2ENR |= BIT(12); // SPI1EN
|
||||
spin(100);
|
||||
spi->CR1 = 0; // disable SPI
|
||||
spi->CR1 = SPI_CR1_SSI_Msk; // SSI
|
||||
spi->CFG1 = (7 << SPI_CFG1_DSIZE_Pos) | (br << SPI_CFG1_MBR_Pos); // DSIZE = 8-bit, MBR
|
||||
spi->CFG2 = SPI_CFG2_SSM_Msk | SPI_CFG2_MASTER_Msk;
|
||||
spi->CR1 |= SPI_CR1_SPE_Msk; // Enable SPI
|
||||
spi->CR1 |= SPI_CR1_CSTART_Msk; // Start transfer
|
||||
}
|
||||
|
||||
static inline uint8_t hal_spi_xfer_byte(SPI_TypeDef *spi, uint8_t byte) {
|
||||
(void)spi;
|
||||
while ((spi->SR & SPI_SR_TXP_Msk) == 0)
|
||||
spin(1); // TXP
|
||||
*(volatile uint8_t *) &spi->TXDR = byte;
|
||||
while (((spi->SR & SPI_SR_RXP_Msk) == 0) && ((spi->SR & SPI_SR_RXWNE_Msk) == 0) && ((spi->SR & SPI_SR_RXPLVL_Msk) == 0))
|
||||
spin(1); // RXP
|
||||
uint8_t rx = *(volatile uint8_t *) &spi->RXDR;
|
||||
return rx;
|
||||
}
|
||||
|
||||
static inline void hal_spi_tx_rx(SPI_TypeDef *spi, uint8_t *tx, uint8_t *rx, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t rx_ = hal_spi_xfer_byte(spi, tx ? tx[i] : 0);
|
||||
if (rx) rx[i] = rx_;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool hal_spi_ready(SPI_TypeDef *spi) {
|
||||
(void) spi;
|
||||
return HAL_GPIO_ReadPin(SPI_RDY_GPIO_Port, SPI_RDY_Pin);
|
||||
}
|
||||
|
||||
static inline void hal_spi_select(SPI_TypeDef *spi, bool s) {
|
||||
(void)spi;
|
||||
HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, s);
|
||||
}
|
||||
|
||||
static inline void hal_spi_done(SPI_TypeDef *spi) {
|
||||
while((spi->SR & SPI_SR_TXC_Msk) == 0) spin(1);
|
||||
spi->IFCR = 0xffff; // clear all flags
|
||||
}
|
||||
|
||||
static bool hwspecific_is_ready(void) {
|
||||
return hal_spi_ready(WIFISPI);
|
||||
}
|
||||
|
||||
static void hwspecific_spi_begin(void *arg) {
|
||||
hal_spi_select(WIFISPI, true);
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
static void hwspecific_spi_txn(void *arg, uint8_t *txdata, uint8_t *rxdata, size_t len) {
|
||||
while (len--) {
|
||||
uint8_t rx = hal_spi_xfer_byte(WIFISPI, txdata != NULL ? *txdata++ : 0);
|
||||
if (rxdata != NULL) *rxdata++ = rx;
|
||||
}
|
||||
hal_spi_done(WIFISPI);
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
static void hwspecific_spi_end(void *arg) {
|
||||
hal_spi_select(WIFISPI, false);
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
void hwspecific_spi_init(void) {
|
||||
HAL_GPIO_WritePin(SPI_CHIP_EN_GPIO_Port, SPI_CHIP_EN_Pin, 0);
|
||||
hal_spi_init(WIFISPI, 128); // runs at 1.25MHz (SYS_CLK/128)
|
||||
mg_delayms(10);
|
||||
HAL_GPIO_WritePin(SPI_CHIP_EN_GPIO_Port, SPI_CHIP_EN_Pin, 1);
|
||||
}
|
||||
|
||||
static const struct mg_tcpip_spi spi = {NULL, hwspecific_spi_begin, hwspecific_spi_end, hwspecific_spi_txn};
|
||||
|
||||
void wifi_setconfig(void *data) {
|
||||
struct mg_tcpip_driver_st67w6_data *d = (struct mg_tcpip_driver_st67w6_data *) data;
|
||||
d->wifi.ssid = WIFI_NAME;
|
||||
d->wifi.pass = WIFI_PASS;
|
||||
d->wifi.apssid = WIFI_AP_NAME;
|
||||
d->wifi.appass = WIFI_AP_PASS;
|
||||
d->wifi.apip = MG_IPV4(192, 168, 169, 1);
|
||||
d->wifi.apmask = MG_IPV4(255, 255, 255, 0);
|
||||
d->wifi.security = 0;
|
||||
d->wifi.apsecurity = 0;
|
||||
d->wifi.apchannel = 10;
|
||||
d->wifi.apmode = ENABLE_WIFI_AP;
|
||||
d->spi = (struct mg_tcpip_spi *) &spi;
|
||||
d->is_ready = hwspecific_is_ready;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Environment setup: https://mongoose.ws/documentation/tutorials/tools/
|
||||
|
||||
CFLAGS = -W -Wall -Wextra -Werror -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_u5/Include
|
||||
CFLAGS += -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard
|
||||
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||
|
||||
SOURCES = main.c hal.c wifi.c $(wildcard mongoose/*.c)
|
||||
SOURCES += cmsis_u5/Source/Templates/gcc/startup_stm32u5a5xx.s
|
||||
|
||||
TOP = ../../../..
|
||||
CFLAGS += -I$(TOP)
|
||||
SOURCES += $(TOP)/mongoose.c
|
||||
|
||||
all build: firmware.bin
|
||||
|
||||
firmware.bin: firmware.elf
|
||||
arm-none-eabi-objcopy -O binary $< $@
|
||||
@echo
|
||||
@echo "To flash, run 'make flash', or use STM32CubeProgrammer"
|
||||
|
||||
firmware.elf: cmsis_core cmsis_u5 $(SOURCES) $(wildcard *.h) link.ld Makefile
|
||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
|
||||
flash: firmware.bin
|
||||
STM32_Programmer_CLI -c port=swd -e all -w $< 0x8000000 -hardRst
|
||||
|
||||
cmsis_core:
|
||||
git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
||||
|
||||
cmsis_u5:
|
||||
git clone -q -c advice.detachedHead=false --depth 1 -b v1.4.2 https://github.com/STMicroelectronics/cmsis_device_u5 $@
|
||||
|
||||
clean:
|
||||
rm -rf firmware.*
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) {
|
||||
uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry
|
||||
if (period == 0) return false; // Avoid division by zero
|
||||
if (diff < period) return false; // Period has not elapsed yet
|
||||
*t += (diff / period) * period; // Preserve cadence, skip missed periods
|
||||
return true;
|
||||
}
|
||||
|
||||
static volatile uint64_t s_ticks; // Milliseconds since boot
|
||||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
||||
s_ticks++;
|
||||
}
|
||||
|
||||
uint64_t hal_get_tick(void) {
|
||||
return s_ticks;
|
||||
};
|
||||
|
||||
uint32_t SystemCoreClock = SYS_FREQUENCY;
|
||||
void SystemInit(void) { // Called automatically by startup code
|
||||
hal_system_init(); // Enable FPU
|
||||
hal_clock_init();
|
||||
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
|
||||
}
|
||||
|
||||
void ExitRun0Mode(void) {
|
||||
}
|
||||
|
||||
struct stat;
|
||||
__attribute__((weak)) int _fstat(int fd, struct stat *st) {
|
||||
(void) fd, (void) st;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern unsigned char _end[]; // End of data section, start of heap. See link.ld
|
||||
static unsigned char *s_current_heap_end = _end;
|
||||
|
||||
size_t hal_ram_used(void) {
|
||||
return (size_t) (s_current_heap_end - _end);
|
||||
}
|
||||
|
||||
size_t hal_ram_free(void) {
|
||||
unsigned char endofstack;
|
||||
return (size_t) (&endofstack - s_current_heap_end);
|
||||
}
|
||||
|
||||
void *_sbrk(int incr) {
|
||||
unsigned char *prev_heap;
|
||||
unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256);
|
||||
prev_heap = s_current_heap_end;
|
||||
// Check how much space we got from the heap end to the stack end
|
||||
if (s_current_heap_end + incr > heap_end) return (void *) -1;
|
||||
s_current_heap_end += incr;
|
||||
return prev_heap;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _open(const char *path) {
|
||||
(void) path;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _close(int fd) {
|
||||
(void) fd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _isatty(int fd) {
|
||||
(void) fd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _lseek(int fd, int ptr, int dir) {
|
||||
(void) fd, (void) ptr, (void) dir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _exit(int status) {
|
||||
(void) status;
|
||||
for (;;) asm volatile("BKPT #0");
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _kill(int pid, int sig) {
|
||||
(void) pid, (void) sig;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _getpid(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _write(int fd, char *ptr, int len) {
|
||||
(void) fd, (void) ptr, (void) len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _read(int fd, char *ptr, int len) {
|
||||
(void) fd, (void) ptr, (void) len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _link(const char *a, const char *b) {
|
||||
(void) a, (void) b;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _unlink(const char *a) {
|
||||
(void) a;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _stat(const char *path, struct stat *st) {
|
||||
(void) path, (void) st;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int mkdir(const char *path, int mode) {
|
||||
(void) path, (void) mode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _init(void) {
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// RM0456
|
||||
// https://www.st.com/resource/en/reference_manual/rm0456-stm32u5-series-armbased-32bit-mcus-stmicroelectronics.pdf
|
||||
// https://www.st.com/resource/en/user_manual/um2861-stm32u5-nucleo144-board-mb1549-stmicroelectronics.pdf
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LED_1 PIN('C', 7) // On-board LED pin (green)
|
||||
#define LED_2 PIN('B', 7) // On-board LED pin (blue)
|
||||
#define LED_3 PIN('G', 2) // On-board LED pin (red)
|
||||
#define LED LED_1 // Use green LED for blinking
|
||||
|
||||
#define SPI_RDY PIN('E', 13)
|
||||
#define SPI_CS PIN('D', 14)
|
||||
#define SPI_CHIP_EN PIN('E', 11)
|
||||
|
||||
#ifndef HAL_DEBUG_UART
|
||||
#define HAL_DEBUG_UART USART1
|
||||
#endif
|
||||
#ifndef UART_DEBUG
|
||||
#define UART_DEBUG HAL_DEBUG_UART
|
||||
#endif
|
||||
|
||||
#ifndef WIFISPI
|
||||
#define WIFISPI SPI1
|
||||
#endif
|
||||
|
||||
#include <stm32u5a5xx.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)
|
||||
|
||||
void hal_init(void);
|
||||
size_t hal_ram_free(void);
|
||||
size_t hal_ram_used(void);
|
||||
|
||||
enum {
|
||||
HAL_D1PRE = 1, // actual divisor value
|
||||
HAL_HPRE = 1, // actual divisor value
|
||||
HAL_D2PRE = 1,
|
||||
HAL_D3PRE = 1,
|
||||
};
|
||||
enum { PLL1_M = 1, PLL1_N = 80, PLL1_P = 2, PLL1_Q = 2, PLL1_R = 2 };
|
||||
#define MSIS_FREQUENCY (4 * 1024 * 1024) // 4 Mhz
|
||||
#define SYS_FREQUENCY (MSIS_FREQUENCY * PLL1_N / PLL1_M / PLL1_P / HAL_D1PRE) // 160MHz
|
||||
#define AHB_FREQUENCY (SYS_FREQUENCY / HAL_HPRE)
|
||||
#define APB2_FREQUENCY (AHB_FREQUENCY / HAL_D2PRE)
|
||||
#define APB1_FREQUENCY (AHB_FREQUENCY / HAL_D1PRE)
|
||||
|
||||
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->AHB2ENR1 |= 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 =
|
||||
SYS_FREQUENCY; // Bus frequency. UART1 is on APB2, rest on APB1
|
||||
|
||||
if (uart == USART1)
|
||||
freq = APB2_FREQUENCY, RCC->APB2ENR |= BIT(14);
|
||||
if (uart == USART2)
|
||||
freq = APB1_FREQUENCY, RCC->APB1ENR1 |= BIT(17);
|
||||
if (uart == USART3)
|
||||
freq = APB1_FREQUENCY, RCC->APB1ENR1 |= 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 DEBUGGING
|
||||
CLRSET(RCC->CCIPR2, 7 << 3, 3 << 3); // use HSI for UART1
|
||||
freq = 64000000;
|
||||
#endif
|
||||
|
||||
hal_gpio_init(tx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_HIGH, 0, af);
|
||||
hal_gpio_init(rx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_HIGH, 0, af);
|
||||
uart->CR1 = 0; // Disable this UART
|
||||
uart->BRR = freq / baud; // Set baud rate
|
||||
uart->CR1 = BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE
|
||||
}
|
||||
static inline void hal_uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
|
||||
uart->TDR = byte;
|
||||
while ((uart->ISR & BIT(7)) == 0)
|
||||
spin(1);
|
||||
}
|
||||
static inline void hal_uart_write_buf(USART_TypeDef *uart, char *buf,
|
||||
size_t len) {
|
||||
while (len-- > 0)
|
||||
hal_uart_write_byte(uart, *(uint8_t *)buf++);
|
||||
}
|
||||
static inline int hal_uart_read_ready(USART_TypeDef *uart) {
|
||||
return uart->ISR & BIT(5); // If RXNE bit is set, data is ready
|
||||
}
|
||||
static inline uint8_t hal_uart_read_byte(USART_TypeDef *uart) {
|
||||
return (uint8_t)(uart->RDR & 255);
|
||||
}
|
||||
|
||||
static inline void hal_rng_init(void) {
|
||||
RCC->CCIPR2 |= RCC_CCIPR2_RNGSEL_0; // RNG clock source pll1_q_ck
|
||||
RCC->AHB2ENR1 |= RCC_AHB2ENR1_RNGEN; // Enable RNG clock
|
||||
RNG->CR = RNG_CR_RNGEN; // Enable RNG
|
||||
}
|
||||
|
||||
static inline uint32_t hal_rng_read(void) {
|
||||
while ((RNG->SR & RNG_SR_DRDY) == 0)
|
||||
(void)0;
|
||||
return RNG->DR;
|
||||
}
|
||||
|
||||
#define MG_HAL_DISABLE_ETHERNET 1
|
||||
|
||||
static inline unsigned int hal_ahb_div2prescval(unsigned int div) {
|
||||
if (div == 1)
|
||||
return 0;
|
||||
unsigned int val = 7;
|
||||
while (div >>= 1)
|
||||
++val;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline unsigned int hal_apb_div2prescval(unsigned int div) {
|
||||
if (div <= 1)
|
||||
return 0;
|
||||
unsigned int val = 0;
|
||||
while (div >>= 1)
|
||||
++val;
|
||||
return val + 2;
|
||||
}
|
||||
|
||||
static inline void hal_clock_init(void) {
|
||||
FLASH->ACR |= BIT(8); // prefetch
|
||||
RCC->AHB3ENR |= RCC_AHB3ENR_PWREN;
|
||||
PWR->SVMCR |= PWR_SVMCR_IO2SV; // Enable VDDIO2 supply
|
||||
PWR->UCPDR |= PWR_UCPDR_UCPD_DBDIS; // Disable the internal Pull-Up in Dead
|
||||
// Battery pins of UCPD peripheral
|
||||
PWR->CR3 |= PWR_CR3_REGSEL; // enable SMPS
|
||||
while ((PWR->SVMSR & BIT(1)) == 0)
|
||||
spin(1);
|
||||
if ((PWR->SVMSR & PWR_SVMSR_ACTVOS) != (PWR_VOSR_VOS_0 | PWR_VOSR_VOS_1)) {
|
||||
// control voltage scaling
|
||||
PWR->VOSR |= PWR_VOSR_VOS_0 | PWR_VOSR_VOS_1 | PWR_VOSR_BOOSTEN;
|
||||
while ((PWR->VOSR & PWR_VOSR_VOSRDY) == 0)
|
||||
spin(1);
|
||||
while ((PWR->SVMSR & PWR_SVMSR_ACTVOSRDY) == 0)
|
||||
spin(1);
|
||||
}
|
||||
PWR->DBPR |= PWR_DBPR_DBP; // enable backup access
|
||||
CLRSET(RCC->BDCR, 3 << 3, 0); // RCC_LSEDRIVE_LOW
|
||||
RCC->BDCR |= RCC_BDCR_LSEON; // LSE enable
|
||||
while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0)
|
||||
spin(1);
|
||||
RCC->BDCR |= RCC_BDCR_LSESYSEN; // LSESYS enable
|
||||
while ((RCC->BDCR & RCC_BDCR_LSESYSRDY) == 0)
|
||||
spin(1);
|
||||
PWR->VOSR &= ~PWR_VOSR_BOOSTEN;
|
||||
RCC->CR &= ~BIT(24); // configure PLL1
|
||||
while ((RCC->CR & RCC_CR_PLL1RDY) != 0)
|
||||
spin(1);
|
||||
RCC->PLL1CFGR = BIT(0) | ((PLL1_M - 1) << 8) | BIT(16) | BIT(17) |
|
||||
BIT(18); // source, PLL1_M, enable PLL1_P, PLL1_Q
|
||||
RCC->PLL1DIVR = (PLL1_N - 1) | ((PLL1_P - 1) << 9) | ((PLL1_Q - 1) << 16) |
|
||||
((PLL1_R - 1) << 24);
|
||||
PWR->VOSR |= PWR_VOSR_BOOSTEN;
|
||||
RCC->CR |= BIT(24); // PLL1ON
|
||||
while ((RCC->CR & RCC_CR_PLL1RDY) == 0)
|
||||
spin(1);
|
||||
CLRSET(FLASH->ACR, 0xf, 4); // flash latency 4
|
||||
RCC->CFGR1 |= 3; // set PLL as sysclk source
|
||||
CLRSET(RCC->CFGR2, 0xf, hal_ahb_div2prescval(HAL_HPRE)); // HPRE
|
||||
CLRSET(RCC->CFGR2, 0x70, hal_apb_div2prescval(HAL_D1PRE) << 4); // D1PRE
|
||||
CLRSET(RCC->CFGR2, 0x700, hal_apb_div2prescval(HAL_D2PRE) << 8); // D2PRE
|
||||
CLRSET(RCC->CFGR3, 0x70, hal_apb_div2prescval(HAL_D3PRE) << 4); // D3PRE
|
||||
}
|
||||
|
||||
static inline void hal_system_init(void) {
|
||||
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
||||
__DSB();
|
||||
__ISB();
|
||||
|
||||
SCB->VTOR = FLASH_BASE; // Vector Table Relocation in Internal FLASH
|
||||
}
|
||||
|
||||
static inline void hal_spi_init(SPI_TypeDef *spi, uint16_t div) {
|
||||
(void)spi;
|
||||
uint32_t br = 0; // Baud rate prescaler: div = 2,4,8...256 -> MBR = 0..7
|
||||
while (div > 2)
|
||||
div >>= 1, br++;
|
||||
if (br > 7)
|
||||
br = 7;
|
||||
|
||||
CLRSET(RCC->CCIPR1, 3 << 20, 1); // SYSCLK source
|
||||
RCC->APB2ENR |= BIT(12); // SPI1EN
|
||||
spin(100);
|
||||
hal_gpio_init(PIN('A', 5), HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_DOWN, 5); // SCK
|
||||
hal_gpio_init(PIN('A', 6), HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_NONE, 5); // MISO
|
||||
hal_gpio_init(PIN('A', 7), HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_NONE, 5); // MOSI
|
||||
hal_gpio_output(SPI_CS); // CS
|
||||
hal_gpio_output(SPI_CHIP_EN); // CHIP_EN
|
||||
hal_gpio_input(SPI_RDY); // RDY
|
||||
spi->CR1 = 0; // disable SPI
|
||||
spi->CR1 = SPI_CR1_SSI_Msk; // SSI
|
||||
spi->CFG1 = (7 << SPI_CFG1_DSIZE_Pos) | (br << SPI_CFG1_MBR_Pos); // DSIZE = 8-bit, MBR
|
||||
spi->CFG2 = SPI_CFG2_SSM_Msk | SPI_CFG2_MASTER_Msk;
|
||||
spi->CR1 |= SPI_CR1_SPE_Msk; // Enable SPI
|
||||
spi->CR1 |= SPI_CR1_CSTART_Msk; // Start transfer
|
||||
}
|
||||
|
||||
static inline uint8_t hal_spi_xfer_byte(SPI_TypeDef *spi, uint8_t byte) {
|
||||
(void)spi;
|
||||
while ((spi->SR & SPI_SR_TXP_Msk) == 0)
|
||||
spin(1); // TXP
|
||||
*(volatile uint8_t *) &spi->TXDR = byte;
|
||||
while (((spi->SR & SPI_SR_RXP_Msk) == 0) && ((spi->SR & SPI_SR_RXWNE_Msk) == 0) && ((spi->SR & SPI_SR_RXPLVL_Msk) == 0))
|
||||
spin(1); // RXP
|
||||
uint8_t rx = *(volatile uint8_t *) &spi->RXDR;
|
||||
return rx;
|
||||
}
|
||||
|
||||
static inline void hal_spi_tx_rx(SPI_TypeDef *spi, uint8_t *tx, uint8_t *rx, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t rx_ = hal_spi_xfer_byte(spi, tx ? tx[i] : 0);
|
||||
if (rx) rx[i] = rx_;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool hal_spi_ready(SPI_TypeDef *spi) {
|
||||
(void) spi;
|
||||
return hal_gpio_read(SPI_RDY);
|
||||
}
|
||||
|
||||
static inline void hal_spi_select(SPI_TypeDef *spi, bool s) {
|
||||
(void)spi;
|
||||
hal_gpio_write(SPI_CS, s);
|
||||
}
|
||||
|
||||
static inline void hal_spi_done(SPI_TypeDef *spi) {
|
||||
while((spi->SR & SPI_SR_TXC_Msk) == 0) spin(1);
|
||||
spi->IFCR = 0xffff; // clear all flags
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
ENTRY(Reset_Handler);
|
||||
MEMORY {
|
||||
flash(rx) : ORIGIN = 0x08000000, LENGTH = 4096k
|
||||
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
|
||||
}
|
||||
_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */
|
||||
|
||||
SECTIONS {
|
||||
.vectors : { KEEP(*(.isr_vector)) } > flash
|
||||
.text : { *(.text* .text.*) } > flash
|
||||
.rodata : { *(.rodata*) } > flash
|
||||
|
||||
.data : {
|
||||
_sdata = .;
|
||||
*(.first_data)
|
||||
*(.data SORT(.data.*))
|
||||
*(.iram .iram* .iram.*)
|
||||
_edata = .;
|
||||
} > sram AT > flash
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
.bss : {
|
||||
_sbss = .;
|
||||
*(.bss SORT(.bss.*) COMMON)
|
||||
_ebss = .;
|
||||
} > sram
|
||||
|
||||
. = ALIGN(8);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "hal.h"
|
||||
|
||||
#define DEBUG_UART USART1
|
||||
#define LED1 PIN('C', 7) // On-board LED pin (green)
|
||||
#define LED2 PIN('B', 7) // On-board LED pin (blue)
|
||||
#define LED3 PIN('G', 2) // On-board LED pin (red)
|
||||
|
||||
// Redirect stdout debug output to UART
|
||||
int _write(int fd, char *ptr, int len) {
|
||||
if (fd == 1 || fd == 2) hal_uart_write_buf(DEBUG_UART, ptr, (size_t) len);
|
||||
return len;
|
||||
}
|
||||
|
||||
static void blink_task(void) {
|
||||
static uint64_t blink_timer = 0;
|
||||
if (hal_timer_expired(&blink_timer, 500, hal_get_tick())) {
|
||||
hal_gpio_toggle(LED1);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t mg_millis(void) {
|
||||
return hal_get_tick();
|
||||
}
|
||||
|
||||
bool mg_random(void *buf, size_t len) {
|
||||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
||||
uint32_t r = hal_rng_read();
|
||||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
} else {
|
||||
mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n",
|
||||
hal_get_tick());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
hal_clock_init();
|
||||
hal_rng_init();
|
||||
hal_gpio_output(LED1);
|
||||
hal_gpio_output(LED2);
|
||||
hal_gpio_output(LED3);
|
||||
hal_uart_init(DEBUG_UART, 115200);
|
||||
|
||||
extern void hwspecific_spi_init();
|
||||
hwspecific_spi_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,14 @@
|
||||
#pragma once
|
||||
|
||||
// See https://mongoose.ws/documentation/#build-options
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
||||
#define MG_ENABLE_CUSTOM_RANDOM 1
|
||||
#define MG_ENABLE_DRIVER_ST67W6 1
|
||||
|
||||
// Set your Wi-Fi configuration using a custom function:
|
||||
extern void wifi_setconfig(void *data);
|
||||
#define MG_SET_WIFI_CONFIG(data) wifi_setconfig(data)
|
||||
@@ -0,0 +1,76 @@
|
||||
// SPDX-FileCopyrightText: 2026 Cesanta Software Limited
|
||||
// SPDX-License-Identifier: GPL-2.0-only or commercial
|
||||
// Generated by Mongoose Wizard, https://mongoose.ws/wizard/
|
||||
|
||||
#include "hal.h"
|
||||
#include "mongoose.h"
|
||||
|
||||
#ifndef WIFI_NAME
|
||||
#define WIFI_NAME ""
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_PASS
|
||||
#define WIFI_PASS ""
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_AP_NAME
|
||||
#define WIFI_AP_NAME "Mongoose"
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_AP_PASS
|
||||
#define WIFI_AP_PASS "mongoose"
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_WIFI_AP
|
||||
#define ENABLE_WIFI_AP 1
|
||||
#endif
|
||||
|
||||
static bool hwspecific_is_ready(void) {
|
||||
return hal_gpio_read(SPI_RDY);
|
||||
}
|
||||
|
||||
static void hwspecific_spi_begin(void *arg) {
|
||||
hal_spi_select(WIFISPI, true);
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
static void hwspecific_spi_txn(void *arg, uint8_t *txdata, uint8_t *rxdata, size_t len) {
|
||||
while (len--) {
|
||||
uint8_t rx = hal_spi_xfer_byte(WIFISPI, txdata != NULL ? *txdata++ : 0);
|
||||
if (rxdata != NULL) *rxdata++ = rx;
|
||||
}
|
||||
hal_spi_done(WIFISPI);
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
static void hwspecific_spi_end(void *arg) {
|
||||
hal_spi_select(WIFISPI, false);
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
void hwspecific_spi_init(void) {
|
||||
hal_gpio_output(SPI_CHIP_EN);
|
||||
hal_gpio_write(SPI_CHIP_EN, 0);
|
||||
hal_gpio_input(SPI_RDY);
|
||||
hal_spi_init(WIFISPI, 128); // runs at 1.25MHz (SYS_CLK/128)
|
||||
mg_delayms(10);
|
||||
hal_gpio_write(SPI_CHIP_EN, 1);
|
||||
}
|
||||
|
||||
static const struct mg_tcpip_spi spi = {NULL, hwspecific_spi_begin, hwspecific_spi_end, hwspecific_spi_txn};
|
||||
|
||||
void wifi_setconfig(void *data) {
|
||||
struct mg_tcpip_driver_st67w6_data *d = (struct mg_tcpip_driver_st67w6_data *) data;
|
||||
d->wifi.ssid = WIFI_NAME;
|
||||
d->wifi.pass = WIFI_PASS;
|
||||
d->wifi.apssid = WIFI_AP_NAME;
|
||||
d->wifi.appass = WIFI_AP_PASS;
|
||||
d->wifi.apip = MG_IPV4(192, 168, 169, 1);
|
||||
d->wifi.apmask = MG_IPV4(255, 255, 255, 0);
|
||||
d->wifi.security = 0;
|
||||
d->wifi.apsecurity = 0;
|
||||
d->wifi.apchannel = 10;
|
||||
d->wifi.apmode = ENABLE_WIFI_AP;
|
||||
d->spi = (struct mg_tcpip_spi *) &spi;
|
||||
d->is_ready = hwspecific_is_ready;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
# Portenta H7 Mongoose Integration
|
||||
|
||||
This guide explains how to bring up a production-grade Web UI dashboard on the
|
||||
Portenta H7 board.
|
||||
|
||||
A pre-configured, ready-to-run project zip is available for download at
|
||||
https://mongoose.ws.
|
||||
|
||||
To integrate the Web UI dashboard into an existing CubeMX project, or to create a
|
||||
new project from scratch:
|
||||
|
||||
1. Configure the peripherals (described below).
|
||||
2. Regenerate your project code and integrate Mongoose core by following
|
||||
https://mongoose.ws/docs/guides/stm32-tcpip-stack/.
|
||||
3. Add the Web UI dashboard by following
|
||||
https://mongoose.ws/docs/guides/web-dashboard-guide/.
|
||||
|
||||
Note: to setup your WiFi login credentials, open the `wifi.c` file located in the
|
||||
`Mongoose` directory and edit the `WIFI_NAME` and `WIFI_PASS` macros.
|
||||
|
||||
## Configure peripherals
|
||||
|
||||
An `.ioc` file is included in this directory for your reference. It was created
|
||||
using the following steps:
|
||||
|
||||
- Open CubeMX. If you are starting a new project, select the STM32747XI
|
||||
microcontroller and create a new project.
|
||||
- In Clock Configuration, set the maximum clock frequency to 200 MHz.
|
||||
- In Pinout & Configuration / Connectivity, enable USART1 in asynchronous mode.
|
||||
Configure pins PA9 and PA10 for USART.
|
||||
@@ -0,0 +1,7 @@
|
||||
if(NOT EXISTS mbed/.git)
|
||||
execute_process(COMMAND git clone --depth 1 --no-checkout -b extrapatches-6.17.0 https://github.com/arduino/mbed-os mbed)
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND git -C mbed sparse-checkout set targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD/resources)
|
||||
execute_process(COMMAND git -C mbed checkout)
|
||||
file(TOUCH wiced_resource.h)
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#define MG_ARCH MG_ARCH_CUBE
|
||||
#define MG_ENABLE_DRIVER_CYW_SDIO 1
|
||||
extern void wifi_setconfig(void *data);
|
||||
#define MG_SET_WIFI_CONFIG(data) wifi_setconfig(data)
|
||||
@@ -0,0 +1,406 @@
|
||||
#MicroXplorer Configuration settings - do not modify
|
||||
CAD.formats=
|
||||
CAD.pinconfig=
|
||||
CAD.provider=
|
||||
CortexM4.IPs=BDMA,DMA,FATFS_M4\:I,FREERTOS_M4\:I,IWDG2\:I,MDMA,NVIC2\:I,RCC,USB_DEVICE_M4\:I,USB_HOST_M4\:I,WWDG2\:I,ADC1\:I,DCMI\:I,TIM3\:I,DEBUG,PDM2PCM_M4\:I,PWR,RESMGR_UTILITY,SYS_M4\:I,CORTEX_M4\:I,OPENAMP_M4\:I,VREFBUF,GPIO
|
||||
CortexM7.IPs=BDMA\:I,DMA\:I,FATFS_M7\:I,FREERTOS_M7\:I,IWDG1\:I,MDMA\:I,NVIC1\:I,RCC\:I,USB_DEVICE_M7\:I,USB_HOST_M7\:I,WWDG1\:I,CORTEX_M7\:I,DEBUG\:I,PDM2PCM_M7\:I,PWR\:I,RESMGR_UTILITY\:I,SYS\:I,OPENAMP_M7\:I,VREFBUF\:I,GPIO\:I,RNG\:I,USART1\:I,SDMMC1\:I,MEMORYMAP\:I
|
||||
CortexM7.Pins=PK5,PK6,PK7,PJ1,PJ5
|
||||
File.Version=6
|
||||
GPIO.groupedBy=Group By Peripherals
|
||||
KeepUserPlacement=false
|
||||
MMTAppReg1.MEMORYMAP.AppRegionName=RAM
|
||||
MMTAppReg1.MEMORYMAP.ContextName=CortexM7
|
||||
MMTAppReg1.MEMORYMAP.CoreName=ARM Cortex-M7
|
||||
MMTAppReg1.MEMORYMAP.DefaultDataRegion=true
|
||||
MMTAppReg1.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,DefaultDataRegion,ContextName,Name
|
||||
MMTAppReg1.MEMORYMAP.Name=RAM
|
||||
MMTAppReg1.MEMORYMAP.Size=131072
|
||||
MMTAppReg1.MEMORYMAP.StartAddress=0x20000000
|
||||
MMTAppReg10.MEMORYMAP.AppRegionName=M4 non Shared Region
|
||||
MMTAppReg10.MEMORYMAP.ContextLink=reserved
|
||||
MMTAppReg10.MEMORYMAP.ContextName=CortexM7
|
||||
MMTAppReg10.MEMORYMAP.CoreName=ARM Cortex-M7
|
||||
MMTAppReg10.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,MemType,ContextName,Name,ReservedRegion,ContextLink
|
||||
MMTAppReg10.MEMORYMAP.MemType=ROM
|
||||
MMTAppReg10.MEMORYMAP.Name=M4 non Shared Region
|
||||
MMTAppReg10.MEMORYMAP.ReservedRegion=true
|
||||
MMTAppReg10.MEMORYMAP.Size=1048576
|
||||
MMTAppReg10.MEMORYMAP.StartAddress=0x08100000
|
||||
MMTAppReg2.MEMORYMAP.AppRegionName=ITCMRAM
|
||||
MMTAppReg2.MEMORYMAP.Cacheability=WTRA
|
||||
MMTAppReg2.MEMORYMAP.ContextName=CortexM7
|
||||
MMTAppReg2.MEMORYMAP.CoreName=ARM Cortex-M7
|
||||
MMTAppReg2.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,ContextName,Name,Cacheability
|
||||
MMTAppReg2.MEMORYMAP.Name=ITCMRAM
|
||||
MMTAppReg2.MEMORYMAP.Size=65536
|
||||
MMTAppReg2.MEMORYMAP.StartAddress=0x00000000
|
||||
MMTAppReg3.MEMORYMAP.AppRegionName=RAM_D1
|
||||
MMTAppReg3.MEMORYMAP.ContextLink=shared
|
||||
MMTAppReg3.MEMORYMAP.ContextName=CortexM7
|
||||
MMTAppReg3.MEMORYMAP.CoreName=ARM Cortex-M7
|
||||
MMTAppReg3.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,ContextName,Name,ContextLink
|
||||
MMTAppReg3.MEMORYMAP.Name=RAM_D1
|
||||
MMTAppReg3.MEMORYMAP.Size=524288
|
||||
MMTAppReg3.MEMORYMAP.StartAddress=0x24000000
|
||||
MMTAppReg4.MEMORYMAP.AppRegionName=M7 non Shared Region
|
||||
MMTAppReg4.MEMORYMAP.ContextLink=reserved
|
||||
MMTAppReg4.MEMORYMAP.ContextName=CortexM4
|
||||
MMTAppReg4.MEMORYMAP.CoreName=ARM Cortex-M4
|
||||
MMTAppReg4.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,ContextName,Name,ReservedRegion,ContextLink
|
||||
MMTAppReg4.MEMORYMAP.Name=M7 non Shared Region
|
||||
MMTAppReg4.MEMORYMAP.ReservedRegion=true
|
||||
MMTAppReg4.MEMORYMAP.Size=524288
|
||||
MMTAppReg4.MEMORYMAP.StartAddress=0x24000000
|
||||
MMTAppReg5.MEMORYMAP.AP=RO_priv_only
|
||||
MMTAppReg5.MEMORYMAP.AppRegionName=FLASH
|
||||
MMTAppReg5.MEMORYMAP.Cacheability=WTRA
|
||||
MMTAppReg5.MEMORYMAP.ContextLink=shared
|
||||
MMTAppReg5.MEMORYMAP.ContextName=CortexM7
|
||||
MMTAppReg5.MEMORYMAP.CoreName=ARM Cortex-M7
|
||||
MMTAppReg5.MEMORYMAP.DefaultCodeRegion=true
|
||||
MMTAppReg5.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,MemType,ContextName,Name,AP,Cacheability,DefaultCodeRegion,ISRRegion,RootBootRegion,ContextLink
|
||||
MMTAppReg5.MEMORYMAP.ISRRegion=true
|
||||
MMTAppReg5.MEMORYMAP.MemType=ROM
|
||||
MMTAppReg5.MEMORYMAP.Name=FLASH
|
||||
MMTAppReg5.MEMORYMAP.RootBootRegion=true
|
||||
MMTAppReg5.MEMORYMAP.Size=786432
|
||||
MMTAppReg5.MEMORYMAP.StartAddress=0x08040000
|
||||
MMTAppReg6.MEMORYMAP.AppRegionName=M7 non Shared Region
|
||||
MMTAppReg6.MEMORYMAP.ContextLink=reserved
|
||||
MMTAppReg6.MEMORYMAP.ContextName=CortexM4
|
||||
MMTAppReg6.MEMORYMAP.CoreName=ARM Cortex-M4
|
||||
MMTAppReg6.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,MemType,ContextName,Name,ReservedRegion,ContextLink
|
||||
MMTAppReg6.MEMORYMAP.MemType=ROM
|
||||
MMTAppReg6.MEMORYMAP.Name=M7 non Shared Region
|
||||
MMTAppReg6.MEMORYMAP.ReservedRegion=true
|
||||
MMTAppReg6.MEMORYMAP.Size=786432
|
||||
MMTAppReg6.MEMORYMAP.StartAddress=0x8040000
|
||||
MMTAppReg7.MEMORYMAP.AppRegionName=RAM
|
||||
MMTAppReg7.MEMORYMAP.Cacheability=NonCacheable
|
||||
MMTAppReg7.MEMORYMAP.ContextLink=shared
|
||||
MMTAppReg7.MEMORYMAP.ContextName=CortexM4
|
||||
MMTAppReg7.MEMORYMAP.CoreName=ARM Cortex-M4
|
||||
MMTAppReg7.MEMORYMAP.DefaultDataRegion=true
|
||||
MMTAppReg7.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,ContextName,Name,Cacheability,DefaultDataRegion,ContextLink
|
||||
MMTAppReg7.MEMORYMAP.Name=RAM
|
||||
MMTAppReg7.MEMORYMAP.Size=294912
|
||||
MMTAppReg7.MEMORYMAP.StartAddress=0x10000000
|
||||
MMTAppReg8.MEMORYMAP.AppRegionName=M4 non Shared Region
|
||||
MMTAppReg8.MEMORYMAP.ContextLink=reserved
|
||||
MMTAppReg8.MEMORYMAP.ContextName=CortexM7
|
||||
MMTAppReg8.MEMORYMAP.CoreName=ARM Cortex-M7
|
||||
MMTAppReg8.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,ContextName,Name,ReservedRegion,ContextLink
|
||||
MMTAppReg8.MEMORYMAP.Name=M4 non Shared Region
|
||||
MMTAppReg8.MEMORYMAP.ReservedRegion=true
|
||||
MMTAppReg8.MEMORYMAP.Size=294912
|
||||
MMTAppReg8.MEMORYMAP.StartAddress=0x10000000
|
||||
MMTAppReg9.MEMORYMAP.AP=RO_priv_only
|
||||
MMTAppReg9.MEMORYMAP.AppRegionName=FLASH
|
||||
MMTAppReg9.MEMORYMAP.Cacheability=NonCacheable
|
||||
MMTAppReg9.MEMORYMAP.ContextLink=shared
|
||||
MMTAppReg9.MEMORYMAP.ContextName=CortexM4
|
||||
MMTAppReg9.MEMORYMAP.CoreName=ARM Cortex-M4
|
||||
MMTAppReg9.MEMORYMAP.DefaultCodeRegion=true
|
||||
MMTAppReg9.MEMORYMAP.IPParameters=StartAddress,Size,CoreName,MemType,ContextName,Name,AP,Cacheability,DefaultCodeRegion,ISRRegion,RootBootRegion,ContextLink
|
||||
MMTAppReg9.MEMORYMAP.ISRRegion=true
|
||||
MMTAppReg9.MEMORYMAP.MemType=ROM
|
||||
MMTAppReg9.MEMORYMAP.Name=FLASH
|
||||
MMTAppReg9.MEMORYMAP.RootBootRegion=true
|
||||
MMTAppReg9.MEMORYMAP.Size=1048576
|
||||
MMTAppReg9.MEMORYMAP.StartAddress=0x08100000
|
||||
MMTAppRegionsCount=10
|
||||
MMTConfigApplied=false
|
||||
MMTProjectManagerApplied=true
|
||||
MMTSectionSuffix=
|
||||
Mcu.CPN=STM32H747XIH6
|
||||
Mcu.Context0=CortexM7
|
||||
Mcu.Context1=CortexM4
|
||||
Mcu.ContextNb=2
|
||||
Mcu.Family=STM32H7
|
||||
Mcu.IP0=CORTEX_M4
|
||||
Mcu.IP1=CORTEX_M7
|
||||
Mcu.IP2=MEMORYMAP
|
||||
Mcu.IP3=NVIC1
|
||||
Mcu.IP4=NVIC2
|
||||
Mcu.IP5=RCC
|
||||
Mcu.IP6=RNG
|
||||
Mcu.IP7=SYS
|
||||
Mcu.IP8=SYS_M4
|
||||
Mcu.IP9=USART1
|
||||
Mcu.IPNb=10
|
||||
Mcu.Name=STM32H747XIHx
|
||||
Mcu.Package=TFBGA240
|
||||
Mcu.Pin0=PK5
|
||||
Mcu.Pin1=PC10
|
||||
Mcu.Pin10=PC8
|
||||
Mcu.Pin11=PC9
|
||||
Mcu.Pin12=PH0-OSC_IN (PH0)
|
||||
Mcu.Pin13=PJ1
|
||||
Mcu.Pin14=PJ5
|
||||
Mcu.Pin15=VP_RNG_VS_RNG
|
||||
Mcu.Pin16=VP_SYS_VS_Systick
|
||||
Mcu.Pin17=VP_SYS_M4_VS_Systick
|
||||
Mcu.Pin18=VP_MEMORYMAP_VS_MEMORYMAP
|
||||
Mcu.Pin2=PC11
|
||||
Mcu.Pin3=PC14-OSC32_IN (OSC32_IN)
|
||||
Mcu.Pin4=PK6
|
||||
Mcu.Pin5=PC12
|
||||
Mcu.Pin6=PK7
|
||||
Mcu.Pin7=PD2
|
||||
Mcu.Pin8=PA10
|
||||
Mcu.Pin9=PA9
|
||||
Mcu.PinsNb=19
|
||||
Mcu.ThirdPartyNb=0
|
||||
Mcu.UserConstants=
|
||||
Mcu.UserName=STM32H747XIHx
|
||||
MxCube.Version=6.17.0
|
||||
MxDb.Version=DB.6.0.170
|
||||
NVIC1.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC1.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC1.ForceEnableDMAVector=true
|
||||
NVIC1.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC1.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC1.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC1.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC1.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||
NVIC1.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC1.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false
|
||||
NVIC1.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC2.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC2.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC2.ForceEnableDMAVector=true
|
||||
NVIC2.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC2.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC2.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC2.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC2.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||
NVIC2.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC2.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false
|
||||
NVIC2.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
PA10.GPIOParameters=GPIO_Label,PinAttribute
|
||||
PA10.GPIO_Label=USART1_RX
|
||||
PA10.Locked=true
|
||||
PA10.Mode=Asynchronous
|
||||
PA10.PinAttribute=CortexM7
|
||||
PA10.Signal=USART1_RX
|
||||
PA9.GPIOParameters=GPIO_Label,PinAttribute
|
||||
PA9.GPIO_Label=USART1_TX
|
||||
PA9.Locked=true
|
||||
PA9.Mode=Asynchronous
|
||||
PA9.PinAttribute=CortexM7
|
||||
PA9.Signal=USART1_TX
|
||||
PC10.GPIOParameters=GPIO_PuPd,GPIO_Label,PinAttribute
|
||||
PC10.GPIO_Label=SDIO_D2
|
||||
PC10.GPIO_PuPd=GPIO_PULLUP
|
||||
PC10.Locked=true
|
||||
PC10.PinAttribute=CortexM7
|
||||
PC10.Signal=SDMMC1_D2
|
||||
PC11.GPIOParameters=GPIO_PuPd,GPIO_Label,PinAttribute
|
||||
PC11.GPIO_Label=SDIO_D3
|
||||
PC11.GPIO_PuPd=GPIO_PULLUP
|
||||
PC11.Locked=true
|
||||
PC11.PinAttribute=CortexM7
|
||||
PC11.Signal=SDMMC1_D3
|
||||
PC12.GPIOParameters=GPIO_PuPd,GPIO_Label,PinAttribute
|
||||
PC12.GPIO_Label=SDIO_CLK
|
||||
PC12.GPIO_PuPd=GPIO_PULLUP
|
||||
PC12.Locked=true
|
||||
PC12.PinAttribute=CortexM7
|
||||
PC12.Signal=SDMMC1_CK
|
||||
PC14-OSC32_IN\ (OSC32_IN).GPIOParameters=GPIO_Label,PinAttribute
|
||||
PC14-OSC32_IN\ (OSC32_IN).GPIO_Label=OSC32_IN
|
||||
PC14-OSC32_IN\ (OSC32_IN).Locked=true
|
||||
PC14-OSC32_IN\ (OSC32_IN).Mode=LSE-External-Clock-Source
|
||||
PC14-OSC32_IN\ (OSC32_IN).PinAttribute=CortexM7
|
||||
PC14-OSC32_IN\ (OSC32_IN).Signal=RCC_OSC32_IN
|
||||
PC8.GPIOParameters=GPIO_PuPd,GPIO_Label,PinAttribute
|
||||
PC8.GPIO_Label=SDIO_D0
|
||||
PC8.GPIO_PuPd=GPIO_PULLUP
|
||||
PC8.Locked=true
|
||||
PC8.PinAttribute=CortexM7
|
||||
PC8.Signal=SDMMC1_D0
|
||||
PC9.GPIOParameters=GPIO_PuPd,GPIO_Label,PinAttribute
|
||||
PC9.GPIO_Label=SDIO_D1
|
||||
PC9.GPIO_PuPd=GPIO_PULLUP
|
||||
PC9.Locked=true
|
||||
PC9.PinAttribute=CortexM7
|
||||
PC9.Signal=SDMMC1_D1
|
||||
PD2.GPIOParameters=GPIO_PuPd,GPIO_Label,PinAttribute
|
||||
PD2.GPIO_Label=SDIO_MMC
|
||||
PD2.GPIO_PuPd=GPIO_PULLUP
|
||||
PD2.Locked=true
|
||||
PD2.PinAttribute=CortexM7
|
||||
PD2.Signal=SDMMC1_CMD
|
||||
PH0-OSC_IN\ (PH0).GPIOParameters=GPIO_Label,PinAttribute
|
||||
PH0-OSC_IN\ (PH0).GPIO_Label=OSC25M_IN
|
||||
PH0-OSC_IN\ (PH0).Locked=true
|
||||
PH0-OSC_IN\ (PH0).Mode=HSE-External-Clock-Source
|
||||
PH0-OSC_IN\ (PH0).PinAttribute=Free
|
||||
PH0-OSC_IN\ (PH0).Signal=RCC_OSC_IN
|
||||
PJ1.ContextOwner=CortexM7
|
||||
PJ1.GPIOParameters=GPIO_Label,PinAttribute
|
||||
PJ1.GPIO_Label=PWR
|
||||
PJ1.Locked=true
|
||||
PJ1.PinAttribute=CortexM7
|
||||
PJ1.Signal=GPIO_Output
|
||||
PJ5.ContextOwner=CortexM7
|
||||
PJ5.GPIOParameters=GPIO_Label,PinAttribute
|
||||
PJ5.GPIO_Label=WAKE
|
||||
PJ5.Locked=true
|
||||
PJ5.PinAttribute=CortexM7
|
||||
PJ5.Signal=GPIO_Input
|
||||
PK5.ContextOwner=CortexM7
|
||||
PK5.GPIOParameters=PinState,GPIO_Label,PinAttribute
|
||||
PK5.GPIO_Label=LED R
|
||||
PK5.Locked=true
|
||||
PK5.PinAttribute=CortexM7
|
||||
PK5.PinState=GPIO_PIN_SET
|
||||
PK5.Signal=GPIO_Output
|
||||
PK6.ContextOwner=CortexM7
|
||||
PK6.GPIOParameters=PinState,GPIO_Label,PinAttribute
|
||||
PK6.GPIO_Label=LED G
|
||||
PK6.Locked=true
|
||||
PK6.PinAttribute=CortexM7
|
||||
PK6.PinState=GPIO_PIN_SET
|
||||
PK6.Signal=GPIO_Output
|
||||
PK7.ContextOwner=CortexM7
|
||||
PK7.GPIOParameters=PinState,GPIO_Label,PinAttribute
|
||||
PK7.GPIO_Label=LED B
|
||||
PK7.Locked=true
|
||||
PK7.PinAttribute=CortexM7
|
||||
PK7.PinState=GPIO_PIN_SET
|
||||
PK7.Signal=GPIO_Output
|
||||
PinOutPanel.CurrentBGAView=Top
|
||||
PinOutPanel.RotationAngle=0
|
||||
ProjectManager.AskForMigrate=true
|
||||
ProjectManager.BackupPrevious=false
|
||||
ProjectManager.BootMode=boot0
|
||||
ProjectManager.CompilerLinker=GCC
|
||||
ProjectManager.CompilerOptimize=6
|
||||
ProjectManager.ComputerToolchain=false
|
||||
ProjectManager.CoupleFile=false
|
||||
ProjectManager.CustomerFirmwarePackage=
|
||||
ProjectManager.DefaultFWLocation=true
|
||||
ProjectManager.DeletePrevious=true
|
||||
ProjectManager.DeviceId=STM32H747XIHx
|
||||
ProjectManager.FirmwarePackage=STM32Cube FW_H7 V1.13.0
|
||||
ProjectManager.FreePins=false
|
||||
ProjectManager.FreePinsContext=CortexM7
|
||||
ProjectManager.HalAssertFull=false
|
||||
ProjectManager.HeapSize=M4-0x200,M7-0x10000
|
||||
ProjectManager.KeepUserCode=true
|
||||
ProjectManager.LastFirmware=true
|
||||
ProjectManager.LibraryCopy=1
|
||||
ProjectManager.MainLocation=Core/Src
|
||||
ProjectManager.NoMain=false
|
||||
ProjectManager.PreviousToolchain=STM32CubeIDE
|
||||
ProjectManager.ProjectBuild=false
|
||||
ProjectManager.ProjectFileName=portenta_h7.ioc
|
||||
ProjectManager.ProjectName=portenta_h7
|
||||
ProjectManager.ProjectStructure=M7\:CortexM7 Project\:true;M4\:CortexM4 Project\:true;
|
||||
ProjectManager.RegisterCallBack=
|
||||
ProjectManager.StackSize=M4-0x400,M7-0x2000
|
||||
ProjectManager.TargetToolchain=CMake
|
||||
ProjectManager.ToolChainLocation=
|
||||
ProjectManager.UAScriptAfterPath=
|
||||
ProjectManager.UAScriptBeforePath=
|
||||
ProjectManager.UnderRoot=false
|
||||
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false-CortexM7,2-MX_GPIO_Init-GPIO-false-HAL-true-CortexM7,3-MX_USART1_UART_Init-USART1-false-HAL-true-CortexM7,4-MX_RNG_Init-RNG-false-HAL-true-CortexM7,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true-CortexM7,0-MX_CORTEX_M4_Init-CORTEX_M4-false-HAL-true-CortexM4
|
||||
RCC.ADCFreq_Value=80000000
|
||||
RCC.AHB12Freq_Value=200000000
|
||||
RCC.AHB4Freq_Value=200000000
|
||||
RCC.APB1Freq_Value=100000000
|
||||
RCC.APB2Freq_Value=100000000
|
||||
RCC.APB3Freq_Value=100000000
|
||||
RCC.APB4Freq_Value=100000000
|
||||
RCC.AXIClockFreq_Value=200000000
|
||||
RCC.CECFreq_Value=32000
|
||||
RCC.CKPERFreq_Value=64000000
|
||||
RCC.CPU2Freq_Value=200000000
|
||||
RCC.CPU2SystikFreq_Value=200000000
|
||||
RCC.CortexFreq_Value=400000000
|
||||
RCC.CpuClockFreq_Value=400000000
|
||||
RCC.D1CPREFreq_Value=400000000
|
||||
RCC.D1PPRE=RCC_APB3_DIV2
|
||||
RCC.D2PPRE1=RCC_APB1_DIV2
|
||||
RCC.D2PPRE2=RCC_APB2_DIV2
|
||||
RCC.D3PPRE=RCC_APB4_DIV2
|
||||
RCC.DFSDMACLkFreq_Value=200000000
|
||||
RCC.DFSDMFreq_Value=100000000
|
||||
RCC.DIVM1=4
|
||||
RCC.DIVM2=4
|
||||
RCC.DIVN1=50
|
||||
RCC.DIVN2=10
|
||||
RCC.DIVP1Freq_Value=400000000
|
||||
RCC.DIVP2Freq_Value=80000000
|
||||
RCC.DIVP3Freq_Value=129000000
|
||||
RCC.DIVQ1=4
|
||||
RCC.DIVQ1Freq_Value=200000000
|
||||
RCC.DIVQ2Freq_Value=80000000
|
||||
RCC.DIVQ3Freq_Value=129000000
|
||||
RCC.DIVR1Freq_Value=400000000
|
||||
RCC.DIVR2Freq_Value=80000000
|
||||
RCC.DIVR3Freq_Value=129000000
|
||||
RCC.DSIFreq_Value=62500000
|
||||
RCC.DSITXEscFreq_Value=15625000
|
||||
RCC.FDCANFreq_Value=200000000
|
||||
RCC.FMCFreq_Value=200000000
|
||||
RCC.FamilyName=M
|
||||
RCC.HCLK3ClockFreq_Value=200000000
|
||||
RCC.HCLKFreq_Value=200000000
|
||||
RCC.HPRE=RCC_HCLK_DIV2
|
||||
RCC.HRTIMFreq_Value=200000000
|
||||
RCC.I2C123Freq_Value=100000000
|
||||
RCC.I2C4Freq_Value=100000000
|
||||
RCC.IPParameters=ADCFreq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1Freq_Value,APB2Freq_Value,APB3Freq_Value,APB4Freq_Value,AXIClockFreq_Value,CECFreq_Value,CKPERFreq_Value,CPU2Freq_Value,CPU2SystikFreq_Value,CortexFreq_Value,CpuClockFreq_Value,D1CPREFreq_Value,D1PPRE,D2PPRE1,D2PPRE2,D3PPRE,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVN1,DIVN2,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3Freq_Value,DIVQ1,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVR1Freq_Value,DIVR2Freq_Value,DIVR3Freq_Value,DSIFreq_Value,DSITXEscFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLKFreq_Value,HPRE,HRTIMFreq_Value,I2C123Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPUART1Freq_Value,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,PLL2FRACN,PLLDSIVCOFreq_Value,PLLFRACN,PWR_Regulator_Voltage_Scale,QSPIFreq_Value,RNGFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI23Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SPI123Freq_Value,SPI45Freq_Value,SPI6Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,SupplySource,Tim1OutputFreq_Value,Tim2OutputFreq_Value,TraceFreq_Value,USART16Freq_Value,USART234578Freq_Value,USBFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value
|
||||
RCC.LPTIM1Freq_Value=100000000
|
||||
RCC.LPTIM2Freq_Value=100000000
|
||||
RCC.LPTIM345Freq_Value=100000000
|
||||
RCC.LPUART1Freq_Value=100000000
|
||||
RCC.LTDCFreq_Value=129000000
|
||||
RCC.MCO1PinFreq_Value=64000000
|
||||
RCC.MCO2PinFreq_Value=400000000
|
||||
RCC.PLL2FRACN=0
|
||||
RCC.PLLDSIVCOFreq_Value=1000000000
|
||||
RCC.PLLFRACN=0
|
||||
RCC.PWR_Regulator_Voltage_Scale=PWR_REGULATOR_VOLTAGE_SCALE1
|
||||
RCC.QSPIFreq_Value=200000000
|
||||
RCC.RNGFreq_Value=48000000
|
||||
RCC.RTCFreq_Value=32000
|
||||
RCC.SAI1Freq_Value=200000000
|
||||
RCC.SAI23Freq_Value=200000000
|
||||
RCC.SAI4AFreq_Value=200000000
|
||||
RCC.SAI4BFreq_Value=200000000
|
||||
RCC.SDMMCFreq_Value=200000000
|
||||
RCC.SPDIFRXFreq_Value=200000000
|
||||
RCC.SPI123Freq_Value=200000000
|
||||
RCC.SPI45Freq_Value=100000000
|
||||
RCC.SPI6Freq_Value=100000000
|
||||
RCC.SWPMI1Freq_Value=100000000
|
||||
RCC.SYSCLKFreq_VALUE=400000000
|
||||
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
|
||||
RCC.SupplySource=PWR_DIRECT_SMPS_SUPPLY
|
||||
RCC.Tim1OutputFreq_Value=200000000
|
||||
RCC.Tim2OutputFreq_Value=200000000
|
||||
RCC.TraceFreq_Value=64000000
|
||||
RCC.USART16Freq_Value=100000000
|
||||
RCC.USART234578Freq_Value=100000000
|
||||
RCC.USBFreq_Value=200000000
|
||||
RCC.VCO1OutputFreq_Value=800000000
|
||||
RCC.VCO2OutputFreq_Value=160000000
|
||||
RCC.VCO3OutputFreq_Value=258000000
|
||||
RCC.VCOInput1Freq_Value=16000000
|
||||
RCC.VCOInput2Freq_Value=16000000
|
||||
RCC.VCOInput3Freq_Value=2000000
|
||||
USART1.IPParameters=VirtualMode-Asynchronous
|
||||
USART1.VirtualMode-Asynchronous=VM_ASYNC
|
||||
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_M4_VS_Systick.Mode=SysTick
|
||||
VP_SYS_M4_VS_Systick.Signal=SYS_M4_VS_Systick
|
||||
VP_SYS_VS_Systick.Mode=SysTick
|
||||
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
|
||||
board=STM32H747I-DISCO
|
||||
boardIOC=true
|
||||
@@ -0,0 +1,153 @@
|
||||
#include "mongoose.h"
|
||||
#include "main.h"
|
||||
|
||||
typedef enum {RESOURCE_IN_MEMORY,RESOURCE_IN_EXTERNAL_STORAGE} resource_location_t;
|
||||
typedef struct {resource_location_t l;unsigned long sz;union{struct {unsigned long o;const char *f;}fs;struct {const char *m;}mem;}val;} resource_hnd_t;
|
||||
|
||||
#include "resources/firmware/COMPONENT_4343W_FS/4343WA1_clm_blob.c"
|
||||
#include "resources/firmware/COMPONENT_4343W_FS/4343WA1_bin.c"
|
||||
#include "resources/nvram/wifi_nvram_image.h"
|
||||
|
||||
#ifndef WIFI_NAME
|
||||
#define WIFI_NAME ""
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_PASS
|
||||
#define WIFI_PASS ""
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_AP_NAME
|
||||
#define WIFI_AP_NAME "Mongoose"
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_AP_PASS
|
||||
#define WIFI_AP_PASS "mongoose"
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_WIFI_AP
|
||||
#define ENABLE_WIFI_AP 0
|
||||
#endif
|
||||
|
||||
// - 58.4 Table 473
|
||||
// - 58.5.8 AHB bw >= 3x SDMMC bus bw; Table 492; SD HS => AHB >= ~20MHz
|
||||
// - SDIO 2.0 section 3.1
|
||||
static inline void sdmmc_set_ds(void) { // NO FLOW CONTROL ??? REALLY ??? *******************************
|
||||
MG_SET_BITS(SDMMC1->CLKCR, (1 << 17) | 0x3ff, (1 << 14) | ((200000000 / (2 * 25000000)) & 0x3ff)); // 4-bit bus, 25MHz
|
||||
}
|
||||
static inline void sdmmc_set_hs(void) { // mbed enables flow control... AIROC does not
|
||||
MG_SET_BITS(SDMMC1->CLKCR, 0x3ff, (1 << 17) | (1 << 14) | ((200000000 / (2 * 50000000)) & 0x3ff)); // hw flow control, 4-bit bus, 50MHz
|
||||
}
|
||||
static inline void sdmmc_init(void) {
|
||||
RCC->AHB3RSTR |= MG_BIT(16); // Reset SDIO block
|
||||
RCC->AHB3RSTR &= ~MG_BIT(16);
|
||||
RCC->D1CCIPR &= ~MG_BIT(16); // 9.7.18, use PLL1Q
|
||||
RCC->AHB3ENR |= MG_BIT(16); // Enable SDIO clock
|
||||
// SDIO pins initialized by Cube; Portenta H7 doesn't pull-up the SDIO bus
|
||||
// 1-bit bus, rising edge, clock always on, no flow control, 400KHz
|
||||
SDMMC1->CLKCR = (200000000 / (2 * 400000)) & 0x3ff;
|
||||
SDMMC1->POWER |= 3 << 0; // SDMMC_POWER_PWRCTRL
|
||||
SDMMC1->DCTRL = MG_BIT(10); // Read Wait control by stopping SDMMCCLK
|
||||
// wait 74 clocks (~200us) before accessing the "card"
|
||||
}
|
||||
|
||||
static inline bool sdmmc_transact(uint8_t cmd, uint32_t arg, uint32_t *resp) {
|
||||
unsigned int wresp = (resp != NULL) ? 1 : 0; // 58.10.4: 2-bit; cmds used
|
||||
uint32_t cmdr = MG_BIT(12) | (wresp << 8) | ((cmd & 0x3f) << 0); // CPSMEN
|
||||
SDMMC1->ARG = arg;
|
||||
MG_SET_BITS(SDMMC1->CMD, 0x00011f3f /* CMDSUSPEND CPSMEN WAITPEND WAITINT WAITRESP CMD */, cmdr);
|
||||
if (wresp == 0) {
|
||||
while ((SDMMC1->STA & SDMMC_STA_CMDSENT) == 0) (void)0;
|
||||
SDMMC1->ICR = 0x002000C5; // BUSYD0END CMDSENT CMDREND CTIMEOUT CCRCFAIL
|
||||
return true;
|
||||
}
|
||||
//while ((SDMMC1->STA & 0x00200045 /*BUSYD0END CMDREND CTIMEOUT CCRCFAIL*/) == 0 || SDMMC1->STA & SDMMC_STA_CPSMACT) spin(1);
|
||||
while (SDMMC1->STA & SDMMC_STA_CPSMACT) (void)0;
|
||||
bool res = (SDMMC1->STA & 0x00200005 /*BUSYD0END CTIMEOUT CCRCFAIL*/) == 0;
|
||||
SDMMC1->ICR = 0x002000C5; // BUSYD0END CMDSENT CMDREND CTIMEOUT CCRCFAIL
|
||||
*resp = SDMMC1->RESP1;
|
||||
if (!res || SDMMC1->RESPCMD != cmd) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline unsigned int _log2(uint16_t x) {
|
||||
unsigned int i = 0;
|
||||
while (x != 0) x = ((uint16_t)x) >> 1, ++i;
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
static inline bool sdmmc_transfer(bool write, uint32_t arg, uint16_t blksz, uint32_t *data, uint32_t length, uint32_t *resp) {
|
||||
uint32_t cmdr = MG_BIT(12) | (1 << 8) | (53 << 0); // CPSMEN WRESP CMD=53
|
||||
bool bmode = (blksz != 0);
|
||||
uint8_t dblksz = bmode ? (uint8_t)_log2(blksz) : 0;
|
||||
uint32_t dctrlr = (dblksz << 4) | (bmode ? (0 << 2) : (1 << 2)) | (write ? 0 : MG_BIT(1)); // DBLOCKSIZE=f(blksz) DTMODE=f(bmode) DTDIR=!write !DTEN
|
||||
SDMMC1->DCTRL = SDMMC_DCTRL_RWMOD;
|
||||
SDMMC1->IDMACTRL = SDMMC_IDMA_IDMAEN; // single buffer
|
||||
SDMMC1->IDMABASE0 = (uint32_t)data;
|
||||
SDMMC1->DTIMER = (uint32_t) 50000000; // 58.10.7, set for 1 sec @50MHz (2 secs @25MHz)
|
||||
SDMMC1->DLEN = length; // 58.10.8 call with a multiple of blksz (we do)
|
||||
MG_SET_BITS(SDMMC1->DCTRL, 0xff /* DBLOCKSIZE DTMODE DTDIR DTEN */, dctrlr);
|
||||
SDMMC1->CMD = SDMMC_CMD_CMDTRANS; // CPSM will perform a data transfer
|
||||
SDMMC1->ARG = arg;
|
||||
SDMMC1->CMD |= cmdr; // other flags cleared above
|
||||
while ((SDMMC1->STA & 0x0020003f) == 0 && SDMMC1->STA & SDMMC_STA_DPSMACT)
|
||||
(void) 0; // incorrect "card" usage will stall here
|
||||
bool res = (SDMMC1->STA & 0x0020003f /* BUSYD0END RXOVERR TXUNDERR DTIMEOUT CTIMEOUT DCRCFAIL CCRCFAIL */) == 0;
|
||||
SDMMC1->CMD = 0;
|
||||
SDMMC1->DLEN = 0;
|
||||
SDMMC1->IDMACTRL = 0;
|
||||
SDMMC1->ICR = (uint32_t) ~0; // clear all flags
|
||||
*resp = SDMMC1->RESP1;
|
||||
SDMMC1->DCTRL = SDMMC_DCTRL_RWMOD;
|
||||
if (!res || SDMMC1->RESPCMD != 53) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void hwspecific_sdio_init(void) {
|
||||
HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, 0);
|
||||
mg_delayms(100);
|
||||
sdmmc_init();
|
||||
mg_delayms(1);
|
||||
HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, 1);
|
||||
mg_delayms(50);
|
||||
}
|
||||
|
||||
void hwspecific_sdio_config(void *sdio, uint8_t cfg) {
|
||||
(void) sdio;
|
||||
if (cfg == 0) return sdmmc_set_ds();
|
||||
if (cfg == 1) return sdmmc_set_hs();
|
||||
}
|
||||
bool hwspecific_sdio_txn(void *sdio, uint8_t cmd, uint32_t arg, uint32_t *resp) {
|
||||
(void) sdio;
|
||||
return sdmmc_transact(cmd, arg, resp);
|
||||
}
|
||||
bool hwspecific_sdio_xfr(void *sdio, bool write, uint32_t arg, uint16_t blksz, uint32_t *data, uint32_t len, uint32_t *resp){
|
||||
(void) sdio;
|
||||
return sdmmc_transfer(write, arg, blksz, data, len, resp);
|
||||
}
|
||||
|
||||
|
||||
static const struct mg_tcpip_sdio sdio = {NULL, hwspecific_sdio_config, hwspecific_sdio_txn, hwspecific_sdio_xfr};
|
||||
|
||||
static const struct mg_tcpip_driver_cyw_firmware fw = {
|
||||
(const uint8_t *)wifi_firmware_image_data, (size_t)sizeof(wifi_firmware_image_data),
|
||||
(const uint8_t *)wifi_nvram_image, (size_t)sizeof(wifi_nvram_image),
|
||||
(const uint8_t *)wifi_firmware_clm_blob_image_data, (size_t)sizeof(wifi_firmware_clm_blob_image_data)};
|
||||
|
||||
|
||||
void wifi_setconfig(void *data) {
|
||||
struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) data;
|
||||
d->bus = (struct mg_tcpip_sdio *) &sdio;
|
||||
d->fw = (struct mg_tcpip_driver_cyw_firmware *)&fw;
|
||||
d->wifi.ssid = WIFI_NAME;
|
||||
d->wifi.pass = WIFI_PASS;
|
||||
d->wifi.apssid = WIFI_AP_NAME;
|
||||
d->wifi.appass = WIFI_AP_PASS;
|
||||
d->wifi.apip = MG_IPV4(192, 168, 111, 1);
|
||||
d->wifi.apmask = MG_IPV4(255, 255, 255, 0);
|
||||
d->wifi.security = 0;
|
||||
d->wifi.apsecurity = 0;
|
||||
d->wifi.apchannel = 10;
|
||||
d->wifi.apmode = ENABLE_WIFI_AP;
|
||||
d->hs = false;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# Environment setup: https://mongoose.ws/documentation/tutorials/tools/
|
||||
|
||||
CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
|
||||
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
|
||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
||||
CFLAGS += -Wno-cast-function-type
|
||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include
|
||||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 -DCORE_CM7
|
||||
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||
|
||||
SOURCES = main.c wifi.c hal.c
|
||||
SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h747xx.s
|
||||
|
||||
TOP = ../../../..
|
||||
CFLAGS += -I$(TOP)
|
||||
SOURCES += $(TOP)/mongoose.c
|
||||
|
||||
# Wi-Fi chip firmware stuff
|
||||
CFLAGS += -Imbed/targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD # nvram header includes a text file
|
||||
|
||||
all build: firmware.bin
|
||||
|
||||
all: firmware.bin
|
||||
|
||||
firmware.elf: cmsis_core cmsis_h7 $(SOURCES) mbed $(wildcard *.h) link.ld Makefile
|
||||
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"
|
||||
|
||||
# Wi-Fi chip firmware
|
||||
mbed:
|
||||
git clone --depth 1 --no-checkout -b extrapatches-6.17.0 https://github.com/arduino/mbed-os $@ && cd $@ && git sparse-checkout set targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD/resources && git checkout
|
||||
touch wiced_resource.h
|
||||
|
||||
flash: firmware.bin
|
||||
dfu-util -a 0 -s 0x8040000:leave -D $<
|
||||
|
||||
cmsis_core:
|
||||
git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
||||
|
||||
cmsis_h7:
|
||||
git clone -q -c advice.detachedHead=false --depth 1 -b v1.10.4 https://github.com/STMicroelectronics/cmsis_device_h7 $@
|
||||
|
||||
clean:
|
||||
rm -rf firmware.*
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) {
|
||||
uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry
|
||||
if (period == 0) return false; // Avoid division by zero
|
||||
if (diff < period) return false; // Period has not elapsed yet
|
||||
*t += (diff / period) * period; // Preserve cadence, skip missed periods
|
||||
return true;
|
||||
}
|
||||
|
||||
static volatile uint64_t s_ticks; // Milliseconds since boot
|
||||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
||||
s_ticks++;
|
||||
}
|
||||
|
||||
uint64_t hal_get_tick(void) {
|
||||
return s_ticks;
|
||||
};
|
||||
|
||||
uint32_t SystemCoreClock = SYS_FREQUENCY;
|
||||
void SystemInit(void) { // Called automatically by startup code
|
||||
hal_system_init(); // Enable FPU
|
||||
hal_clock_init();
|
||||
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
|
||||
}
|
||||
|
||||
void ExitRun0Mode(void) {
|
||||
}
|
||||
|
||||
struct stat;
|
||||
__attribute__((weak)) int _fstat(int fd, struct stat *st) {
|
||||
(void) fd, (void) st;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern unsigned char _end[]; // End of data section, start of heap. See link.ld
|
||||
static unsigned char *s_current_heap_end = _end;
|
||||
|
||||
size_t hal_ram_used(void) {
|
||||
return (size_t) (s_current_heap_end - _end);
|
||||
}
|
||||
|
||||
size_t hal_ram_free(void) {
|
||||
unsigned char endofstack;
|
||||
return (size_t) (&endofstack - s_current_heap_end);
|
||||
}
|
||||
|
||||
void *_sbrk(int incr) {
|
||||
unsigned char *prev_heap;
|
||||
unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256);
|
||||
prev_heap = s_current_heap_end;
|
||||
// Check how much space we got from the heap end to the stack end
|
||||
if (s_current_heap_end + incr > heap_end) return (void *) -1;
|
||||
s_current_heap_end += incr;
|
||||
return prev_heap;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _open(const char *path) {
|
||||
(void) path;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _close(int fd) {
|
||||
(void) fd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _isatty(int fd) {
|
||||
(void) fd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _lseek(int fd, int ptr, int dir) {
|
||||
(void) fd, (void) ptr, (void) dir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _exit(int status) {
|
||||
(void) status;
|
||||
for (;;) asm volatile("BKPT #0");
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _kill(int pid, int sig) {
|
||||
(void) pid, (void) sig;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _getpid(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _write(int fd, char *ptr, int len) {
|
||||
(void) fd, (void) ptr, (void) len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _read(int fd, char *ptr, int len) {
|
||||
(void) fd, (void) ptr, (void) len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _link(const char *a, const char *b) {
|
||||
(void) a, (void) b;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _unlink(const char *a) {
|
||||
(void) a;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _stat(const char *path, struct stat *st) {
|
||||
(void) path, (void) st;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int mkdir(const char *path, int mode) {
|
||||
(void) path, (void) mode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _init(void) {
|
||||
}
|
||||
@@ -0,0 +1,509 @@
|
||||
// Copyright (c) 2022-2023 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// RM0399
|
||||
// https://www.st.com/resource/en/reference_manual/rm0399-stm32h745755-and-stm32h747757-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
|
||||
// https://www.st.com/resource/en/datasheet/stm32h747xi.pdf
|
||||
// https://docs.arduino.cc/hardware/portenta-h7/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LED_1 PIN('K', 5) // On-board LED pin (red)
|
||||
#define LED_2 PIN('K', 6) // On-board LED pin (green)
|
||||
#define LED_3 PIN('K', 7) // On-board LED pin (blue)
|
||||
#define LED LED_2 // Use green LED for blinking
|
||||
|
||||
#ifndef HAL_DEBUG_UART
|
||||
#define HAL_DEBUG_UART USART1
|
||||
#endif
|
||||
#ifndef UART_DEBUG
|
||||
#define UART_DEBUG HAL_DEBUG_UART
|
||||
#endif
|
||||
|
||||
#include <stm32h747xx.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)
|
||||
|
||||
void hal_init(void);
|
||||
size_t hal_ram_free(void);
|
||||
size_t hal_ram_used(void);
|
||||
|
||||
// System clock (2.1, Fig 1; 8.5, Fig 45; 8.5.5, Fig 47; 8.5.6, Fig 49)
|
||||
// - This board defaults to work with an SMPS regulator, so:
|
||||
// - SYS_FREQUENCY <= 400 MHz; hclk = SYS_FREQUENCY / HPRE ; hclk <= 200 MHz;
|
||||
// APB clocks <= 100 MHz.
|
||||
// - D1 domain bus matrix (and so flash) runs at hclk frequency. Configure flash
|
||||
// latency (WS) in accordance to hclk freq (4.3.8, Table 17)
|
||||
// - The Ethernet controller is in D2 domain and runs at hclk frequency
|
||||
enum {
|
||||
HAL_D1CPRE = 1, // actual divisor value
|
||||
HAL_HPRE = 2, // actual divisor value
|
||||
HAL_D1PPRE = 4, // register values, divisor value = BIT(value - 3) = / 2
|
||||
HAL_D2PPRE1 = 4,
|
||||
HAL_D2PPRE2 = 4,
|
||||
HAL_D3PPRE = 4
|
||||
};
|
||||
// PLL1_P: odd division factors are not allowed (8.7.13) (according to Cube, '1'
|
||||
// is also an "odd division factor").
|
||||
// Make sure your chip is revision 'V', otherwise set PLL1_N = 400
|
||||
enum { PLL1_HSI = 64, PLL1_M = 32, PLL1_N = 400, PLL1_P = 2, PLL1_Q = 4 };
|
||||
#define SYS_FREQUENCY \
|
||||
((PLL1_HSI * PLL1_N / PLL1_M / PLL1_P / HAL_D1CPRE) * 1000000)
|
||||
// #define SYS_FREQUENCY ((PLL1_HSI / HAL_D1CPRE) * 1000000)
|
||||
// #define SYS_FREQUENCY 64000000
|
||||
#define AHB_FREQUENCY (SYS_FREQUENCY / HAL_HPRE)
|
||||
#define APB2_FREQUENCY (AHB_FREQUENCY / (BIT(HAL_D2PPRE2 - 3)))
|
||||
#define APB1_FREQUENCY (AHB_FREQUENCY / (BIT(HAL_D2PPRE1 - 3)))
|
||||
#define PLL1_Q_FREQUENCY ((PLL1_HSI * PLL1_N / PLL1_M / PLL1_Q) * 1000000)
|
||||
|
||||
static inline void spin(volatile uint32_t n) {
|
||||
while (n--)
|
||||
(void)0;
|
||||
}
|
||||
|
||||
enum {
|
||||
HAL_GPIO_MODE_INPUT,
|
||||
HAL_GPIO_MODE_OUTPUT,
|
||||
HAL_GPIO_MODE_AF,
|
||||
HAL_GPIO_MODE_ANALOG
|
||||
};
|
||||
enum { HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_OTYPE_OPEN_DRAIN };
|
||||
enum {
|
||||
HAL_GPIO_SPEED_LOW,
|
||||
HAL_GPIO_SPEED_MEDIUM,
|
||||
HAL_GPIO_SPEED_HIGH,
|
||||
HAL_GPIO_SPEED_INSANE
|
||||
};
|
||||
enum { HAL_GPIO_PULL_NONE, HAL_GPIO_PULL_UP, HAL_GPIO_PULL_DOWN };
|
||||
|
||||
#define HAL_GPIO(N) ((GPIO_TypeDef *)(0x40000000 + 0x18020000UL + 0x400 * (N)))
|
||||
|
||||
static GPIO_TypeDef *hal_gpio_bank(uint16_t pin) {
|
||||
return HAL_GPIO(PINBANK(pin));
|
||||
}
|
||||
static inline void hal_gpio_toggle(uint16_t pin) {
|
||||
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
|
||||
uint32_t mask = BIT(PINNO(pin));
|
||||
gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0);
|
||||
}
|
||||
static inline int hal_gpio_read(uint16_t pin) {
|
||||
return hal_gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0;
|
||||
}
|
||||
static inline void hal_gpio_write(uint16_t pin, bool val) {
|
||||
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
|
||||
gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16);
|
||||
}
|
||||
static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
||||
uint8_t speed, uint8_t pull, uint8_t af) {
|
||||
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
|
||||
uint8_t n = (uint8_t)(PINNO(pin));
|
||||
RCC->AHB4ENR |= BIT(PINBANK(pin)); // Enable GPIO clock
|
||||
CLRSET(gpio->OTYPER, 1UL << n, ((uint32_t)type) << n);
|
||||
CLRSET(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t)speed) << (n * 2));
|
||||
CLRSET(gpio->PUPDR, 3UL << (n * 2), ((uint32_t)pull) << (n * 2));
|
||||
CLRSET(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4),
|
||||
((uint32_t)af) << ((n & 7) * 4));
|
||||
CLRSET(gpio->MODER, 3UL << (n * 2), ((uint32_t)mode) << (n * 2));
|
||||
}
|
||||
static inline void hal_gpio_input(uint16_t pin) {
|
||||
hal_gpio_init(pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_HIGH, HAL_GPIO_PULL_NONE, 0);
|
||||
}
|
||||
static inline void hal_gpio_output(uint16_t pin) {
|
||||
hal_gpio_init(pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_HIGH, HAL_GPIO_PULL_NONE, 0);
|
||||
}
|
||||
|
||||
// D2 Kernel clock (8.7.21) USART1 defaults to pclk2 (APB2), while USART2,3
|
||||
// default to pclk1 (APB1). Even if using other kernel clocks, the APBx clocks
|
||||
// must be enabled for CPU access, as the kernel clock drives the BRR, not the
|
||||
// APB bus interface
|
||||
static inline void hal_uart_init(USART_TypeDef *uart, unsigned long baud) {
|
||||
uint8_t af = 7; // Alternate function
|
||||
uint16_t rx = 0, tx = 0; // pins
|
||||
uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1
|
||||
|
||||
if (uart == USART1)
|
||||
freq = APB2_FREQUENCY, RCC->APB2ENR |= BIT(4);
|
||||
if (uart == USART2)
|
||||
freq = APB1_FREQUENCY, RCC->APB1LENR |= BIT(17);
|
||||
if (uart == USART3)
|
||||
freq = APB1_FREQUENCY, RCC->APB1LENR |= BIT(18);
|
||||
|
||||
if (uart == USART1)
|
||||
tx = PIN('A', 9), rx = PIN('A', 10);
|
||||
if (uart == USART2)
|
||||
tx = PIN('A', 2), rx = PIN('A', 3);
|
||||
if (uart == USART3)
|
||||
tx = PIN('D', 8), rx = PIN('D', 9);
|
||||
|
||||
#if 1 // CONSTANT BAUD RATE FOR DEBUGGING
|
||||
CLRSET(RCC->D2CCIP2R, 7 << 3, 3 << 3); // use HSI for UART1
|
||||
freq = 64000000;
|
||||
#endif
|
||||
|
||||
hal_gpio_init(tx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_HIGH, 0, af);
|
||||
hal_gpio_init(rx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_HIGH, 0, af);
|
||||
uart->CR1 = 0; // Disable this UART
|
||||
uart->BRR = freq / baud; // Set baud rate
|
||||
uart->CR1 = BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE
|
||||
}
|
||||
static inline void hal_uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
|
||||
uart->TDR = byte;
|
||||
while ((uart->ISR & BIT(7)) == 0)
|
||||
spin(1);
|
||||
}
|
||||
static inline void hal_uart_write_buf(USART_TypeDef *uart, char *buf,
|
||||
size_t len) {
|
||||
while (len-- > 0)
|
||||
hal_uart_write_byte(uart, *(uint8_t *)buf++);
|
||||
}
|
||||
static inline int hal_uart_read_ready(USART_TypeDef *uart) {
|
||||
return uart->ISR & BIT(5); // If RXNE bit is set, data is ready
|
||||
}
|
||||
static inline uint8_t hal_uart_read_byte(USART_TypeDef *uart) {
|
||||
return (uint8_t)(uart->RDR & 255);
|
||||
}
|
||||
|
||||
static inline void hal_rng_init(void) {
|
||||
RCC->D2CCIP2R |= RCC_D2CCIP2R_RNGSEL_0; // RNG clock source pll1_q_ck
|
||||
RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; // Enable RNG clock
|
||||
RNG->CR = RNG_CR_RNGEN; // Enable RNG
|
||||
}
|
||||
|
||||
static inline uint32_t hal_rng_read(void) {
|
||||
while ((RNG->SR & RNG_SR_DRDY) == 0)
|
||||
(void)0;
|
||||
return RNG->DR;
|
||||
}
|
||||
|
||||
// NO Hw pull-ups on PHY RXD0,1,DV; set them to enable autonegotiation
|
||||
static inline void ethernet_init(void) {
|
||||
// Initialise Ethernet. Enable MAC GPIO pins, see schematics
|
||||
uint16_t pins1[] = {PIN('A', 7), PIN('C', 4), PIN('C', 5)};
|
||||
for (size_t i = 0; i < sizeof(pins1) / sizeof(pins1[0]); i++) {
|
||||
hal_gpio_init(pins1[i], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_UP,
|
||||
11); // 11 is the Ethernet function
|
||||
}
|
||||
uint16_t pins2[] = {PIN('A', 1), PIN('A', 2), PIN('C', 1),
|
||||
PIN('G', 11), PIN('G', 12), PIN('G', 13)};
|
||||
for (size_t i = 0; i < sizeof(pins2) / sizeof(pins2[0]); i++) {
|
||||
hal_gpio_init(pins2[i], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_NONE,
|
||||
11); // 11 is the Ethernet function
|
||||
}
|
||||
NVIC_EnableIRQ(ETH_IRQn); // Setup Ethernet IRQ handler
|
||||
CLRSET(SYSCFG->PMCR, 7 << 21, 4 << 21); // Use RMII (13.3.1)
|
||||
RCC->AHB1ENR |= BIT(15) | BIT(16) | BIT(17); // Enable Ethernet clocks
|
||||
}
|
||||
|
||||
static inline char hal_chiprev(void) {
|
||||
uint16_t rev = (uint16_t)(((uint32_t)DBGMCU->IDCODE) >> 16);
|
||||
if (rev == 0x1003)
|
||||
return 'Y';
|
||||
if (rev == 0x2003)
|
||||
return 'V';
|
||||
return '?';
|
||||
}
|
||||
|
||||
static inline unsigned int hal_div2prescval(unsigned int div) {
|
||||
// 0 --> /1; 8 --> /2 ... 11 --> /16; 12 --> /64 ... 15 --> /512
|
||||
if (div == 1)
|
||||
return 0;
|
||||
if (div > 16)
|
||||
div /= 2;
|
||||
unsigned int val = 7;
|
||||
while (div >>= 1)
|
||||
++val;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline unsigned int hal_pllrge(unsigned int f) {
|
||||
unsigned int val = 0;
|
||||
while (f >>= 1)
|
||||
++val;
|
||||
return val - 1;
|
||||
}
|
||||
|
||||
// HSE: 25MHz in PH0; LSE: in PC14; both unused
|
||||
static inline void
|
||||
hal_clock_init(void) { // Called automatically by startup code
|
||||
// Set flash latency. RM section 4.9.1, section 4.3.8 table 16
|
||||
CLRSET(FLASH->ACR, (FLASH_ACR_WRHIGHFREQ_Msk | FLASH_ACR_LATENCY_Msk),
|
||||
FLASH_ACR_LATENCY_2WS | FLASH_ACR_WRHIGHFREQ_1);
|
||||
CLRSET(PWR->CR3, BIT(1), BIT(2)); // select SMPS
|
||||
while ((PWR->CSR1 & BIT(13)) == 0)
|
||||
spin(1); // ACTVOSRDY
|
||||
PWR->D3CR |= BIT(15) | BIT(14); // Select VOS1
|
||||
uint32_t f = PWR->D3CR; // fake read to wait for bus clocking
|
||||
while ((PWR->CSR1 & BIT(13)) == 0)
|
||||
spin(1); // ACTVOSRDY
|
||||
#if 0
|
||||
SYSCFG->PWRCR |= BIT(0); // ODEN for LDO to go 480MHz
|
||||
f = SYSCFG->PWRCR;
|
||||
while ((PWR->CSR1 & BIT(13)) == 0) spin(1); // ACTVOSRDY
|
||||
#endif
|
||||
(void)f;
|
||||
RCC->CFGR &= ~(3 << 0); // Set clock source to HSI (bootloader...)
|
||||
RCC->CR &= ~BIT(24); // Disable PLL1
|
||||
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);
|
||||
// DIVQ1EN DIVP1EN PLL1RGE !PLL1VCOSEL !PLL1FRACEN
|
||||
CLRSET(RCC->PLLCFGR, (3 << 2) | BIT(1) | BIT(0),
|
||||
BIT(17) | BIT(16) | hal_pllrge(PLL1_HSI / PLL1_M) << 2);
|
||||
CLRSET(RCC->PLL1DIVR, (0x7F << 16) | (0x7F << 9) | (0x1FF << 0),
|
||||
((PLL1_Q - 1) << 16) | ((PLL1_P - 1) << 9) | ((PLL1_N - 1) << 0));
|
||||
CLRSET(RCC->PLLCKSELR, (0x3F << 4) | (3 << 0), PLL1_M << 4); // PLL1: HSI/M
|
||||
RCC->CR |= BIT(24); // Enable PLL1
|
||||
while ((RCC->CR & BIT(25)) == 0)
|
||||
spin(1); // Wait until done
|
||||
RCC->CFGR |= (3 << 0); // Set clock source to PLL1
|
||||
while ((RCC->CFGR & (7 << 3)) != (3 << 3))
|
||||
spin(1); // Wait until done
|
||||
RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN; // Enable SYSCFG
|
||||
}
|
||||
|
||||
static inline void hal_system_init(void) {
|
||||
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
||||
SCB_DisableDCache(); // The bootloader enables caches, disable them
|
||||
SCB_DisableICache();
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
|
||||
#define PWRPIN PIN('J', 1)
|
||||
|
||||
// - 58.4 Table 473
|
||||
// - 58.5.8 AHB bw >= 3x SDMMC bus bw; Table 492; SD HS => AHB >= ~20MHz
|
||||
// - SDIO 2.0 section 3.1
|
||||
static inline void hal_sdmmc_set_ds(void) { // NO FLOW CONTROL
|
||||
CLRSET(SDMMC1->CLKCR, (1 << 17) | 0x3ff,
|
||||
(1 << 14) |
|
||||
((PLL1_Q_FREQUENCY / (2 * 25000000)) & 0x3ff)); // 4-bit bus, 25MHz
|
||||
}
|
||||
static inline void
|
||||
hal_sdmmc_set_hs(void) { // mbed enables flow control... AIROC does not
|
||||
CLRSET(SDMMC1->CLKCR, 0x3ff,
|
||||
(1 << 17) | (1 << 14) |
|
||||
((PLL1_Q_FREQUENCY / (2 * 50000000)) &
|
||||
0x3ff)); // hw flow control, 4-bit bus, 50MHz
|
||||
}
|
||||
static inline void hal_sdmmc_init(void) {
|
||||
RCC->AHB3RSTR |= BIT(16); // Reset SDIO block
|
||||
RCC->AHB3RSTR &= ~BIT(16);
|
||||
RCC->D1CCIPR &= ~BIT(16); // 9.7.18, use PLL1Q
|
||||
RCC->AHB3ENR |= BIT(16); // Enable SDIO clock
|
||||
// Initialise SDIO pins, see schematics
|
||||
uint16_t pins[] = {PIN('C', 8), PIN('C', 9), PIN('C', 10),
|
||||
PIN('C', 11), PIN('C', 12), PIN('D', 2)};
|
||||
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
|
||||
// Portenta H7 doesn't pull-up the SDIO bus
|
||||
hal_gpio_init(pins[i], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
||||
HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_UP,
|
||||
12); // 12 is the SDMMC1 (SDIO) function
|
||||
}
|
||||
hal_gpio_input(PIN('J', 5)); // wake, ignored
|
||||
// 1-bit bus, rising edge, clock always on, no flow control, 400KHz
|
||||
SDMMC1->CLKCR = (PLL1_Q_FREQUENCY / (2 * 400000)) & 0x3ff;
|
||||
SDMMC1->POWER |= 3 << 0; // SDMMC_POWER_PWRCTRL
|
||||
SDMMC1->DCTRL = BIT(10); // Read Wait control by stopping SDMMCCLK
|
||||
// wait 74 clocks (~200us) before accessing the "card"
|
||||
}
|
||||
|
||||
static inline bool hal_sdmmc_transact(uint8_t cmd, uint32_t arg,
|
||||
uint32_t *resp) {
|
||||
unsigned int wresp = (resp != NULL) ? 1 : 0; // 58.10.4: 2-bit; cmds used
|
||||
uint32_t cmdr = BIT(12) | (wresp << 8) | ((cmd & 0x3f) << 0); // CPSMEN
|
||||
SDMMC1->ARG = arg;
|
||||
CLRSET(SDMMC1->CMD,
|
||||
0x00011f3f /* CMDSUSPEND CPSMEN WAITPEND WAITINT WAITRESP CMD */,
|
||||
cmdr);
|
||||
if (wresp == 0) {
|
||||
while ((SDMMC1->STA & SDMMC_STA_CMDSENT) == 0)
|
||||
spin(1);
|
||||
SDMMC1->ICR = 0x002000C5; // BUSYD0END CMDSENT CMDREND CTIMEOUT CCRCFAIL
|
||||
return true;
|
||||
}
|
||||
// while ((SDMMC1->STA & 0x00200045 /*BUSYD0END CMDREND CTIMEOUT CCRCFAIL*/)
|
||||
// == 0 || SDMMC1->STA & SDMMC_STA_CPSMACT) spin(1);
|
||||
while (SDMMC1->STA & SDMMC_STA_CPSMACT)
|
||||
spin(1);
|
||||
bool res = (SDMMC1->STA & 0x00200005 /*BUSYD0END CTIMEOUT CCRCFAIL*/) == 0;
|
||||
SDMMC1->ICR = 0x002000C5; // BUSYD0END CMDSENT CMDREND CTIMEOUT CCRCFAIL
|
||||
*resp = SDMMC1->RESP1;
|
||||
if (!res || SDMMC1->RESPCMD != cmd)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline unsigned int hal_log2(uint16_t x) {
|
||||
unsigned int i = 0;
|
||||
while (x != 0)
|
||||
x = ((uint16_t)x) >> 1, ++i;
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
static inline bool hal_sdmmc_transfer(bool write, uint32_t arg, uint16_t blksz,
|
||||
uint32_t *data, uint32_t length,
|
||||
uint32_t *resp) {
|
||||
uint32_t cmdr = BIT(12) | (1 << 8) | (53 << 0); // CPSMEN WRESP CMD=53
|
||||
bool bmode = (blksz != 0);
|
||||
uint8_t dblksz = bmode ? (uint8_t)hal_log2(blksz) : 0;
|
||||
uint32_t dctrlr =
|
||||
(dblksz << 4) | (bmode ? (0 << 2) : (1 << 2)) |
|
||||
(write
|
||||
? 0
|
||||
: BIT(1)); // DBLOCKSIZE=f(blksz) DTMODE=f(bmode) DTDIR=!write !DTEN
|
||||
SDMMC1->DCTRL = SDMMC_DCTRL_RWMOD;
|
||||
SDMMC1->IDMACTRL = SDMMC_IDMA_IDMAEN; // single buffer
|
||||
SDMMC1->IDMABASE0 = (uint32_t)data;
|
||||
SDMMC1->DTIMER = (uint32_t)50000000; // 58.10.7, set for 1 sec @50MHz (2 secs @25MHz)
|
||||
SDMMC1->DLEN = length; // 58.10.8 call with a multiple of blksz (we do)
|
||||
CLRSET(SDMMC1->DCTRL, 0xff /* DBLOCKSIZE DTMODE DTDIR DTEN */, dctrlr);
|
||||
SDMMC1->CMD = SDMMC_CMD_CMDTRANS; // CPSM will perform a data transfer
|
||||
SDMMC1->ARG = arg;
|
||||
SDMMC1->CMD |= cmdr; // other flags cleared above
|
||||
while ((SDMMC1->STA & 0x0020003f) == 0 && SDMMC1->STA & SDMMC_STA_DPSMACT)
|
||||
spin(1); // incorrect "card" usage will stall here
|
||||
bool res = (SDMMC1->STA & 0x0020003f /* BUSYD0END RXOVERR TXUNDERR DTIMEOUT CTIMEOUT DCRCFAIL CCRCFAIL */) == 0;
|
||||
SDMMC1->CMD = 0;
|
||||
SDMMC1->DLEN = 0;
|
||||
SDMMC1->IDMACTRL = 0;
|
||||
SDMMC1->ICR = (uint32_t)~0; // clear all flags
|
||||
*resp = SDMMC1->RESP1;
|
||||
SDMMC1->DCTRL = SDMMC_DCTRL_RWMOD;
|
||||
if (!res || SDMMC1->RESPCMD != 53)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Bit-banged SPI, pin wiring does not allow using a hw SPI peripheral
|
||||
#define CYWSPI NULL
|
||||
#define BBSPI_SPIN 1
|
||||
|
||||
static inline void hal_spi_init(void *spi, uint8_t div) {
|
||||
// Initialise bit-banged SPI, see: schematics; CYW DS 4.1.1 Table 5, 13.7
|
||||
// Table 22
|
||||
hal_gpio_input(PIN('C', 8)); // DO -> MISO
|
||||
hal_gpio_input(PIN('C', 9)); // IRQ -> ignore
|
||||
hal_gpio_output(PIN('C', 10)); // D2 <-- strap for SPI mode
|
||||
hal_gpio_output(PIN('C', 11)); // CS
|
||||
hal_gpio_output(PIN('C', 12)); // SCLK
|
||||
hal_gpio_output(PIN('D', 2)); // DI -> MOSI
|
||||
// select SPI mode at power-on/reset time (not WL_REG_ON, actual POR)
|
||||
// "Sampling occurs a few milliseconds after an internal POR
|
||||
// or deassertion of the external POR
|
||||
hal_gpio_write(PIN('C', 10), 0);
|
||||
hal_gpio_write(PIN('D', 2), 0); // idle values
|
||||
hal_gpio_write(PIN('C', 12), 0);
|
||||
hal_gpio_write(PIN('C', 11), 0); // no power at startup
|
||||
(void)spi;
|
||||
(void)div;
|
||||
}
|
||||
|
||||
static inline void hal_spi_write_byte(void *spi, uint8_t byte) {
|
||||
unsigned int n = 8;
|
||||
while (n--) {
|
||||
hal_gpio_write(PIN('D', 2), byte & 0x80);
|
||||
spin(BBSPI_SPIN);
|
||||
hal_gpio_write(PIN('C', 12), 1);
|
||||
byte <<= 1;
|
||||
spin(BBSPI_SPIN);
|
||||
hal_gpio_write(PIN('C', 12), 0);
|
||||
}
|
||||
hal_gpio_write(PIN('D', 2), 0);
|
||||
(void)spi;
|
||||
}
|
||||
|
||||
static inline uint8_t hal_spi_read_byte(void *spi) {
|
||||
uint8_t byte = 0;
|
||||
unsigned int n = 8;
|
||||
while (n--) {
|
||||
byte <<= 1;
|
||||
spin(BBSPI_SPIN);
|
||||
byte |= hal_gpio_read(PIN('C', 8)) ? 1 : 0;
|
||||
hal_gpio_write(PIN('C', 12), 1);
|
||||
spin(BBSPI_SPIN);
|
||||
hal_gpio_write(PIN('C', 12), 0);
|
||||
}
|
||||
(void)spi;
|
||||
return byte;
|
||||
}
|
||||
|
||||
static inline void hal_spi_select(void *spi, bool s) {
|
||||
hal_gpio_write(PIN('C', 11), !s);
|
||||
(void)spi;
|
||||
}
|
||||
|
||||
// Current bootloader sets all outputs in the PMIC, no need to use I2C.
|
||||
// The bootloader inits I2C1 and chips in there, but we change MCU clock
|
||||
// DS 4 Table 12, schematic PB6,7
|
||||
static inline void hal_i2c_init(I2C_TypeDef *i2c) {
|
||||
CLRSET(RCC->D2CCIP2R, 3 << 12, 2 << 12); // use HSI for I2C1 (64MHz)
|
||||
RCC->APB1LENR |= BIT(21); // enable I2C clock
|
||||
hal_gpio_init(PIN('B', 6), HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_OPEN_DRAIN,
|
||||
HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_NONE, 4);
|
||||
hal_gpio_init(PIN('B', 7), HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_OPEN_DRAIN,
|
||||
HAL_GPIO_SPEED_INSANE, HAL_GPIO_PULL_NONE, 4);
|
||||
i2c->CR1 = 0; // disable before any config change
|
||||
i2c->CR1 = BIT(12); // 50.7 disable filters
|
||||
i2c->TIMINGR = 10U << 28 | 3 << 20 | 2 << 16 | 3 << 8 | 9 << 0; // < 400KHz
|
||||
i2c->CR1 |= BIT(0); // enable after fully configured
|
||||
}
|
||||
|
||||
static inline void hal_i2c_write_reg(I2C_TypeDef *i2c, uint8_t addr,
|
||||
uint8_t reg, uint8_t byte) {
|
||||
i2c->CR2 = BIT(25) | 2 << 16 |
|
||||
addr << 1; // write byte to reg in chip at addr, AUTOEND
|
||||
i2c->CR2 |= BIT(13); // START
|
||||
while ((i2c->ISR & BIT(0)) == 0)
|
||||
spin(1); // TXE
|
||||
i2c->TXDR = reg;
|
||||
while ((i2c->ISR & BIT(0)) == 0)
|
||||
spin(1); // TXE
|
||||
i2c->TXDR = byte;
|
||||
while ((i2c->ISR & BIT(5)) == 0)
|
||||
spin(1); // STOPF
|
||||
i2c->ICR |= BIT(5); // STOPCF, clear STOPF
|
||||
}
|
||||
|
||||
static inline uint8_t hal_i2c_read_reg(I2C_TypeDef *i2c, uint8_t addr,
|
||||
uint8_t reg) {
|
||||
i2c->CR2 = 1 << 16 | addr << 1; // write reg addr to chip at addr
|
||||
i2c->CR2 |= BIT(13); // START
|
||||
while ((i2c->ISR & BIT(0)) == 0)
|
||||
spin(1); // TXE
|
||||
i2c->TXDR = reg;
|
||||
while ((i2c->ISR & BIT(6)) == 0)
|
||||
spin(1); // TC
|
||||
i2c->CR2 = BIT(13) | BIT(10) | 1 << 16 | addr << 1; // read 1 byte, AUTOEND
|
||||
i2c->CR2 |= BIT(25); // START
|
||||
while ((i2c->ISR & BIT(2)) == 0)
|
||||
spin(1); // RXNE
|
||||
uint8_t byte = (uint8_t)i2c->RXDR;
|
||||
while ((i2c->ISR & BIT(5)) == 0)
|
||||
spin(1); // STOPF
|
||||
i2c->ICR |= BIT(5); // STOPCF, clear STOPF
|
||||
return byte;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* DTCMRAM (rwx) : ORIGIN = 0x20000400, LENGTH = 128k - 1k */ /* bootloader starts at 0x20000000 */
|
||||
|
||||
ENTRY(Reset_Handler);
|
||||
MEMORY {
|
||||
flash(rx) : ORIGIN = 0x08040000, LENGTH = 2048k - 0x40000 /* bootloader starts at 0x08000000 */
|
||||
sram(rwx) : ORIGIN = 0x24000000, LENGTH = 512k
|
||||
}
|
||||
_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */
|
||||
|
||||
SECTIONS {
|
||||
.vectors : { KEEP(*(.isr_vector)) } > flash
|
||||
.text : { *(.text* .text.*) } > flash
|
||||
.rodata : { *(.rodata*) } > flash
|
||||
|
||||
.data : {
|
||||
_sdata = .;
|
||||
*(.first_data)
|
||||
*(.data SORT(.data.*))
|
||||
*(.iram .iram* .iram.*)
|
||||
_edata = .;
|
||||
} > sram AT > flash
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
.bss : {
|
||||
_sbss = .;
|
||||
*(.bss SORT(.bss.*) COMMON)
|
||||
_ebss = .;
|
||||
} > sram
|
||||
|
||||
. = ALIGN(8);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "hal.h"
|
||||
|
||||
#define DEBUG_UART USART1
|
||||
#define LED1 PIN('K', 5) // On-board LED pin (red)
|
||||
#define LED2 PIN('K', 6) // On-board LED pin (green)
|
||||
#define LED3 PIN('K', 7) // On-board LED pin (blue)
|
||||
|
||||
// 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);
|
||||
|
||||
extern void hwspecific_sdio_init(void);
|
||||
hwspecific_sdio_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,16 @@
|
||||
#pragma once
|
||||
|
||||
// See https://mongoose.ws/documentation/#build-options
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
||||
#define MG_ENABLE_CUSTOM_RANDOM 1
|
||||
#define MG_ENABLE_DRIVER_CYW_SDIO 1
|
||||
|
||||
// MAC address is read from OTP by the driver
|
||||
|
||||
// Set your Wi-Fi configuration using a custom function:
|
||||
extern void wifi_setconfig(void *data);
|
||||
#define MG_SET_WIFI_CONFIG(data) wifi_setconfig(data)
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-FileCopyrightText: 2025 Cesanta Software Limited
|
||||
// SPDX-License-Identifier: GPL-2.0-only or commercial
|
||||
// Generated by Mongoose Wizard, https://mongoose.ws/wizard/
|
||||
|
||||
#include "hal.h"
|
||||
#include "mongoose.h"
|
||||
|
||||
#ifndef WIFI_NAME
|
||||
#define WIFI_NAME ""
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_PASS
|
||||
#define WIFI_PASS ""
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_AP_NAME
|
||||
#define WIFI_AP_NAME "Mongoose"
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_AP_PASS
|
||||
#define WIFI_AP_PASS "mongoose"
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_WIFI_AP
|
||||
#define ENABLE_WIFI_AP 1
|
||||
#endif
|
||||
|
||||
void hwspecific_sdio_init(void) {
|
||||
hal_gpio_output(PWRPIN);
|
||||
hal_gpio_write(PWRPIN, 0);
|
||||
mg_delayms(100);
|
||||
hal_sdmmc_init();
|
||||
mg_delayms(1);
|
||||
hal_gpio_write(PWRPIN, 1);
|
||||
mg_delayms(50);
|
||||
}
|
||||
|
||||
static void hwspecific_sdio_config(void *sdio, uint8_t cfg) {
|
||||
(void) sdio;
|
||||
if (cfg == 0) return hal_sdmmc_set_ds();
|
||||
if (cfg == 1) return hal_sdmmc_set_hs();
|
||||
}
|
||||
static bool hwspecific_sdio_txn(void *sdio, uint8_t cmd, uint32_t arg, uint32_t *resp) {
|
||||
(void) sdio;
|
||||
return hal_sdmmc_transact(cmd, arg, resp);
|
||||
}
|
||||
static bool hwspecific_sdio_xfr(void *sdio, bool write, uint32_t arg, uint16_t blksz, uint32_t *data, uint32_t len, uint32_t *resp){
|
||||
(void) sdio;
|
||||
return hal_sdmmc_transfer(write, arg, blksz, data, len, resp);
|
||||
}
|
||||
|
||||
static const struct mg_tcpip_sdio sdio = {NULL, hwspecific_sdio_config, hwspecific_sdio_txn, hwspecific_sdio_xfr};
|
||||
|
||||
// clang-format off
|
||||
typedef enum {RESOURCE_IN_MEMORY,RESOURCE_IN_EXTERNAL_STORAGE} resource_location_t;
|
||||
typedef struct {resource_location_t l;unsigned long sz;union{struct {unsigned long o;const char *f;}fs;struct {const char *m;}mem;}val;} resource_hnd_t;
|
||||
#include "mbed/targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD/resources/firmware/COMPONENT_4343W_FS/4343WA1_bin.c"
|
||||
#include "mbed/targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD/resources/firmware/COMPONENT_4343W_FS/4343WA1_clm_blob.c"
|
||||
#include "mbed/targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD/resources/nvram/wifi_nvram_image.h"
|
||||
// clang-format on
|
||||
static const struct mg_tcpip_driver_cyw_firmware fw = {
|
||||
(const uint8_t *)wifi_firmware_image_data, (size_t)sizeof(wifi_firmware_image_data),
|
||||
(const uint8_t *)wifi_nvram_image, (size_t)sizeof(wifi_nvram_image),
|
||||
(const uint8_t *)wifi_firmware_clm_blob_image_data, (size_t)sizeof(wifi_firmware_clm_blob_image_data)};
|
||||
|
||||
void wifi_setconfig(void *data) {
|
||||
struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) data;
|
||||
d->bus = (struct mg_tcpip_sdio *) &sdio;
|
||||
d->fw = (struct mg_tcpip_driver_cyw_firmware *)&fw;
|
||||
d->wifi.ssid = WIFI_NAME;
|
||||
d->wifi.pass = WIFI_PASS;
|
||||
d->wifi.apssid = WIFI_AP_NAME;
|
||||
d->wifi.appass = WIFI_AP_PASS;
|
||||
d->wifi.apip = MG_IPV4(192, 168, 111, 1);
|
||||
d->wifi.apmask = MG_IPV4(255, 255, 255, 0);
|
||||
d->wifi.security = 0;
|
||||
d->wifi.apsecurity = 0;
|
||||
d->wifi.apchannel = 10;
|
||||
d->wifi.apmode = ENABLE_WIFI_AP;
|
||||
d->hs = false;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
# STM32H573I-DK Mongoose Integration
|
||||
|
||||
This guide explains how to bring up a production-grade Web UI dashboard on the
|
||||
STM32H573I-DK development board.
|
||||
|
||||
A pre-configured, ready-to-run project zip is available for download at
|
||||
https://mongoose.ws.
|
||||
|
||||
To integrate the Web UI dashboard into an existing CubeMX project, or to create a
|
||||
new project from scratch:
|
||||
|
||||
1. Configure the peripherals (described below).
|
||||
2. Regenerate your project code and integrate Mongoose core by following
|
||||
https://mongoose.ws/docs/guides/stm32-tcpip-stack/.
|
||||
3. Add the Web UI dashboard by following
|
||||
https://mongoose.ws/docs/guides/web-dashboard-guide/.
|
||||
|
||||
## Configure peripherals
|
||||
|
||||
An `.ioc` file is included in this directory for your reference. It was created
|
||||
using the following steps:
|
||||
|
||||
- Open CubeMX. If you are starting a new project, select the STM32H573I
|
||||
microcontroller and create a new project.
|
||||
- In Clock Configuration, set the maximum clock frequency to 250 MHz.
|
||||
- In Pinout & Configuration / Connectivity, enable USART1 in asynchronous mode.
|
||||
Configure pins PA9 and PA10 for USART.
|
||||
- In Pinout & Configuration / Connectivity, enable ETH in RMII mode and set pins
|
||||
PA1, PA2, PA7, PC1, PC4, PC5, PG11, PG12, and PG13 for Ethernet.
|
||||
@@ -0,0 +1,237 @@
|
||||
#MicroXplorer Configuration settings - do not modify
|
||||
CAD.formats=
|
||||
CAD.pinconfig=
|
||||
CAD.provider=
|
||||
CORTEX_M33_NS.userName=CORTEX_M33
|
||||
ETH.IPParameters=MediaInterface
|
||||
ETH.MediaInterface=HAL_ETH_RMII_MODE
|
||||
File.Version=6
|
||||
GPIO.groupedBy=
|
||||
KeepUserPlacement=false
|
||||
MMTAppRegionsCount=0
|
||||
MMTConfigApplied=false
|
||||
MMTSectionSuffix=
|
||||
Mcu.CPN=STM32H573IIK3Q
|
||||
Mcu.ContextProject=TrustZoneDisabled
|
||||
Mcu.Family=STM32H5
|
||||
Mcu.IP0=BOOTPATH
|
||||
Mcu.IP1=CORTEX_M33_NS
|
||||
Mcu.IP2=ETH
|
||||
Mcu.IP3=MEMORYMAP
|
||||
Mcu.IP4=NVIC
|
||||
Mcu.IP5=PWR
|
||||
Mcu.IP6=RCC
|
||||
Mcu.IP7=RNG
|
||||
Mcu.IP8=SYS
|
||||
Mcu.IP9=USART1
|
||||
Mcu.IPNb=10
|
||||
Mcu.Name=STM32H573IIKxQ
|
||||
Mcu.Package=UFBGA176
|
||||
Mcu.Pin0=PG12
|
||||
Mcu.Pin1=PG13
|
||||
Mcu.Pin10=PA7
|
||||
Mcu.Pin11=VP_CORTEX_M33_NS_VS_Hclk
|
||||
Mcu.Pin12=VP_PWR_VS_SECSignals
|
||||
Mcu.Pin13=VP_PWR_VS_LPOM
|
||||
Mcu.Pin14=VP_RNG_VS_RNG
|
||||
Mcu.Pin15=VP_SYS_VS_Systick
|
||||
Mcu.Pin16=VP_BOOTPATH_VS_BOOTPATH
|
||||
Mcu.Pin17=VP_MEMORYMAP_VS_MEMORYMAP
|
||||
Mcu.Pin2=PG11
|
||||
Mcu.Pin3=PA10
|
||||
Mcu.Pin4=PA9
|
||||
Mcu.Pin5=PC1
|
||||
Mcu.Pin6=PA1
|
||||
Mcu.Pin7=PA2
|
||||
Mcu.Pin8=PC4
|
||||
Mcu.Pin9=PC5
|
||||
Mcu.PinsNb=18
|
||||
Mcu.ThirdPartyNb=0
|
||||
Mcu.UserConstants=
|
||||
Mcu.UserName=STM32H573IIKxQ
|
||||
MxCube.Version=6.17.0
|
||||
MxDb.Version=DB.6.0.170
|
||||
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.ETH_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
|
||||
NVIC.ForceEnableDMAVector=true
|
||||
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
|
||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
PA1.Mode=RMII
|
||||
PA1.Signal=ETH_REF_CLK
|
||||
PA10.Locked=true
|
||||
PA10.Mode=Asynchronous
|
||||
PA10.Signal=USART1_RX
|
||||
PA2.Mode=RMII
|
||||
PA2.Signal=ETH_MDIO
|
||||
PA7.Mode=RMII
|
||||
PA7.Signal=ETH_CRS_DV
|
||||
PA9.Locked=true
|
||||
PA9.Mode=Asynchronous
|
||||
PA9.Signal=USART1_TX
|
||||
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=STM32H573IIKxQ
|
||||
PCC.PartNumber=STM32H573IIKxQ
|
||||
PCC.Series=STM32H5
|
||||
PCC.Temperature=25
|
||||
PCC.Vdd=3.0
|
||||
PG11.Mode=RMII
|
||||
PG11.Signal=ETH_TX_EN
|
||||
PG12.Locked=true
|
||||
PG12.Mode=RMII
|
||||
PG12.Signal=ETH_TXD1
|
||||
PG13.Mode=RMII
|
||||
PG13.Signal=ETH_TXD0
|
||||
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=STM32H573IIKxQ
|
||||
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=STM32CubeIDE
|
||||
ProjectManager.ProjectBuild=false
|
||||
ProjectManager.ProjectFileName=h573.ioc
|
||||
ProjectManager.ProjectName=h573
|
||||
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_USART1_UART_Init-USART1-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
|
||||
USART1.IPParameters=VirtualMode-Asynchronous
|
||||
USART1.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_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,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_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_stm32h573xx.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 -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_h5:
|
||||
git clone -q -c advice.detachedHead=false --depth 1 -b v1.2.0 https://github.com/STMicroelectronics/cmsis_device_h5 $@
|
||||
|
||||
clean:
|
||||
rm -rf firmware.*
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) {
|
||||
uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry
|
||||
if (period == 0) return false; // Avoid division by zero
|
||||
if (diff < period) return false; // Period has not elapsed yet
|
||||
*t += (diff / period) * period; // Preserve cadence, skip missed periods
|
||||
return true;
|
||||
}
|
||||
|
||||
static volatile uint64_t s_ticks; // Milliseconds since boot
|
||||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
||||
s_ticks++;
|
||||
}
|
||||
|
||||
uint64_t hal_get_tick(void) {
|
||||
return s_ticks;
|
||||
};
|
||||
|
||||
uint32_t SystemCoreClock = SYS_FREQUENCY;
|
||||
void SystemInit(void) { // Called automatically by startup code
|
||||
hal_system_init(); // Enable FPU
|
||||
hal_clock_init();
|
||||
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
|
||||
}
|
||||
|
||||
void ExitRun0Mode(void) {
|
||||
}
|
||||
|
||||
struct stat;
|
||||
__attribute__((weak)) int _fstat(int fd, struct stat *st) {
|
||||
(void) fd, (void) st;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern unsigned char _end[]; // End of data section, start of heap. See link.ld
|
||||
static unsigned char *s_current_heap_end = _end;
|
||||
|
||||
size_t hal_ram_used(void) {
|
||||
return (size_t) (s_current_heap_end - _end);
|
||||
}
|
||||
|
||||
size_t hal_ram_free(void) {
|
||||
unsigned char endofstack;
|
||||
return (size_t) (&endofstack - s_current_heap_end);
|
||||
}
|
||||
|
||||
void *_sbrk(int incr) {
|
||||
unsigned char *prev_heap;
|
||||
unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256);
|
||||
prev_heap = s_current_heap_end;
|
||||
// Check how much space we got from the heap end to the stack end
|
||||
if (s_current_heap_end + incr > heap_end) return (void *) -1;
|
||||
s_current_heap_end += incr;
|
||||
return prev_heap;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _open(const char *path) {
|
||||
(void) path;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _close(int fd) {
|
||||
(void) fd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _isatty(int fd) {
|
||||
(void) fd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _lseek(int fd, int ptr, int dir) {
|
||||
(void) fd, (void) ptr, (void) dir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _exit(int status) {
|
||||
(void) status;
|
||||
for (;;) asm volatile("BKPT #0");
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _kill(int pid, int sig) {
|
||||
(void) pid, (void) sig;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _getpid(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _write(int fd, char *ptr, int len) {
|
||||
(void) fd, (void) ptr, (void) len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _read(int fd, char *ptr, int len) {
|
||||
(void) fd, (void) ptr, (void) len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _link(const char *a, const char *b) {
|
||||
(void) a, (void) b;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _unlink(const char *a) {
|
||||
(void) a;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _stat(const char *path, struct stat *st) {
|
||||
(void) path, (void) st;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int mkdir(const char *path, int mode) {
|
||||
(void) path, (void) mode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void _init(void) {
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// https://www.st.com/resource/en/reference_manual/dm00031020-stm32f405-415-stm32f407-417-stm32f427-437-and-stm32f429-439-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf
|
||||
// https://www.st.com/resource/en/datasheet/stm32f429zi.pdf
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stm32h573xx.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 HAL_ETH_PINS \
|
||||
PIN('A', 1), /* ETH_REF_CLK */ \
|
||||
PIN('A', 2), /* ETH_MDIO */ \
|
||||
PIN('A', 7), /* ETH_CRS_DV */ \
|
||||
PIN('C', 1), /* ETH_MDC */ \
|
||||
PIN('C', 4), /* ETH_RXD0 */ \
|
||||
PIN('C', 5), /* ETH_RXD1 */ \
|
||||
PIN('G', 11), /* ETH_TX_EN */ \
|
||||
PIN('G', 12), /* ETH_TXD1 */ \
|
||||
PIN('G', 13) /* ETH_TXD0 */
|
||||
|
||||
#define BIT(x) (1UL << (x))
|
||||
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
|
||||
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
|
||||
#define PINNO(pin) (pin & 255)
|
||||
#define PINBANK(pin) (pin >> 8)
|
||||
|
||||
void hal_init(void);
|
||||
size_t hal_ram_free(void);
|
||||
size_t hal_ram_used(void);
|
||||
|
||||
// System clock (11.4, Figure 48; 11.4.5, Figure 51; 11.4.8
|
||||
// SYS_FREQUENCY <= 250 MHz; (SYS_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, 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 |= RCC_APB2ENR_USART1EN;
|
||||
tx = PIN('A', 9), rx = PIN('A', 10);
|
||||
} else if (uart == USART2) {
|
||||
freq = APB1_FREQUENCY, RCC->APB1LENR |= RCC_APB1LENR_USART2EN;
|
||||
tx = PIN('A', 2), rx = PIN('A', 3);
|
||||
} else if (uart == USART3) {
|
||||
freq = APB1_FREQUENCY, RCC->APB1LENR |= RCC_APB1LENR_USART3EN;
|
||||
tx = PIN('D', 8), rx = PIN('D', 9);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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 */
|
||||
|
||||
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,70 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "hal.h"
|
||||
|
||||
#define DEBUG_UART USART1
|
||||
#define LED1 PIN('I', 9) // On-board LED pin (green)
|
||||
#define LED2 PIN('I', 8) // On-board LED pin (orange)
|
||||
#define LED3 PIN('F', 1) // On-board LED pin (red)
|
||||
|
||||
// Redirect stdout debug output to UART
|
||||
int _write(int fd, char *ptr, int len) {
|
||||
if (fd == 1 || fd == 2) hal_uart_write_buf(DEBUG_UART, ptr, (size_t) len);
|
||||
return len;
|
||||
}
|
||||
|
||||
static void blink_task(void) {
|
||||
static uint64_t blink_timer = 0;
|
||||
if (hal_timer_expired(&blink_timer, 500, hal_get_tick())) {
|
||||
hal_gpio_toggle(LED1);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t mg_millis(void) {
|
||||
return hal_get_tick();
|
||||
}
|
||||
|
||||
bool mg_random(void *buf, size_t len) {
|
||||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
||||
uint32_t r = hal_rng_read();
|
||||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
} else {
|
||||
mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n",
|
||||
hal_get_tick());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
hal_clock_init();
|
||||
hal_rng_init();
|
||||
hal_gpio_output(LED1);
|
||||
hal_gpio_output(LED2);
|
||||
hal_gpio_output(LED3);
|
||||
hal_uart_init(DEBUG_UART, 115200);
|
||||
|
||||
hal_ethernet_init();
|
||||
|
||||
// Start a minimal web server
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 0);
|
||||
blink_task();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
||||
#define MG_ENABLE_CUSTOM_RANDOM 1
|
||||
#define MG_ENABLE_DRIVER_STM32H 1
|
||||
#define MG_OTA MG_OTA_STM32H5
|
||||
|
||||
// Construct MAC address from the MCU unique ID. It is defined in the
|
||||
// ST CMSIS header as UID_BASE
|
||||
#define MGUID ((uint32_t *) 0x1FFF7A10) // 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)
|
||||
Reference in new issue
Block a user