Skip to content

Commit 7d6a1fe

Browse files
author
Jamie Smith
authored
Add CompositeEMAC and use it to rewrite STM32 Ethernet MAC driver (#438)
* Start on EMAC rewrite, but realized I can't do zero copy Tx Make progress on driver More progress, but I realized that I can't free packets from an ISR... Driver building, now I can start testing... Add CompositeEthMac MAC boots and can send! Rx not working yet though Sending and receiving sort of working! Clean up CTP code to use structs Fix dumb cache and off by one issues with Rx Fix a couple memory issues, making progress... Fix double free when transmission uses more than 1 descriptor Start adding multicast support Making progress on multicast support Multicast filter working! Tests passing! Improve mcast filter test * multicast test working now! * Working with no hacky workarounds!!!11!11! * Update Nanostack memory manager, run formatter, make tests test nanostack * Fix build * Keep workin' on CompositeEMAC * Implement GenericEthPhy * Implement Tx DMA * Start on Rx DMA * Finish Rx DMA and multicast subscribes * Progress on MAC driver * Initial implementation of MAC driver complete! * CompositeEMAC inits! * Phy task and Tx seem to work! * Rx kinda working * Almost working! Just missing memory freed callback * Woring! Add initial support for STM32H5 as well * Fix STM32H5 init * Ethernet working on STM32H5! * Run formatter * Fix us ticker build error * Start on MAC v1 driver * Working on v1 DMA * Initial implementation of v1 DMA * Fix some bugs, Tx DMA working but no packets are getting transmitted * Tx and Rx working! * Update F2 and F4 eth inits * Try to fix bank test * Disable Ethernet in HALs * Apparently old GCC can't do attribute packed + alignas * Add RMII watchdog, add power test, fix unittests build * Debugging EMAC reboot test * Fix deinit crash on STM32F7 * Fix a couple issues with the power down test * Start on docs * Oops missed diagram * Fix typo * Bugfix, improve docs * Fix PNG * More docs, renames * More renames, fix != * Document Tx DMA * Fix some DMA bugs: - Broken check in Tx DMA meant it was always copying packets - Tx DMA would assert fail from trying to free nullptr if an allocation failed during packet copy - Rx DMA would not reset firstDescIdx after seeing an error descriptor, leading to an attempt to receive a 0 length packet about 20% of the time we ran the EMAC memory test * Make EMAC memory test smarter. It now disables pool allocations when disabling input memory, and errors out if the MAC was working when it shouldn't've been. * Document most of Rx DMA, do rename * Reformat, fix STM32 Eth v2 potential to have issues when the Tx ring gets full * Finish documenting Rx DMA
1 parent 1fdce7d commit 7d6a1fe

File tree

116 files changed

+12352
-4634
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+12352
-4634
lines changed

connectivity/drivers/emac/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ if(NOT "DEVICE_EMAC=1" IN_LIST MBED_TARGET_DEFINITIONS)
55
return()
66
endif()
77

8-
add_library(mbed-emac STATIC EXCLUDE_FROM_ALL)
8+
add_library(mbed-emac STATIC EXCLUDE_FROM_ALL
9+
sources/CompositeEMAC.cpp
10+
sources/GenericEthPhy.cpp
11+
sources/PhyDrivers.cpp)
12+
13+
target_include_directories(mbed-emac PUBLIC include)
914

1015
if("ARM_FM" IN_LIST MBED_TARGET_LABELS)
1116
add_subdirectory(TARGET_ARM_FM)

connectivity/drivers/emac/CompositeEMAC.md

Lines changed: 234 additions & 0 deletions
Large diffs are not rendered by default.

connectivity/drivers/emac/TARGET_STM/CMakeLists.txt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,28 @@ elseif("STM32F7" IN_LIST MBED_TARGET_LABELS)
99
add_subdirectory(TARGET_STM32F7)
1010
elseif("STM32H7" IN_LIST MBED_TARGET_LABELS)
1111
add_subdirectory(TARGET_STM32H7)
12+
elseif("STM32H5" IN_LIST MBED_TARGET_LABELS)
13+
add_subdirectory(TARGET_STM32H5)
1214
endif()
1315

1416
target_include_directories(mbed-emac
1517
PUBLIC
1618
.
1719
)
1820

19-
target_sources(mbed-emac
20-
PRIVATE
21-
stm32xx_emac.cpp
22-
)
21+
if("STM32H7" IN_LIST MBED_TARGET_LABELS OR "STM32H5" IN_LIST MBED_TARGET_LABELS)
22+
target_sources(mbed-emac
23+
PRIVATE
24+
STM32EthMACv2.cpp
25+
)
26+
endif()
27+
28+
if("STM32F2" IN_LIST MBED_TARGET_LABELS OR "STM32F4" IN_LIST MBED_TARGET_LABELS OR "STM32F7" IN_LIST MBED_TARGET_LABELS)
29+
target_sources(mbed-emac
30+
PRIVATE
31+
STM32EthMACv1.cpp
32+
)
33+
endif()
34+
35+
36+
target_compile_options(mbed-emac PRIVATE -Wno-packed-bitfield-compat)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* Copyright (c) 2025 Jamie Smith
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include "device.h"
20+
#include "CompositeEMAC.h"
21+
#include "MbedCRC.h"
22+
23+
// Figure out the Ethernet IP version in use
24+
#if defined(TARGET_STM32H5) || defined(TARGET_STM32H7)
25+
#define ETH_IP_VERSION_V2
26+
#else
27+
#define ETH_IP_VERSION_V1
28+
#endif
29+
30+
namespace mbed
31+
{
32+
constexpr auto MDIO_TRANSACTION_TIMEOUT = std::chrono::milliseconds(1); // used by STMicro HAL
33+
34+
inline constexpr size_t NUM_PERFECT_FILTER_REGS = 3;
35+
static const std::pair<volatile uint32_t *, volatile uint32_t *> MAC_ADDR_PERF_FILTER_REGS[NUM_PERFECT_FILTER_REGS] = {
36+
{&ETH->MACA1HR, &ETH->MACA1LR},
37+
{&ETH->MACA2HR, &ETH->MACA2LR},
38+
{&ETH->MACA3HR, &ETH->MACA3LR}
39+
};
40+
41+
/// Write a MAC address into the given registers with the needed encoding
42+
static inline void writeMACAddress(const CompositeEMAC::MACAddress & mac, volatile uint32_t *addrHighReg, volatile uint32_t *addrLowReg)
43+
{
44+
/* Set MAC addr bits 32 to 47 */
45+
*addrHighReg = (static_cast<uint32_t>(mac[5]) << 8) | static_cast<uint32_t>(mac[4]) | ETH_MACA1HR_AE_Msk;
46+
/* Set MAC addr bits 0 to 31 */
47+
*addrLowReg = (static_cast<uint32_t>(mac[3]) << 24) | (static_cast<uint32_t>(mac[2]) << 16) |
48+
(static_cast<uint32_t>(mac[1]) << 8) | static_cast<uint32_t>(mac[0]);
49+
}
50+
51+
/// Add a MAC address to the multicast hash filter.
52+
void addHashFilterMAC(ETH_TypeDef * base, const CompositeEMAC::MACAddress & mac) {
53+
#if defined(ETH_IP_VERSION_V2)
54+
uint32_t volatile * hashRegs[] = {
55+
&base->MACHT0R,
56+
&base->MACHT1R
57+
};
58+
#else
59+
uint32_t volatile * hashRegs[] = {
60+
&base->MACHTLR,
61+
&base->MACHTHR
62+
};
63+
#endif
64+
65+
// Note: as always, the datasheet description of how to do this CRC was vague and slightly wrong.
66+
// This forum thread figured it out: https://community.st.com/t5/stm32-mcus-security/calculating-ethernet-multicast-filter-hash-value/td-p/416984
67+
// What the datasheet SHOULD say is:
68+
// Compute the Ethernet CRC-32 of the MAC address, with initial value of 1s, final XOR of ones, and input reflection on but output reflection off
69+
// Then, take the upper 6 bits and use that to index the hash table.
70+
71+
mbed::MbedCRC<POLY_32BIT_ANSI> crcCalc(0xFFFFFFFF, 0xFFFFFFFF, true, false);
72+
73+
// Compute Ethernet CRC-32 of the MAC address
74+
uint32_t crc;
75+
crcCalc.compute(mac.data(), mac.size(), &crc);
76+
77+
// Take upper 6 bits
78+
uint32_t hashVal = crc >> 26;
79+
80+
// Set correct bit in hash filter
81+
*hashRegs[hashVal >> 5] |= (1 << (hashVal & 0x1F));
82+
}
83+
84+
}

0 commit comments

Comments
 (0)