diff --git a/README.md b/README.md
index 3d6b9e4338..f549319882 100644
--- a/README.md
+++ b/README.md
@@ -624,73 +624,74 @@ We have out-of-box support for many development boards including documentation.
DISCO-F303VC
DISCO-F401VC
DISCO-F407VG
-DISCO-F429ZI
+DISCO-F411VE
+DISCO-F429ZI
DISCO-F469NI
DISCO-F746NG
DISCO-F769NI
-DISCO-L152RC
+DISCO-L152RC
DISCO-L476VG
FEATHER-M0
FEATHER-M4
-FEATHER-RP2040
+FEATHER-RP2040
MEGA-2560-PRO
NUCLEO-F031K6
NUCLEO-F042K6
-NUCLEO-F072RB
+NUCLEO-F072RB
NUCLEO-F091RC
NUCLEO-F103RB
NUCLEO-F303K8
-NUCLEO-F303RE
+NUCLEO-F303RE
NUCLEO-F334R8
NUCLEO-F401RE
NUCLEO-F411RE
-NUCLEO-F429ZI
+NUCLEO-F429ZI
NUCLEO-F439ZI
NUCLEO-F446RE
NUCLEO-F446ZE
-NUCLEO-F746ZG
+NUCLEO-F746ZG
NUCLEO-F767ZI
NUCLEO-G070RB
NUCLEO-G071RB
-NUCLEO-G431KB
+NUCLEO-G431KB
NUCLEO-G431RB
NUCLEO-G474RE
NUCLEO-H723ZG
-NUCLEO-H743ZI
+NUCLEO-H743ZI
NUCLEO-L031K6
NUCLEO-L053R8
NUCLEO-L152RE
-NUCLEO-L432KC
+NUCLEO-L432KC
NUCLEO-L452RE
NUCLEO-L476RG
NUCLEO-L496ZG-P
-NUCLEO-L552ZE-Q
+NUCLEO-L552ZE-Q
NUCLEO-U575ZI-Q
OLIMEXINO-STM32
Raspberry Pi Pico
-SAMD21-MINI
+SAMD21-MINI
SAMD21-XPLAINED-PRO
SAME54-XPLAINED-PRO
SAME70-XPLAINED
-SAMG55-XPLAINED-PRO
+SAMG55-XPLAINED-PRO
SAMV71-XPLAINED-ULTRA
Smart Response XE
STM32-F4VE
-STM32F030-DEMO
+STM32F030-DEMO
THINGPLUS-RP2040
diff --git a/examples/generic/usb/project.xml b/examples/generic/usb/project.xml
index 91e2aceba2..4abc6e9b9f 100644
--- a/examples/generic/usb/project.xml
+++ b/examples/generic/usb/project.xml
@@ -5,6 +5,7 @@
+
diff --git a/src/modm/board/disco_f411ve/board.hpp b/src/modm/board/disco_f411ve/board.hpp
new file mode 100644
index 0000000000..0e4b470a2b
--- /dev/null
+++ b/src/modm/board/disco_f411ve/board.hpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2024, Thomas Sommer
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+#pragma once
+
+#include
+#include
+#include
+
+using namespace modm::platform;
+
+namespace Board
+{
+/// @ingroup modm_board_disco_f411ve
+/// @{
+using namespace modm::literals;
+
+/// STM32F411 running at 96MHz generated from the external 8MHz crystal
+struct SystemClock
+{
+ static constexpr uint32_t Frequency = 96_MHz;
+ static constexpr uint32_t Ahb = Frequency;
+ static constexpr uint32_t Apb1 = Frequency / 2;
+ static constexpr uint32_t Apb2 = Frequency;
+
+ static constexpr uint32_t Adc = Apb2;
+
+ static constexpr uint32_t Spi1 = Apb2;
+ static constexpr uint32_t Spi2 = Apb1;
+ static constexpr uint32_t Spi3 = Apb1;
+ static constexpr uint32_t Spi4 = Apb2;
+ static constexpr uint32_t Spi5 = Apb2;
+
+ static constexpr uint32_t Usart1 = Apb2;
+ static constexpr uint32_t Usart2 = Apb1;
+ static constexpr uint32_t Usart3 = Apb1;
+ static constexpr uint32_t Uart4 = Apb1;
+ static constexpr uint32_t Uart5 = Apb1;
+ static constexpr uint32_t Usart6 = Apb2;
+ static constexpr uint32_t Uart7 = Apb1;
+ static constexpr uint32_t Uart8 = Apb1;
+
+ static constexpr uint32_t I2c1 = Apb1;
+ static constexpr uint32_t I2c2 = Apb1;
+ static constexpr uint32_t I2c3 = Apb1;
+
+ static constexpr uint32_t Apb1Timer = Apb1 * 2;
+ static constexpr uint32_t Apb2Timer = Apb2 * 2;
+ static constexpr uint32_t Timer1 = Apb2Timer;
+ static constexpr uint32_t Timer2 = Apb1Timer;
+ static constexpr uint32_t Timer3 = Apb1Timer;
+ static constexpr uint32_t Timer4 = Apb1Timer;
+ static constexpr uint32_t Timer5 = Apb1Timer;
+ static constexpr uint32_t Timer9 = Apb2Timer;
+ static constexpr uint32_t Timer10 = Apb2Timer;
+ static constexpr uint32_t Timer11 = Apb2Timer;
+
+ static constexpr uint32_t Usb = 48_MHz;
+
+ static bool inline enable()
+ {
+ Rcc::enableExternalCrystal(); // 8MHz
+ const Rcc::PllFactors pllFactors{
+ .pllM = 7, // 8MHz / M=7 -> ~1.14MHz
+ .pllN = 336, // 1.14MHz * N=336 -> 384MHz
+ .pllP = 4, // 384MHz / P=4 -> 96MHz = F_cpu
+ .pllQ = 8, // 384MHz / P=8 -> 48MHz = F_usb
+ };
+ Rcc::enablePll(Rcc::PllSource::ExternalCrystal, pllFactors);
+ // set flash latency for 100MHz
+ Rcc::setFlashLatency();
+ // switch system clock to PLL output
+ Rcc::enableSystemClock(Rcc::SystemClockSource::Pll);
+ Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1);
+ // APB1 has max. 50MHz
+ // APB2 has max. 100MHz
+ Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2);
+ Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1);
+ // update frequencies for busy-wait delay functions
+ Rcc::updateCoreFrequency();
+
+ return true;
+ }
+};
+
+using LedUsb = GpioOutputA9;
+using ClockOut = GpioOutputA8;
+using SystemClockOut = GpioOutputC9;
+
+using Button = GpioInputA0;
+
+// 4 user colored LEDs aligned in a circle
+using LedGreen = GpioOutputD12;
+using LedOrange = GpioOutputD13;
+using LedRed = GpioOutputD14;
+using LedBlue = GpioOutputD15;
+using Leds = SoftwareGpioPort;
+/// @}
+
+namespace lis3
+{
+/// @ingroup modm_board_disco_f411ve
+/// @{
+using Int = GpioInputE1; // LIS302DL_INT2
+
+using Cs = GpioOutputE3; // LIS302DL_CS_I2C/SPI
+using Sck = GpioOutputA5; // SPI1_SCK
+using Mosi = GpioOutputA7; // SPI1_MOSI
+using Miso = GpioInputA6; // SPI1_MISO
+
+using SpiMaster = SpiMaster1;
+using Transport = modm::Lis3TransportSpi;
+/// @}
+}
+
+
+namespace cs43
+{
+/// @ingroup modm_board_disco_f411ve
+/// @{
+using Lrck = GpioOutputA4; // I2S3_WS
+using Mclk = GpioOutputC7; // I2S3_MCK
+using Sclk = GpioOutputC10; // I2S3_SCK
+using Sdin = GpioOutputC12; // I2S3_SD
+
+using Reset = GpioOutputD4; // Audio_RST
+using Scl = GpioB6; // Audio_SCL
+using Sda = GpioB9; // Audio_SDA
+
+using I2cMaster = I2cMaster1;
+// using I2sMaster = I2sMaster3;
+/// @}
+}
+
+
+namespace mp45
+{
+/// @ingroup modm_board_disco_f411ve
+/// @{
+using Clk = GpioOutputB10; // CLK_IN: I2S2_CK
+using Dout = GpioInputC3; // PDM_OUT: I2S2_SD
+// using I2sMaster = I2sMaster2;
+/// @}
+}
+
+
+namespace usb
+{
+/// @ingroup modm_board_disco_f411ve
+/// @{
+using Vbus = GpioInputA9; // VBUS_FS: USB_OTG_HS_VBUS
+using Id = GpioA10; // OTG_FS_ID: USB_OTG_FS_ID
+using Dm = GpioA11; // OTG_FS_DM: USB_OTG_FS_DM
+using Dp = GpioA12; // OTG_FS_DP: USB_OTG_FS_DP
+
+using Overcurrent = GpioInputD5; // OTG_FS_OverCurrent
+using Power = GpioOutputC0; // OTG_FS_PowerSwitchOn
+
+using Device = UsbFs;
+/// @}
+}
+
+/// @ingroup modm_board_disco_f411ve
+/// @{
+inline void
+initialize()
+{
+ SystemClock::enable();
+ SysTickTimer::initialize();
+
+ Leds::setOutput(modm::Gpio::Low);
+ LedUsb::setOutput(modm::Gpio::Low);
+
+ Button::setInput(Gpio::InputType::Floating);
+}
+
+inline void
+initializeLis3()
+{
+ lis3::Int::setInput();
+ lis3::Cs::setOutput(modm::Gpio::High);
+
+ lis3::SpiMaster::connect();
+ lis3::SpiMaster::initialize();
+ lis3::SpiMaster::setDataMode(lis3::SpiMaster::DataMode::Mode3);
+}
+
+/// not supported yet, due to missing I2S driver
+inline void
+initializeCs43()
+{
+ // cs43::Lrck::connect(cs43::I2sMaster::Ws);
+ // cs43::Mclk::connect(cs43::I2sMaster::Mck);
+ // cs43::Sclk::connect(cs43::I2sMaster::Ck);
+ // cs43::Sdin::connect(cs43::I2sMaster::Sd);
+
+ cs43::Reset::setOutput(modm::Gpio::High);
+
+ cs43::I2cMaster::connect();
+ cs43::I2cMaster::initialize();
+}
+
+/// not supported yet, due to missing I2S driver
+inline void
+initializeMp45()
+{
+ // mp45::Clk::connect(mp45::I2sMaster::Ck);
+ // mp45::Dout::connect(mp45::I2sMaster::Sd);
+}
+
+inline void
+initializeUsbFs(uint8_t priority=3)
+{
+ usb::Device::initialize(priority);
+ usb::Device::connect();
+
+ usb::Overcurrent::setInput();
+ usb::Vbus::setInput();
+ // Enable VBUS sense (B device) via pin PA9
+ USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_NOVBUSSENS;
+ USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBUSBSEN;
+}
+/// @}
+}
diff --git a/src/modm/board/disco_f411ve/board.xml b/src/modm/board/disco_f411ve/board.xml
new file mode 100644
index 0000000000..ee97f5e7f9
--- /dev/null
+++ b/src/modm/board/disco_f411ve/board.xml
@@ -0,0 +1,14 @@
+
+
+
+ ../../../../repo.lb
+
+
+
+
+ stm32f411vet6
+
+
+ modm:board:disco-f411ve
+
+
diff --git a/src/modm/board/disco_f411ve/module.lb b/src/modm/board/disco_f411ve/module.lb
new file mode 100644
index 0000000000..3d736c326f
--- /dev/null
+++ b/src/modm/board/disco_f411ve/module.lb
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2024, Thomas Sommer
+#
+# This file is part of the modm project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+# -----------------------------------------------------------------------------
+
+def init(module):
+ module.name = ":board:disco-f411ve"
+ module.description = """\
+# STM32F4DISCOVERY
+
+[Discovery kit for STM32F411](https://www.st.com/en/evaluation-tools/32f411ediscovery.html)
+"""
+
+def prepare(module, options):
+ if not options[":target"].partname.startswith("stm32f411ve"):
+ return False
+
+ module.depends(
+ ":architecture:clock",
+ ":driver:lis3dsh",
+ ":driver:lsm303a",
+ ":driver:l3gd20",
+ ":platform:clock",
+ ":platform:core",
+ ":platform:gpio",
+ ":platform:i2c:1",
+ ":platform:spi:1",
+ ":platform:usb:fs")
+ return True
+
+def build(env):
+ env.outbasepath = "modm/src/modm/board"
+ env.substitutions = {
+ "with_logger": False,
+ "with_assert": env.has_module(":architecture:assert")
+ }
+ env.template("../board.cpp.in", "board.cpp")
+ env.copy('.')
+ env.collect(":build:openocd.source", "board/stm32f4discovery.cfg");