Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion boards/stm32h563zi_nucleo/Makefile.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

PLATFORM = stm32h5
TESTS ?= clock gpio timer flash rng
TESTS ?= clock gpio timer flash rng eth

GCC = $(GCC_PATH)arm-none-eabi-gcc
LD = $(GCC_PATH)arm-none-eabi-ld
Expand Down Expand Up @@ -29,6 +29,8 @@ BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/spi.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/rng.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/crypto.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/block.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/eth.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/eth_phy/*.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/stm32h5_*.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c)

Expand Down
161 changes: 160 additions & 1 deletion boards/stm32h563zi_nucleo/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stddef.h>
#include "board.h"
#include <wolfHAL/platform/st/stm32h563xx.h>
#include <wolfHAL/eth_phy/lan8742a.h>
#include "peripheral.h"

/* SysTick timing */
Expand Down Expand Up @@ -52,13 +53,22 @@ static const whal_Stm32h5Rcc_Clk g_clocks[] = {
{WHAL_STM32H563_GPIOA_CLOCK},
{WHAL_STM32H563_GPIOB_CLOCK},
{WHAL_STM32H563_GPIOD_CLOCK},
{WHAL_STM32H563_GPIOC_CLOCK},
{WHAL_STM32H563_GPIOG_CLOCK},
{WHAL_STM32H563_USART2_CLOCK},
{WHAL_STM32H563_SPI1_CLOCK},
{WHAL_STM32H563_RNG_CLOCK},
{WHAL_STM32H563_SBS_CLOCK},
};
#define CLOCK_COUNT (sizeof(g_clocks) / sizeof(g_clocks[0]))

static const whal_Stm32h5Rcc_Clk g_ethClocks[] = {
{WHAL_STM32H563_ETH_CLOCK},
{WHAL_STM32H563_ETHTX_CLOCK},
{WHAL_STM32H563_ETHRX_CLOCK},
};
#define ETH_CLOCK_COUNT (sizeof(g_ethClocks) / sizeof(g_ethClocks[0]))

/* GPIO */
whal_Gpio g_whalGpio = {
WHAL_STM32H563_GPIO_DEVICE,
Expand Down Expand Up @@ -127,6 +137,78 @@ whal_Gpio g_whalGpio = {
.speed = WHAL_STM32H5_GPIO_SPEED_FAST,
.pull = WHAL_STM32H5_GPIO_PULL_UP,
},
[ETH_RMII_REF_CLK_PIN] = { /* RMII REF_CLK on PA1 */
.port = WHAL_STM32H5_GPIO_PORT_A,
.pin = 1,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
[ETH_RMII_MDIO_PIN] = { /* RMII MDIO on PA2 */
.port = WHAL_STM32H5_GPIO_PORT_A,
.pin = 2,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
[ETH_RMII_MDC_PIN] = { /* RMII MDC on PC1 */
.port = WHAL_STM32H5_GPIO_PORT_C,
.pin = 1,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
[ETH_RMII_CRS_DV_PIN] = { /* RMII CRS_DV on PA7 */
.port = WHAL_STM32H5_GPIO_PORT_A,
.pin = 7,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
[ETH_RMII_RXD0_PIN] = { /* RMII RXD0 on PC4 */
.port = WHAL_STM32H5_GPIO_PORT_C,
.pin = 4,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
[ETH_RMII_RXD1_PIN] = { /* RMII RXD1 on PC5 */
.port = WHAL_STM32H5_GPIO_PORT_C,
.pin = 5,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
[ETH_RMII_TX_EN_PIN] = { /* RMII TX_EN on PG11 */
.port = WHAL_STM32H5_GPIO_PORT_G,
.pin = 11,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
[ETH_RMII_TXD0_PIN] = { /* RMII TXD0 on PG13 */
.port = WHAL_STM32H5_GPIO_PORT_G,
.pin = 13,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
[ETH_RMII_TXD1_PIN] = { /* RMII TXD1 on PB15 */
.port = WHAL_STM32H5_GPIO_PORT_B,
.pin = 15,
.mode = WHAL_STM32H5_GPIO_MODE_ALTFN,
.speed = WHAL_STM32H5_GPIO_SPEED_HIGH,
.pull = WHAL_STM32H5_GPIO_PULL_NONE,
.altFn = 11,
},
},
.pinCount = PIN_COUNT,
},
Expand Down Expand Up @@ -184,6 +266,49 @@ whal_Flash g_whalFlash = {
},
};

/* Ethernet */
#define ETH_TX_DESC_COUNT 4
#define ETH_RX_DESC_COUNT 4
#define ETH_TX_BUF_SIZE 1536
#define ETH_RX_BUF_SIZE 1536

static whal_Stm32h5Eth_TxDesc ethTxDescs[ETH_TX_DESC_COUNT]
__attribute__((aligned(16)));
static whal_Stm32h5Eth_RxDesc ethRxDescs[ETH_RX_DESC_COUNT]
__attribute__((aligned(16)));
static uint8_t ethTxBufs[ETH_TX_DESC_COUNT * ETH_TX_BUF_SIZE]
__attribute__((aligned(4)));
static uint8_t ethRxBufs[ETH_RX_DESC_COUNT * ETH_RX_BUF_SIZE]
__attribute__((aligned(4)));

whal_Eth g_whalEth = {
WHAL_STM32H563_ETH_DEVICE,

.cfg = &(whal_Stm32h5Eth_Cfg) {
.macAddr = {0x00, 0x80, 0xE1, 0x00, 0x00, 0x01},
.txDescs = ethTxDescs,
.txBufs = ethTxBufs,
.txDescCount = ETH_TX_DESC_COUNT,
.txBufSize = ETH_TX_BUF_SIZE,
.rxDescs = ethRxDescs,
.rxBufs = ethRxBufs,
.rxDescCount = ETH_RX_DESC_COUNT,
.rxBufSize = ETH_RX_BUF_SIZE,
.timeout = &g_whalTimeout,
},
};

/* Ethernet PHY (LAN8742A) */
whal_EthPhy g_whalEthPhy = {
.eth = &g_whalEth,
.addr = BOARD_ETH_PHY_ADDR,
.driver = &whal_Lan8742a_Driver,

.cfg = &(whal_Lan8742a_Cfg) {
.timeout = &g_whalTimeout,
},
};

void Board_WaitMs(size_t ms)
{
uint32_t startCount = g_tick;
Expand All @@ -210,13 +335,24 @@ whal_Error Board_Init(void)
if (err)
return err;

/* Enable clocks */
/* Enable clocks (excludes ETH — needs SBS RMII config first) */
for (size_t i = 0; i < CLOCK_COUNT; i++) {
err = whal_Clock_Enable(&g_whalClock, &g_clocks[i]);
if (err)
return err;
}

/* Select RMII mode in SBS_PMCR (SBS base 0x44000400 + 0x100) bits [23:21] = 0b100 */
*(volatile uint32_t *)0x44000500 =
(*(volatile uint32_t *)0x44000500 & ~(7UL << 21)) | (4UL << 21);

/* Enable ETH clocks after RMII mode is selected */
for (size_t i = 0; i < ETH_CLOCK_COUNT; i++) {
err = whal_Clock_Enable(&g_whalClock, &g_ethClocks[i]);
if (err)
return err;
}

/* Enable HSI48 for RNG kernel clock */
err = whal_Stm32h5Rcc_Ext_EnableHsi48(&g_whalClock, 1);
if (err)
Expand All @@ -238,6 +374,14 @@ whal_Error Board_Init(void)
if (err)
return err;

err = whal_Eth_Init(&g_whalEth);
if (err)
return err;

err = whal_EthPhy_Init(&g_whalEthPhy);
if (err)
return err;

err = whal_Timer_Init(&g_whalTimer);
if (err)
return err;
Expand Down Expand Up @@ -269,6 +413,14 @@ whal_Error Board_Deinit(void)
if (err)
return err;

err = whal_EthPhy_Deinit(&g_whalEthPhy);
if (err)
return err;

err = whal_Eth_Deinit(&g_whalEth);
if (err)
return err;

err = whal_Rng_Deinit(&g_whalRng);
if (err)
return err;
Expand All @@ -285,6 +437,13 @@ whal_Error Board_Deinit(void)
if (err)
return err;

/* Disable ETH clocks */
for (size_t i = 0; i < ETH_CLOCK_COUNT; i++) {
err = whal_Clock_Disable(&g_whalClock, &g_ethClocks[i]);
if (err)
return err;
}

/* Disable clocks */
for (size_t i = 0; i < CLOCK_COUNT; i++) {
err = whal_Clock_Disable(&g_whalClock, &g_clocks[i]);
Expand Down
16 changes: 16 additions & 0 deletions boards/stm32h563zi_nucleo/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ extern whal_Uart g_whalUart;
extern whal_Spi g_whalSpi;
extern whal_Rng g_whalRng;
extern whal_Flash g_whalFlash;
extern whal_Eth g_whalEth;
extern whal_EthPhy g_whalEthPhy;

extern whal_Timeout g_whalTimeout;
extern volatile uint32_t g_tick;
Expand All @@ -24,6 +26,15 @@ enum {
SPI_MISO_PIN,
SPI_MOSI_PIN,
SPI_CS_PIN,
ETH_RMII_REF_CLK_PIN,
ETH_RMII_MDIO_PIN,
ETH_RMII_MDC_PIN,
ETH_RMII_CRS_DV_PIN,
ETH_RMII_RXD0_PIN,
ETH_RMII_RXD1_PIN,
ETH_RMII_TX_EN_PIN,
ETH_RMII_TXD0_PIN,
ETH_RMII_TXD1_PIN,
PIN_COUNT,
};

Expand All @@ -33,6 +44,11 @@ enum {
#define BOARD_FLASH_TEST_ADDR 0x081FE000
#define BOARD_FLASH_SECTOR_SZ 0x2000

/* Ethernet PHY: LAN8742A on MDIO address 0 */
#define BOARD_ETH_PHY_ADDR 0
#define BOARD_ETH_PHY_ID1 0x0007
#define BOARD_ETH_PHY_ID2 0xC131

whal_Error Board_Init(void);
whal_Error Board_Deinit(void);
void Board_WaitMs(size_t ms);
Expand Down
92 changes: 92 additions & 0 deletions docs/writing_a_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -792,3 +792,95 @@ calling Clock Init.
### Disable

Disable a specific power supply output. The inverse of Enable.

---

## Ethernet

Header: `wolfHAL/eth/eth.h`

The Ethernet driver controls a MAC (Media Access Controller) with an integrated
DMA engine. It manages descriptor rings in RAM for transmit and receive, handles
MDIO bus access for PHY communication, and configures the MAC for the negotiated
link speed and duplex.

### Init

Initialize the MAC, DMA, and MTL. Set up TX and RX descriptor rings in RAM,
program the MAC address, and configure DMA bus mode and burst lengths. Does NOT
enable TX/RX — call Start for that. The descriptor and buffer memory must be
pre-allocated by the board and passed via the config struct. Validate all config
fields (descriptor counts > 0, buffer pointers non-NULL, buffer sizes > 0).

### Deinit

Perform a DMA software reset to clear all state.

### Start

Configure the MAC speed and duplex to match the PHY, enable MAC TX/RX, start
the DMA TX and RX engines, and kick the RX DMA by writing the tail pointer.
Speed and duplex are passed as parameters — the board reads these from the PHY
driver before calling Start.

### Stop

Stop DMA TX and RX engines, then disable MAC TX and RX.

### Send

Transmit a single Ethernet frame. Find the next available TX descriptor (OWN=0),
copy the frame into the pre-allocated TX buffer, fill in the descriptor fields
(buffer address, length, OWN=1, FD, LD), and write the DMA tail pointer to kick
transmission. Return WHAL_ENOTREADY if no descriptor is available. Validate that
the frame length does not exceed the TX buffer size.

### Recv

Receive a single Ethernet frame by polling. Check the next RX descriptor — if
OWN=0, DMA has written a frame. Read the packet length from the descriptor, copy
the frame data to the caller's buffer, re-arm the descriptor (set OWN=1), and
update the tail pointer. Return WHAL_ENOTREADY if no frame is available, or
WHAL_EHARDWARE if the error summary bit is set.

### MdioRead

Read a 16-bit PHY register via the MDIO management bus. Write the PHY address,
register address, and read command to the MDIO address register, poll for
completion, then read the data register. Use a timeout to avoid infinite hang
if the PHY is not responding.

### MdioWrite

Write a 16-bit value to a PHY register via MDIO. Write the data first, then
issue the write command and poll for completion with a timeout.

---

## EthPhy

Header: `wolfHAL/eth_phy/eth_phy.h`

The Ethernet PHY driver handles link negotiation and status for an external PHY
chip connected to a MAC via the MDIO bus. The PHY device struct holds a pointer
to its parent MAC (for MDIO access) and the PHY address on the bus. Different
PHY chips (e.g., LAN8742A, DP83848) have different vendor-specific registers
but share the same API.

### Init

Reset the PHY via software reset (BCR bit 15), wait for the reset bit to
self-clear, then enable autonegotiation. Does not block waiting for link — the
board or application polls GetLinkState separately.

### Deinit

Power down the PHY or release resources. May be a no-op on simple PHYs.

### GetLinkState

Read the current link status, negotiated speed, and duplex mode. The IEEE 802.3
BSR register (reg 1) link bit is latching-low — read it twice and use the second
result for current status. Speed and duplex are read from a vendor-specific
status register (e.g., register 0x1F on LAN8742A). Return speed as 10 or 100,
and duplex as WHAL_ETH_DUPLEX_HALF or WHAL_ETH_DUPLEX_FULL.
Loading
Loading