diff --git a/src/shared/drivers/dma/DMA.cpp b/src/shared/drivers/dma/DMA.cpp
index 1a60eeabbcf1f6a4fa38ae781a102a8f48eca1ec..5edfcec61870ccd4a4eb55c962e596592195c2ea 100644
--- a/src/shared/drivers/dma/DMA.cpp
+++ b/src/shared/drivers/dma/DMA.cpp
@@ -307,14 +307,30 @@ bool DMADriver::tryChannel(DMADefs::DMAStreamId id)
     return streams.count(id) == 0;
 }
 
-DMAStream* DMADriver::acquireStream(DMADefs::DMAStreamId id,
-                                    DMADefs::Channel channel)
+DMAStream* DMADriver::acquireStreamBlocking(
+    DMADefs::DMAStreamId id, DMADefs::Channel channel,
+    const std::chrono::nanoseconds timeout)
 {
     Lock<FastMutex> l(mutex);
 
-    // Wait until the channel is free
+    // Wait until the stream is free or the timeout expires
     while (streams.count(id) != 0)
-        cv.wait(l);
+    {
+        if (timeout == std::chrono::nanoseconds::zero())
+        {
+            cv.wait(l);
+        }
+        else
+        {
+            auto res = cv.timedWait(l, timeout.count());
+
+            if (res == TimedWaitResult::Timeout)
+            {
+                // The timeout expired
+                return nullptr;
+            }
+        }
+    }
 
     // Enable the clock if not already done
     // TODO: Enable DMA1 or DMA2
@@ -324,27 +340,45 @@ DMAStream* DMADriver::acquireStream(DMADefs::DMAStreamId id,
     return streams[id] = new DMAStream(id, channel);
 }
 
-DMAStream* DMADriver::automaticAcquireStream(DMADefs::Peripherals peripheral)
+DMAStream* DMADriver::automaticAcquireStreamBlocking(
+    DMADefs::Peripherals peripheral, const std::chrono::nanoseconds timeout)
 {
-    auto availableStreams = DMADefs::mapPeripherals.equal_range(peripheral);
+    const 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)
+    while (true)
     {
-        DMADefs::DMAStreamId id  = it->second.first;
-        DMADefs::Channel channel = it->second.second;
+        // Iterate through the streams for that peripheral,
+        // return the first available
+        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);
+            }
+        }
 
-        if (streams.count(id) == 0)
+        if (timeout == std::chrono::nanoseconds::zero())
         {
-            // Stream is free
-            return streams[id] = new DMAStream(id, channel);
+            cv.wait(l);
         }
-    }
+        else
+        {
+            auto res = cv.timedWait(l, timeout.count());
 
-    // TODO: improve error handling
-    return nullptr;
+            if (res == TimedWaitResult::Timeout)
+            {
+                // The timeout expired
+                return nullptr;
+            }
+        }
+    }
 }
 
 void DMADriver::releaseStream(DMADefs::DMAStreamId id)
diff --git a/src/shared/drivers/dma/DMA.h b/src/shared/drivers/dma/DMA.h
index e94b49ea7d3c5f58c7e9aa34c86effe89cda4d35..3bb976f0f48391b4631fdd6e1ff1f59cfc462a9b 100644
--- a/src/shared/drivers/dma/DMA.h
+++ b/src/shared/drivers/dma/DMA.h
@@ -99,10 +99,34 @@ public:
 
     bool tryChannel(DMADefs::DMAStreamId id);
 
-    DMAStream* acquireStream(DMADefs::DMAStreamId id, DMADefs::Channel channel);
+    /**
+     * @brief Try to acquire the specified stream and initialize it with the
+     * correct channel.
+     * @param id The id of the stream to be acquired.
+     * @param channel The channel used to initialize the stream.
+     * @param timeout The maximum time that will be waited when in blocking
+     * mode, 0 to disable the timeout and wait forever.
+     * @return The pointer to the allocated stream if successful, nullptr if the
+     * timeout expired.
+     */
+    DMAStream* acquireStreamBlocking(DMADefs::DMAStreamId id,
+                                     DMADefs::Channel channel,
+                                     const std::chrono::nanoseconds timeout);
 
-    // TODO: change name
-    DMAStream* automaticAcquireStream(DMADefs::Peripherals peripheral);
+    /**
+     * @brief Try to acquire a stream that is connected to the specified
+     * peripheral.
+     * @param peripheral The wanted peripheral.
+     * @param timeout The maximum time that will be waited when in blocking
+     * mode, 0 to disable the timeout and wait forever.
+     * @return The pointer to the allocated stream if successful, nullptr if the
+     * timeout expired.
+     *
+     * TODO: change name
+     */
+    DMAStream* automaticAcquireStreamBlocking(
+        DMADefs::Peripherals peripheral,
+        const std::chrono::nanoseconds timeout);
 
     void releaseStream(DMADefs::DMAStreamId id);
 
diff --git a/src/tests/drivers/test-dma-mem-to-mem.cpp b/src/tests/drivers/test-dma-mem-to-mem.cpp
index aa53a2b7fce11090e443c9334add7deaf617e713..d4970559df83786494acea4fdc851c308bff158b 100644
--- a/src/tests/drivers/test-dma-mem-to-mem.cpp
+++ b/src/tests/drivers/test-dma-mem-to-mem.cpp
@@ -33,11 +33,8 @@ 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);
+    DMAStream *stream = DMADriver::instance().automaticAcquireStreamBlocking(
+        DMADefs::Peripherals::PE_MEM_ONLY, std::chrono::seconds::zero());
 
     if (stream == nullptr)
     {