From d04b9c25f9803a2b7ab87042cfa66b6dd12d94e4 Mon Sep 17 00:00:00 2001
From: Ahmad Faour <ahmad.faour@polymtl.ca>
Date: Thu, 28 Oct 2021 22:28:43 +0000
Subject: [PATCH] Add Dma feature with Usart 2 RX and TX

---
 .devcontainer/devcontainer.json               |   6 +-
 .vscode/launch.json                           |   4 +
 .vscode/settings.json                         |   3 +-
 .../dma/abstract-dma/abstract-dma-init.hpp    |  24 ++++
 .../dma/abstract-dma/abstract-dma.cpp         | 131 ++++++++++++++++++
 .../dma/abstract-dma/abstract-dma.hpp         |  36 +++++
 .../dma/dma-register/dma-channel.hpp          |   7 +
 .../dma/dma-register/dma-circular-mode.hpp    |   7 +
 .../dma/dma-register/dma-direction.hpp        |   9 ++
 .../dma/dma-register/dma-memory-increment.hpp |  10 ++
 .../dma/dma-register/dma-memory-size.hpp      |   7 +
 .../dma-register/dma-peripheral-increment.hpp |   9 ++
 .../dma/dma-register/dma-peripheral-size.hpp  |  11 ++
 .../dma/dma-register/dma-peripheral.hpp       |   7 +
 .../dma/dma-register/dma-register.hpp         |   8 ++
 library/stm32f072xb/dma/dma.cpp               |  15 ++
 library/stm32f072xb/dma/dma.hpp               |  28 ++++
 .../gpio/abstract-gpio/abstract-gpio-init.hpp |   4 +-
 library/stm32f072xb/meson.build               |   8 +-
 .../uart/abstract-uart/abstract-uart.cpp      |   8 ++
 .../uart/abstract-uart/abstract-uart.hpp      |   4 +-
 samples/meson.build                           |   1 +
 samples/stm32f072xb/dma-uart/main.cpp         |  65 +++++++++
 23 files changed, 402 insertions(+), 10 deletions(-)
 create mode 100644 library/stm32f072xb/dma/abstract-dma/abstract-dma-init.hpp
 create mode 100644 library/stm32f072xb/dma/abstract-dma/abstract-dma.cpp
 create mode 100644 library/stm32f072xb/dma/abstract-dma/abstract-dma.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-channel.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-circular-mode.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-direction.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-memory-increment.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-memory-size.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-peripheral-increment.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-peripheral-size.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-peripheral.hpp
 create mode 100644 library/stm32f072xb/dma/dma-register/dma-register.hpp
 create mode 100644 library/stm32f072xb/dma/dma.cpp
 create mode 100644 library/stm32f072xb/dma/dma.hpp
 create mode 100644 samples/stm32f072xb/dma-uart/main.cpp

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index b42b897..c64ce34 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -2,12 +2,12 @@
 	"name": "Machine PM - Embedded Development",
 	"dockerFile": "./Dockerfile",
 	"settings": {
-		"terminal.integrated.shell.linux": "/bin/zsh"
+		"terminal.integrated.defaultProfile.linux": "zsh",
 	},
 	"extensions": [
 		"asabil.meson",
-		"marus25.cortex-debug",
-		"ms-vscode.cpptools",
+		"marus25.cortex-debug@0.4.4",
+		"ms-vscode.cpptools@1.5.1",
 		"xaver.clang-format",
 		"visualstudioexptteam.vscodeintellicode",
 		"mhutchie.git-graph",
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 919f29b..2ae10e0 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -45,6 +45,10 @@
 				{
 					"label": "Extended Interrupt Sample",
 					"value": "extended-interrupt"
+				},
+				{
+					"label": "Dma Uart",
+					"value": "dma-uart"
 				}
 			]
 		}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 1a0d568..6b208bf 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,7 +1,6 @@
 {
 	"editor.formatOnSave": true,
 	"task.problemMatchers.neverPrompt": true,
-	"task.autoDetect": "off",
 	"files.autoSave": "onFocusChange",
 	"mesonbuild.buildFolder": "build",
 	"search.exclude": {
@@ -9,5 +8,5 @@
 	},
 	"[cpp]": {
 		"editor.defaultFormatter": "xaver.clang-format"
-	},
+	}
 }
diff --git a/library/stm32f072xb/dma/abstract-dma/abstract-dma-init.hpp b/library/stm32f072xb/dma/abstract-dma/abstract-dma-init.hpp
new file mode 100644
index 0000000..22a65d0
--- /dev/null
+++ b/library/stm32f072xb/dma/abstract-dma/abstract-dma-init.hpp
@@ -0,0 +1,24 @@
+#ifndef ABSTRACT_DMA_INIT_H
+#define ABSTRACT_DMA_INIT_H
+
+#include <variant>
+
+#include "dma-register.hpp"
+
+namespace stm32f072xb {
+
+struct AbstractDmaInit {
+	const DmaPeripheral peripheral;
+	const DmaDirection direction;
+	const DmaCircularMode circularMode;
+	const DmaMemoryIncrement memoryIncrement;
+	const DmaMemorySize memorySize;
+	const DmaPeripheralIncrement peripheralIncrement;
+	const DmaPeripheralSize peripheralSize;
+	const uint8_t* buffer;
+	const uint16_t bufferSize;
+};
+
+}  // namespace stm32f072xb
+
+#endif
diff --git a/library/stm32f072xb/dma/abstract-dma/abstract-dma.cpp b/library/stm32f072xb/dma/abstract-dma/abstract-dma.cpp
new file mode 100644
index 0000000..ad0f160
--- /dev/null
+++ b/library/stm32f072xb/dma/abstract-dma/abstract-dma.cpp
@@ -0,0 +1,131 @@
+#include "abstract-dma.hpp"
+
+using namespace stm32f072xb;
+
+AbstractDma::AbstractDma(DMA_Channel_TypeDef* dmaChannel, AbstractDmaInit& dmaInit)
+    : _dmaChannel(dmaChannel), _dmaInit(dmaInit) {
+	if (!READ_BIT(RCC->AHBENR, RCC_AHBENR_DMAEN)) {
+		SET_BIT(RCC->AHBENR, RCC_AHBENR_DMAEN);
+	}
+	setupRegister();
+}
+
+AbstractDma::~AbstractDma() {
+	stop();
+}
+
+void AbstractDma::start() {
+	if (READ_BIT(_dmaChannel->CCR, DMA_CCR_EN)) {
+		stop();
+		setNumberOfDataTransfer(_dmaInit.bufferSize);
+	}
+	SET_BIT(_dmaChannel->CCR, DMA_CCR_EN);
+}
+
+void AbstractDma::stop() {
+	CLEAR_BIT(_dmaChannel->CCR, DMA_CCR_EN);
+}
+
+void AbstractDma::setupRegister() {
+	WRITE_REG(_dmaChannel->CCR, 0);
+	setPeripheral(_dmaInit.peripheral);
+	setMemory(_dmaInit.buffer);
+	setNumberOfDataTransfer(_dmaInit.bufferSize);
+	setDirection(_dmaInit.direction);
+	setCircularMode(_dmaInit.circularMode);
+	setMemoryIncrement(_dmaInit.memoryIncrement);
+	setMemorySize(_dmaInit.memorySize);
+	setPeripheralIncrement(_dmaInit.peripheralIncrement);
+	setPeripheralSize(_dmaInit.peripheralSize);
+}
+
+void AbstractDma::setPeripheral(DmaPeripheral peripheral) {
+	switch (peripheral) {
+		case DmaPeripheral::USART2_RX:
+			WRITE_REG(_dmaChannel->CPAR, (uint32_t)&USART2->RDR);
+			break;
+		case DmaPeripheral::USART2_TX:
+			WRITE_REG(_dmaChannel->CPAR, (uint32_t)&USART2->TDR);
+			break;
+	}
+}
+
+void AbstractDma::setMemory(const uint8_t* buffer) {
+	WRITE_REG(_dmaChannel->CMAR, (uint32_t)(buffer));
+}
+
+void AbstractDma::setNumberOfDataTransfer(uint16_t numberOfDataTransfer) {
+	WRITE_REG(_dmaChannel->CNDTR, numberOfDataTransfer);
+}
+
+void AbstractDma::setDirection(DmaDirection direction) {
+	switch (direction) {
+		case DmaDirection::MEMORY_TO_PERIPHERAL:
+			SET_BIT(_dmaChannel->CCR, DMA_CCR_DIR);
+			break;
+		case DmaDirection::PERIPHERAL_TO_MEMORY:
+			CLEAR_BIT(_dmaChannel->CCR, DMA_CCR_DIR);
+			break;
+	}
+}
+
+void AbstractDma::setCircularMode(DmaCircularMode circularMode) {
+	switch (circularMode) {
+		case DmaCircularMode::ENABLE:
+			SET_BIT(_dmaChannel->CCR, DMA_CCR_CIRC);
+			break;
+		case DmaCircularMode::DISABLE:
+			CLEAR_BIT(_dmaChannel->CCR, DMA_CCR_CIRC);
+			break;
+	}
+}
+
+void AbstractDma::setMemoryIncrement(DmaMemoryIncrement memoryIncrement) {
+	switch (memoryIncrement) {
+		case DmaMemoryIncrement::ENABLE:
+			SET_BIT(_dmaChannel->CCR, DMA_CCR_MINC);
+			break;
+		case DmaMemoryIncrement::DISABLE:
+			CLEAR_BIT(_dmaChannel->CCR, DMA_CCR_MINC);
+			break;
+	}
+}
+
+void AbstractDma::setMemorySize(DmaMemorySize memorySize) {
+	switch (memorySize) {
+		case DmaMemorySize::BYTE:
+			CLEAR_BIT(_dmaChannel->CCR, DMA_CCR_MSIZE);
+			break;
+		case DmaMemorySize::HALF_WORD:
+			MODIFY_REG(_dmaChannel->CCR, DMA_CCR_PSIZE, DMA_CCR_MSIZE_0);
+			break;
+		case DmaMemorySize::WORD:
+			MODIFY_REG(_dmaChannel->CCR, DMA_CCR_PSIZE, DMA_CCR_MSIZE_1);
+			break;
+	}
+}
+
+void AbstractDma::setPeripheralIncrement(DmaPeripheralIncrement peripheralIncrement) {
+	switch (peripheralIncrement) {
+		case DmaPeripheralIncrement::ENABLE:
+			SET_BIT(_dmaChannel->CCR, DMA_CCR_PINC);
+			break;
+		case DmaPeripheralIncrement::DISABLE:
+			CLEAR_BIT(_dmaChannel->CCR, DMA_CCR_PINC);
+			break;
+	}
+}
+
+void AbstractDma::setPeripheralSize(DmaPeripheralSize peripheralSize) {
+	switch (peripheralSize) {
+		case DmaPeripheralSize::BYTE:
+			CLEAR_BIT(_dmaChannel->CCR, DMA_CCR_PSIZE);
+			break;
+		case DmaPeripheralSize::HALF_WORD:
+			MODIFY_REG(_dmaChannel->CCR, DMA_CCR_PSIZE, DMA_CCR_PSIZE_0);
+			break;
+		case DmaPeripheralSize::WORD:
+			MODIFY_REG(_dmaChannel->CCR, DMA_CCR_PSIZE, DMA_CCR_PSIZE_1);
+			break;
+	}
+}
diff --git a/library/stm32f072xb/dma/abstract-dma/abstract-dma.hpp b/library/stm32f072xb/dma/abstract-dma/abstract-dma.hpp
new file mode 100644
index 0000000..1a60dd5
--- /dev/null
+++ b/library/stm32f072xb/dma/abstract-dma/abstract-dma.hpp
@@ -0,0 +1,36 @@
+#ifndef ABSTRACT_DMA_H
+#define ABSTRACT_DMA_H
+
+#include <stm32f0xx.h>
+#include "abstract-dma-init.hpp"
+
+namespace stm32f072xb {
+
+class AbstractDma {
+   public:
+	AbstractDma(DMA_Channel_TypeDef* dmaChannel, AbstractDmaInit& dmaInit);
+	~AbstractDma();
+	void start();
+	void stop();
+
+   protected:
+	void setupRegister();
+
+   private:
+	void setPeripheral(DmaPeripheral peripheral);
+	void setMemory(const uint8_t* buffer);
+	void setNumberOfDataTransfer(uint16_t numberOfDataTransfer);
+	void setDirection(DmaDirection direction);
+	void setCircularMode(DmaCircularMode circularMode);
+	void setMemoryIncrement(DmaMemoryIncrement memoryIncrement);
+	void setMemorySize(DmaMemorySize memorySize);
+	void setPeripheralIncrement(DmaPeripheralIncrement peripheralIncrement);
+	void setPeripheralSize(DmaPeripheralSize peripheralSize);
+
+	DMA_Channel_TypeDef* _dmaChannel;
+	AbstractDmaInit& _dmaInit;
+};
+
+}  // namespace stm32f072xb
+
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-channel.hpp b/library/stm32f072xb/dma/dma-register/dma-channel.hpp
new file mode 100644
index 0000000..0ff56fa
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-channel.hpp
@@ -0,0 +1,7 @@
+#ifndef DMA_CHANNEL_H
+#define DMA_CHANNEL_H
+
+namespace stm32f072xb {
+enum class DmaChannel { CHANNEL1, CHANNEL2, CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6, CHANNEL7 };
+}
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-circular-mode.hpp b/library/stm32f072xb/dma/dma-register/dma-circular-mode.hpp
new file mode 100644
index 0000000..dcbd3a7
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-circular-mode.hpp
@@ -0,0 +1,7 @@
+#ifndef DMA_CIRCULAR_MODE_H
+#define DMA_CIRCULAR_MODE_H
+
+namespace stm32f072xb {
+enum class DmaCircularMode { DISABLE, ENABLE };
+}
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-direction.hpp b/library/stm32f072xb/dma/dma-register/dma-direction.hpp
new file mode 100644
index 0000000..aa64be8
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-direction.hpp
@@ -0,0 +1,9 @@
+#ifndef DMA_DIRECTION_H
+#define DMA_DIRECTION_H
+
+namespace stm32f072xb {
+enum class DmaDirection { MEMORY_TO_PERIPHERAL, PERIPHERAL_TO_MEMORY };
+
+}
+
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-memory-increment.hpp b/library/stm32f072xb/dma/dma-register/dma-memory-increment.hpp
new file mode 100644
index 0000000..fee7f1c
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-memory-increment.hpp
@@ -0,0 +1,10 @@
+#ifndef DMA_MEMORY_INCREMENT_H
+#define DMA_MEMORY_INCREMENT_H
+
+namespace stm32f072xb {
+enum class DmaMemoryIncrement {
+	DISABLE,
+	ENABLE,
+};
+}
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-memory-size.hpp b/library/stm32f072xb/dma/dma-register/dma-memory-size.hpp
new file mode 100644
index 0000000..8ed07e2
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-memory-size.hpp
@@ -0,0 +1,7 @@
+#ifndef DMA_MEMORY_SIZE_H
+#define DMA_MEMORY_SIZE_H
+
+namespace stm32f072xb {
+enum class DmaMemorySize { BYTE, HALF_WORD, WORD };
+}
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-peripheral-increment.hpp b/library/stm32f072xb/dma/dma-register/dma-peripheral-increment.hpp
new file mode 100644
index 0000000..66c0401
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-peripheral-increment.hpp
@@ -0,0 +1,9 @@
+#ifndef DMA_PERIPHERAL_INCREMENT_H
+#define DMA_PERIPHERAL_INCREMENT_H
+namespace stm32f072xb {
+enum class DmaPeripheralIncrement {
+	DISABLE,
+	ENABLE,
+};
+}
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-peripheral-size.hpp b/library/stm32f072xb/dma/dma-register/dma-peripheral-size.hpp
new file mode 100644
index 0000000..00539a5
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-peripheral-size.hpp
@@ -0,0 +1,11 @@
+#ifndef DMA_PERIPHERAL_SIZE_H
+#define DMA_PERIPHERAL_SIZE_H
+
+namespace stm32f072xb {
+enum class DmaPeripheralSize {
+	BYTE,
+	HALF_WORD,
+	WORD,
+};
+}
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-peripheral.hpp b/library/stm32f072xb/dma/dma-register/dma-peripheral.hpp
new file mode 100644
index 0000000..059067d
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-peripheral.hpp
@@ -0,0 +1,7 @@
+#ifndef DMA_PERIPHERAL_H
+#define DMA_PERIPHERAL_H
+
+namespace stm32f072xb {
+enum class DmaPeripheral { USART2_RX, USART2_TX };
+}
+#endif
diff --git a/library/stm32f072xb/dma/dma-register/dma-register.hpp b/library/stm32f072xb/dma/dma-register/dma-register.hpp
new file mode 100644
index 0000000..c332794
--- /dev/null
+++ b/library/stm32f072xb/dma/dma-register/dma-register.hpp
@@ -0,0 +1,8 @@
+#include "dma-channel.hpp"
+#include "dma-circular-mode.hpp"
+#include "dma-direction.hpp"
+#include "dma-memory-increment.hpp"
+#include "dma-memory-size.hpp"
+#include "dma-peripheral-increment.hpp"
+#include "dma-peripheral-size.hpp"
+#include "dma-peripheral.hpp"
diff --git a/library/stm32f072xb/dma/dma.cpp b/library/stm32f072xb/dma/dma.cpp
new file mode 100644
index 0000000..8c8b5ed
--- /dev/null
+++ b/library/stm32f072xb/dma/dma.cpp
@@ -0,0 +1,15 @@
+#include "dma.hpp"
+
+using namespace stm32f072xb;
+
+Dma<DmaChannel::CHANNEL4, DmaPeripheral::USART2_TX>::Dma(AbstractDmaInit& dmaInit,
+                                                         Uart<UartRegister::UART2, Port::A>& uart)
+    : AbstractDma(DMA1_Channel4, dmaInit) {
+	uart.enableDmaTransmission();
+}
+
+Dma<DmaChannel::CHANNEL5, DmaPeripheral::USART2_RX>::Dma(AbstractDmaInit& dmaInit,
+                                                         Uart<UartRegister::UART2, Port::A>& uart)
+    : AbstractDma(DMA1_Channel5, dmaInit) {
+	uart.enableDmaReception();
+}
diff --git a/library/stm32f072xb/dma/dma.hpp b/library/stm32f072xb/dma/dma.hpp
new file mode 100644
index 0000000..42ab955
--- /dev/null
+++ b/library/stm32f072xb/dma/dma.hpp
@@ -0,0 +1,28 @@
+
+#ifndef DMA_H
+#define DMA_H
+
+#include "abstract-dma.hpp"
+#include "dma-register.hpp"
+#include "stm32f072xb.h"
+#include "uart.hpp"
+
+namespace stm32f072xb {
+
+template <DmaChannel T, DmaPeripheral P>
+class Dma {};
+
+template <>
+class Dma<DmaChannel::CHANNEL4, DmaPeripheral::USART2_TX> : public AbstractDma {
+   public:
+	Dma(AbstractDmaInit& dmaInit, Uart<UartRegister::UART2, Port::A>& uart);
+};
+
+template <>
+class Dma<DmaChannel::CHANNEL5, DmaPeripheral::USART2_RX> : public AbstractDma {
+   public:
+	Dma(AbstractDmaInit& dmaInit, Uart<UartRegister::UART2, Port::A>& uart);
+};
+
+}  // namespace stm32f072xb
+#endif
diff --git a/library/stm32f072xb/gpio/abstract-gpio/abstract-gpio-init.hpp b/library/stm32f072xb/gpio/abstract-gpio/abstract-gpio-init.hpp
index 01e45c2..9df7217 100644
--- a/library/stm32f072xb/gpio/abstract-gpio/abstract-gpio-init.hpp
+++ b/library/stm32f072xb/gpio/abstract-gpio/abstract-gpio-init.hpp
@@ -1,8 +1,8 @@
-#include "gpio-register.hpp"
-
 #ifndef ABSTRACT_GPIO_INIT_H
 #define ABSTRACT_GPIO_INIT_H
 
+#include "gpio-register.hpp"
+
 namespace stm32f072xb {
 
 struct AbstractGpioInit {
diff --git a/library/stm32f072xb/meson.build b/library/stm32f072xb/meson.build
index 783422d..860bfb0 100644
--- a/library/stm32f072xb/meson.build
+++ b/library/stm32f072xb/meson.build
@@ -4,18 +4,22 @@ stm32f072xb_modules		= []
 stm32f072xb_includes	= []
 stm32f072xb_sources 	= []
 
-stm32f072xb_modules += ['gpio/abstract-gpio']
 stm32f072xb_modules += ['gpio']
+stm32f072xb_modules += ['gpio/abstract-gpio']
 stm32f072xb_modules += ['gpio/gpio-register']
 stm32f072xb_modules += ['gpio/output-gpio']
 stm32f072xb_modules += ['gpio/input-gpio']
 stm32f072xb_modules += ['gpio/alternate-gpio']
 stm32f072xb_modules += ['gpio/uart-gpio']
 
-stm32f072xb_modules += ['uart/abstract-uart']
 stm32f072xb_modules += ['uart']
+stm32f072xb_modules += ['uart/abstract-uart']
 stm32f072xb_modules += ['uart/uart-register']
 
+stm32f072xb_modules += ['dma']
+stm32f072xb_modules += ['dma/abstract-dma']
+stm32f072xb_modules += ['dma/dma-register']
+
 stm32f072xb_modules += ['basic-timer']
 
 fs = import('fs')
diff --git a/library/stm32f072xb/uart/abstract-uart/abstract-uart.cpp b/library/stm32f072xb/uart/abstract-uart/abstract-uart.cpp
index bfa38aa..5c65adb 100644
--- a/library/stm32f072xb/uart/abstract-uart/abstract-uart.cpp
+++ b/library/stm32f072xb/uart/abstract-uart/abstract-uart.cpp
@@ -89,3 +89,11 @@ void AbstractUart::enableTransmitter() {
 void AbstractUart::enableReception() {
 	SET_BIT(_uart->CR1, USART_CR1_RE);  // enable Reception (p.734)
 }
+
+void AbstractUart::enableDmaReception() {
+	SET_BIT(USART2->CR3, USART_CR3_DMAR);
+}
+
+void AbstractUart::enableDmaTransmission() {
+	SET_BIT(USART2->CR3, USART_CR3_DMAT);
+}
diff --git a/library/stm32f072xb/uart/abstract-uart/abstract-uart.hpp b/library/stm32f072xb/uart/abstract-uart/abstract-uart.hpp
index bc50990..4ea79ca 100644
--- a/library/stm32f072xb/uart/abstract-uart/abstract-uart.hpp
+++ b/library/stm32f072xb/uart/abstract-uart/abstract-uart.hpp
@@ -8,12 +8,14 @@ namespace stm32f072xb {
 class AbstractUart {
    public:
 	AbstractUart(USART_TypeDef* uart, AbstractUartInit uartInit);
+	~AbstractUart();
 	USART_TypeDef* getUart() { return _uart; };
 
 	char readWord();
 	void writeWord(uint16_t word);
 
-	~AbstractUart();
+	void enableDmaReception();
+	void enableDmaTransmission();
 
    protected:
 	void setupRegister();
diff --git a/samples/meson.build b/samples/meson.build
index 1ef686b..dc471f6 100644
--- a/samples/meson.build
+++ b/samples/meson.build
@@ -7,6 +7,7 @@ samples += ['gpio']
 samples += ['interruption']
 samples += ['pwm']
 samples += ['extended-interrupt']
+samples += ['dma-uart']
 # samples += ['timeout']
 samples += ['uart']
 
diff --git a/samples/stm32f072xb/dma-uart/main.cpp b/samples/stm32f072xb/dma-uart/main.cpp
new file mode 100644
index 0000000..88978e1
--- /dev/null
+++ b/samples/stm32f072xb/dma-uart/main.cpp
@@ -0,0 +1,65 @@
+#include <stm32f072xb.h>
+#include <dma.hpp>
+#include <gpio.hpp>
+#include <uart-gpio.hpp>
+#include <uart.hpp>
+
+using namespace stm32f072xb;
+
+AbstractUartInit uartInit = {WordLength::HEIGHT_BITS, StopBits::ONE_BIT, 115200};
+UartGpio<UartRegister::UART2, UartGpioType::RX, Port::A> rxGpio;
+UartGpio<UartRegister::UART2, UartGpioType::TX, Port::A> txGpio;
+
+Uart<UartRegister::UART2, Port::A> uartTxRx(uartInit, txGpio, rxGpio);
+
+constexpr uint8_t bufferSize = 5;
+uint8_t buffer[bufferSize] = {0};
+
+AbstractDmaInit dmaUartRxInit = {DmaPeripheral::USART2_RX,
+                                 DmaDirection::PERIPHERAL_TO_MEMORY,
+                                 DmaCircularMode::ENABLE,
+                                 DmaMemoryIncrement::ENABLE,
+                                 DmaMemorySize::BYTE,
+                                 DmaPeripheralIncrement::DISABLE,
+                                 DmaPeripheralSize::BYTE,
+                                 buffer,
+                                 bufferSize};
+Dma<DmaChannel::CHANNEL5, DmaPeripheral::USART2_RX> dmaUartRx(dmaUartRxInit, uartTxRx);
+AbstractDmaInit dmaUartTxInit = {DmaPeripheral::USART2_TX,
+                                 DmaDirection::MEMORY_TO_PERIPHERAL,
+                                 DmaCircularMode::DISABLE,
+                                 DmaMemoryIncrement::ENABLE,
+                                 DmaMemorySize::BYTE,
+                                 DmaPeripheralIncrement::DISABLE,
+                                 DmaPeripheralSize::BYTE,
+                                 buffer,
+                                 bufferSize};
+
+Dma<DmaChannel::CHANNEL4, DmaPeripheral::USART2_TX> dmaUartTx(dmaUartTxInit, uartTxRx);
+
+extern "C" void DMA1_Channel4_5_6_7_IRQHandler() {
+	if (READ_BIT(DMA1->ISR, DMA_ISR_TEIF6)) {  // DMA Error occured
+		SET_BIT(DMA1->IFCR, DMA_IFCR_CTEIF6);  // Clear interrupt register
+	}
+
+	if (READ_BIT(DMA1->ISR, DMA_ISR_TCIF5)) {
+		SET_BIT(DMA1->IFCR, DMA_IFCR_CTCIF5);
+		dmaUartTx.start();
+	}
+}
+
+void enableDmaChannel4_5_6_7Irq();
+
+int main() {
+	SET_BIT(DMA1_Channel5->CCR, DMA_CCR_TCIE);
+	enableDmaChannel4_5_6_7Irq();
+	dmaUartRx.start();
+
+	while (true) {
+	}
+}
+
+void enableDmaChannel4_5_6_7Irq() {
+	NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);
+	NVIC_SetPriority(DMA1_Channel4_5_6_7_IRQn, 0);
+}
-- 
GitLab