From 2c8e7e48fc4fbb6e7aae7a8b807db99e54909ab5 Mon Sep 17 00:00:00 2001
From: Fabrizio Monti <fabrizio.monti@skywarder.eu>
Date: Fri, 14 Feb 2025 20:36:39 +0100
Subject: [PATCH] [DMA] Implemented dynamic stream acquire and moved
 definitions inside DMADefs.

---
 src/shared/drivers/dma/DMA.cpp            |  82 +++--
 src/shared/drivers/dma/DMA.h              |  81 ++--
 src/shared/drivers/dma/DMADefs.h          | 426 ++++++++++++++++++++++
 src/tests/drivers/test-dma-mem-to-mem.cpp |  20 +-
 4 files changed, 520 insertions(+), 89 deletions(-)
 create mode 100644 src/shared/drivers/dma/DMADefs.h

diff --git a/src/shared/drivers/dma/DMA.cpp b/src/shared/drivers/dma/DMA.cpp
index fef96ad56..1a60eeabb 100644
--- a/src/shared/drivers/dma/DMA.cpp
+++ b/src/shared/drivers/dma/DMA.cpp
@@ -39,7 +39,7 @@ void __attribute__((naked)) DMA1_Stream0_IRQHandler()
 void __attribute__((used)) DMA1_Stream0_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA1_Str0);
+        Boardcore::DMADefs::DMAStreamId::DMA1_Str0);
 }
 
 // TODO: decide how to handle this situation
@@ -53,7 +53,7 @@ void __attribute__((used)) DMA1_Stream0_IRQImpl()
 // void __attribute__((used)) DMA1_Stream1_IRQImpl()
 // {
 //     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-//         Boardcore::DMAStreamId::DMA1_Str1);
+//         Boardcore::DMADefs::DMAStreamId::DMA1_Str1);
 // }
 
 void __attribute__((naked)) DMA1_Stream2_IRQHandler()
@@ -66,7 +66,7 @@ void __attribute__((naked)) DMA1_Stream2_IRQHandler()
 void __attribute__((used)) DMA1_Stream2_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA1_Str2);
+        Boardcore::DMADefs::DMAStreamId::DMA1_Str2);
 }
 
 // TODO: decide how to handle this situation
@@ -93,7 +93,7 @@ void __attribute__((naked)) DMA1_Stream4_IRQHandler()
 void __attribute__((used)) DMA1_Stream4_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA1_Str4);
+        Boardcore::DMADefs::DMAStreamId::DMA1_Str4);
 }
 
 void __attribute__((naked)) DMA1_Stream5_IRQHandler()
@@ -106,7 +106,7 @@ void __attribute__((naked)) DMA1_Stream5_IRQHandler()
 void __attribute__((used)) DMA1_Stream5_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA1_Str5);
+        Boardcore::DMADefs::DMAStreamId::DMA1_Str5);
 }
 
 void __attribute__((naked)) DMA1_Stream6_IRQHandler()
@@ -119,7 +119,7 @@ void __attribute__((naked)) DMA1_Stream6_IRQHandler()
 void __attribute__((used)) DMA1_Stream6_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA1_Str6);
+        Boardcore::DMADefs::DMAStreamId::DMA1_Str6);
 }
 
 void __attribute__((naked)) DMA1_Stream7_IRQHandler()
@@ -132,7 +132,7 @@ void __attribute__((naked)) DMA1_Stream7_IRQHandler()
 void __attribute__((used)) DMA1_Stream7_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA1_Str7);
+        Boardcore::DMADefs::DMAStreamId::DMA1_Str7);
 }
 
 void __attribute__((naked)) DMA2_Stream0_IRQHandler()
@@ -145,7 +145,7 @@ void __attribute__((naked)) DMA2_Stream0_IRQHandler()
 void __attribute__((used)) DMA2_Stream0_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA2_Str0);
+        Boardcore::DMADefs::DMAStreamId::DMA2_Str0);
 }
 
 void __attribute__((naked)) DMA2_Stream1_IRQHandler()
@@ -158,7 +158,7 @@ void __attribute__((naked)) DMA2_Stream1_IRQHandler()
 void __attribute__((used)) DMA2_Stream1_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA2_Str1);
+        Boardcore::DMADefs::DMAStreamId::DMA2_Str1);
 }
 
 void __attribute__((naked)) DMA2_Stream2_IRQHandler()
@@ -171,7 +171,7 @@ void __attribute__((naked)) DMA2_Stream2_IRQHandler()
 void __attribute__((used)) DMA2_Stream2_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA2_Str2);
+        Boardcore::DMADefs::DMAStreamId::DMA2_Str2);
 }
 
 // TODO: decide how to handle this situation
@@ -186,7 +186,7 @@ void __attribute__((used)) DMA2_Stream2_IRQImpl()
 // void __attribute__((used)) DMA2_Stream3_IRQImpl()
 // {
 //     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-//         Boardcore::DMAStreamId::DMA2_Str3);
+//         Boardcore::DMADefs::DMAStreamId::DMA2_Str3);
 // }
 
 void __attribute__((naked)) DMA2_Stream4_IRQHandler()
@@ -199,7 +199,7 @@ void __attribute__((naked)) DMA2_Stream4_IRQHandler()
 void __attribute__((used)) DMA2_Stream4_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA2_Str4);
+        Boardcore::DMADefs::DMAStreamId::DMA2_Str4);
 }
 
 void __attribute__((naked)) DMA2_Stream5_IRQHandler()
@@ -212,7 +212,7 @@ void __attribute__((naked)) DMA2_Stream5_IRQHandler()
 void __attribute__((used)) DMA2_Stream5_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA2_Str5);
+        Boardcore::DMADefs::DMAStreamId::DMA2_Str5);
 }
 
 void __attribute__((naked)) DMA2_Stream6_IRQHandler()
@@ -225,7 +225,7 @@ void __attribute__((naked)) DMA2_Stream6_IRQHandler()
 void __attribute__((used)) DMA2_Stream6_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA2_Str6);
+        Boardcore::DMADefs::DMAStreamId::DMA2_Str6);
 }
 
 void __attribute__((naked)) DMA2_Stream7_IRQHandler()
@@ -238,13 +238,13 @@ void __attribute__((naked)) DMA2_Stream7_IRQHandler()
 void __attribute__((used)) DMA2_Stream7_IRQImpl()
 {
     Boardcore::DMADriver::instance().IRQhandleInterrupt(
-        Boardcore::DMAStreamId::DMA2_Str7);
+        Boardcore::DMADefs::DMAStreamId::DMA2_Str7);
 }
 
 namespace Boardcore
 {
 
-void DMADriver::IRQhandleInterrupt(DMAStreamId id)
+void DMADriver::IRQhandleInterrupt(DMADefs::DMAStreamId id)
 {
     auto stream = streams[id];
 
@@ -298,7 +298,7 @@ DMADriver& DMADriver::instance()
     return instance;
 }
 
-bool DMADriver::tryChannel(DMAStreamId id)
+bool DMADriver::tryChannel(DMADefs::DMAStreamId id)
 {
     Lock<FastMutex> l(mutex);
 
@@ -307,7 +307,8 @@ bool DMADriver::tryChannel(DMAStreamId id)
     return streams.count(id) == 0;
 }
 
-DMAStream& DMADriver::acquireStream(DMAStreamId id)
+DMAStream* DMADriver::acquireStream(DMADefs::DMAStreamId id,
+                                    DMADefs::Channel channel)
 {
     Lock<FastMutex> l(mutex);
 
@@ -320,10 +321,33 @@ DMAStream& DMADriver::acquireStream(DMAStreamId id)
     // if (streams.size() == 0)
     //     RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
 
-    return *(streams[id] = new DMAStream(id));
+    return streams[id] = new DMAStream(id, channel);
 }
 
-void DMADriver::releaseStream(DMAStreamId id)
+DMAStream* DMADriver::automaticAcquireStream(DMADefs::Peripherals peripheral)
+{
+    auto availableStreams = DMADefs::mapPeripherals.equal_range(peripheral);
+
+    // Iterate through the streams for that peripheral,
+    // return the first available
+    Lock<FastMutex> l(mutex);
+    for (auto it = availableStreams.first; it != availableStreams.second; ++it)
+    {
+        DMADefs::DMAStreamId id  = it->second.first;
+        DMADefs::Channel channel = it->second.second;
+
+        if (streams.count(id) == 0)
+        {
+            // Stream is free
+            return streams[id] = new DMAStream(id, channel);
+        }
+    }
+
+    // TODO: improve error handling
+    return nullptr;
+}
+
+void DMADriver::releaseStream(DMADefs::DMAStreamId id)
 {
     Lock<FastMutex> l(mutex);
 
@@ -365,7 +389,7 @@ void DMAStream::setup(DMATransaction transaction)
     while (registers->CR & DMA_SxCR_EN)
         ;
 
-    registers->CR |= static_cast<uint32_t>(transaction.channel);
+    setChannel(currentChannel);
     registers->CR |= static_cast<uint32_t>(transaction.direction);
     registers->CR |= static_cast<uint32_t>(transaction.priority);
     if (transaction.circularMode)
@@ -560,21 +584,27 @@ void DMAStream::setNumberOfDataItems(const uint16_t nBytes)
     registers->NDTR                = nBytes;
 }
 
+void DMAStream::setChannel(const DMADefs::Channel channel)
+{
+    registers->CR |= static_cast<uint32_t>(channel);
+}
+
 int DMAStream::getCurrentBufferNumber()
 {
     return (registers->CR & DMA_SxCR_CT) != 0 ? 2 : 1;
 }
 
-DMAStream::DMAStream(DMAStreamId id) : id(id)
+DMAStream::DMAStream(DMADefs::DMAStreamId id, DMADefs::Channel channel)
+    : id(id), currentChannel(channel)
 {
     // Get the channel registers base address and the interrupt flags clear
     // register address
-    if (id < DMAStreamId::DMA2_Str0)
+    if (id < DMADefs::DMAStreamId::DMA2_Str0)
     {
         registers = reinterpret_cast<DMA_Stream_TypeDef*>(
             DMA1_BASE + 0x10 + 0x18 * static_cast<uint8_t>(id));
 
-        if (id < DMAStreamId::DMA1_Str4)
+        if (id < DMADefs::DMAStreamId::DMA1_Str4)
         {
             // Streams from 0 to 3 use low registers (LIFCR and LISR)
             IFCR = &DMA1->LIFCR;
@@ -592,7 +622,7 @@ DMAStream::DMAStream(DMAStreamId id) : id(id)
         registers = reinterpret_cast<DMA_Stream_TypeDef*>(
             DMA2_BASE + 0x10 + 0x18 * (static_cast<uint8_t>(id) - 8));
 
-        if (id < DMAStreamId::DMA2_Str4)
+        if (id < DMADefs::DMAStreamId::DMA2_Str4)
         {
             // Streams from 0 to 3 use low registers (LIFCR and LISR)
             IFCR = &DMA2->LIFCR;
@@ -612,7 +642,7 @@ DMAStream::DMAStream(DMAStreamId id) : id(id)
     IFindex    = (offset % 2) * 6 + (offset / 2) * 16;
 
     // Select the interrupt
-    irqNumber = irqNumberMapping[static_cast<uint8_t>(id)];
+    irqNumber = DMADefs::irqNumberMapping[static_cast<uint8_t>(id)];
 }
 
 }  // namespace Boardcore
diff --git a/src/shared/drivers/dma/DMA.h b/src/shared/drivers/dma/DMA.h
index 754e9ba8f..e94b49ea7 100644
--- a/src/shared/drivers/dma/DMA.h
+++ b/src/shared/drivers/dma/DMA.h
@@ -22,7 +22,6 @@
 
 #pragma once
 
-#include <interfaces/arch_registers.h>
 #include <kernel/scheduler/scheduler.h>
 #include <kernel/sync.h>
 #include <utils/TimedPollingFlag.h>
@@ -31,6 +30,8 @@
 #include <functional>
 #include <map>
 
+#include "DMADefs.h"
+
 namespace Boardcore
 {
 
@@ -43,57 +44,8 @@ namespace Boardcore
 #define DMA_SxCR_PSIZE_Pos (11U)
 #endif
 
-enum class DMAStreamId : uint8_t
-{
-    // TODO: some streams are commented because the
-    // corresponding irq handler is already defined
-    // by miosix. For now those streams are not usable,
-    // decide how to handle this situation.
-
-    DMA1_Str0 = 0,
-    // DMA1_Str1 = 1,
-    DMA1_Str2 = 2,
-    // DMA1_Str3 = 3,
-    DMA1_Str4 = 4,
-    DMA1_Str5 = 5,
-    DMA1_Str6 = 6,
-    DMA1_Str7 = 7,
-    DMA2_Str0 = 8,
-    DMA2_Str1 = 9,
-    DMA2_Str2 = 10,
-    // DMA2_Str3 = 11,
-    DMA2_Str4 = 12,
-    DMA2_Str5 = 13,
-    DMA2_Str6 = 14,
-    DMA2_Str7 = 15,
-};
-
-/**
- * @brief Mapping between `DMAStreamId` and the corresponding irq number.
- * This is needed because irq number values are not contiguous and they are
- * architecture dependent.
- */
-const IRQn_Type irqNumberMapping[] = {
-    DMA1_Stream0_IRQn, DMA1_Stream1_IRQn, DMA1_Stream2_IRQn, DMA1_Stream3_IRQn,
-    DMA1_Stream4_IRQn, DMA1_Stream5_IRQn, DMA1_Stream6_IRQn, DMA1_Stream7_IRQn,
-    DMA2_Stream0_IRQn, DMA2_Stream1_IRQn, DMA2_Stream2_IRQn, DMA2_Stream3_IRQn,
-    DMA2_Stream4_IRQn, DMA2_Stream5_IRQn, DMA2_Stream6_IRQn, DMA2_Stream7_IRQn,
-};
-
 struct DMATransaction
 {
-    enum class Channel : uint32_t
-    {
-        CHANNEL0 = 0,
-        CHANNEL1 = DMA_SxCR_CHSEL_0,
-        CHANNEL2 = DMA_SxCR_CHSEL_1,
-        CHANNEL3 = DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0,
-        CHANNEL4 = DMA_SxCR_CHSEL_2,
-        CHANNEL5 = DMA_SxCR_CHSEL_2 | DMA_SxCR_CHSEL_0,
-        CHANNEL6 = DMA_SxCR_CHSEL_2 | DMA_SxCR_CHSEL_1,
-        CHANNEL7 = DMA_SxCR_CHSEL,
-    };
-
     enum class Direction : uint16_t
     {
         MEM_TO_MEM = DMA_SxCR_DIR_1,
@@ -116,7 +68,6 @@ struct DMATransaction
         BITS_32,
     };
 
-    Channel channel                      = Channel::CHANNEL0;
     Direction direction                  = Direction::MEM_TO_MEM;
     Priority priority                    = Priority::LOW;
     DataSize srcSize                     = DataSize::BITS_32;
@@ -142,15 +93,18 @@ class DMAStream;
 class DMADriver
 {
 public:
-    void IRQhandleInterrupt(DMAStreamId id);
+    void IRQhandleInterrupt(DMADefs::DMAStreamId id);
 
     static DMADriver& instance();
 
-    bool tryChannel(DMAStreamId id);
+    bool tryChannel(DMADefs::DMAStreamId id);
 
-    DMAStream& acquireStream(DMAStreamId id);
+    DMAStream* acquireStream(DMADefs::DMAStreamId id, DMADefs::Channel channel);
 
-    void releaseStream(DMAStreamId id);
+    // TODO: change name
+    DMAStream* automaticAcquireStream(DMADefs::Peripherals peripheral);
+
+    void releaseStream(DMADefs::DMAStreamId id);
 
 private:
     DMADriver();
@@ -159,7 +113,7 @@ private:
 
     miosix::FastMutex mutex;
     miosix::ConditionVariable cv;
-    std::map<DMAStreamId, DMAStream*> streams;
+    std::map<DMADefs::DMAStreamId, DMAStream*> streams;
 
 public:
     DMADriver(const DMADriver&)            = delete;
@@ -218,6 +172,12 @@ public:
      */
     void setNumberOfDataItems(const uint16_t nBytes);
 
+    /**
+     * @brief Select the channel to be used by the stream during
+     * the transactions.
+     */
+    void setChannel(const DMADefs::Channel channel);
+
     /**
      * @brief Returns the last read status of the half transfer flag.
      *
@@ -260,6 +220,10 @@ public:
      */
     int getCurrentBufferNumber();
 
+    inline DMADefs::DMAStreamId getStreamId() { return id; }
+
+    inline DMADefs::Channel getCurrentChannel() { return currentChannel; }
+
     inline void clearHalfTransferFlag()
     {
         *IFCR |= DMA_LIFCR_CHTIF0 << IFindex;
@@ -294,7 +258,7 @@ public:
     }
 
 private:
-    DMAStream(DMAStreamId id);
+    DMAStream(DMADefs::DMAStreamId id, DMADefs::Channel channel);
 
     DMATransaction currentSetup;
 
@@ -316,7 +280,8 @@ private:
     std::function<void()> transferCompleteCallback;
     std::function<void()> errorCallback;
 
-    DMAStreamId id;
+    DMADefs::DMAStreamId id;
+    DMADefs::Channel currentChannel;
     IRQn_Type irqNumber;
     DMA_Stream_TypeDef* registers;
 
diff --git a/src/shared/drivers/dma/DMADefs.h b/src/shared/drivers/dma/DMADefs.h
new file mode 100644
index 000000000..bdbca679f
--- /dev/null
+++ b/src/shared/drivers/dma/DMADefs.h
@@ -0,0 +1,426 @@
+/* Copyright (c) 2025 Skyward Experimental Rocketry
+ * Author: Fabrizio Monti
+ *
+ * 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 <interfaces/arch_registers.h>
+#include <stdint.h>
+
+#include <map>
+
+namespace Boardcore
+{
+
+namespace DMADefs
+{
+
+enum class DMAStreamId : uint8_t
+{
+    // TODO: some streams are commented because the
+    // corresponding irq handler is already defined
+    // by miosix. For now those streams are not usable,
+    // decide how to handle this situation.
+
+    DMA1_Str0 = 0,
+    // DMA1_Str1 = 1,
+    DMA1_Str2 = 2,
+    // DMA1_Str3 = 3,
+    DMA1_Str4 = 4,
+    DMA1_Str5 = 5,
+    DMA1_Str6 = 6,
+    DMA1_Str7 = 7,
+    DMA2_Str0 = 8,
+    DMA2_Str1 = 9,
+    DMA2_Str2 = 10,
+    // DMA2_Str3 = 11,
+    DMA2_Str4 = 12,
+    DMA2_Str5 = 13,
+    DMA2_Str6 = 14,
+    DMA2_Str7 = 15,
+};
+
+/**
+ * @brief Mapping between `DMAStreamId` and the corresponding irq number.
+ * This is needed because irq number values are not contiguous and they are
+ * architecture dependent.
+ */
+const IRQn_Type irqNumberMapping[] = {
+    DMA1_Stream0_IRQn, DMA1_Stream1_IRQn, DMA1_Stream2_IRQn, DMA1_Stream3_IRQn,
+    DMA1_Stream4_IRQn, DMA1_Stream5_IRQn, DMA1_Stream6_IRQn, DMA1_Stream7_IRQn,
+    DMA2_Stream0_IRQn, DMA2_Stream1_IRQn, DMA2_Stream2_IRQn, DMA2_Stream3_IRQn,
+    DMA2_Stream4_IRQn, DMA2_Stream5_IRQn, DMA2_Stream6_IRQn, DMA2_Stream7_IRQn,
+};
+
+/**
+ * @brief Channels selectable for each dma stream.
+ */
+enum class Channel : uint32_t
+{
+    CHANNEL0 = 0,
+    CHANNEL1 = DMA_SxCR_CHSEL_0,
+    CHANNEL2 = DMA_SxCR_CHSEL_1,
+    CHANNEL3 = DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0,
+    CHANNEL4 = DMA_SxCR_CHSEL_2,
+    CHANNEL5 = DMA_SxCR_CHSEL_2 | DMA_SxCR_CHSEL_0,
+    CHANNEL6 = DMA_SxCR_CHSEL_2 | DMA_SxCR_CHSEL_1,
+    CHANNEL7 = DMA_SxCR_CHSEL,
+};
+
+/**
+ * @brief All the peripherals connected to dma.
+ */
+enum class Peripherals : uint8_t
+{
+    PE_MEM_ONLY,
+
+    PE_SPI1_TX,
+    PE_SPI1_RX,
+    PE_SPI2_TX,
+    PE_SPI2_RX,
+    PE_SPI3_TX,
+    PE_SPI3_RX,
+    PE_SPI4_TX,
+    PE_SPI4_RX,
+    PE_SPI5_TX,
+    PE_SPI5_RX,
+    PE_SPI6_TX,
+    PE_SPI6_RX,
+    PE_USART1_TX,
+    PE_USART1_RX,
+    PE_USART2_TX,
+    PE_USART2_RX,
+    PE_USART3_TX,
+    PE_USART3_RX,
+    PE_UART4_TX,
+    PE_UART4_RX,
+    PE_UART5_TX,
+    PE_UART5_RX,
+    PE_USART6_TX,
+    PE_USART6_RX,
+    PE_UART7_TX,
+    PE_UART7_RX,
+    PE_UART8_TX,
+    PE_UART8_RX,
+    PE_I2C1_TX,
+    PE_I2C1_RX,
+    PE_I2C2_TX,
+    PE_I2C2_RX,
+    PE_I2C3_TX,
+    PE_I2C3_RX,
+    PE_I2S2_EXT_TX,
+    PE_I2S2_EXT_RX,
+    PE_I2S3_EXT_TX,
+    PE_I2S3_EXT_RX,
+    PE_TIM1_UP,
+    PE_TIM1_TRIG,
+    PE_TIM1_COM,
+    PE_TIM1_CH1,
+    PE_TIM1_CH2,
+    PE_TIM1_CH3,
+    PE_TIM1_CH4,
+    PE_TIM2_UP,
+    PE_TIM2_CH1,
+    PE_TIM2_CH2,
+    PE_TIM2_CH3,
+    PE_TIM2_CH4,
+    PE_TIM3_UP,
+    PE_TIM3_TRIG,
+    PE_TIM3_CH1,
+    PE_TIM3_CH2,
+    PE_TIM3_CH3,
+    PE_TIM3_CH4,
+    PE_TIM4_UP,
+    PE_TIM4_CH1,
+    PE_TIM4_CH2,
+    PE_TIM4_CH3,
+    PE_TIM5_UP,
+    PE_TIM5_TRIG,
+    PE_TIM5_CH1,
+    PE_TIM5_CH2,
+    PE_TIM5_CH3,
+    PE_TIM5_CH4,
+    PE_TIM6_UP,
+    PE_TIM7_UP,
+    PE_TIM8_UP,
+    PE_TIM8_TRIG,
+    PE_TIM8_COM,
+    PE_TIM8_CH1,
+    PE_TIM8_CH2,
+    PE_TIM8_CH3,
+    PE_TIM8_CH4,
+    PE_DAC1,
+    PE_DAC2,
+    PE_ADC1,
+    PE_ADC2,
+    PE_ADC3,
+    PE_SAI1_A,
+    PE_SAI1_B,
+    PE_DCMI,
+    PE_SDIO,
+    PE_CRYP_OUT,
+    PE_CRYP_IN,
+    PE_HASH_IN,
+
+};
+
+/**
+ * @brief Maps the peripherals to the dma streams (and
+ * the corresponding channel) that are connected with.
+ */
+const std::multimap<Peripherals, std::pair<DMAStreamId, Channel>>
+    mapPeripherals = {
+
+        // MEM-TO-MEM (only dma2 can perform mem-to-mem copy)
+        {Peripherals::PE_MEM_ONLY, {DMAStreamId::DMA2_Str0, Channel::CHANNEL0}},
+        {Peripherals::PE_MEM_ONLY, {DMAStreamId::DMA2_Str1, Channel::CHANNEL0}},
+        {Peripherals::PE_MEM_ONLY, {DMAStreamId::DMA2_Str2, Channel::CHANNEL0}},
+        // {Peripherals::PE_MEM_ONLY, {DMAStreamId::DMA2_Str3,
+        // Channel::CHANNEL0}}, // Stream currently not supported
+        {Peripherals::PE_MEM_ONLY, {DMAStreamId::DMA2_Str4, Channel::CHANNEL0}},
+        {Peripherals::PE_MEM_ONLY, {DMAStreamId::DMA2_Str5, Channel::CHANNEL0}},
+        {Peripherals::PE_MEM_ONLY, {DMAStreamId::DMA2_Str6, Channel::CHANNEL0}},
+        {Peripherals::PE_MEM_ONLY, {DMAStreamId::DMA2_Str7, Channel::CHANNEL0}},
+
+        // SPI
+        {Peripherals::PE_SPI1_TX, {DMAStreamId::DMA2_Str5, Channel::CHANNEL3}},
+        // {Peripherals::PE_SPI1_TX, {DMAStreamId::DMA2_Str3,
+        // Channel::CHANNEL3}}, // Stream currently not supported
+        {Peripherals::PE_SPI1_RX, {DMAStreamId::DMA2_Str2, Channel::CHANNEL3}},
+        {Peripherals::PE_SPI1_RX, {DMAStreamId::DMA2_Str0, Channel::CHANNEL3}},
+
+        {Peripherals::PE_SPI2_TX, {DMAStreamId::DMA1_Str4, Channel::CHANNEL0}},
+        // {Peripherals::PE_SPI2_RX, {DMAStreamId::DMA1_Str3,
+        // Channel::CHANNEL0}}, // Stream currently not supported
+
+        {Peripherals::PE_SPI3_TX, {DMAStreamId::DMA1_Str5, Channel::CHANNEL0}},
+        {Peripherals::PE_SPI3_TX, {DMAStreamId::DMA1_Str7, Channel::CHANNEL0}},
+        {Peripherals::PE_SPI3_RX, {DMAStreamId::DMA1_Str0, Channel::CHANNEL0}},
+        {Peripherals::PE_SPI3_RX, {DMAStreamId::DMA1_Str2, Channel::CHANNEL0}},
+
+        // {Peripherals::PE_SPI4_TX, {DMAStreamId::DMA2_Str1,
+        // Channel::CHANNEL4}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SPI4_TX, {DMAStreamId::DMA2_Str4,
+        // Channel::CHANNEL5}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SPI4_RX, {DMAStreamId::DMA2_Str0,
+        // Channel::CHANNEL4}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SPI4_RX, {DMAStreamId::DMA2_Str3,
+        // Channel::CHANNEL5}}, // available on STM32F42xxx and STM32F43xxx only
+
+        // {Peripherals::PE_SPI5_TX, {DMAStreamId::DMA2_Str4,
+        // Channel::CHANNEL2}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SPI5_TX, {DMAStreamId::DMA2_Str6,
+        // Channel::CHANNEL7}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SPI5_RX, {DMAStreamId::DMA2_Str3,
+        // Channel::CHANNEL2}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SPI5_RX, {DMAStreamId::DMA2_Str5,
+        // Channel::CHANNEL7}}, // available on STM32F42xxx and STM32F43xxx only
+
+        // {Peripherals::PE_SPI6_TX, {DMAStreamId::DMA2_Str5,
+        // Channel::CHANNEL1}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SPI6_RX, {DMAStreamId::DMA2_Str6,
+        // Channel::CHANNEL1}}, // available on STM32F42xxx and STM32F43xxx only
+
+        // UART & USART
+        {Peripherals::PE_USART1_TX,
+         {DMAStreamId::DMA2_Str7, Channel::CHANNEL4}},
+        {Peripherals::PE_USART1_RX,
+         {DMAStreamId::DMA2_Str2, Channel::CHANNEL4}},
+        {Peripherals::PE_USART1_RX,
+         {DMAStreamId::DMA2_Str5, Channel::CHANNEL4}},
+
+        {Peripherals::PE_USART2_TX,
+         {DMAStreamId::DMA1_Str6, Channel::CHANNEL4}},
+        {Peripherals::PE_USART2_RX,
+         {DMAStreamId::DMA1_Str5, Channel::CHANNEL4}},
+
+        // {Peripherals::PE_USART3_TX, {DMAStreamId::DMA1_Str3,
+        // Channel::CHANNEL4}}, // Stream currently not supported
+        {Peripherals::PE_USART3_TX,
+         {DMAStreamId::DMA1_Str4, Channel::CHANNEL7}},
+        // {Peripherals::PE_USART3_RX, {DMAStreamId::DMA1_Str1,
+        // Channel::CHANNEL4}}, // Stream currently not supported
+
+        {Peripherals::PE_UART4_TX, {DMAStreamId::DMA1_Str4, Channel::CHANNEL4}},
+        {Peripherals::PE_UART4_RX, {DMAStreamId::DMA1_Str2, Channel::CHANNEL4}},
+
+        {Peripherals::PE_UART5_TX, {DMAStreamId::DMA1_Str7, Channel::CHANNEL4}},
+        {Peripherals::PE_UART5_RX, {DMAStreamId::DMA1_Str0, Channel::CHANNEL4}},
+
+        // {Peripherals::PE_UART7_TX, {DMAStreamId::DMA1_Str1,
+        // Channel::CHANNEL5}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_UART7_RX, {DMAStreamId::DMA1_Str3,
+        // Channel::CHANNEL5}}, // available on STM32F42xxx and STM32F43xxx only
+
+        // {Peripherals::PE_UART8_TX, {DMAStreamId::DMA1_Str0,
+        // Channel::CHANNEL5}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_UART8_RX, {DMAStreamId::DMA1_Str6,
+        // Channel::CHANNEL5}}, // available on STM32F42xxx and STM32F43xxx only
+
+        {Peripherals::PE_USART6_TX,
+         {DMAStreamId::DMA2_Str6, Channel::CHANNEL5}},
+        {Peripherals::PE_USART6_TX,
+         {DMAStreamId::DMA2_Str7, Channel::CHANNEL5}},
+        {Peripherals::PE_USART6_RX,
+         {DMAStreamId::DMA2_Str1, Channel::CHANNEL5}},
+        {Peripherals::PE_USART6_RX,
+         {DMAStreamId::DMA2_Str2, Channel::CHANNEL5}},
+
+        // I2C
+        {Peripherals::PE_I2C1_TX, {DMAStreamId::DMA1_Str6, Channel::CHANNEL1}},
+        {Peripherals::PE_I2C1_TX, {DMAStreamId::DMA1_Str7, Channel::CHANNEL1}},
+        {Peripherals::PE_I2C1_RX, {DMAStreamId::DMA1_Str0, Channel::CHANNEL1}},
+        {Peripherals::PE_I2C1_RX, {DMAStreamId::DMA1_Str5, Channel::CHANNEL1}},
+
+        {Peripherals::PE_I2C2_TX, {DMAStreamId::DMA1_Str7, Channel::CHANNEL7}},
+        {Peripherals::PE_I2C2_RX, {DMAStreamId::DMA1_Str2, Channel::CHANNEL7}},
+        // {Peripherals::PE_I2C2_RX, {DMAStreamId::DMA1_Str3,
+        // Channel::CHANNEL7}}, // Stream currently not supported
+
+        {Peripherals::PE_I2C3_TX, {DMAStreamId::DMA1_Str4, Channel::CHANNEL3}},
+        {Peripherals::PE_I2C3_RX, {DMAStreamId::DMA1_Str2, Channel::CHANNEL3}},
+
+        {Peripherals::PE_I2S2_EXT_TX,
+         {DMAStreamId::DMA1_Str4, Channel::CHANNEL2}},
+        // {Peripherals::PE_I2S2_EXT_RX, {DMAStreamId::DMA1_Str3,
+        // Channel::CHANNEL3}}, // Stream currently not supported
+
+        {Peripherals::PE_I2S3_EXT_TX,
+         {DMAStreamId::DMA1_Str5, Channel::CHANNEL2}},
+        {Peripherals::PE_I2S3_EXT_RX,
+         {DMAStreamId::DMA1_Str2, Channel::CHANNEL2}},
+        {Peripherals::PE_I2S3_EXT_RX,
+         {DMAStreamId::DMA1_Str0, Channel::CHANNEL3}},
+
+        // TIMERS
+        {Peripherals::PE_TIM1_UP, {DMAStreamId::DMA2_Str5, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM1_TRIG,
+         {DMAStreamId::DMA2_Str0, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM1_TRIG,
+         {DMAStreamId::DMA2_Str4, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM1_COM, {DMAStreamId::DMA2_Str4, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM1_CH1, {DMAStreamId::DMA2_Str6, Channel::CHANNEL0}},
+        {Peripherals::PE_TIM1_CH1, {DMAStreamId::DMA2_Str1, Channel::CHANNEL6}},
+        // {Peripherals::PE_TIM1_CH1, {DMAStreamId::DMA2_Str3,
+        // Channel::CHANNEL6}}, // Stream currently not supported
+        {Peripherals::PE_TIM1_CH2, {DMAStreamId::DMA2_Str6, Channel::CHANNEL0}},
+        {Peripherals::PE_TIM1_CH2, {DMAStreamId::DMA2_Str2, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM1_CH3, {DMAStreamId::DMA2_Str6, Channel::CHANNEL0}},
+        {Peripherals::PE_TIM1_CH3, {DMAStreamId::DMA2_Str6, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM1_CH4, {DMAStreamId::DMA2_Str4, Channel::CHANNEL6}},
+
+        // {Peripherals::PE_TIM2_UP, {DMAStreamId::DMA1_Str1,
+        // Channel::CHANNEL3}}, // Stream currently not supported
+        {Peripherals::PE_TIM2_UP, {DMAStreamId::DMA1_Str7, Channel::CHANNEL3}},
+        {Peripherals::PE_TIM2_CH1, {DMAStreamId::DMA1_Str5, Channel::CHANNEL3}},
+        {Peripherals::PE_TIM2_CH2, {DMAStreamId::DMA1_Str6, Channel::CHANNEL3}},
+        // {Peripherals::PE_TIM2_CH3, {DMAStreamId::DMA1_Str1,
+        // Channel::CHANNEL3}}, // Stream currently not supported
+        {Peripherals::PE_TIM2_CH4, {DMAStreamId::DMA1_Str6, Channel::CHANNEL3}},
+        {Peripherals::PE_TIM2_CH4, {DMAStreamId::DMA1_Str7, Channel::CHANNEL3}},
+
+        {Peripherals::PE_TIM3_UP, {DMAStreamId::DMA1_Str2, Channel::CHANNEL5}},
+        {Peripherals::PE_TIM3_TRIG,
+         {DMAStreamId::DMA1_Str4, Channel::CHANNEL5}},
+        {Peripherals::PE_TIM3_CH1, {DMAStreamId::DMA1_Str4, Channel::CHANNEL5}},
+        {Peripherals::PE_TIM3_CH2, {DMAStreamId::DMA1_Str5, Channel::CHANNEL5}},
+        {Peripherals::PE_TIM3_CH3, {DMAStreamId::DMA1_Str7, Channel::CHANNEL5}},
+        {Peripherals::PE_TIM3_CH4, {DMAStreamId::DMA1_Str2, Channel::CHANNEL5}},
+
+        {Peripherals::PE_TIM4_UP, {DMAStreamId::DMA1_Str6, Channel::CHANNEL2}},
+        {Peripherals::PE_TIM4_CH1, {DMAStreamId::DMA1_Str0, Channel::CHANNEL2}},
+        // {Peripherals::PE_TIM4_CH2, {DMAStreamId::DMA1_Str3,
+        // Channel::CHANNEL2}}, // Stream currently not supported
+        {Peripherals::PE_TIM4_CH3, {DMAStreamId::DMA1_Str7, Channel::CHANNEL2}},
+
+        {Peripherals::PE_TIM5_UP, {DMAStreamId::DMA1_Str0, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM5_UP, {DMAStreamId::DMA1_Str6, Channel::CHANNEL6}},
+        // {Peripherals::PE_TIM5_TRIG, {DMAStreamId::DMA1_Str1,
+        // Channel::CHANNEL6}}, // Stream currently not supported
+        // {Peripherals::PE_TIM5_TRIG, {DMAStreamId::DMA1_Str3,
+        // Channel::CHANNEL6}}, // Stream currently not supported
+        {Peripherals::PE_TIM5_CH1, {DMAStreamId::DMA1_Str2, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM5_CH2, {DMAStreamId::DMA1_Str4, Channel::CHANNEL6}},
+        {Peripherals::PE_TIM5_CH3, {DMAStreamId::DMA1_Str0, Channel::CHANNEL6}},
+        // {Peripherals::PE_TIM5_CH4, {DMAStreamId::DMA1_Str1,
+        // Channel::CHANNEL6}}, // Stream currently not supported
+        // {Peripherals::PE_TIM5_CH4, {DMAStreamId::DMA1_Str3,
+        // Channel::CHANNEL6}}, // Stream currently not supported
+
+        // {Peripherals::PE_TIM6_UP, {DMAStreamId::DMA1_Str1,
+        // Channel::CHANNEL7}}, // Stream currently not supported
+
+        {Peripherals::PE_TIM7_UP, {DMAStreamId::DMA1_Str2, Channel::CHANNEL1}},
+        {Peripherals::PE_TIM7_UP, {DMAStreamId::DMA1_Str4, Channel::CHANNEL1}},
+
+        {Peripherals::PE_TIM8_UP, {DMAStreamId::DMA2_Str1, Channel::CHANNEL7}},
+        {Peripherals::PE_TIM8_TRIG,
+         {DMAStreamId::DMA2_Str7, Channel::CHANNEL7}},
+        {Peripherals::PE_TIM8_COM, {DMAStreamId::DMA2_Str7, Channel::CHANNEL7}},
+        {Peripherals::PE_TIM8_CH1, {DMAStreamId::DMA2_Str2, Channel::CHANNEL0}},
+        {Peripherals::PE_TIM8_CH1, {DMAStreamId::DMA2_Str2, Channel::CHANNEL7}},
+        {Peripherals::PE_TIM8_CH2, {DMAStreamId::DMA2_Str2, Channel::CHANNEL0}},
+        // {Peripherals::PE_TIM8_CH2, {DMAStreamId::DMA2_Str3,
+        // Channel::CHANNEL7}}, // Stream currently not supported
+        {Peripherals::PE_TIM8_CH3, {DMAStreamId::DMA2_Str2, Channel::CHANNEL0}},
+        {Peripherals::PE_TIM8_CH3, {DMAStreamId::DMA2_Str4, Channel::CHANNEL7}},
+        {Peripherals::PE_TIM8_CH4, {DMAStreamId::DMA2_Str7, Channel::CHANNEL7}},
+
+        // Others
+        {Peripherals::PE_DAC1, {DMAStreamId::DMA1_Str5, Channel::CHANNEL7}},
+        {Peripherals::PE_DAC2, {DMAStreamId::DMA1_Str6, Channel::CHANNEL7}},
+
+        {Peripherals::PE_ADC1, {DMAStreamId::DMA2_Str0, Channel::CHANNEL0}},
+        {Peripherals::PE_ADC1, {DMAStreamId::DMA2_Str4, Channel::CHANNEL0}},
+
+        {Peripherals::PE_ADC2, {DMAStreamId::DMA2_Str2, Channel::CHANNEL1}},
+        // {Peripherals::PE_ADC2, {DMAStreamId::DMA2_Str3, Channel::CHANNEL1}},
+        // // Stream currently not supported
+
+        {Peripherals::PE_ADC3, {DMAStreamId::DMA2_Str0, Channel::CHANNEL2}},
+        {Peripherals::PE_ADC3, {DMAStreamId::DMA2_Str1, Channel::CHANNEL2}},
+
+        // {Peripherals::PE_SAI1_A, {DMAStreamId::DMA2_Str1,
+        // Channel::CHANNEL0}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SAI1_A, {DMAStreamId::DMA2_Str3,
+        // Channel::CHANNEL0}}, // available on STM32F42xxx and STM32F43xxx only
+
+        // {Peripherals::PE_SAI1_B, {DMAStreamId::DMA2_Str5,
+        // Channel::CHANNEL0}}, // available on STM32F42xxx and STM32F43xxx only
+        // {Peripherals::PE_SAI1_B, {DMAStreamId::DMA2_Str4,
+        // Channel::CHANNEL1}}, // available on STM32F42xxx and STM32F43xxx only
+
+        {Peripherals::PE_DCMI, {DMAStreamId::DMA2_Str1, Channel::CHANNEL1}},
+        {Peripherals::PE_DCMI, {DMAStreamId::DMA2_Str7, Channel::CHANNEL1}},
+
+        // {Peripherals::PE_SDIO, {DMAStreamId::DMA2_Str3, Channel::CHANNEL4}},
+        // // Stream currently not supported
+        {Peripherals::PE_SDIO, {DMAStreamId::DMA2_Str6, Channel::CHANNEL4}},
+
+        {Peripherals::PE_CRYP_OUT, {DMAStreamId::DMA2_Str5, Channel::CHANNEL2}},
+        {Peripherals::PE_CRYP_IN, {DMAStreamId::DMA2_Str6, Channel::CHANNEL2}},
+
+        {Peripherals::PE_HASH_IN, {DMAStreamId::DMA2_Str7, Channel::CHANNEL2}},
+};
+
+}  // namespace DMADefs
+
+}  // namespace Boardcore
\ No newline at end of file
diff --git a/src/tests/drivers/test-dma-mem-to-mem.cpp b/src/tests/drivers/test-dma-mem-to-mem.cpp
index f11549bcd..aa53a2b7f 100644
--- a/src/tests/drivers/test-dma-mem-to-mem.cpp
+++ b/src/tests/drivers/test-dma-mem-to-mem.cpp
@@ -29,12 +29,22 @@
 using namespace miosix;
 using namespace Boardcore;
 
-DMAStream &stream = DMADriver::instance().acquireStream(DMAStreamId::DMA2_Str0);
-
 void printBuffer(uint8_t *buffer, size_t size);
 
 int main()
 {
+    // DMAStream* stream =
+    // DMADriver::instance().acquireStream(DMADefs::DMAStreamId::DMA2_Str0,
+    // DMADefs::Channel::CHANNEL0);
+    DMAStream *stream = DMADriver::instance().automaticAcquireStream(
+        DMADefs::Peripherals::PE_MEM_ONLY);
+
+    if (stream == nullptr)
+    {
+        printf("Error, cannot allocate dma stream\n");
+        return 0;
+    }
+
     /**
      * In this test we want to copy a buffer1 into buffer2 with the DMA.
      */
@@ -59,11 +69,11 @@ int main()
         .dstIncrement      = true,
         .enableTransferCompleteInterrupt = true,
     };
-    stream.setup(trn);
-    stream.enable();
+    stream->setup(trn);
+    stream->enable();
 
     auto begin = std::chrono::steady_clock::now();
-    stream.waitForTransferComplete();
+    stream->waitForTransferComplete();
     auto end = std::chrono::steady_clock::now();
 
     printf("After:\n");
-- 
GitLab