diff --git a/CMakeLists.txt b/CMakeLists.txt
index 197c8e5e501c4239fb7514fc2eb0dfce6743c0f7..cd569bd1c47ea3fbc8942de427aef77eea875a6c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -227,9 +227,6 @@ sbs_target(test-timer-utils stm32f429zi_stm32f4discovery)
 add_executable(test-timestamptimer src/tests/drivers/timer/test-timestamptimer.cpp)
 sbs_target(test-timestamptimer stm32f429zi_stm32f4discovery)
 
-add_executable(test-vn100serial src/tests/drivers/test-vn100serial.cpp)
-sbs_target(test-vn100serial stm32f407vg_stm32f4discovery)
-
 add_executable(test-xbee-bidir src/tests/drivers/xbee/test-xbee-bidir.cpp)
 sbs_target(test-xbee-bidir stm32f429zi_skyward_death_stack_x)
 
@@ -245,8 +242,11 @@ sbs_target(test-xbee-rcv stm32f429zi_stm32f4discovery)
 add_executable(test-xbee-snd src/tests/drivers/xbee/test-xbee-snd.cpp)
 sbs_target(test-xbee-snd stm32f429zi_stm32f4discovery)
 
-add_executable(test-usart src/tests/drivers/usart/test-usart.cpp)
-sbs_target(test-usart stm32f407vg_stm32f4discovery)
+add_executable(test-usart-f4 src/tests/drivers/usart/test-usart.cpp)
+sbs_target(test-usart-f4 stm32f429zi_stm32f4discovery)
+
+add_executable(test-usart-f7 src/tests/drivers/usart/test-usart.cpp)
+sbs_target(test-usart-f7 stm32f767zi_nucleo)
 
 add_executable(test-i2c-driver-f4 src/tests/drivers/i2c/test-i2c-driver.cpp)
 sbs_target(test-i2c-driver-f4 stm32f429zi_stm32f4discovery)
diff --git a/src/entrypoints/runcam-settings.cpp b/src/entrypoints/runcam-settings.cpp
index 770fc5f5386a71daa280410e20a893877830df31..d87ac005682aa80bf319a4cec48f8bb96240efca 100644
--- a/src/entrypoints/runcam-settings.cpp
+++ b/src/entrypoints/runcam-settings.cpp
@@ -52,7 +52,10 @@ int main()
 
     tx.alternateFunction(7);
     rx.alternateFunction(7);
-    Runcam test(1);
+
+    USART usart1(USART1, 115200);
+
+    Runcam test(usart1);
     if (!test.init())
     {
         return -1;
diff --git a/src/shared/drivers/runcam/Runcam.cpp b/src/shared/drivers/runcam/Runcam.cpp
index 87f14d8b9289e69ea3a54517873b496139ad448c..95f51480e9fc191290612370819de20893c16d33 100644
--- a/src/shared/drivers/runcam/Runcam.cpp
+++ b/src/shared/drivers/runcam/Runcam.cpp
@@ -27,7 +27,7 @@
 namespace Boardcore
 {
 
-Runcam::Runcam(unsigned int portNumber) : portNumber(portNumber) {}
+Runcam::Runcam(USARTInterface &usart) : usart(usart) {}
 
 bool Runcam::init()
 {
@@ -38,12 +38,6 @@ bool Runcam::init()
         return true;
     }
 
-    if (!configureSerialCommunication())
-    {
-        LOG_ERR(logger, "Unable to config camera port");
-        return false;
-    }
-
     isInit = true;
 
     Runcam::moveDown();
@@ -63,39 +57,18 @@ bool Runcam::close()
         return true;
     }
 
-    // Close the serial
-    if (!serialInterface->closeSerial())
-    {
-        LOG_ERR(logger, "Unable to close serial communication");
-        return false;
-    }
-
     isInit = false;
 
-    // Free the serialInterface memory
-    delete serialInterface;
-
     return true;
 }
 
-void Runcam::openMenu() { serialInterface->send(&OPEN_MENU, 4); }
-
-void Runcam::selectSetting() { serialInterface->send(&SELECT_SETTING, 4); }
+void Runcam::openMenu() { usart.write(&OPEN_MENU, sizeof(OPEN_MENU)); }
 
-void Runcam::moveDown() { serialInterface->send(&MOVE_DOWN, 4); }
-
-bool Runcam::configureSerialCommunication()
+void Runcam::selectSetting()
 {
-    serialInterface = new RuncamSerial(portNumber, defaultBaudRate);
-
-    // Check correct serial init
-    if (!serialInterface->init())
-    {
-        LOG_ERR(logger, "Unable to config the default serial port");
-        return false;
-    }
-
-    return true;
+    usart.write(&SELECT_SETTING, sizeof(SELECT_SETTING));
 }
 
+void Runcam::moveDown() { usart.write(&MOVE_DOWN, sizeof(MOVE_DOWN)); }
+
 }  // namespace Boardcore
diff --git a/src/shared/drivers/runcam/Runcam.h b/src/shared/drivers/runcam/Runcam.h
index eabb564aee0b43d768e2b0c15fa0f490f4d2310f..3095ae5003835c30f54218c34779eb914819826e 100644
--- a/src/shared/drivers/runcam/Runcam.h
+++ b/src/shared/drivers/runcam/Runcam.h
@@ -105,7 +105,7 @@ through the two modes: Video/OSD settings(Long press wifi button);
 #include <diagnostic/PrintLogger.h>
 #include <utils/Debug.h>
 
-#include "RuncamSerial.h"
+#include "drivers/usart/USART.h"
 
 namespace Boardcore
 {
@@ -116,7 +116,9 @@ namespace Boardcore
 class Runcam
 {
 public:
-    Runcam(unsigned int portNumber = defaultPortNumber);
+    explicit Runcam(USARTInterface &serial);
+
+    Runcam() = delete;
 
     bool init();
 
@@ -129,12 +131,6 @@ public:
     void moveDown();
 
 private:
-    /**
-     * @brief Configure Serial Communication
-     */
-    bool configureSerialCommunication();
-
-    unsigned int portNumber;
     bool isInit = false;
 
     /**
@@ -153,12 +149,9 @@ private:
      */
     uint32_t OPEN_MENU = 0xCC01024D;
 
-    RuncamSerial *serialInterface = nullptr;
+    USARTInterface &usart;
 
     PrintLogger logger = Logging::getLogger("runcam");
-
-    static const unsigned int defaultBaudRate   = 115200;
-    static const unsigned int defaultPortNumber = 1;
 };
 
 }  // namespace Boardcore
diff --git a/src/shared/drivers/runcam/RuncamSerial.h b/src/shared/drivers/runcam/RuncamSerial.h
deleted file mode 100644
index bf5158e0b33039d6bc2216248151df59139f1eab..0000000000000000000000000000000000000000
--- a/src/shared/drivers/runcam/RuncamSerial.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/* Copyright (c) 2021 Skyward Experimental Rocketry
- * Author: Matteo Pignataro
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#pragma once
-
-#include <arch/common/drivers/serial.h>
-#include <fcntl.h>
-#include <filesystem/file_access.h>
-#include <miosix.h>
-
-namespace Boardcore
-{
-
-/**
- * @brief Class to communicate with the Runcam via serial.
- */
-class RuncamSerial
-{
-public:
-    RuncamSerial(int serialPortNumber, int serialBaudRate);
-
-    /**
-     * @brief Initialization method
-     * @return Boolean which communicates the init process result
-     */
-    bool init();
-
-    /**
-     * @brief Writes in Serial data
-     * Note: to send std::string via serial you need to pass use "c_str()"
-     * method
-     * @param Data to be sent via serial
-     * @return Boolean which communicates the send process result
-     */
-    template <typename DataSend>
-    bool send(DataSend *data, int length);
-
-    /**
-     * @brief Reads from serial
-     * @param Pointer to the data structure where we need to store data
-     * @return Boolean which communicates the recive process result
-     */
-    template <typename DataReceive>
-    bool recv(DataReceive *data, int length);
-
-    /**
-     * @brief Closes the serial communication
-     */
-    bool closeSerial();
-
-private:
-    int serialPortNumber;
-    int serialBaudRate;
-    int serialFileDescriptor = 0;
-    bool isInit              = false;
-};
-
-inline RuncamSerial::RuncamSerial(int serialPortNumber, int serialBaudRate)
-    : serialPortNumber(serialPortNumber), serialBaudRate(serialBaudRate)
-{
-}
-
-inline bool RuncamSerial::init()
-{
-    // If already initialized i avoid the procedure
-    if (isInit)
-    {
-        return true;
-    }
-
-    // Retrieve the file system instance
-    miosix::intrusive_ref_ptr<miosix::DevFs> devFs =
-        miosix::FilesystemManager::instance().getDevFs();
-
-    // Create the serial file which we read and write to communicate
-    if (!(devFs->addDevice(
-            "Runcam",
-            miosix::intrusive_ref_ptr<miosix::Device>(
-                new miosix::STM32Serial(serialPortNumber, serialBaudRate)))))
-    {
-        return false;
-    }
-
-    // Open the file
-    serialFileDescriptor = open("/dev/Runcam", O_RDWR);
-
-    // Check the descriptor
-    if (serialFileDescriptor <= 0)
-    {
-        return false;
-    }
-
-    // Success
-    isInit = true;
-    return true;
-}
-
-template <typename DataSend>
-inline bool RuncamSerial::send(DataSend *data, int length)
-{
-    // Check if the serial has been previously initialized
-    if (!isInit)
-    {
-        return false;
-    }
-
-    // Write the file with the data
-    if (!write(serialFileDescriptor, data, length))
-    {
-        return false;
-    }
-
-    return true;
-}
-
-template <typename DataReceive>
-inline bool RuncamSerial::recv(DataReceive *data, int length)
-{
-    if (!isInit)
-    {
-        return false;
-    }
-
-    // Read the data and store it in memory
-    if (!read(serialFileDescriptor, data, length))
-    {
-        return false;
-    }
-
-    return true;
-}
-
-inline bool RuncamSerial::closeSerial()
-{
-    // Retrieve the file system instance
-    miosix::intrusive_ref_ptr<miosix::DevFs> devFs =
-        miosix::FilesystemManager::instance().getDevFs();
-
-    // Close the file descriptor
-    close(serialFileDescriptor);
-
-    // Remove the file
-    if (!(devFs->remove("Runcam")))
-    {
-        return false;
-    }
-
-    return true;
-}
-
-}  // namespace Boardcore
diff --git a/src/shared/drivers/usart/USART.cpp b/src/shared/drivers/usart/USART.cpp
index 00a6485273e5353d3b08a1c2523b4a1a3711a865..171edb219ac19b73147b84d101ed9c0945d35b5a 100644
--- a/src/shared/drivers/usart/USART.cpp
+++ b/src/shared/drivers/usart/USART.cpp
@@ -32,14 +32,16 @@
 #include "filesystem/file_access.h"
 #include "miosix.h"
 
-Boardcore::USART *Boardcore::USART::ports[N_USART_PORTS];
+///< Pointer to serial port classes to let interrupts access the classes
+Boardcore::USART *ports[N_USART_PORTS];
 
+#ifdef USART1
 /**
  * \internal Interrupt routine for usart1 actual implementation.
  */
 void __attribute__((used)) usart1irqImplBoardcore()
 {
-    Boardcore::USART *port_boardcore = Boardcore::USART::ports[0];
+    Boardcore::USART *port_boardcore = ports[0];
     if (port_boardcore)
         port_boardcore->IRQhandleInterrupt();
     else
@@ -59,13 +61,15 @@ void __attribute__((naked, used)) USART1_IRQHandler()
     asm volatile("bl _Z22usart1irqImplBoardcorev");
     restoreContext();
 }
+#endif
 
+#ifdef USART2
 /**
  * \internal Interrupt routine for usart2 actual implementation.
  */
 void __attribute__((used)) usart2irqImplBoardcore()
 {
-    Boardcore::USART *port_boardcore = Boardcore::USART::ports[1];
+    Boardcore::USART *port_boardcore = ports[1];
     if (port_boardcore)
         port_boardcore->IRQhandleInterrupt();
     else
@@ -85,13 +89,15 @@ void __attribute__((naked, used)) USART2_IRQHandler()
     asm volatile("bl _Z22usart2irqImplBoardcorev");
     restoreContext();
 }
+#endif
 
+#ifdef USART3
 /**
  * \internal Interrupt routine for usart3 actual implementation.
  */
 void __attribute__((used)) usart3irqImplBoardcore()
 {
-    Boardcore::USART *port_boardcore = Boardcore::USART::ports[2];
+    Boardcore::USART *port_boardcore = ports[2];
     if (port_boardcore)
         port_boardcore->IRQhandleInterrupt();
     else
@@ -111,13 +117,15 @@ void __attribute__((naked, used)) USART3_IRQHandler()
     asm volatile("bl _Z22usart3irqImplBoardcorev");
     restoreContext();
 }
+#endif
 
+#ifdef UART4
 /**
  * \internal Interrupt routine for uart4 actual implementation.
  */
 void __attribute__((used)) uart4irqImplBoardcore()
 {
-    Boardcore::USART *port_boardcore = Boardcore::USART::ports[3];
+    Boardcore::USART *port_boardcore = ports[3];
     if (port_boardcore)
         port_boardcore->IRQhandleInterrupt();
     else
@@ -137,13 +145,15 @@ void __attribute__((naked, used)) UART4_IRQHandler()
     asm volatile("bl _Z21uart4irqImplBoardcorev");
     restoreContext();
 }
+#endif
 
+#ifdef UART5
 /**
  * \internal Interrupt routine for uart5 actual implementation.
  */
 void __attribute__((used)) uart5irqImplBoardcore()
 {
-    Boardcore::USART *port_boardcore = Boardcore::USART::ports[4];
+    Boardcore::USART *port_boardcore = ports[4];
     if (port_boardcore)
         port_boardcore->IRQhandleInterrupt();
     else
@@ -163,13 +173,15 @@ void __attribute__((naked, used)) UART5_IRQHandler()
     asm volatile("bl _Z21uart5irqImplBoardcorev");
     restoreContext();
 }
+#endif
 
+#ifdef USART6
 /**
  * \internal Interrupt routine for usart6 actual implementation.
  */
 void __attribute__((used)) usart6irqImplBoardcore()
 {
-    Boardcore::USART *port_boardcore = Boardcore::USART::ports[5];
+    Boardcore::USART *port_boardcore = ports[5];
     if (port_boardcore)
         port_boardcore->IRQhandleInterrupt();
     else
@@ -189,15 +201,15 @@ void __attribute__((naked, used)) USART6_IRQHandler()
     asm volatile("bl _Z22usart6irqImplBoardcorev");
     restoreContext();
 }
+#endif
 
-#ifdef STM32F429xx
-
+#ifdef UART7
 /**
  * \internal Interrupt routine for uart7 actual implementation.
  */
 void __attribute__((used)) uart7irqImplBoardcore()
 {
-    Boardcore::USART *port_boardcore = Boardcore::USART::ports[6];
+    Boardcore::USART *port_boardcore = ports[6];
     if (port_boardcore)
         port_boardcore->IRQhandleInterrupt();
     else
@@ -217,13 +229,15 @@ void __attribute__((naked, used)) UART7_IRQHandler()
     asm volatile("bl _Z21uart7irqImplBoardcorev");
     restoreContext();
 }
+#endif
 
+#ifdef UART8
 /**
  * \internal Interrupt routine for uart8 actual implementation.
  */
 void __attribute__((used)) uart8irqImplBoardcore()
 {
-    Boardcore::USART *port_boardcore = Boardcore::USART::ports[7];
+    Boardcore::USART *port_boardcore = ports[7];
     if (port_boardcore)
         port_boardcore->IRQhandleInterrupt();
     else
@@ -243,129 +257,132 @@ void __attribute__((naked, used)) UART8_IRQHandler()
     asm volatile("bl _Z21uart8irqImplBoardcorev");
     restoreContext();
 }
-
-#endif  // STM32F429xx
+#endif
 
 namespace Boardcore
 {
 
-USARTInterface::~USARTInterface() {}
-
-void USART::IRQhandleInterrupt()
-{
-    char c;
-
-#ifndef _ARCH_CORTEXM7_STM32F7
-    // If read data register is empty then read data
-    if (usart->SR & USART_SR_RXNE)
-    {
-        // Always read data, since this clears interrupt flags
-        c = usart->DR;
-        // If no error put data in buffer
-        if (!(usart->SR & USART_SR_FE))
-            if (rxQueue.tryPut(c) == false)  // FIFO overflow
-                ;
-
-        idle = false;
-    }
-
-    if (usart->SR & USART_SR_IDLE)
-        idle = true;
-
-    if (usart->SR & USART_SR_IDLE || rxQueue.size() >= rxQueue.capacity() / 2)
-    {
-        c = usart->DR;  // Clears interrupt flags
-
-        // Enough data in buffer or idle line, awake thread
-        if (rxWaiting)
-        {
-            rxWaiting->IRQwakeup();
-            rxWaiting = 0;
-        }
-    }
-#else
-    // If read data register is empty then read data
-    if (usart->ISR & USART_ISR_RXNE)
-    {
-        // Always read data
-        c = usart->RDR;
-        // If no error put data in buffer
-        if (!(usart->ISR & USART_ISR_FE))
-            if (rxQueue.tryPut(c) == false)  // FIFO overflow
-                ;
-
-        idle = false;
-    }
-
-    if (usart->ISR & USART_ISR_IDLE)
-        idle = true;
-
-    if (usart->ISR & USART_ISR_IDLE || rxQueue.size() >= rxQueue.capacity() / 2)
-    {
-        usart->ICR = USART_ICR_IDLECF;  // Clears interrupt flags
-
-        // Enough data in buffer or idle line, awake thread
-        if (rxWaiting)
-        {
-            rxWaiting->IRQwakeup();
-            rxWaiting = 0;
-        }
-    }
-#endif
-}
-
-USART::USART(USARTType *usart, Baudrate baudrate, unsigned int queueLen)
-    : rxQueue(queueLen)
+USARTInterface::USARTInterface(USARTType *usart, int baudrate)
+    : usart(usart), baudrate(baudrate)
 {
     // Setting the id of the serial port
     switch (reinterpret_cast<uint32_t>(usart))
     {
+#ifdef USART1
         case USART1_BASE:
-            this->id = 1;
-            irqn     = USART1_IRQn;
+            this->id             = 1;
+            irqn                 = USART1_IRQn;
+            this->serialPortName = std::string("usart1");
             break;
+#endif
+#ifdef USART2
         case USART2_BASE:
-            this->id = 2;
-            irqn     = USART2_IRQn;
+            this->id             = 2;
+            irqn                 = USART2_IRQn;
+            this->serialPortName = std::string("usart2");
             break;
+#endif
+#ifdef USART3
         case USART3_BASE:
-            this->id = 3;
-            irqn     = USART3_IRQn;
+            this->id             = 3;
+            irqn                 = USART3_IRQn;
+            this->serialPortName = std::string("usart3");
             break;
+#endif
+#ifdef UART4
         case UART4_BASE:
-            this->id = 4;
-            irqn     = UART4_IRQn;
+            this->id             = 4;
+            irqn                 = UART4_IRQn;
+            this->serialPortName = std::string("uart4");
             break;
+#endif
+#ifdef UART5
         case UART5_BASE:
-            this->id = 5;
-            irqn     = UART5_IRQn;
+            this->id             = 5;
+            irqn                 = UART5_IRQn;
+            this->serialPortName = std::string("uart5");
             break;
+#endif
+#ifdef USART6
         case USART6_BASE:
-            this->id = 6;
-            irqn     = USART6_IRQn;
+            this->id             = 6;
+            irqn                 = USART6_IRQn;
+            this->serialPortName = std::string("usart6");
             break;
-#ifdef STM32F429xx
+#endif
+#ifdef UART7
         case UART7_BASE:
-            this->id = 7;
-            irqn     = UART7_IRQn;
+            this->id             = 7;
+            irqn                 = UART7_IRQn;
+            this->serialPortName = std::string("uart7");
             break;
+#endif
+#ifdef UART8
         case UART8_BASE:
-            this->id = 8;
-            irqn     = UART8_IRQn;
+            this->id             = 8;
+            irqn                 = UART8_IRQn;
+            this->serialPortName = std::string("uart8");
             break;
-#endif  // STM32F429xx
+#endif
+        default:
+            LOG_ERR(logger, "USART selected not supported!");
+            D(assert(false && "USART selected not supported!"));
     }
+}
 
-    this->usart = usart;
+USARTInterface::~USARTInterface() {}
 
-    // Enabling the peripheral on the right APB
-    ClockUtils::enablePeripheralClock(usart);
+void USART::IRQhandleInterrupt()
+{
+    char c;
+    bool received = false;
+    bool framingError;
 
-    // Enabling the usart peripheral
+#ifndef _ARCH_CORTEXM7_STM32F7
+    // If read data register is empty then read data
+    received = ((usart->SR & USART_SR_RXNE) == 0 ? false : true);
+    // If no error put data in buffer
+    framingError = ((usart->SR & USART_SR_FE) == 0 ? false : true);
+    idle         = ((usart->SR & USART_SR_IDLE) == 0 ? false : true);
+    // Always read data, since this clears interrupt flags
+    c = usart->DR;
+#else
+    // If read data register is empty then read data
+    received = ((usart->ISR & USART_ISR_RXNE) == 0 ? false : true);
+    // If no error put data in buffer
+    framingError = ((usart->ISR & USART_ISR_FE) == 0 ? false : true);
+    idle         = ((usart->ISR & USART_ISR_IDLE) == 0 ? false : true);
+    // Clears interrupt flags
+    usart->ICR = USART_ICR_IDLECF;
+    // Always read data, since this clears interrupt flags
+    c = usart->RDR;
+#endif
+
+    // If we received some data without framing error but the tryPut failed,
+    // report a FIFO overflow
+    if (framingError || (received && !rxQueue.tryPut(c)))
     {
-        miosix::FastInterruptDisableLock dLock;
-        usart->CR1 |= USART_CR1_UE;
+        error = true;
+    }
+
+    // Wake up thread if communication finished (idle state), buffer reached
+    // half of his capacity or error occurred
+    if (error || idle || (rxQueue.size() >= rxQueue.capacity() / 2))
+    {
+        // Enough data in buffer or idle line, awake thread
+        if (rxWaiting)
+        {
+            rxWaiting->IRQwakeup();
+            rxWaiting = nullptr;
+        }
     }
+}
+
+USART::USART(USARTType *usart, int baudrate, unsigned int queueLen)
+    : USARTInterface(usart, baudrate), rxQueue(queueLen)
+{
+    // Enabling the peripheral on the right APB
+    ClockUtils::enablePeripheralClock(usart);
 
     // Setting the baudrate chosen
     setBaudrate(baudrate);
@@ -375,60 +392,48 @@ USART::USART(USARTType *usart, Baudrate baudrate, unsigned int queueLen)
     setWordLength(USART::WordLength::BIT8);
     setParity(USART::ParityBit::NO_PARITY);
     setOversampling(false);
-}
-
-USART::~USART()
-{
-    miosix::FastInterruptDisableLock dLock;
-
-    // Take out the usart object we are going to destruct
-    USART::ports[this->id - 1] = nullptr;
-
-    // Disabling the usart
-    usart->CR1 &= ~(USART_CR1_UE | USART_CR1_TE | USART_CR1_RE);
-
-    // Disabling the interrupt of the serial port
-    NVIC_DisableIRQ(irqn);
-}
-
-bool USART::init()
-{
-    if (id < 1 || id > MAX_SERIAL_PORTS)
-    {
-        TRACE("Not supported USART id\n");
-        return false;
-    }
 
     {
         miosix::FastInterruptDisableLock dLock;
 
         // Enable usart, receiver, receiver interrupt and idle interrupt
-        usart->CR1 |= USART_CR1_RXNEIE    // Interrupt on data received
+        usart->CR1 |= USART_CR1_UE        // Enabling the uart peripheral
+                      | USART_CR1_RXNEIE  // Interrupt on data received
                       | USART_CR1_IDLEIE  // interrupt on idle line
                       | USART_CR1_TE      // Transmission enabled
                       | USART_CR1_RE;     // Reception enabled
 
         // Sample only one bit
         usart->CR3 |= USART_CR3_ONEBIT;
+    }
 
-        // Enabling the interrupt for the relative serial port
-        NVIC_SetPriority(irqn, 15);
-        NVIC_EnableIRQ(irqn);
+    // Add to the array of usarts so that the interrupts can see it
+    ports[id - 1] = this;
 
-        // Add to the array of usarts so that the interrupts can see it
-        USART::ports[id - 1] = this;
-    }
+    // Enabling the interrupt for the relative serial port
+    NVIC_SetPriority(irqn, 15);
+    NVIC_EnableIRQ(irqn);
 
     // Clearing the queue for random data read at the beginning
-    miosix::Thread::sleep(1);
     this->clearQueue();
+}
 
-    return true;
+USART::~USART()
+{
+    miosix::FastInterruptDisableLock dLock;
+
+    // Take out the usart object we are going to destruct
+    ports[this->id - 1] = nullptr;
+
+    // Disabling the usart
+    usart->CR1 &= ~(USART_CR1_UE | USART_CR1_TE | USART_CR1_RE);
+
+    // Disabling the interrupt of the serial port
+    NVIC_DisableIRQ(irqn);
 }
 
 void USART::setWordLength(WordLength wordLength)
 {
-
     miosix::FastInterruptDisableLock dLock;
     (wordLength == WordLength::BIT8 ? usart->CR1 &= ~USART_CR1_M
                                     : usart->CR1 |= USART_CR1_M);
@@ -462,7 +467,7 @@ void USART::setOversampling(bool oversampling)
                   : usart->CR1 &= ~USART_CR1_OVER8);
 }
 
-void USART::setBaudrate(Baudrate baudrate)
+void USART::setBaudrate(int baudrate)
 {
     /*
      * Baudrate setting:
@@ -475,55 +480,49 @@ void USART::setBaudrate(Baudrate baudrate)
      */
     miosix::InterruptDisableLock dLock;
 
-    /*
-     * TODO: This is modified only for compatibility with the past, MUST check
-     * the clock settings in order to use the right method
-     * 'getAPBPeripheralsClock()'
-     */
     // USART1 and USART6 are always connected to the APB2, while all the others
     // UART/USART peripherals are always connected to APB1
-    uint32_t f = ClockUtils::getAPBTimersClock(
+    uint32_t f = ClockUtils::getAPBPeripheralsClock(
         (id == 1 || id == 6 ? ClockUtils::APB::APB2     // High speed APB2
                             : ClockUtils::APB::APB1));  // Low speed APB1
 
     // <<4 in order to shift to left of 4 positions, to create a fixed point
     // number of 4 decimal digits /8 == >>3 in order to divide per 8 (from the
-    // formula in the datasheet)
-    uint32_t USART_DIV = ((f << 1) / (((int)baudrate * (over8 ? 1 : 2))));
+    // formula in the datasheet). So it should be << 1 but, in order to make the
+    // approximation later, we shift it of 2 positions
+    uint32_t brr = ((f << 2) / (((int)baudrate * (over8 ? 1 : 2))));
 
     // rounding to the nearest
-    uint32_t brr = (USART_DIV / 2) + (USART_DIV & 1);
-
-    if (over8)
-    {
-        brr += brr & 1;
-    }
-
-    usart->BRR = brr;
+    usart->BRR = (brr / 2) + (brr & 1);
 
     this->baudrate = baudrate;
 }
 
-int USART::read(void *buffer, size_t nBytes)
+bool USART::readImpl(void *buffer, size_t nBytes, size_t &nBytesRead,
+                     const bool blocking)
 {
     miosix::Lock<miosix::FastMutex> l(rxMutex);
 
     char *buf     = reinterpret_cast<char *>(buffer);
     size_t result = 0;
+    error         = false;
     miosix::FastInterruptDisableLock dLock;
     for (;;)
     {
-        // Try to get data from the queue
+        // Try to get all the data possible from the queue
         for (; result < nBytes; result++)
         {
-            if (rxQueue.tryGet(buf[result]) == false)
+            if (!rxQueue.tryGet(buf[result]))
                 break;
+
             // This is here just not to keep IRQ disabled for the whole loop
             miosix::FastInterruptEnableLock eLock(dLock);
         }
 
-        // Not checking if the nBytes read are more than 0
-        if (result == nBytes || (idle && result > 0))
+        // If blocking, we are waiting for at least one byte of data before
+        // returning. If not blocking, in the case the bus is idle we return
+        // anyway
+        if ((result == nBytes) || (idle && (!blocking || (result > 0))))
             break;
 
         // Wait for data in the queue
@@ -537,11 +536,12 @@ int USART::read(void *buffer, size_t nBytes)
             }
         } while (rxWaiting);
     }
+    nBytesRead = result;
 
-    return result;
+    return (result > 0);
 }
 
-int USART::write(void *buffer, size_t nBytes)
+void USART::write(const void *buffer, size_t nBytes)
 {
     miosix::Lock<miosix::FastMutex> l(txMutex);
 
@@ -561,11 +561,9 @@ int USART::write(void *buffer, size_t nBytes)
         usart->TDR = *buf++;
 #endif
     }
-
-    return i;
 }
 
-int USART::writeString(const char *buffer)
+void USART::writeString(const char *buffer)
 {
     int i = 0;
     miosix::Lock<miosix::FastMutex> l(txMutex);
@@ -595,75 +593,55 @@ int USART::writeString(const char *buffer)
 
         i++;
     };
-
-    return i;
 }
 
 void USART::clearQueue() { rxQueue.reset(); }
 
-STM32SerialWrapper::STM32SerialWrapper(USARTType *usart, Baudrate baudrate)
+STM32SerialWrapper::STM32SerialWrapper(USARTType *usart, int baudrate)
+    : USARTInterface(usart, baudrate)
 {
-    this->usart    = usart;
-    this->baudrate = baudrate;
-    switch (reinterpret_cast<uint32_t>(usart))
+    if (this->id < 1 || this->id > 4)
     {
-        case USART1_BASE:
-            this->id = 1;
-            initPins(u1tx1::getPin(), 7, u1rx1::getPin(), 7);
-            this->serialPortName = std::string("usart1");
-            break;
-        case USART2_BASE:
-            this->id = 2;
-            initPins(u2tx1::getPin(), 7, u2rx1::getPin(), 7);
-            this->serialPortName = std::string("usart2");
-            break;
-        case USART3_BASE:
-            this->id = 3;
-            initPins(u3tx1::getPin(), 7, u3rx1::getPin(), 7);
-            this->serialPortName = std::string("usart3");
-            break;
-        case UART4_BASE:
-            this->id = 4;
-            initPins(u4tx1::getPin(), 8, u4rx1::getPin(), 8);
-            this->serialPortName = std::string("uart4");
-            break;
+        LOG_ERR(logger, "USART selected not supported for STM32SerialWrapper!");
+        D(assert(false &&
+                 "USART selected not supported for STM32SerialWrapper!"));
+    }
+
+    // Creates and adds the serial port to the devices
+    this->serial = new miosix::STM32Serial(id, baudrate);
+
+    if (!serialCommSetup())
+    {
+        LOG_ERR(logger,
+                "[STM32SerialWrapper] can't initialize serial communication!");
+        D(assert(false &&
+                 "[STM32SerialWrapper] Error : can't initialize serial "
+                 "communication!\n"));
     }
-    initialized = false;
-    fd          = -1;
 }
 
-STM32SerialWrapper::STM32SerialWrapper(USARTType *usart, Baudrate baudrate,
+STM32SerialWrapper::STM32SerialWrapper(USARTType *usart, int baudrate,
                                        miosix::GpioPin tx, miosix::GpioPin rx)
+    : USARTInterface(usart, baudrate)
 {
-    this->usart    = usart;
-    this->baudrate = baudrate;
-    switch (reinterpret_cast<uint32_t>(usart))
+    if (this->id < 1 || this->id > 4)
     {
-        case USART1_BASE:
-            this->id             = 1;
-            this->serialPortName = std::string("usart1");
-            break;
-        case USART2_BASE:
-            this->id             = 2;
-            this->serialPortName = std::string("usart2");
-            break;
-        case USART3_BASE:
-            this->id             = 3;
-            this->serialPortName = std::string("usart3");
-            break;
-        case UART4_BASE:
-            this->id             = 4;
-            this->serialPortName = std::string("uart4");
-            break;
+        LOG_ERR(logger, "USART selected not supported for STM32SerialWrapper!");
+        D(assert(false &&
+                 "USART selected not supported for STM32SerialWrapper!"));
     }
 
-    if (id < 4)
-        initPins(tx, 7, rx, 7);
-    else
-        initPins(tx, 8, rx, 8);
+    // Creates and adds the serial port to the devices
+    this->serial = new miosix::STM32Serial(id, baudrate, tx, rx);
 
-    initialized = false;
-    fd          = -1;
+    if (!serialCommSetup())
+    {
+        LOG_ERR(logger,
+                "[STM32SerialWrapper] can't initialize serial communication!");
+        D(assert(false &&
+                 "[STM32SerialWrapper] Error : can't initialize serial "
+                 "communication!\n"));
+    }
 }
 
 STM32SerialWrapper::~STM32SerialWrapper()
@@ -674,50 +652,15 @@ STM32SerialWrapper::~STM32SerialWrapper()
     devFs->remove(serialPortName.c_str());
 }
 
-bool STM32SerialWrapper::init()
-{
-    if (id > 4)
-    {
-        TRACE(
-            "[STM32SerialWrapper] USART id greater than 3 is not supported\n");
-        return false;
-    }
-
-    if (initialized)
-    {
-        TRACE(
-            "[STM32SerialWrapper] Error : serial communication already "
-            "initialized!\n");
-        return false;
-    }
-    else if (!serialCommSetup())
-    {
-        TRACE(
-            "[STM32SerialWrapper] Error : can't initialize serial "
-            "communication!\n");
-        return false;
-    }
-
-    initialized = true;
-    return true;
-}
-
 bool STM32SerialWrapper::serialCommSetup()
 {
-    // Creates and adds the serial port to the devices
-    if (!pinInitialized)
-        serial = new miosix::STM32Serial(id, static_cast<int>(baudrate));
-    else
-    {
-        serial =
-            new miosix::STM32Serial(id, static_cast<int>(baudrate), tx, rx);
-    }
-
     // Adds a device to the file system
     if (!miosix::FilesystemManager::instance().getDevFs()->addDevice(
             serialPortName.c_str(),
             miosix::intrusive_ref_ptr<miosix::Device>(serial)))
+    {
         return false;
+    }
 
     // Path string "/dev/<name_of_port>" for the port we want to open
     std::string serialPortPath = "/dev/" + serialPortName;
@@ -734,41 +677,33 @@ bool STM32SerialWrapper::serialCommSetup()
     return true;
 }
 
-bool STM32SerialWrapper::initPins(miosix::GpioPin tx, int nAFtx,
-                                  miosix::GpioPin rx, int nAFrx)
+bool STM32SerialWrapper::readImpl(void *buffer, size_t nBytes,
+                                  size_t &nBytesRead, const bool blocking)
 {
-    if (pinInitialized)
-        return false;
-
-    miosix::FastInterruptDisableLock dLock;
-
-    this->tx = tx;
-    this->rx = rx;
-
-    tx.mode(miosix::Mode::ALTERNATE);
-    tx.alternateFunction(nAFtx);
-
-    rx.mode(miosix::Mode::ALTERNATE);
-    rx.alternateFunction(nAFrx);
+    // non-blocking read not supported in STM32SerialWrapper
+    if (!blocking)
+    {
+        LOG_ERR(logger,
+                "STM32SerialWrapper::read doesn't support non-blocking read");
+        D(assert(false &&
+                 "STM32SerialWrapper::read doesn't support non-blocking read"));
+    }
 
-    pinInitialized = true;
-    return true;
-}
+    size_t n   = ::read(fd, buffer, nBytes);
+    nBytesRead = n;
 
-int STM32SerialWrapper::writeString(const char *data)
-{
-    // strlen + 1 in order to send the '/0' terminated string
-    return ::write(fd, data, strlen(data) + 1);
+    return (n > 0);
 }
 
-int STM32SerialWrapper::write(void *buf, size_t nChars)
+void STM32SerialWrapper::write(const void *buffer, size_t nBytes)
 {
-    return ::write(fd, buf, nChars);
+    ::write(fd, buffer, nBytes);
 }
 
-int STM32SerialWrapper::read(void *buf, size_t nBytes)
+void STM32SerialWrapper::writeString(const char *buffer)
 {
-    return ::read(fd, buf, nBytes);
+    // strlen + 1 in order to send the '/0' terminated string
+    ::write(fd, buffer, strlen(buffer) + 1);
 }
 
 }  // namespace Boardcore
diff --git a/src/shared/drivers/usart/USART.h b/src/shared/drivers/usart/USART.h
index 8ba3a9369992fb7b5ab33d281e3e9ff3deadebcf..0e45b41a40753aa0fd0e97f41bd47dd2b04f065e 100644
--- a/src/shared/drivers/usart/USART.h
+++ b/src/shared/drivers/usart/USART.h
@@ -22,6 +22,7 @@
 
 #pragma once
 
+#include <diagnostic/PrintLogger.h>
 #include <interfaces/arch_registers.h>
 #include <miosix.h>
 #include <utils/ClockUtils.h>
@@ -37,69 +38,26 @@ using USARTType = USART_TypeDef;
 using USARTType = USART_TypeDef;
 #endif
 
-#ifdef STM32F429xx
+#if defined(UART8)
 #define N_USART_PORTS 8
-#else
+#elif defined(UART7)
+#define N_USART_PORTS 7
+#elif defined(USART6)
 #define N_USART_PORTS 6
+#elif defined(UART5)
+#define N_USART_PORTS 5
+#elif defined(UART4)
+#define N_USART_PORTS 4
+#elif defined(USART3)
+#define N_USART_PORTS 3
+#elif defined(USART2)
+#define N_USART_PORTS 2
+#elif defined(USART1)
+#define N_USART_PORTS 1
+#else
+#error "Your architecture doesn't support UART"
 #endif
 
-// A nice feature of the stm32 is that the USART are connected to the same
-// GPIOS in all families, stm32f1, f2, f4 and l1. Additionally, USART1 and
-// USART6 are always connected to the APB2, while the other USART/UARTs are
-// connected to the APB1.
-
-// USART1: AF7
-typedef miosix::Gpio<GPIOB_BASE, 6> u1tx1;
-typedef miosix::Gpio<GPIOB_BASE, 7> u1rx1;
-typedef miosix::Gpio<GPIOA_BASE, 9> u1tx2;
-typedef miosix::Gpio<GPIOA_BASE, 10> u1rx2;
-// typedef miosix::Gpio<GPIOA_BASE, 11> u1cts;
-// typedef miosix::Gpio<GPIOA_BASE, 12> u1rts;
-
-// USART2: AF7
-typedef miosix::Gpio<GPIOA_BASE, 2> u2tx1;
-typedef miosix::Gpio<GPIOA_BASE, 3> u2rx1;
-typedef miosix::Gpio<GPIOD_BASE, 5> u2tx2;
-typedef miosix::Gpio<GPIOD_BASE, 6> u2rx2;
-// typedef miosix::Gpio<GPIOA_BASE, 0> u2cts;
-// typedef miosix::Gpio<GPIOA_BASE, 1> u2rts;
-
-// USART3: AF7
-typedef miosix::Gpio<GPIOB_BASE, 10> u3tx1;
-typedef miosix::Gpio<GPIOB_BASE, 11> u3rx1;
-typedef miosix::Gpio<GPIOD_BASE, 8> u3tx2;
-typedef miosix::Gpio<GPIOD_BASE, 9> u3rx2;
-// typedef miosix::Gpio<GPIOB_BASE, 13> u3cts;
-// typedef miosix::Gpio<GPIOB_BASE, 14> u3rts;
-
-// UART4: AF8
-typedef miosix::Gpio<GPIOA_BASE, 0> u4tx1;
-typedef miosix::Gpio<GPIOA_BASE, 1> u4rx1;
-typedef miosix::Gpio<GPIOC_BASE, 10> u4tx2;
-typedef miosix::Gpio<GPIOC_BASE, 11> u4rx2;
-
-// UART5: AF8
-typedef miosix::Gpio<GPIOC_BASE, 12> u5tx;
-typedef miosix::Gpio<GPIOD_BASE, 2> u5rx;
-
-// USART6: AF8
-typedef miosix::Gpio<GPIOC_BASE, 6> u6tx1;
-typedef miosix::Gpio<GPIOC_BASE, 7> u6rx1;
-#ifdef STM32F429xx
-typedef miosix::Gpio<GPIOG_BASE, 14> u6tx2;
-typedef miosix::Gpio<GPIOG_BASE, 9> u6rx2;
-
-// USART7: AF8
-typedef miosix::Gpio<GPIOE_BASE, 8> u7tx1;
-typedef miosix::Gpio<GPIOE_BASE, 7> u7rx1;
-typedef miosix::Gpio<GPIOF_BASE, 7> u7tx2;
-typedef miosix::Gpio<GPIOF_BASE, 6> u7rx2;
-
-// USART8: AF8
-typedef miosix::Gpio<GPIOE_BASE, 1> u8tx;
-typedef miosix::Gpio<GPIOE_BASE, 0> u8rx;
-#endif  // STM32F429xx
-
 namespace Boardcore
 {
 
@@ -110,47 +68,55 @@ namespace Boardcore
 class USARTInterface
 {
 public:
-    enum class Baudrate : int
-    {
-        // B1200   = 1200, // NOT WORKING WITH 1200 baud
-        B2400   = 2400,
-        B9600   = 9600,
-        B19200  = 19200,
-        B38400  = 38400,
-        B57600  = 57600,
-        B115200 = 115200,
-        B230400 = 230400,
-        B256000 = 256000,
-        B460800 = 460800,
-        B921600 = 921600
-    };
+    /**
+     * @brief Constructor of the USART in order to assign usart and baudrate.
+     * @param usart Pointer to the USART interface.
+     * @param baudrate Baudrate in bit per second. Default values are [2400,
+     * 9600, 19200, 38400, 57600, 115200, 230400, 256000, 460800, 921600]
+     */
+    explicit USARTInterface(USARTType *usart, int baudrate);
 
     virtual ~USARTInterface() = 0;
 
     /**
-     * @brief Initializes the peripheral enabling his interrupts, the interrupts
-     * in the NVIC.
-     *
-     * All the setup phase (with the setting of the pins and their alternate
-     * functions) must be done before the initialization of the peripheral.
+     * @brief Blocking read operation to read nBytes or till the data transfer
+     * is complete.
+     * @param buffer Buffer that will contain the received data.
+     * @param nBytes Maximum size of the buffer.
+     * @return If operation succeeded.
      */
-    virtual bool init() = 0;
+    [[nodiscard]] virtual bool readBlocking(void *buffer, size_t nBytes)
+    {
+        size_t temp;
+        return readImpl(buffer, nBytes, temp, true);
+    };
 
     /**
      * @brief Blocking read operation to read nBytes or till the data transfer
      * is complete.
+     * @param buffer Buffer that will contain the received data.
+     * @param nBytes Maximum size of the buffer.
+     * @param nBytesRead Number of bytes read in the transaction.
+     * @return If operation succeeded.
      */
-    virtual int read(void *buffer, size_t nBytes) = 0;
+    [[nodiscard]] virtual bool readBlocking(void *buffer, size_t nBytes,
+                                            size_t &nBytesRead)
+    {
+        return readImpl(buffer, nBytes, nBytesRead, true);
+    };
 
     /**
      * @brief Blocking write operation.
+     * @param buffer Buffer that contains the data to be sent.
+     * @param nBytes Bytes to be sent.
      */
-    virtual int write(void *buf, size_t nChars) = 0;
+    virtual void write(const void *buf, size_t nBytes) = 0;
 
     /**
      * @brief Write a string to the serial, comprising the '\0' character.
+     * @param buffer Buffer that contains the string to be sent.
      */
-    virtual int writeString(const char *buffer) = 0;
+    virtual void writeString(const char *buffer) = 0;
 
     /**
      * @brief Returns the id of the serial.
@@ -158,13 +124,29 @@ public:
     int getId() { return id; };
 
 protected:
-    miosix::GpioPin tx{GPIOA_BASE, 0};
-    miosix::GpioPin rx{GPIOA_BASE, 0};
+    /**
+     * @brief Read method implementation that supports both blocking and
+     * non-blocking mode and the return of the number of bytes read.
+     * @param buffer Buffer that will contain the received data.
+     * @param nBytes Maximum size of the buffer.
+     * @param nBytesRead Number of bytes read.
+     * @param blocking Whether the read should block or not; in case it isn't
+     * blocking the read could return also 0 bytes.
+     * @return If operation succeeded.
+     */
+    virtual bool readImpl(void *buffer, size_t nBytes, size_t &nBytesRead,
+                          const bool blocking) = 0;
 
     USARTType *usart;
-    int id           = -1;  ///< Can be from 1 to 8, -1 is invalid
-    bool initialized = false;
-    Baudrate baudrate;  ///< Baudrate of the serial communication
+    int id = -1;                 ///< Can be from 1 to 8, -1 is invalid.
+    IRQn_Type irqn;              ///< IRQ number
+    std::string serialPortName;  ///< Port name of the port that has to be
+                                 ///< created for the communication
+    int baudrate;  ///< Baudrate of the serial communication; standard ones
+                   ///< are [2400, 9600, 19200, 38400, 57600, 115200,
+                   ///< 230400, 256000, 460800, 921600]
+
+    PrintLogger logger = Logging::getLogger("usart");
 };
 
 /**
@@ -188,9 +170,6 @@ public:
         PARITY    = 1
     };
 
-    ///< Pointer to serial port classes to let interrupts access the classes
-    static USART *ports[];
-
     /**
      * @brief Interrupt handler that deals with receive and idle interrupts.
      *
@@ -208,12 +187,18 @@ public:
      *
      * @param usart structure that represents the usart peripheral [accepted
      * are: USART1, USART2, USART3, UART4, UART5, USART6, UART7, UART8].
-     * @param baudrate member of the enum Baudrate that represents the baudrate
-     * with which the communication will take place.
+     * @param baudrate Baudrate in bit per second. Default values are [2400,
+     * 9600, 19200, 38400, 57600, 115200, 230400, 256000, 460800, 921600]
      */
-    USART(USARTType *usart, Baudrate baudrate,
+    USART(USARTType *usart, int baudrate,
           unsigned int queueLen = usart_queue_default_capacity);
 
+    ///< Delete copy/move constructors/operators.
+    USART(const USART &)            = delete;
+    USART &operator=(const USART &) = delete;
+    USART(USART &&)                 = delete;
+    USART &operator=(USART &&)      = delete;
+
     /**
      * @brief Disables the flags for the generation of the interrupts, the IRQ
      * from the NVIC, the peripheral and removes his pointer from the ports
@@ -222,30 +207,47 @@ public:
     ~USART() override;
 
     /**
-     * @brief Initializes the peripheral enabling his interrupts, the interrupts
-     * in the NVIC and setting the pins with the appropriate alternate
-     * functions.
+     * @brief Non-blocking read operation to read nBytes or till the data
+     * transfer is complete.
+     * @warning could also read 0 bytes.
      *
-     * All the setup phase must be done before the initialization of the
-     * peripheral. The pins must be initialized before calling this function.
+     * @param buffer Buffer that will contain the received data.
+     * @param nBytes Maximum size of the buffer.
+     * @return If operation succeeded.
      */
-    bool init() override;
+    [[nodiscard]] bool read(void *buffer, size_t nBytes)
+    {
+        size_t temp;
+        return readImpl(buffer, nBytes, temp, false);
+    }
 
     /**
-     * @brief Blocking read operation to read nBytes or till the data transfer
-     * is complete.
+     * @brief Non-blocking read operation to read nBytes or till the data
+     * transfer is complete.
+     * @warning could also read 0 bytes.
+     *
+     * @param buffer Buffer that will contain the received data.
+     * @param nBytes Maximum size of the buffer.
+     * @param nBytesRead Number of bytes read.
+     * @return If operation succeeded.
      */
-    int read(void *buffer, size_t nBytes) override;
+    [[nodiscard]] bool read(void *buffer, size_t nBytes, size_t &nBytesRead)
+    {
+        return readImpl(buffer, nBytes, nBytesRead, false);
+    };
 
     /**
      * @brief Blocking write operation.
+     * @param buffer Buffer that contains the data to be sent.
+     * @param nBytes Bytes to be sent.
      */
-    int write(void *buf, size_t nChars) override;
+    void write(const void *buf, size_t nBytes);
 
     /**
      * @brief Write a string to the serial, comprising the '\0' character.
+     * @param buffer Buffer that contains the string to be sent.
      */
-    int writeString(const char *buffer) override;
+    void writeString(const char *buffer);
 
     /**
      * @brief Set the length of the word to 8 or to 9.
@@ -272,9 +274,10 @@ public:
     /**
      * @brief Set the baudrate in the BRR register.
      *
-     * @param pb Baudrate element that represents the baudrate.
+     * @param baudrate Baudrate in bit per second. Default values are [2400,
+     * 9600, 19200, 38400, 57600, 115200, 230400, 256000, 460800, 921600]
      */
-    void setBaudrate(Baudrate br);
+    void setBaudrate(int baudrate);
 
     /**
      * @brief Sets the Over8 bit.
@@ -290,7 +293,19 @@ public:
     void clearQueue();
 
 private:
-    IRQn_Type irqn;
+    /**
+     * @brief Read method implementation that supports both
+     * blocking/non-blocking mode and the return of the number of bytes read.
+     * @param buffer Buffer that will contain the received data.
+     * @param nBytes Maximum size of the buffer.
+     * @param nBytesRead Number of bytes read.
+     * @param blocking Whether the read should block or not; in case it isn't
+     * blocking the read could return also 0 bytes.
+     * @return If operation succeeded.
+     */
+    [[nodiscard]] bool readImpl(void *buffer, size_t nBytes, size_t &nBytesRead,
+                                const bool blocking) override;
+
     miosix::FastMutex rxMutex;  ///< mutex for receiving on serial
     miosix::FastMutex txMutex;  ///< mutex for transmitting on serial
 
@@ -303,6 +318,7 @@ private:
     WordLength wordLength = WordLength::BIT8;
     int stopBits          = 1;      ///< Number of stop bits [1,2]
     bool over8            = false;  ///< Oversalmpling 8 bit
+    bool error            = false;  ///< Error occurred while receiving message
 
     ///< Default queue length
     const static unsigned int usart_queue_default_capacity = 256;
@@ -321,64 +337,63 @@ public:
      * - USART2: tx=PA2  rx=PA3
      * - USART3: tx=PB10 rx=PB11
      * @param usart structure that represents the usart peripheral [accepted
-     * are: USART1, USART2, USART3].
-     * @param baudrate member of the enum Baudrate that represents the baudrate
-     * with which the communication will take place.
+     * are: USART1, USART2, USART3, UART4].
+     * @param baudrate baudrate in bit per second. Default values are [2400,
+     * 9600, 19200, 38400, 57600, 115200, 230400, 256000, 460800, 921600]
      */
-    STM32SerialWrapper(USARTType *usart, Baudrate baudrate);
+    STM32SerialWrapper(USARTType *usart, int baudrate);
 
     /**
      * @brief Initializes the serialPortName and initializes the serial port
      * using custom pins.
      * @param usart structure that represents the usart peripheral [accepted
-     * are: USART1, USART2, USART3].
-     * @param baudrate member of the enum Baudrate that represents the baudrate
-     * with which the communication will take place.
+     * are: USART1, USART2, USART3, UART4].
+     * @param baudrate baudrate in bit per second. Default values are [2400,
+     * 9600, 19200, 38400, 57600, 115200, 230400, 256000, 460800, 921600]
      * @param tx Tranmission pin
      * @param rx Reception pin
      */
-    STM32SerialWrapper(USARTType *usart, Baudrate baudrate, miosix::GpioPin tx,
+    STM32SerialWrapper(USARTType *usart, int baudrate, miosix::GpioPin tx,
                        miosix::GpioPin rx);
 
+    ///< Delete copy/move constructors/operators.
+    STM32SerialWrapper(const STM32SerialWrapper &)            = delete;
+    STM32SerialWrapper &operator=(const STM32SerialWrapper &) = delete;
+    STM32SerialWrapper(STM32SerialWrapper &&)                 = delete;
+    STM32SerialWrapper &operator=(STM32SerialWrapper &&)      = delete;
+
     /**
      * @brief Removes the device from the list of the devices and closes the
      * file of the device.
      */
     ~STM32SerialWrapper();
 
-    /**
-     * @brief Initializes the peripheral.
-     *
-     * @see{STM32SerialWrapper::serialCommSetup}
-     */
-    bool init();
-
-    /**
-     * @brief Blocking read operation to read nBytes or till the data transfer
-     * is complete.
-     */
-    int read(void *buffer, size_t nBytes);
-
     /**
      * @brief Blocking write operation.
+     * @param buffer Buffer that contains the data to be sent.
+     * @param nBytes Bytes to be sent.
      */
-    int write(void *buf, size_t nChars);
+    void write(const void *buf, size_t nBytes);
 
     /**
      * @brief Write a string to the serial, comprising the '\0' character.
+     * @param buffer Buffer that contains the string to be sent.
      */
-    int writeString(const char *buffer);
+    void writeString(const char *buffer);
 
 private:
     /**
-     * @brief Initializes the pins with the appropriate alternate functions.
-     *
-     * @param tx Tranmission pin.
-     * @param nAFtx Tranmission pin alternate function.
-     * @param rx Reception pin.
-     * @param nAFrx Reception pin alternate function.
+     * @brief Read method implementation that supports both
+     * blocking/non-blocking mode and the return of the number of bytes read.
+     * @param buffer Buffer that will contain the received data.
+     * @param nBytes Maximum size of the buffer.
+     * @param nBytesRead Number of bytes read.
+     * @param blocking Whether the read should block or not; in case it isn't
+     * blocking the read could return also 0 bytes.
+     * @return If operation succeeded.
      */
-    bool initPins(miosix::GpioPin tx, int nAFtx, miosix::GpioPin rx, int nAFrx);
+    [[nodiscard]] bool readImpl(void *buffer, size_t nBytes, size_t &nBytesRead,
+                                const bool blocking) override;
 
     /**
      * @brief Creates a device that represents the serial port, adds it to the
@@ -386,14 +401,8 @@ private:
      */
     bool serialCommSetup();
 
-    ///< True if initPins() already called successfully, false otherwise
-    bool pinInitialized = false;
-
     miosix::STM32Serial *serial;  ///< Pointer to the serial object
 
-    //< Port name of the port that has to be created for the communication
-    std::string serialPortName;
-
     ///< File descriptor of the serial port file opened for transmission
     int fd;
 };
diff --git a/src/shared/radio/SerialTransceiver/SerialTransceiver.h b/src/shared/radio/SerialTransceiver/SerialTransceiver.h
index f5e0ae00b22a814f475341a31626bf1548bb6bcf..2618524dc0823fe5c4288ddf288e867879f3f37e 100644
--- a/src/shared/radio/SerialTransceiver/SerialTransceiver.h
+++ b/src/shared/radio/SerialTransceiver/SerialTransceiver.h
@@ -44,7 +44,7 @@ public:
 
     ssize_t receive(uint8_t* packet, size_t packetLength)
     {
-        return usart.read(packet, packetLength);
+        return usart.readBlocking(packet, packetLength);
     }
 
 private:
diff --git a/src/shared/sensors/MBLoadCell/MBLoadCell.cpp b/src/shared/sensors/MBLoadCell/MBLoadCell.cpp
index 7f943cd5c2078d7d26c0d0b4ecf2db0433c67416..6fd07f1ddb8d3b7c98d87533f20d6b0d5dd5d689 100644
--- a/src/shared/sensors/MBLoadCell/MBLoadCell.cpp
+++ b/src/shared/sensors/MBLoadCell/MBLoadCell.cpp
@@ -33,31 +33,15 @@ using ctrlPin2 = miosix::Gpio<GPIOC_BASE, 2>;  ///< Control R/W pin 2
 namespace Boardcore
 {
 
-MBLoadCell::MBLoadCell(LoadCellModes mode, int serialPortNum,
-                       int baudrate = 2400)
+MBLoadCell::MBLoadCell(USARTInterface &serial, LoadCellModes mode)
+    : serial(serial)
 {
     this->settings.mode = mode;
     maxPrint = maxSetted = minPrint = minSetted = 0;
-
-    // Creating the instance of the serial interface
-    serial = new SerialInterface(baudrate, serialPortNum);
 }
 
 bool MBLoadCell::init()
 {
-    if (serial->isInit())
-    {
-        lastError = SensorErrors::ALREADY_INIT;
-    }
-
-    // Initializing the serial connection
-    if (!serial->init())
-    {
-        lastError = SensorErrors::INIT_FAIL;
-        TRACE("[MBLoadCell] init of the serial communication failed\n");
-        return false;
-    }
-
     {
         // Disabling interrupts in order to set with no problems the ctrl pins
         miosix::FastInterruptDisableLock dLock;
@@ -288,12 +272,12 @@ void MBLoadCell::generateRequest(DataAsciiRequest &req,
     req.setChecksum();
 }
 
-void MBLoadCell::transmitASCII(std::string buf)
+void MBLoadCell::transmitASCII(const std::string &buf)
 {
     // Setting both the control pins to high in order to transmit
     ctrlPin1::high();
     ctrlPin2::high();
-    serial->sendString(buf);
+    serial.writeString(buf.c_str());
     miosix::Thread::sleep(10);  // Needs some time (>5ms) idk why
 }
 
@@ -304,7 +288,7 @@ std::string MBLoadCell::receiveASCII()
     // Setting both the control pins to low in order to receive
     ctrlPin1::low();
     ctrlPin2::low();
-    int len  = serial->recvString(buf, 64);
+    int len  = serial.readBlocking(buf, 64);
     buf[len] = '\0';
 
     return std::string(buf);
@@ -316,7 +300,7 @@ void MBLoadCell::receive(T *buf)
     // Setting both the control pins to low in order to receive
     ctrlPin1::low();
     ctrlPin2::low();
-    serial->recvData(buf);
+    serial.readBlocking(buf, sizeof(buf));
 }
 
 }  // namespace Boardcore
diff --git a/src/shared/sensors/MBLoadCell/MBLoadCell.h b/src/shared/sensors/MBLoadCell/MBLoadCell.h
index d8e57f5f65bdded510a9ad6830bed13d1c053106..1eb6fcdba07819dd4cec4f301db093e6d4c18463 100644
--- a/src/shared/sensors/MBLoadCell/MBLoadCell.h
+++ b/src/shared/sensors/MBLoadCell/MBLoadCell.h
@@ -29,8 +29,8 @@
 #include <string>
 
 #include "MBLoadCellData.h"
+#include "drivers/usart/USART.h"
 #include "miosix.h"
-#include "utils/SerialInterface.h"
 
 namespace Boardcore
 {
@@ -54,10 +54,9 @@ public:
      * @brief constructor that initializes the serial communication with the
      * load cell
      * @param mode the mode in which the load cell is in
-     * @param serialPortNum port number to which the load cell is connected
-     * @param baudrate baudrate set on the TLB converter
+     * @param serial the serial port to be used
      */
-    MBLoadCell(LoadCellModes mode, int serialPortNum, int baudrate);
+    MBLoadCell(USARTInterface &serial, LoadCellModes mode);
 
     /**
      * @brief Initializes the serial communication with the load cell.
@@ -136,7 +135,7 @@ protected:
      *
      * @param buf The message to send.
      */
-    void transmitASCII(std::string buf);
+    void transmitASCII(const std::string &buf);
 
     /**
      * @brief Wrapper to the serial recvString method. This also sets the
@@ -166,7 +165,7 @@ private:
     bool minPrint;
 
     ///< Pointer to the instance of the serial port used for the connection
-    SerialInterface *serial;
+    USARTInterface &serial;
 };
 
 }  // namespace Boardcore
diff --git a/src/shared/sensors/UBXGPS/UBXGPSSerial.cpp b/src/shared/sensors/UBXGPS/UBXGPSSerial.cpp
index 957f0a04a36f33b1cd6e7af6b41a27f3929ee1a5..c7051b97e07f6faaa5637081e19384a7ce0cc3b2 100644
--- a/src/shared/sensors/UBXGPS/UBXGPSSerial.cpp
+++ b/src/shared/sensors/UBXGPS/UBXGPSSerial.cpp
@@ -31,9 +31,8 @@ using namespace miosix;
 namespace Boardcore
 {
 
-UBXGPSSerial::UBXGPSSerial(USARTInterface::Baudrate baudrate,
-                           uint8_t sampleRate, USARTType* usartNumber,
-                           USARTInterface::Baudrate defaultBaudrate)
+UBXGPSSerial::UBXGPSSerial(int baudrate, uint8_t sampleRate,
+                           USARTType* usartNumber, int defaultBaudrate)
 {
     this->usart           = nullptr;
     this->baudrate        = baudrate;
@@ -155,13 +154,11 @@ bool UBXGPSSerial::setBaudrateAndUBX(bool safe)
         0x00, 0x00               // reserved2
     };
 
-    int baud = (int)baudrate;
-
     // Prepare baudrate
-    payload[8]  = baud;
-    payload[9]  = baud >> 8;
-    payload[10] = baud >> 16;
-    payload[11] = baud >> 24;
+    payload[8]  = baudrate;
+    payload[9]  = baudrate >> 8;
+    payload[10] = baudrate >> 16;
+    payload[11] = baudrate >> 24;
 
     UBXFrame frame{UBXMessage::UBX_CFG_PRT, payload, sizeof(payload)};
 
@@ -174,7 +171,6 @@ bool UBXGPSSerial::setBaudrateAndUBX(bool safe)
 bool UBXGPSSerial::setSerialCommunication()
 {
     usart = new USART(usartNumber, defaultBaudrate);
-    usart->init();
     // Change the baudrate only if it is different than the default
     if (baudrate != defaultBaudrate)
     {
@@ -303,11 +299,7 @@ bool UBXGPSSerial::writeUBXFrame(const UBXFrame& frame)
     uint8_t packedFrame[frame.getLength()];
     frame.writePacked(packedFrame);
 
-    if (usart->write(packedFrame, frame.getLength()) < 0)
-    {
-        LOG_ERR(logger, "Failed to write ubx message");
-        return false;
-    }
+    usart->write(packedFrame, frame.getLength());
 
     return true;
 }
diff --git a/src/shared/sensors/UBXGPS/UBXGPSSerial.h b/src/shared/sensors/UBXGPS/UBXGPSSerial.h
index 55cba451ca6db1a4e078f24e74ca76cdedc7e56e..733d2ed6ca2893abf4eb22e9ec2db96ed75885f5 100644
--- a/src/shared/sensors/UBXGPS/UBXGPSSerial.h
+++ b/src/shared/sensors/UBXGPS/UBXGPSSerial.h
@@ -63,11 +63,8 @@ public:
      * @param serialPortName Name of the file for the gps device.
      * @param defaultBaudrate Startup baudrate (38400 for NEO-M9N).
      */
-    UBXGPSSerial(
-        USARTInterface::Baudrate baudrate = USARTInterface::Baudrate::B921600,
-        uint8_t sampleRate = 10, USARTType *usartNumber = USART2,
-        USARTInterface::Baudrate defaultBaudrate =
-            USARTInterface::Baudrate::B38400);
+    UBXGPSSerial(int baudrate = 921600, uint8_t sampleRate = 10,
+                 USARTType *usartNumber = USART2, int defaultBaudrate = 38400);
 
     /**
      * @brief Sets up the serial port baudrate, disables the NMEA messages,
@@ -161,8 +158,8 @@ private:
 
     void run() override;
 
-    Boardcore::USARTInterface::Baudrate baudrate;
-    Boardcore::USARTInterface::Baudrate defaultBaudrate;
+    int baudrate;
+    int defaultBaudrate;
     uint8_t sampleRate;  // [Hz]
     USARTType *usartNumber;
     USART *usart;  // The usart interface
diff --git a/src/shared/sensors/VN100/VN100.cpp b/src/shared/sensors/VN100/VN100.cpp
index 826d51f855f7289affd4eb67b784aed5b4fb99c8..e55f1937fe1d7f91037eab57213b679e46fbd501 100644
--- a/src/shared/sensors/VN100/VN100.cpp
+++ b/src/shared/sensors/VN100/VN100.cpp
@@ -27,8 +27,8 @@
 namespace Boardcore
 {
 
-VN100::VN100(USARTType *portNumber, USARTInterface::Baudrate baudRate,
-             CRCOptions crc, uint16_t samplePeriod)
+VN100::VN100(USARTType *portNumber, int baudRate, CRCOptions crc,
+             uint16_t samplePeriod)
     : portNumber(portNumber), baudRate(baudRate), crc(crc)
 {
     this->samplePeriod = samplePeriod;
@@ -151,11 +151,7 @@ bool VN100::sampleRaw()
     }
 
     // Send the IMU sampling command
-    if (!(serialInterface->writeString(preSampleImuString->c_str())))
-    {
-        LOG_WARN(logger, "Unable to sample due to serial communication error");
-        return false;
-    }
+    serialInterface->writeString(preSampleImuString->c_str());
 
     // Wait some time
     // TODO dimension the time
@@ -245,11 +241,7 @@ VN100Data VN100::sampleData()
     }
 
     // Returns Quaternion, Magnetometer, Accelerometer and Gyro
-    if (!(serialInterface->writeString(preSampleImuString->c_str())))
-    {
-        // If something goes wrong i return the last sampled data
-        return lastSample;
-    }
+    serialInterface->writeString(preSampleImuString->c_str());
 
     // Wait some time
     // TODO dimension the time
@@ -277,11 +269,7 @@ VN100Data VN100::sampleData()
     // Returns Magnetometer, Accelerometer, Gyroscope, Temperature and Pressure
     // (UNCOMPENSATED) DO NOT USE THESE MAGNETOMETER, ACCELEROMETER AND
     // GYROSCOPE VALUES
-    if (!(serialInterface->writeString(preSampleTempPressString->c_str())))
-    {
-        // If something goes wrong i return the last sampled data
-        return lastSample;
-    }
+    serialInterface->writeString(preSampleTempPressString->c_str());
 
     // Wait some time
     // TODO dimension the time
@@ -331,10 +319,10 @@ bool VN100::disableAsyncMessages(bool waitResponse)
 bool VN100::configDefaultSerialPort()
 {
     // Initial default settings
-    serialInterface = new USART(portNumber, USARTInterface::Baudrate::B115200);
+    serialInterface = new USART(portNumber, 115200);
 
     // Check correct serial init
-    return serialInterface->init();
+    return true;
 }
 
 /**
@@ -346,7 +334,7 @@ bool VN100::configUserSerialPort()
     std::string command;
 
     // I format the command to change baud rate
-    command = fmt::format("{}{}", "VNWRG,5,", static_cast<int>(baudRate));
+    command = fmt::format("{}{}", "VNWRG,5,", baudRate);
 
     // I can send the command
     if (!sendStringCommand(command))
@@ -361,7 +349,7 @@ bool VN100::configUserSerialPort()
     serialInterface = new USART(portNumber, baudRate);
 
     // Check correct serial init
-    return serialInterface->init();
+    return true;
 }
 
 bool VN100::setCrc(bool waitResponse)
@@ -666,10 +654,7 @@ bool VN100::sendStringCommand(std::string command)
     }
 
     // I send the final command
-    if (!serialInterface->writeString(command.c_str()))
-    {
-        return false;
-    }
+    serialInterface->writeString(command.c_str());
 
     // Wait some time
     // TODO dimension the time
@@ -682,7 +667,7 @@ bool VN100::recvStringCommand(char *command, int maxLength)
 {
     int i = 0;
     // Read the buffer
-    if (!(serialInterface->read(command, maxLength)))
+    if (!(serialInterface->readBlocking(command, maxLength)))
     {
         return false;
     }
diff --git a/src/shared/sensors/VN100/VN100.h b/src/shared/sensors/VN100/VN100.h
index a3f9d63c50bcfcd0b1f0a719122d9abfdd041f51..d2d5c6c943c088c09a9eae55417276fa07a228ff 100644
--- a/src/shared/sensors/VN100/VN100.h
+++ b/src/shared/sensors/VN100/VN100.h
@@ -86,10 +86,9 @@ public:
      * @param Redundancy check option.
      * @param samplePeriod Sampling period in ms
      */
-    VN100(USARTType *portNumber    = USART2,
-          USART::Baudrate baudRate = USART::Baudrate::B921600,
-          CRCOptions crc           = CRCOptions::CRC_ENABLE_8,
-          uint16_t samplePeriod    = 20);
+    VN100(USARTType *portNumber = USART2, int baudRate = 921600,
+          CRCOptions crc        = CRCOptions::CRC_ENABLE_8,
+          uint16_t samplePeriod = 20);
 
     bool init() override;
 
@@ -240,7 +239,7 @@ private:
     uint16_t calculateChecksum16(uint8_t *message, int length);
 
     USARTType *portNumber;
-    USART::Baudrate baudRate;
+    int baudRate;
     uint16_t samplePeriod;
     CRCOptions crc;
     bool isInit = false;
diff --git a/src/shared/sensors/VN100/VN100Serial.h b/src/shared/sensors/VN100/VN100Serial.h
deleted file mode 100644
index 22f416772b629f7b0d987b1a13e7f449bc4f4f52..0000000000000000000000000000000000000000
--- a/src/shared/sensors/VN100/VN100Serial.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/* Copyright (c) 2021 Skyward Experimental Rocketry
- * Author: Matteo Pignataro
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/** BRIEF INTRODUCTION
- * This class is used to create a communication easily with UART ports.
- * In particular it handles the creation and the basic primitives
- * for standard communication protocols (init, send, recv and close).
- * The user should pay more attention on the concept behind the use of this
- * class. The principle under the class is that miosix communicates via USART
- * ports using a file based principle (Unix style). Because of that you need to
- * consider that the receive file works as a LIFO queue, in fact the last
- * message is returned over the less recent messages, so if you accumulate
- * various messages of variable length, you might end up with a message which
- * represents the most recent communication + other previous stuff.
- */
-
-#pragma once
-
-#include <arch/common/drivers/serial.h>
-#include <fcntl.h>
-#include <filesystem/file_access.h>
-#include <miosix.h>
-namespace Boardcore
-{
-
-/**
- * @brief Class to communicate with the vn100 via the UART interface.
- */
-class VN100Serial
-{
-public:
-    VN100Serial(unsigned int serialPortNumber, unsigned int serialBaudRate);
-
-    bool init();
-
-    /**
-     * @brief Writes in Serial data.
-     *
-     * Note: to send std::string via serial you need to pass use "c_str()"
-     * method.
-     *
-     * @param data Data to be sent via serial.
-     * @param length Array length.
-     *
-     * @return True if operation succeeded.
-     */
-    template <typename DataSend>
-    bool send(DataSend *data, int length);
-
-    /**
-     * @brief Reads from serial.
-     *
-     * @param data Array where to store data.
-     * @param length Array length.
-     *
-     * @return True if operation succeeded.
-     */
-    template <typename DataReceive>
-    bool recv(DataReceive *data, int length);
-
-    bool closeSerial();
-
-private:
-    unsigned int serialPortNumber;
-    unsigned int serialBaudRate;
-
-    int serialFileDescriptor = 0;
-
-    bool isInit = false;
-};
-
-inline VN100Serial::VN100Serial(unsigned int serialPortNumber,
-                                unsigned int serialBaudRate)
-    : serialPortNumber(serialPortNumber), serialBaudRate(serialBaudRate)
-{
-}
-
-inline bool VN100Serial::init()
-{
-    // If already initialized i avoid the procedure
-    if (isInit)
-    {
-        return true;
-    }
-
-    // Retrieve the file system instance
-    miosix::intrusive_ref_ptr<miosix::DevFs> devFs =
-        miosix::FilesystemManager::instance().getDevFs();
-
-    // Create the serial file which we read and write to communicate
-    if (!(devFs->addDevice(
-            "vn100",
-            miosix::intrusive_ref_ptr<miosix::Device>(
-                new miosix::STM32Serial(serialPortNumber, serialBaudRate)))))
-    {
-        return false;
-    }
-
-    // Open the file
-    serialFileDescriptor = open("/dev/vn100", O_RDWR);
-
-    // Check the descriptor
-    if (serialFileDescriptor <= 0)
-    {
-        return false;
-    }
-
-    // Success
-    isInit = true;
-    return true;
-}
-
-template <typename DataSend>
-inline bool VN100Serial::send(DataSend *data, int length)
-{
-    // Check if the serial has been previously initialized
-    if (!isInit)
-    {
-        return false;
-    }
-
-    // Write the file with the data
-    if (!write(serialFileDescriptor, data, length))
-    {
-        return false;
-    }
-
-    return true;
-}
-
-template <typename DataReceive>
-inline bool VN100Serial::recv(DataReceive *data, int length)
-{
-    if (!isInit)
-    {
-        return false;
-    }
-
-    // Read the data and store it in memory
-    if (!read(serialFileDescriptor, data, length))
-    {
-        return false;
-    }
-
-    return true;
-}
-
-inline bool VN100Serial::closeSerial()
-{
-    // Retrieve the file system instance
-    miosix::intrusive_ref_ptr<miosix::DevFs> devFs =
-        miosix::FilesystemManager::instance().getDevFs();
-
-    // Close the file descriptor
-    close(serialFileDescriptor);
-
-    // Remove the file
-    if (!(devFs->remove("vn100")))
-    {
-        return false;
-    }
-
-    return true;
-}
-
-}  // namespace Boardcore
diff --git a/src/shared/utils/SerialInterface.h b/src/shared/utils/SerialInterface.h
deleted file mode 100644
index 674f7bf3e9a9f68e07e24bb297610daeac40d95f..0000000000000000000000000000000000000000
--- a/src/shared/utils/SerialInterface.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (c) 2020 Skyward Experimental Rocketry
- * Author: Emilio Corigliano
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#pragma once
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <utils/Debug.h>
-
-#include <string>
-
-#include "arch/common/drivers/serial.h"
-#include "filesystem/file_access.h"
-#include "miosix.h"
-
-namespace Boardcore
-{
-
-/**
- * @brief Creates and opens a serial port on the board and provides templated
- * "sendData" and "recvData" functions in order to send and receive any data
- * structure needed, or "sendString" and "recvString" in order to send and
- * receive strings.
- */
-class SerialInterface
-{
-public:
-    /**
-     * Constructor of the serial communication with default parameters
-     * @param baudrate port baudrate (default: 19200 as miosix)
-     * @param serialPortNum number from 1 to 3 in order to set the USART to use
-     * (default: 2 [tx_board=PA2  rx_board=PA3 cts=PA0  rts=PA1])
-     * @param serialPortName name of the serial port to open (default:
-     * "simulation")
-     */
-    SerialInterface(int baudrate = 19200, int serialPortNum = 2,
-                    std::string serialPortName = "load_cell")
-    {
-        this->baudrate       = baudrate;
-        this->serialPortNum  = serialPortNum;
-        this->serialPortName = serialPortName;
-        initialized          = false;
-        fd                   = -1;
-    }
-
-    ~SerialInterface()
-    {
-        miosix::intrusive_ref_ptr<miosix::DevFs> devFs =
-            miosix::FilesystemManager::instance().getDevFs();
-        close(fd);
-        devFs->remove(serialPortName.c_str());
-    }
-
-    /**
-     * @brief Initializes the object if it's the first call to this function
-     * @return true if initialization is successful, false otherwise
-     */
-    bool init()
-    {
-        if (initialized)
-        {
-            TRACE(
-                "[SerialCommunication] Error : serial communication already "
-                "initialized!\n");
-            return false;
-        }
-        else if (!serialCommSetup())
-        {
-            TRACE(
-                "[SerialCommunication] Error : can't initialize serial "
-                "communication!\n");
-            return false;
-        }
-
-        initialized = true;
-        return true;
-    }
-
-    /**
-     * @brief Sends a string to the serial
-     * @param data pointer to the string '\0' terminated
-     * @return bytes sent through serial
-     */
-    int sendString(std::string data)
-    {
-        return write(fd, data.c_str(), data.length());
-    }
-
-    /**
-     * @brief Receives a string from the serial
-     * @param data pointer to the destination string
-     * @param maxLen maximum length of the string to read
-     * @return bytes received from serial
-     */
-    int recvString(char *data, int maxLen) { return read(fd, data, maxLen); }
-
-    /**
-     * @brief Receives the data from the simulated sensors and deserializes it
-     * in the templated format
-     * @param data pointer to the struct for the data to receive
-     */
-    template <typename T>
-    void recvData(T *data)
-    {
-        read(fd, data, sizeof(T));
-    }
-
-    /**
-     * @brief Sends the position of the simulated actuators as the templated
-     * type
-     * @param data pointer to the struct of the data to send
-     */
-    template <typename U>
-    void sendData(U *data)
-    {
-        write(fd, data, sizeof(U));
-    }
-
-    std::string getPortName() { return serialPortName; }
-
-    bool isInit() { return initialized; }
-
-private:
-    /* Creates and opens the serial port for communication between OBSW and
-     * simulation device */
-    bool serialCommSetup()
-    {
-        // Takes the file system pointer of the devices
-        miosix::intrusive_ref_ptr<miosix::DevFs> devFs =
-            miosix::FilesystemManager::instance().getDevFs();
-
-        // Creates and adds the serial port to the devices
-        if (!devFs->addDevice(
-                serialPortName.c_str(),
-                miosix::intrusive_ref_ptr<miosix::Device>(
-                    new miosix::STM32Serial(serialPortNum, baudrate))))
-            return false;
-
-        // path string "/dev/<name_of_port>" for the port we want to open
-        std::string serialPortPath = "/dev/" + serialPortName;
-
-        // open serial port
-        fd = open(serialPortPath.c_str(), O_RDWR);
-
-        if (fd <= -1)
-        {
-            TRACE("Cannot open %s\n", serialPortPath.c_str());
-            return false;
-        }
-
-        return true;
-    }
-
-    std::string serialPortName; /**< Port name of the serial port that has to be
-                              created for the communication */
-    int fd; /**< Stores the file descriptor of the serial port file opened for
-               trasmission */
-    int serialPortNum; /**< Stores the USART<serialPortNum> used for the
-                          trasmission range[1:3] */
-    int baudrate;      /**< Baudrate of the serial port */
-    bool initialized;  /**< True if init() already called successfully, false
-                      otherwise */
-};
-
-}  // namespace Boardcore
diff --git a/src/tests/algorithms/NAS/test-nas-parafoil.cpp b/src/tests/algorithms/NAS/test-nas-parafoil.cpp
index 7af7e41c3861b95483cd136018fe2977216046e1..12d106ca45c05d91eeb3e112d1df31e249ae12fc 100644
--- a/src/tests/algorithms/NAS/test-nas-parafoil.cpp
+++ b/src/tests/algorithms/NAS/test-nas-parafoil.cpp
@@ -112,8 +112,7 @@ void init()
     imu = new MPU9250(spi1, sensors::mpu9250::cs::getPin());
     imu->init();
 
-    gps = new UBXGPSSerial(USARTInterface::Baudrate::B38400, 10, USART2,
-                           USARTInterface::Baudrate::B38400);
+    gps = new UBXGPSSerial(38400, 10, USART2, 38400);
     gps->init();
     gps->start();
 
diff --git a/src/tests/drivers/test-MBLoadCell.cpp b/src/tests/drivers/test-MBLoadCell.cpp
index f5d97bb0da552add766b54542ba97f45b014e32d..6b94d3879cd6db4db898e9fecdf8e65f36a55b7b 100644
--- a/src/tests/drivers/test-MBLoadCell.cpp
+++ b/src/tests/drivers/test-MBLoadCell.cpp
@@ -25,7 +25,8 @@
 #include <string.h>
 #include <utils/ButtonHandler/ButtonHandler.h>
 
-//#define PRINT_ALL_SAMPLES // To be defined if we want to print all the samples
+// #define PRINT_ALL_SAMPLES // To be defined if we want to print all the
+// samples
 
 using namespace Boardcore;
 using namespace miosix;
@@ -58,6 +59,7 @@ int main()
 {
     // In order to disable DEBUG prints of the button press events
     Logging::getStdOutLogSink().setLevel(LOGL_WARNING);
+    USART usart(USART1, 115200);
 
     /**
      * Use of CONT_MOD_TD: transmits net and gross weight
@@ -66,7 +68,7 @@ int main()
      * - use of serial port 2: in stm32f407vg TX=PA2, RX=PA3
      * - use of serial port 1: in stm32f407vg TX=PA9, RX=PA10
      */
-    MBLoadCell loadCell(LoadCellModes::CONT_MOD_T, 2, 115200);
+    MBLoadCell loadCell(usart, LoadCellModes::CONT_MOD_T);
 
     // Instanciating the button
     ButtonHandler::getInstance().registerButtonCallback(
diff --git a/src/tests/drivers/test-mavlink.cpp b/src/tests/drivers/test-mavlink.cpp
index 2f4883c1335bed4c243a00a5d9ba63aaf208fc28..8e70f5a51d734894a0d0a4d42dd0d9a97964c744 100644
--- a/src/tests/drivers/test-mavlink.cpp
+++ b/src/tests/drivers/test-mavlink.cpp
@@ -52,7 +52,7 @@ MavDriver* mavlink;
  */
 int main()
 {
-    STM32SerialWrapper serial(USART1, USARTInterface::Baudrate::B19200);
+    STM32SerialWrapper serial(USART1, 19200);
     transceiver = new SerialTransceiver(serial);
     mavlink = new MavDriver(transceiver, nullptr, silenceAfterSend, maxPktAge);
 
diff --git a/src/tests/drivers/test-vn100serial.cpp b/src/tests/drivers/test-vn100serial.cpp
deleted file mode 100644
index 1367ece32003ff557a789c06684467f972b96038..0000000000000000000000000000000000000000
--- a/src/tests/drivers/test-vn100serial.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Copyright (c) 2021 Skyward Experimental Rocketry
- * Author: Matteo Pignataro
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <sensors/VN100/VN100Serial.h>
-
-#include <string>
-
-using namespace miosix;
-using namespace std;
-using namespace Boardcore;
-
-int main()
-{
-    char recvString[200];
-    // Object string with the message
-    string message("Communication\n\r");
-
-    GpioPin tx(GPIOB_BASE, 6);
-    GpioPin rx(GPIOB_BASE, 7);
-
-    tx.mode(miosix::Mode::ALTERNATE);
-    rx.mode(miosix::Mode::ALTERNATE);
-
-    tx.alternateFunction(7);
-    rx.alternateFunction(7);
-
-    // Serial inferface
-    VN100Serial serial{1, 115200};
-
-    if (!serial.init())
-    {
-        printf("Init failed\n");
-        return 0;
-    }
-    printf("Success!\n");
-
-    // Loop to send the data via serial
-    while (1)
-    {
-        serial.send(message.c_str(), message.length());
-        // Sleep
-        miosix::Thread::sleep(100);
-        // Receive the string
-        serial.recv(recvString, 200);
-        // Print it out
-        printf("%s\n", recvString);
-    }
-
-    serial.closeSerial();
-
-    return 0;
-}
diff --git a/src/tests/drivers/usart/test-usart.cpp b/src/tests/drivers/usart/test-usart.cpp
index 728f374b30b12b02fcbcc97fd55f33f73054ce86..eb52fa565da67bbba723059ccbdd889a1facf929 100644
--- a/src/tests/drivers/usart/test-usart.cpp
+++ b/src/tests/drivers/usart/test-usart.cpp
@@ -29,7 +29,6 @@
 #include "string"
 #include "string.h"
 #include "thread"
-#include "utils/SerialInterface.h"
 
 using namespace miosix;
 using namespace Boardcore;
@@ -49,6 +48,63 @@ using namespace Boardcore;
  * doesn't have this problem.
  */
 
+// A nice feature of the stm32 is that the USART are connected to the same
+// GPIOS in all families, stm32f1, f2, f4 and l1. Additionally, USART1 and
+// USART6 are always connected to the APB2, while the other USART/UARTs are
+// connected to the APB1.
+
+// USART1: AF7
+typedef miosix::Gpio<GPIOB_BASE, 6> u1tx1;
+typedef miosix::Gpio<GPIOB_BASE, 7> u1rx1;
+typedef miosix::Gpio<GPIOA_BASE, 9> u1tx2;
+typedef miosix::Gpio<GPIOA_BASE, 10> u1rx2;
+// typedef miosix::Gpio<GPIOA_BASE, 11> u1cts;
+// typedef miosix::Gpio<GPIOA_BASE, 12> u1rts;
+
+// USART2: AF7
+typedef miosix::Gpio<GPIOA_BASE, 2> u2tx1;
+typedef miosix::Gpio<GPIOA_BASE, 3> u2rx1;
+typedef miosix::Gpio<GPIOD_BASE, 5> u2tx2;
+typedef miosix::Gpio<GPIOD_BASE, 6> u2rx2;
+// typedef miosix::Gpio<GPIOA_BASE, 0> u2cts;
+// typedef miosix::Gpio<GPIOA_BASE, 1> u2rts;
+
+// USART3: AF7
+typedef miosix::Gpio<GPIOB_BASE, 10> u3tx1;
+typedef miosix::Gpio<GPIOB_BASE, 11> u3rx1;
+typedef miosix::Gpio<GPIOD_BASE, 8> u3tx2;
+typedef miosix::Gpio<GPIOD_BASE, 9> u3rx2;
+// typedef miosix::Gpio<GPIOB_BASE, 13> u3cts;
+// typedef miosix::Gpio<GPIOB_BASE, 14> u3rts;
+
+// UART4: AF8
+typedef miosix::Gpio<GPIOA_BASE, 0> u4tx1;
+typedef miosix::Gpio<GPIOA_BASE, 1> u4rx1;
+typedef miosix::Gpio<GPIOC_BASE, 10> u4tx2;
+typedef miosix::Gpio<GPIOC_BASE, 11> u4rx2;
+
+// UART5: AF8
+typedef miosix::Gpio<GPIOC_BASE, 12> u5tx;
+typedef miosix::Gpio<GPIOD_BASE, 2> u5rx;
+
+// USART6: AF8
+typedef miosix::Gpio<GPIOC_BASE, 6> u6tx1;
+typedef miosix::Gpio<GPIOC_BASE, 7> u6rx1;
+#ifdef STM32F429xx
+typedef miosix::Gpio<GPIOG_BASE, 14> u6tx2;
+typedef miosix::Gpio<GPIOG_BASE, 9> u6rx2;
+
+// USART7: AF8
+typedef miosix::Gpio<GPIOE_BASE, 8> u7tx1;
+typedef miosix::Gpio<GPIOE_BASE, 7> u7rx1;
+typedef miosix::Gpio<GPIOF_BASE, 7> u7tx2;
+typedef miosix::Gpio<GPIOF_BASE, 6> u7rx2;
+
+// USART8: AF8
+typedef miosix::Gpio<GPIOE_BASE, 1> u8tx;
+typedef miosix::Gpio<GPIOE_BASE, 0> u8rx;
+#endif  // STM32F429xx
+
 typedef struct
 {
     char dataChar;
@@ -64,12 +120,8 @@ typedef struct
 } StructToSend;
 StructToSend struct_tx = {'C', 42, 420.69, 48.84};
 char buf_tx[64]        = "Testing communication, but very very very loong :D";
-USARTInterface::Baudrate baudrates[] = {
-    USARTInterface::Baudrate::B2400,   USARTInterface::Baudrate::B9600,
-    USARTInterface::Baudrate::B19200,  USARTInterface::Baudrate::B38400,
-    USARTInterface::Baudrate::B57600,  USARTInterface::Baudrate::B115200,
-    USARTInterface::Baudrate::B230400, USARTInterface::Baudrate::B460800,
-    USARTInterface::Baudrate::B921600};
+int baudrates[]        = {2400,   9600,   19200,  38400,  57600,
+                          115200, 230400, 256000, 460800, 921600};
 
 /**
  * Communication: src -> dst
@@ -77,8 +129,9 @@ USARTInterface::Baudrate baudrates[] = {
  */
 bool testCommunicationSequential(USARTInterface *src, USARTInterface *dst)
 {
-    char buf_rx[64];
-    StructToSend struct_rx;
+    char buf_rx[64] = {0};
+    StructToSend struct_rx{0};
+    size_t nReads{0};
     bool passed = true;
 
     /************************** SENDING STRING **************************/
@@ -87,10 +140,24 @@ bool testCommunicationSequential(USARTInterface *src, USARTInterface *dst)
     printf("\t%d--> sent: \t'%s'\n", src->getId(), buf_tx);
     src->writeString(buf_tx);
     // Thread::sleep(10); // enable to pass the test with STM32SerialWrapper
-    dst->read(buf_rx, 64);
+    if (!dst->readBlocking(buf_rx, 64, nReads))
+    {
+        printf("### NO DATA READ ###\n");
+        passed = false;
+    }
 
     printf("\t%d<-- received: \t'%s'\n", dst->getId(), buf_rx);
 
+    if (nReads != strlen(buf_tx) + 1)
+    {
+        printf("### READ WRONG NUMBER OF BYTES ###\n");
+        passed = false;
+    }
+    else
+    {
+        printf("*** READ EXACT NUMBER OF BYTES ***\n");
+    }
+
     if (strcmp(buf_tx, buf_rx) == 0)
     {
         printf("*** %d -> %d WORKING!\n", src->getId(), dst->getId());
@@ -107,7 +174,12 @@ bool testCommunicationSequential(USARTInterface *src, USARTInterface *dst)
     printf("\t%d--> sent: \t'%s'\n", src->getId(), struct_tx.print().c_str());
     src->write(&struct_tx, sizeof(StructToSend));
     // Thread::sleep(10); // enable to pass the test with STM32SerialWrapper
-    dst->read(&struct_rx, sizeof(StructToSend));
+    if (!dst->readBlocking(&struct_rx, sizeof(StructToSend)))
+    {
+        printf("### NO DATA READ ###\n");
+        passed = false;
+    }
+
     printf("\t%d<-- received: \t'%s'\n", dst->getId(),
            struct_rx.print().c_str());
 
@@ -121,6 +193,13 @@ bool testCommunicationSequential(USARTInterface *src, USARTInterface *dst)
         passed = false;
     }
 
+    // Testing the non blocking read only if USART class
+    if ((dynamic_cast<const USART *>(dst) != nullptr) &&
+        !dynamic_cast<USART *>(dst)->read(&struct_rx, sizeof(StructToSend)))
+    {
+        printf("Non blocking read passed!\n");
+    }
+
     return passed;
 }
 
@@ -137,60 +216,60 @@ bool testCommunicationSequential(USARTInterface *src, USARTInterface *dst)
 int main()
 {
     // Init serial port pins
-    u1rx2::getPin().mode(miosix::Mode::ALTERNATE);
-    u1rx2::getPin().alternateFunction(7);
-    u1tx1::getPin().mode(miosix::Mode::ALTERNATE);
-    u1tx1::getPin().alternateFunction(7);
-
-    u2rx1::getPin().mode(miosix::Mode::ALTERNATE);
-    u2rx1::getPin().alternateFunction(7);
-    u2tx1::getPin().mode(miosix::Mode::ALTERNATE);
-    u2tx1::getPin().alternateFunction(7);
-
-    // u4rx1::getPin().mode(miosix::Mode::ALTERNATE);
-    // u4rx1::getPin().alternateFunction(8);
-    // u4tx1::getPin().mode(miosix::Mode::ALTERNATE);
-    // u4tx1::getPin().alternateFunction(8);
-
-    bool testPassed = true;
-    printf("*** SERIAL 3 WORKING!\n");
-    for (unsigned int iBaud = 0;
-         iBaud < sizeof(baudrates) / sizeof(baudrates[0]); iBaud++)
+    u6rx1::getPin().mode(miosix::Mode::ALTERNATE);
+    u6rx1::getPin().alternateFunction(8);
+    u6tx1::getPin().mode(miosix::Mode::ALTERNATE);
+    u6tx1::getPin().alternateFunction(8);
+
+    u4rx2::getPin().mode(miosix::Mode::ALTERNATE);
+    u4rx2::getPin().alternateFunction(8);
+    u4tx2::getPin().mode(miosix::Mode::ALTERNATE);
+    u4tx2::getPin().alternateFunction(8);
+
+    for (;;)
     {
-        USARTInterface::Baudrate baudrate = baudrates[iBaud];
-        printf("\n\n########################### %d\n", (int)baudrate);
+        bool testPassed = true;
+        printf("*** SERIAL 3 WORKING!\n");
 
-        // declaring the usart peripherals
-        STM32SerialWrapper usartx(USART1, baudrate);
-        usartx.init();
+        for (int baudrate : baudrates)
+        {
+            printf("\n\n########################### %d\n", baudrate);
+            // declaring the usart peripherals
+            USART usartx(USART6, baudrate);
+            // usartx.setBaudrate(baudrate);
+            // usartx.setOversampling(false);
+            // usartx.setStopBits(1);
+            // usartx.setWordLength(USART::WordLength::BIT8);
+            // usartx.setParity(USART::ParityBit::NO_PARITY);
 
-        STM32SerialWrapper usarty(USART2, baudrate);
-        // usarty.setOversampling(false);
-        // usarty.setStopBits(1);
-        // usarty.setWordLength(USART::WordLength::BIT8);
-        // usarty.setParity(USART::ParityBit::NO_PARITY);
-        usarty.init();
+            // USART usarty(UART4, baudrate);
+            STM32SerialWrapper usarty(UART4, baudrate, u4rx2::getPin(),
+                                      u4tx2::getPin());
 
-        // testing transmission (both char and binary) "serial 1 <- serial 2"
-        testPassed &= testCommunicationSequential(&usartx, &usarty);
+            // testing transmission (both char and binary) "serial 1 <- serial
+            // 2"
+            testPassed &= testCommunicationSequential(&usartx, &usarty);
 
-        // testing transmission (both char and binary) "serial 1 -> serial 2"
-        testPassed &= testCommunicationSequential(&usarty, &usartx);
-    }
+            // testing transmission (both char and binary) "serial 1 -> serial
+            // 2"
+            testPassed &= testCommunicationSequential(&usarty, &usartx);
+        }
 
-    if (testPassed)
-    {
-        printf(
-            "********************************\n"
-            "***        TEST PASSED       ***\n"
-            "********************************\n");
-    }
-    else
-    {
-        printf(
-            "################################\n"
-            "###        TEST FAILED       ###\n"
-            "################################\n");
+        if (testPassed)
+        {
+            printf(
+                "********************************\n"
+                "***        TEST PASSED       ***\n"
+                "********************************\n");
+        }
+        else
+        {
+            printf(
+                "################################\n"
+                "###        TEST FAILED       ###\n"
+                "################################\n");
+        }
+        Thread::sleep(5000);
     }
     return 0;
 }
diff --git a/src/tests/radio/test-mavlinkdriver.cpp b/src/tests/radio/test-mavlinkdriver.cpp
index c7d14b5108f9304be08b6284a6efd3404a8e0e32..812c1566470528c2554e3d6f5e6552c45f4272c1 100644
--- a/src/tests/radio/test-mavlinkdriver.cpp
+++ b/src/tests/radio/test-mavlinkdriver.cpp
@@ -36,7 +36,10 @@
 using namespace miosix;
 using namespace Boardcore;
 
-USART usart(USART2, USARTInterface::Baudrate::B115200);
+typedef miosix::Gpio<GPIOA_BASE, 2> u2tx;
+typedef miosix::Gpio<GPIOA_BASE, 3> u2rx;
+
+USART usart(USART2, 115200);
 SerialTransceiver transceiver(usart);
 MavlinkDriver<20, 10> mavlink(&transceiver);
 
@@ -44,10 +47,10 @@ void payloadGenerator();
 
 int main()
 {
-    u2rx1::mode(Mode::ALTERNATE);
-    u2rx1::alternateFunction(7);
-    u2tx1::mode(Mode::ALTERNATE);
-    u2tx1::alternateFunction(7);
+    u2rx::mode(Mode::ALTERNATE);
+    u2rx::alternateFunction(7);
+    u2tx::mode(Mode::ALTERNATE);
+    u2tx::alternateFunction(7);
 
     TaskScheduler scheduler;
     scheduler.addTask(payloadGenerator, 2000);
diff --git a/src/tests/sensors/test-ubxgps-serial.cpp b/src/tests/sensors/test-ubxgps-serial.cpp
index 722cbef731806d27ff720684cba32f0b6e11fab6..472f3dcde05177c0409262a5aa43c929bb363dc3 100644
--- a/src/tests/sensors/test-ubxgps-serial.cpp
+++ b/src/tests/sensors/test-ubxgps-serial.cpp
@@ -37,8 +37,7 @@ int main()
     printf("Welcome to the ublox test\n");
 
     // Keep GPS baud rate at default for easier testing
-    UBXGPSSerial gps(USARTInterface::Baudrate::B38400, RATE, USART2,
-                     USARTInterface::Baudrate::B9600);
+    UBXGPSSerial gps(38400, RATE, USART2, 9600);
     UBXGPSData dataGPS;
     printf("Gps allocated\n");
 
diff --git a/src/tests/sensors/test-vn100.cpp b/src/tests/sensors/test-vn100.cpp
index 991f26650bedc095a014b686ab81a92e488b47d8..2e93b1eff2ce610def3f0bfe76feed3f7418efc2 100644
--- a/src/tests/sensors/test-vn100.cpp
+++ b/src/tests/sensors/test-vn100.cpp
@@ -31,8 +31,7 @@ int main()
 {
     VN100Data sample;
     string sampleRaw;
-    VN100 sensor{USART1, USARTInterface::Baudrate::B921600,
-                 VN100::CRCOptions::CRC_ENABLE_16};
+    VN100 sensor{USART1, 921600, VN100::CRCOptions::CRC_ENABLE_16};
 
     // Let the sensor start up
     Thread::sleep(1000);
diff --git a/src/tests/test-max485.cpp b/src/tests/test-max485.cpp
index 18bb9077befedf2d449ad8707bf85a740e3b6dce..61a7068b17278cbe24640e37b9857e8c2fc645ae 100644
--- a/src/tests/test-max485.cpp
+++ b/src/tests/test-max485.cpp
@@ -58,9 +58,9 @@
  *
  */
 
+#include "drivers/usart/USART.h"
 #include "string.h"
 #include "thread"
-#include "utils/SerialInterface.h"
 
 using namespace miosix;
 using namespace Boardcore;
@@ -75,20 +75,16 @@ using ctrlPin2_s2 = miosix::Gpio<GPIOC_BASE, 2>;
 
 char msg[64] = "Testing communication :D";
 char rcv[64];
-int baudrates[] = {2400,   3600,   4800,   9600,  19200,
-                   115200, 230400, 460800, 921600};
+int baudrates[] = {2400,   9600,   19200,  38400,  57600,
+                   115200, 230400, 256000, 460800, 921600};
 
 // function for the thread that has to read from serial
-void readSer(SerialInterface *s)
-{
-    s->recvString(rcv, 64);
-    printf("\t<--%s received: \t'%s'\n", s->getPortName().c_str(), rcv);
-}
+void readSer(USARTInterface &s) {}
 
 // Communicatio: src -> dst
 template <typename GPIO1_src, typename GPIO2_src, typename GPIO1_dst,
           typename GPIO2_dst>
-void testCommunication(char *data, SerialInterface *src, SerialInterface *dst)
+void testCommunication(char *data, USARTInterface &src, USARTInterface &dst)
 {
     // resetting the buffer so precedent tests won't affect this one
     memset(rcv, 0, strlen(rcv) + 1);
@@ -102,21 +98,24 @@ void testCommunication(char *data, SerialInterface *src, SerialInterface *dst)
     GPIO2_dst::low();
 
     // thread that reads from serial
-    std::thread t(readSer, dst);
+    std::thread t(
+        [&]()
+        {
+            dst.readBlocking(rcv, 64);
+            printf("\t<--%d received: \t'%s'\n", dst.getId(), rcv);
+        });
 
-    printf("\t-->%s sending: \t'%s'\n", src->getPortName().c_str(), data);
-    src->sendString(data);
+    printf("\t-->%d sending: \t'%s'\n", src.getId(), data);
+    src.writeString(data);
     t.join();
 
     if (strcmp(data, rcv) == 0)
     {
-        printf("*** %s -> %s WORKING!\n", src->getPortName().c_str(),
-               dst->getPortName().c_str());
+        printf("*** %d -> %d WORKING!\n", src.getId(), dst.getId());
     }
     else
     {
-        printf("### ERROR: %s -> %s!\n", src->getPortName().c_str(),
-               dst->getPortName().c_str());
+        printf("### ERROR: %d -> %d!\n", src.getId(), dst.getId());
     }
 }
 
@@ -136,30 +135,18 @@ int main()
     {
         Thread::sleep(1000);
 
-        // Setting the baudrate to 2400, maximum functioning baudrate for the
-        // Max485 adapters
-        SerialInterface serial1(baudrates[iBaud], 1, "ser1");
-        SerialInterface serial2(baudrates[iBaud], 2, "ser2");
+        // instantiating the two USART drivers
+        USART serial1(USART1, baudrates[iBaud]);
+        USART serial2(USART2, baudrates[iBaud]);
 
-        if (!serial2.init())
-        {
-            printf("[Serial2] Wrong initialization\n");
-            return 1;
-        }
-
-        if (!serial1.init())
-        {
-            printf("[Serial1] Wrong initialization\n");
-            return 1;
-        }
-        printf("\n########################### %d\n", baudrates[iBaud]);
+        printf("\n########################### %d\n", (int)baudrates[iBaud]);
         // testing transmission "serial 1 <- serial 2"
         testCommunication<ctrlPin1_s2, ctrlPin2_s2, ctrlPin1_s1, ctrlPin2_s1>(
-            msg, &serial2, &serial1);
+            msg, serial2, serial1);
 
         // testing transmission "serial 1 -> serial 2"
         testCommunication<ctrlPin1_s1, ctrlPin2_s1, ctrlPin1_s2, ctrlPin2_s2>(
-            msg, &serial1, &serial2);
+            msg, serial1, serial2);
     }
 
     return 0;