diff --git a/IDE/STM32Cube/README.md b/IDE/STM32Cube/README.md new file mode 100644 index 0000000..0397ba6 --- /dev/null +++ b/IDE/STM32Cube/README.md @@ -0,0 +1,144 @@ +# wolfIP for STM32 CubeIDE + +This guide explains how to use wolfIP on any STM32 microcontroller with Ethernet using STM32CubeMX and the wolfIP CMSIS pack. + +## Supported STM32 Families + +| Family | Interface Config | Auto-Detected | Example Boards | +|----------|------------------|---------------|----------------| +| STM32F4 | SYSCFG->PMC | Yes | NUCLEO-F429ZI, STM32F4-Discovery | +| STM32F7 | SYSCFG->PMC | Yes | NUCLEO-F746ZG, NUCLEO-F767ZI | +| STM32H5 | SBS->PMCR | Yes | NUCLEO-H563ZI, NUCLEO-H573ZI | +| STM32H7 | SYSCFG->PMCR | Yes | NUCLEO-H743ZI, NUCLEO-H753ZI | +| Others | Manual | Fallback | See family reference manual | + +## Quick Start + +### Step 1: Install the wolfIP Pack + +1. Download the pack from [wolfSSL](https://www.wolfssl.com/files/ide/I-CUBE-wolfIP.pack) +2. In STM32CubeMX: **Help → Manage Embedded Software Packages → From Local** +3. Select `I-CUBE-wolfIP.pack` and accept the license + +### Step 2: Create CubeMX Project + +1. Create new project for your board +2. Configure **Connectivity → ETH**: + - Mode: **RMII** (or MII depending on board) + - Verify GPIO pin assignments match your board's PHY (CubeMX auto-configures for NUCLEO boards) +3. Configure **System Core → NVIC**: + - **ETH global interrupt: ENABLED** (CRITICAL - required for RX) +4. Configure **Software Packs → Select Components**: + - Expand wolfIP → Check **Core** and **Eth** +5. Configure **Software Packs → wolfIP**: + - Enable the library checkbox +6. Generate code (Makefile recommended for command-line builds) + +**Note:** For NUCLEO boards, CubeMX auto-configures the correct ETH GPIO pins. For custom boards, verify pins match your PHY datasheet. + +**That's it for CubeMX!** No MspInit changes needed - the driver auto-configures RMII/MII. + +### Step 3: Add wolfIP Code to main.c + +Add this code to your CubeMX-generated main.c in the corresponding USER CODE sections: + +**In USER CODE BEGIN Includes:** +```c +#include "wolfip.h" +#include "stm32_hal_eth.h" +``` + +**In USER CODE BEGIN PV:** +```c +static struct wolfIP *ipstack = NULL; +``` + +**In USER CODE BEGIN 2 (after MX_ETH_Init):** +```c +wolfIP_init_static(&ipstack); +if (stm32_hal_eth_init(wolfIP_getdev(ipstack)) != 0) { + Error_Handler(); +} +wolfIP_ipconfig_set(ipstack, + atoip4("192.168.0.200"), + atoip4("255.255.255.0"), + atoip4("192.168.0.1")); +``` + +**In USER CODE BEGIN 3 (inside while loop):** +```c +wolfIP_poll(ipstack, HAL_GetTick()); +``` + +**In USER CODE BEGIN 4:** +```c +uint32_t wolfIP_getrandom(void) +{ + static uint32_t seed = 12345; + seed = seed * 1103515245 + 12345; + return (seed >> 16) ^ HAL_GetTick(); +} +``` + +**Alternative: Use DHCP** instead of static IP by enabling DHCP in Software Packs -> wolfIP settings. + +### Step 4: Build and Test + +1. Build the project +2. Flash to your board +3. Connect Ethernet cable +4. Ping from your PC: `ping 192.168.0.200` + +## Troubleshooting + +### No ping response + +1. **Check NVIC**: ETH global interrupt must be ENABLED in CubeMX +2. **Check cable**: Ensure Ethernet cable is connected and link LED is on +3. **Check IP**: Ensure IP address is on same subnet as your PC +4. **Check return value**: Verify `stm32_hal_eth_init()` returns 0 + +### stm32_hal_eth_init() returns -3 + +This means the ETH reinitialization failed. Check: +- ETH peripheral is properly configured in CubeMX +- GPIO pins are correctly assigned for your board's PHY + +### Unsupported STM32 family + +For families not auto-detected (F4, F7, H5, H7), add RMII/MII config in MspInit: + +```c +void HAL_ETH_MspInit(ETH_HandleTypeDef* heth) +{ + if(heth->Instance==ETH) + { + /* USER CODE BEGIN ETH_MspInit 0 */ + /* Manual RMII config - see your STM32 family reference manual */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; /* Example for F4/F7 */ + /* USER CODE END ETH_MspInit 0 */ + ... + } +} +``` + +## Using TLS with wolfIP + +To use TLS (HTTPS, secure sockets): + +1. First install wolfSSL pack: [wolfSSL CubeIDE Guide](https://github.com/wolfSSL/wolfssl/blob/master/IDE/STM32Cube/README.md) +2. In Software Packs, also check **wolfSSL-IO** component +3. See wolfSSL examples for TLS socket usage + +## Additional Resources + +- [wolfIP GitHub](https://github.com/wolfSSL/wolfip) +- [STM32H563 Bare-metal Example](../../src/port/stm32h563/) +- [wolfSSL Support](mailto:support@wolfssl.com) + +## Notes + +- wolfIP uses zero dynamic memory allocation - all buffers are pre-allocated +- Default configuration supports 4 TCP sockets, 4 UDP sockets +- Adjust `config.h` for different socket pool sizes or buffer sizes diff --git a/IDE/STM32Cube/default_conf.ftl b/IDE/STM32Cube/default_conf.ftl new file mode 100644 index 0000000..eafec78 --- /dev/null +++ b/IDE/STM32Cube/default_conf.ftl @@ -0,0 +1,172 @@ +[#ftl] +/** + ****************************************************************************** + * File Name : ${name} + * Description : This file provides code for the configuration + * of the ${name} instances. + ****************************************************************************** +[@common.optinclude name=mxTmpFolder+"/license.tmp"/][#--include License text --] + ****************************************************************************** + */ +[#assign s = name] +[#assign toto = s?replace(".","_")] +[#assign toto = toto?replace("/","")] +[#assign toto = toto?replace("-","_")] +[#assign inclusion_protection = toto?upper_case] +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __${inclusion_protection}__ +#define __${inclusion_protection}__ + +#ifdef __cplusplus + extern "C" { +#endif + + +/* Includes ------------------------------------------------------------------*/ +[#if includes??] +[#list includes as include] +#include "${include}" +[/#list] +[/#if] + +[#-- SWIPdatas is a list of SWIPconfigModel --] +[#list SWIPdatas as SWIP] +[#-- Global variables --] +[#if SWIP.variables??] + [#list SWIP.variables as variable] +extern ${variable.value} ${variable.name}; + [/#list] +[/#if] + +[#-- Global variables --] + +[#assign instName = SWIP.ipName] +[#assign fileName = SWIP.fileName] +[#assign version = SWIP.version] + +/** + MiddleWare name : ${instName} + MiddleWare fileName : ${fileName} + MiddleWare version : ${version} +*/ +[#if SWIP.defines??] + [#list SWIP.defines as definition] +/*---------- [#if definition.comments??]${definition.comments}[/#if] -----------*/ +#define ${definition.name} #t#t ${definition.value} +[#if definition.description??]${definition.description} [/#if] + [/#list] +[/#if] + + + +[/#list] + +/* ------------------------------------------------------------------------- */ +/* Platform */ +/* ------------------------------------------------------------------------- */ +#define WOLFIP_STM32_CUBEMX +#define NO_FILESYSTEM + +/* ------------------------------------------------------------------------- */ +/* Socket Pool Configuration */ +/* ------------------------------------------------------------------------- */ +#if defined(WOLFIP_CONF_MAX_TCP) && WOLFIP_CONF_MAX_TCP > 0 + #define MAX_TCPSOCKETS WOLFIP_CONF_MAX_TCP +#else + #define MAX_TCPSOCKETS 4 +#endif + +#if defined(WOLFIP_CONF_MAX_UDP) && WOLFIP_CONF_MAX_UDP > 0 + #define MAX_UDPSOCKETS WOLFIP_CONF_MAX_UDP +#else + #define MAX_UDPSOCKETS 2 +#endif + +#if defined(WOLFIP_CONF_MAX_ICMP) && WOLFIP_CONF_MAX_ICMP > 0 + #define MAX_ICMPSOCKETS WOLFIP_CONF_MAX_ICMP +#else + #define MAX_ICMPSOCKETS 2 +#endif + +/* ------------------------------------------------------------------------- */ +/* Buffer Configuration */ +/* ------------------------------------------------------------------------- */ +#if defined(WOLFIP_CONF_MTU) && WOLFIP_CONF_MTU > 0 + #define LINK_MTU WOLFIP_CONF_MTU +#else + #define LINK_MTU 1536 +#endif + +#define RXBUF_SIZE (LINK_MTU * 16) +#define TXBUF_SIZE (LINK_MTU * 16) + +/* ------------------------------------------------------------------------- */ +/* Network Configuration */ +/* ------------------------------------------------------------------------- */ +#define ETHERNET +#define MAX_NEIGHBORS 16 + +/* ------------------------------------------------------------------------- */ +/* Enable/Disable Features */ +/* ------------------------------------------------------------------------- */ + +/* DHCP Client */ +#if defined(WOLFIP_CONF_DHCP) && WOLFIP_CONF_DHCP == 1 + #define WOLFIP_ENABLE_DHCP +#endif + +/* HTTP Server */ +#if defined(WOLFIP_CONF_HTTP) && WOLFIP_CONF_HTTP == 1 + #define WOLFIP_ENABLE_HTTP +#endif + +/* Loopback Interface */ +#undef WOLFIP_ENABLE_LOOPBACK +#if defined(WOLFIP_CONF_LOOPBACK) && WOLFIP_CONF_LOOPBACK == 1 + #define WOLFIP_ENABLE_LOOPBACK 1 + #ifndef WOLFIP_MAX_INTERFACES + #define WOLFIP_MAX_INTERFACES 2 + #endif +#else + #define WOLFIP_ENABLE_LOOPBACK 0 +#endif + +/* IP Forwarding */ +#undef WOLFIP_ENABLE_FORWARDING +#if defined(WOLFIP_CONF_FORWARDING) && WOLFIP_CONF_FORWARDING == 1 + #define WOLFIP_ENABLE_FORWARDING 1 +#else + #define WOLFIP_ENABLE_FORWARDING 0 +#endif + +#ifndef WOLFIP_MAX_INTERFACES + #define WOLFIP_MAX_INTERFACES 1 +#endif + +/* ------------------------------------------------------------------------- */ +/* Debugging */ +/* ------------------------------------------------------------------------- */ +#if defined(WOLFIP_CONF_DEBUG) && WOLFIP_CONF_DEBUG == 1 + #define DEBUG +#else + #undef DEBUG +#endif + +/* ------------------------------------------------------------------------- */ +/* wolfSSL Integration */ +/* ------------------------------------------------------------------------- */ +/* Define WOLFSSL_WOLFIP to enable wolfSSL IO callbacks for TLS support. + * Requires wolfSSL Cube Pack to be installed and configured. + */ +/* #define WOLFSSL_WOLFIP */ + +#ifdef __cplusplus +} +#endif +#endif /* __${inclusion_protection}__ */ + +/** + * @} + */ + +/*****END OF FILE****/ diff --git a/Makefile b/Makefile index 4b062c3..6e1938c 100644 --- a/Makefile +++ b/Makefile @@ -195,6 +195,8 @@ build/tcp_netcat_select: $(OBJ) build/port/posix/bsd_socket.o build/test/tcp_net build/test-wolfssl:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP build/test-httpd:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP -Isrc/http +build/test/test_httpd.o:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP -DWOLFIP_ENABLE_HTTP -Isrc/http +build/http/httpd.o:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP -DWOLFIP_ENABLE_HTTP -Isrc/http build/test-wolfssl-forwarding:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP -DWOLFIP_MAX_INTERFACES=2 -DWOLFIP_ENABLE_FORWARDING=1 build/test-wolfssl: $(OBJ) build/test/test_native_wolfssl.o build/port/wolfssl_io.o build/certs/server_key.o build/certs/ca_cert.o build/certs/server_cert.o diff --git a/config.h b/config.h index ea0f429..e35e8c8 100644 --- a/config.h +++ b/config.h @@ -32,6 +32,11 @@ #define WOLFIP_ENABLE_LOOPBACK 0 #endif +/* Enable HTTP server for POSIX builds */ +#ifndef WOLFIP_ENABLE_HTTP +#define WOLFIP_ENABLE_HTTP +#endif + #if WOLFIP_ENABLE_LOOPBACK && WOLFIP_MAX_INTERFACES < 2 #error "WOLFIP_ENABLE_LOOPBACK requires WOLFIP_MAX_INTERFACES > 1" #endif diff --git a/src/http/httpd.c b/src/http/httpd.c index 429a6d8..e8173a7 100644 --- a/src/http/httpd.c +++ b/src/http/httpd.c @@ -41,6 +41,9 @@ * * */ + +#ifdef WOLFIP_ENABLE_HTTP + #include "wolfip.h" #include "httpd.h" #include @@ -525,3 +528,5 @@ int httpd_init(struct httpd *httpd, struct wolfIP *s, uint16_t port, void *ssl_c wolfIP_register_callback(s, httpd->listen_sd, http_accept_cb, httpd); return 0; } + +#endif /* WOLFIP_ENABLE_HTTP */ diff --git a/src/http/httpd.h b/src/http/httpd.h index a94a245..82ea6a0 100644 --- a/src/http/httpd.h +++ b/src/http/httpd.h @@ -1,5 +1,8 @@ #ifndef WOLF_HTTPD_H #define WOLF_HTTPD_H + +#ifdef WOLFIP_ENABLE_HTTP + #ifdef WOLFSSL_USER_SETTINGS #include #else @@ -8,6 +11,7 @@ #include #include #include +#include #define HTTP_METHOD_LEN 8 #define HTTP_PATH_LEN 128 @@ -86,5 +90,6 @@ void http_send_418_teapot(struct http_client *hc); int http_url_decode(char *buf, size_t len); int http_url_encode(char *buf, size_t len, size_t max_len); +#endif /* WOLFIP_ENABLE_HTTP */ -#endif +#endif /* WOLF_HTTPD_H */ diff --git a/src/port/stm32_hal/stm32_hal_eth.c b/src/port/stm32_hal/stm32_hal_eth.c new file mode 100644 index 0000000..0d25bcd --- /dev/null +++ b/src/port/stm32_hal/stm32_hal_eth.c @@ -0,0 +1,300 @@ +/* stm32_hal_eth.c + * + * Copyright (C) 2024-2025 wolfSSL Inc. + * + * HAL-based Ethernet driver for wolfIP - portable across STM32 families + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include "stm32_hal_eth.h" +#include "main.h" +#include + +/* + * Supported STM32 families for automatic RMII/MII configuration: + * + * | Family | Interface Register | Method | + * |----------|-------------------|-------------------------------| + * | STM32H5 | SBS->PMCR | HAL_SBS_ETHInterfaceSelect() | + * | STM32H7 | SYSCFG->PMCR | Direct register write | + * | STM32F4 | SYSCFG->PMC | Direct register write | + * | STM32F7 | SYSCFG->PMC | Direct register write | + * | Others | (manual) | User configures in MspInit | + */ + +/* External references to HAL ETH handle and TX config (from CubeMX-generated code) */ +extern ETH_HandleTypeDef heth; +extern ETH_TxPacketConfigTypeDef TxConfig; + +/* Track if interface has been configured */ +static uint8_t interface_configured = 0; + +/** + * @brief Configure RMII/MII interface based on STM32 family + * + * This function automatically configures the Ethernet interface (RMII/MII) + * based on the detected STM32 family. It uses compile-time macros defined + * by the STM32 HAL to determine the correct configuration method. + * + * IMPORTANT: For best results, call this function BEFORE HAL_ETH_Init(). + * The ideal location is at the start of HAL_ETH_MspInit() in your + * stm32xxxx_hal_msp.c file, before enabling ETH clocks. + * + * If using the wolfIP CMSIS pack, this is called automatically during + * stm32_hal_eth_init(). However, some families may require earlier + * configuration - see documentation for your specific board. + * + * @return 0 if configuration succeeded or family auto-detected + * @return 1 if unknown family (user must configure manually in MspInit) + */ +int stm32_hal_eth_configure_interface(void) +{ + if (interface_configured) { + return 0; /* Already configured */ + } + +#if defined(STM32H5) || defined(STM32H563xx) || defined(STM32H573xx) || \ + defined(STM32H503xx) || defined(STM32H533xx) || defined(STM32H562xx) + /* STM32H5 series: Use SBS for RMII selection */ + __HAL_RCC_SBS_CLK_ENABLE(); + HAL_SBS_ETHInterfaceSelect(SBS_ETH_RMII); + interface_configured = 1; + return 0; + +#elif defined(STM32H7) || defined(STM32H743xx) || defined(STM32H753xx) || \ + defined(STM32H747xx) || defined(STM32H757xx) || defined(STM32H723xx) || \ + defined(STM32H733xx) || defined(STM32H725xx) || defined(STM32H735xx) || \ + defined(STM32H730xx) || defined(STM32H750xx) || defined(STM32H742xx) || \ + defined(STM32H745xx) || defined(STM32H755xx) + /* STM32H7 series: Use SYSCFG PMCR for RMII selection */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + /* Clear EPIS bits and set for RMII */ + SYSCFG->PMCR &= ~SYSCFG_PMCR_EPIS_SEL; + SYSCFG->PMCR |= SYSCFG_PMCR_EPIS_SEL_2; /* RMII mode */ + interface_configured = 1; + return 0; + +#elif defined(STM32F4) || defined(STM32F407xx) || defined(STM32F417xx) || \ + defined(STM32F427xx) || defined(STM32F429xx) || defined(STM32F437xx) || \ + defined(STM32F439xx) || defined(STM32F446xx) || defined(STM32F469xx) || \ + defined(STM32F479xx) + /* STM32F4 series: Use SYSCFG PMC for RMII selection */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; /* RMII mode */ + interface_configured = 1; + return 0; + +#elif defined(STM32F7) || defined(STM32F745xx) || defined(STM32F746xx) || \ + defined(STM32F756xx) || defined(STM32F765xx) || defined(STM32F767xx) || \ + defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx) || \ + defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) + /* STM32F7 series: Use SYSCFG PMC for RMII selection */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; /* RMII mode */ + interface_configured = 1; + return 0; + +#else + /* Unknown family - user must configure in HAL_ETH_MspInit() */ + /* This is not an error - just means manual configuration needed */ + return 1; +#endif +} + +/* RX buffer for HAL ETH - must be 32-byte aligned for DMA on STM32H5/H7 */ +#define ETH_RX_BUFFER_SIZE 1536 +static uint8_t rx_buffer[ETH_RX_BUFFER_SIZE] __attribute__((aligned(32))); + +/* Track if we have a pending received frame */ +static volatile uint8_t rx_frame_pending = 0; +static volatile uint32_t rx_frame_length = 0; + +/* Flag set by RX complete interrupt - avoids blocking HAL_ETH_ReadData calls */ +static volatile uint8_t rx_data_available = 0; + +/** + * @brief HAL ETH RX allocation callback + * Called by HAL when it needs a buffer to store received data + */ +void HAL_ETH_RxAllocateCallback(uint8_t **buff) +{ + *buff = rx_buffer; +} + +/** + * @brief HAL ETH RX link callback + * Called by HAL when a complete frame has been received + */ +void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length) +{ + (void)pStart; + (void)pEnd; + (void)buff; + + rx_frame_length = Length; + rx_frame_pending = 1; +} + +/** + * @brief HAL ETH RX Complete Callback + * Called by HAL from ETH IRQ handler when a frame has been received. + * This requires ETH global interrupt to be enabled in CubeMX NVIC settings. + */ +void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth_ptr) +{ + (void)heth_ptr; + rx_data_available = 1; +} + +/** + * @brief Poll for received Ethernet frames + * + * Uses hybrid approach: primarily interrupt-driven but also polls periodically + * to catch any missed interrupts. This ensures reliable reception across all + * STM32 families while avoiding the blocking behavior of polling every cycle. + */ +static int hal_eth_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) +{ + uint32_t frame_len = 0; + void *payload = NULL; + static uint32_t poll_count = 0; + + (void)dev; + + /* Check if ETH is started */ + if (heth.gState != HAL_ETH_STATE_STARTED) { + return 0; + } + + poll_count++; + + /* Check for data: either interrupt flagged it, or periodic poll (every 100 cycles) */ + if (rx_data_available || (poll_count % 100) == 0) { + rx_data_available = 0; + + if (HAL_ETH_ReadData(&heth, &payload) == HAL_OK) { + if (rx_frame_pending && rx_frame_length > 0) { + frame_len = rx_frame_length; + if (frame_len > len) { + frame_len = len; + } + memcpy(frame, rx_buffer, frame_len); + rx_frame_pending = 0; + rx_frame_length = 0; + return (int)frame_len; + } + } + } + + return 0; +} + +/** + * @brief Send an Ethernet frame + */ +static int hal_eth_send(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) +{ + ETH_BufferTypeDef tx_buffer; + HAL_StatusTypeDef status; + + (void)dev; + + if (len == 0 || len > ETH_RX_BUFFER_SIZE) { + return -1; + } + + /* Configure TX buffer */ + tx_buffer.buffer = frame; + tx_buffer.len = len; + tx_buffer.next = NULL; + + /* Update TX config */ + TxConfig.Length = len; + TxConfig.TxBuffer = &tx_buffer; + TxConfig.pData = NULL; + + /* Transmit frame - 100ms timeout */ + status = HAL_ETH_Transmit(&heth, &TxConfig, 100); + + if (status == HAL_OK) { + return (int)len; + } + + return -1; +} + +/** + * @brief Initialize the HAL-based Ethernet driver + * + * This function automatically configures RMII/MII for the detected STM32 + * family, reinitializes the ETH peripheral with correct settings, and + * starts the Ethernet MAC. + * + * No manual configuration needed - works automatically on all supported + * STM32 families (F4, F7, H5, H7). + */ +int stm32_hal_eth_init(struct wolfIP_ll_dev *ll) +{ + HAL_StatusTypeDef status; + + if (ll == NULL) { + return -1; + } + + /* + * Auto-configure RMII/MII interface for this STM32 family. + * Then reinitialize ETH to apply the settings. + * This allows fully automatic setup with zero user code in MspInit. + */ + if (stm32_hal_eth_configure_interface() == 0) { + /* Family was auto-detected - reinit ETH to apply RMII/MII config */ + HAL_ETH_DeInit(&heth); + if (HAL_ETH_Init(&heth) != HAL_OK) { + return -3; + } + } + /* If configure returned 1 (unknown family), assume user configured in MspInit */ + + /* Copy MAC address from HAL handle */ + memcpy(ll->mac, heth.Init.MACAddr, 6); + strncpy(ll->ifname, "eth0", sizeof(ll->ifname) - 1); + ll->ifname[sizeof(ll->ifname) - 1] = '\0'; + + /* Set wolfIP callbacks */ + ll->poll = hal_eth_poll; + ll->send = hal_eth_send; + + /* Start the Ethernet MAC in interrupt mode for RX */ + status = HAL_ETH_Start_IT(&heth); + if (status != HAL_OK) { + return -2; + } + + return 0; +} + +/* wolfIP callbacks for CubeMX builds */ +#ifdef WOLFIP_STM32_CUBEMX + +uint64_t wolfip_get_time_ms(void) +{ + return (uint64_t)HAL_GetTick(); +} + +#endif /* WOLFIP_STM32_CUBEMX */ diff --git a/src/port/stm32_hal/stm32_hal_eth.h b/src/port/stm32_hal/stm32_hal_eth.h new file mode 100644 index 0000000..afe3a3d --- /dev/null +++ b/src/port/stm32_hal/stm32_hal_eth.h @@ -0,0 +1,158 @@ +/* stm32_hal_eth.h + * + * Copyright (C) 2024-2025 wolfSSL Inc. + * + * HAL-based Ethernet driver for wolfIP - portable across STM32 families + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/** + * @file stm32_hal_eth.h + * @brief Portable STM32 HAL Ethernet driver for wolfIP + * + * This driver provides a portable Ethernet interface that works across all + * STM32 families with Ethernet peripheral (F4, F7, H5, H7, etc.) using the + * STM32 HAL library. + * + * ## Supported STM32 Families (Auto-Detected) + * + * | Family | Interface Config | Status | + * |----------|---------------------|---------------| + * | STM32F4 | SYSCFG->PMC | Auto | + * | STM32F7 | SYSCFG->PMC | Auto | + * | STM32H5 | SBS->PMCR | Auto | + * | STM32H7 | SYSCFG->PMCR | Auto | + * | Others | Manual in MspInit | Fallback | + * + * ## Quick Start - Zero Configuration! + * + * Just add wolfIP code to main.c - NO changes to MspInit needed: + * + * @code + * #include "wolfip.h" + * #include "stm32_hal_eth.h" + * + * int main(void) + * { + * struct wolfIP *ipstack; + * + * // CubeMX-generated initialization + * HAL_Init(); + * SystemClock_Config(); + * MX_GPIO_Init(); + * MX_ETH_Init(); + * + * // Initialize wolfIP (same code on ALL STM32 boards) + * wolfIP_init_static(&ipstack); + * stm32_hal_eth_init(wolfIP_getdev(ipstack)); // Auto-configures RMII/MII! + * wolfIP_ipconfig_set(ipstack, + * atoip4("192.168.1.100"), + * atoip4("255.255.255.0"), + * atoip4("192.168.1.1")); + * + * // Main loop + * while (1) { + * wolfIP_poll(ipstack, HAL_GetTick()); + * } + * } + * @endcode + * + * ## CubeMX Configuration Requirements + * + * 1. **ETH Peripheral** (Connectivity -> ETH) + * - Mode: RMII (or MII depending on your board's PHY) + * + * 2. **NVIC Settings** (System Core -> NVIC) - CRITICAL + * - ETH global interrupt: **ENABLED** + * - Without this, received frames will not be detected + * + * 3. **GPIO Configuration** + * - CubeMX auto-configures correct pins for NUCLEO boards + * + * ## How It Works + * + * The driver automatically: + * 1. Detects your STM32 family at compile time + * 2. Configures RMII/MII interface (SBS/SYSCFG) + * 3. Reinitializes ETH with correct settings + * 4. Starts the MAC in interrupt mode + * + * No manual MspInit changes required for supported families! + * + * ## Implementation Notes + * + * - Uses hybrid RX: interrupt-driven (HAL_ETH_Start_IT) + periodic polling + * - DMA buffers are 32-byte aligned (required for STM32H5/H7) + * - Assumes CubeMX generates `heth` and `TxConfig` as extern globals + */ + +#ifndef WOLFIP_STM32_HAL_ETH_H +#define WOLFIP_STM32_HAL_ETH_H + +#include +#include "wolfip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configure RMII/MII interface for the detected STM32 family + * + * This function is called automatically by stm32_hal_eth_init(). + * You typically don't need to call this directly. + * + * For unsupported families, returns 1 and user must configure + * RMII/MII manually in HAL_ETH_MspInit(). + * + * @return 0 on success (family detected and configured) + * @return 1 if unknown family (manual configuration required) + */ +int stm32_hal_eth_configure_interface(void); + +/** + * @brief Initialize the HAL-based Ethernet driver for wolfIP + * + * This function automatically: + * 1. Configures RMII/MII for the detected STM32 family + * 2. Reinitializes ETH peripheral with correct settings + * 3. Copies MAC address to wolfIP device + * 4. Registers poll/send callbacks + * 5. Starts the Ethernet MAC in interrupt mode + * + * Prerequisites: + * - HAL_ETH_Init() called (via MX_ETH_Init) + * - ETH global interrupt enabled in CubeMX NVIC settings + * + * NO changes to MspInit required for supported families (F4, F7, H5, H7)! + * + * @param ll Pointer to wolfIP low-level device structure + * (obtained via wolfIP_getdev()) + * + * @return 0 on success + * @return -1 if ll is NULL + * @return -2 if HAL_ETH_Start_IT() fails + * @return -3 if HAL_ETH_Init() fails during reinit + */ +int stm32_hal_eth_init(struct wolfIP_ll_dev *ll); + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFIP_STM32_HAL_ETH_H */