diff --git a/zephyr/modules/owntech_adc_driver/zephyr/CMakeLists.txt b/zephyr/modules/owntech_adc_driver/zephyr/CMakeLists.txt
index 114e0ad21debb5a3c917211a7075d0e4975f4de4..79eae10d75ed65195b9dddce0b2ba1ea8da5cfc2 100644
--- a/zephyr/modules/owntech_adc_driver/zephyr/CMakeLists.txt
+++ b/zephyr/modules/owntech_adc_driver/zephyr/CMakeLists.txt
@@ -7,9 +7,7 @@ if(CONFIG_OWNTECH_ADC_DRIVER)
 
   # Select source files to be compiled
   zephyr_library_sources(
-    ./src/adc_channels.c
     ./src/adc_core.c
-    ./src/adc_helper.c
     ./public_api/adc.c
     )
 endif()
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.c b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.c
index 183398cc56cfa7b6814affabf26bf807dbac03a3..f8deddda5aed677ceaf031d5b5edbfadf89ca9ee 100644
--- a/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.c
+++ b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2022 LAAS-CNRS
+ * Copyright (c) 2021-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -18,7 +18,7 @@
  */
 
 /**
- * @date   2022
+ * @date   2023
  *
  * @author Clément Foucher <clement.foucher@laas.fr>
  */
@@ -28,7 +28,6 @@
 #include <stm32_ll_adc.h>
 
 // Current module private functions
-#include "../src/adc_channels.h"
 #include "../src/adc_core.h"
 
 // Current file header
@@ -39,153 +38,203 @@
 // Constants
 
 #define NUMBER_OF_ADCS 4
+#define NUMBER_OF_CHANNELS_PER_ADC 16
 
 
 /////
 // Local variables
 
-static uint32_t adc_trigger_sources[NUMBER_OF_ADCS] = {0};
-static uint32_t adc_discontinuous_mode[NUMBER_OF_ADCS] = {0};
+static adc_ev_src_t adc_trigger_sources[NUMBER_OF_ADCS]    = {software};
+static uint32_t     adc_discontinuous_mode[NUMBER_OF_ADCS] = {0};
+static uint32_t     enabled_channels_count[NUMBER_OF_ADCS] = {0};
+static bool         enable_dma[NUMBER_OF_ADCS]             = {false};
+
+static uint32_t     enabled_channels[NUMBER_OF_ADCS][NUMBER_OF_CHANNELS_PER_ADC] = {0};
 
 
 /////
 // Public API
 
-void adc_init()
+void adc_configure_trigger_source(uint8_t adc_number, adc_ev_src_t trigger_source)
 {
-	adc_core_init();
-	adc_channels_init();
+	if ( (adc_number == 0) || (adc_number > NUMBER_OF_ADCS) )
+		return;
+
+	adc_trigger_sources[adc_number-1] = trigger_source;
+
 }
 
-void adc_set_dual_mode(uint8_t dual_mode)
+void adc_configure_discontinuous_mode(uint8_t adc_number, uint32_t discontinuous_count)
 {
-	adc_core_set_dual_mode(dual_mode);
+	if ( (adc_number == 0) || (adc_number > NUMBER_OF_ADCS) )
+		return;
+
+	adc_discontinuous_mode[adc_number-1] = discontinuous_count;
 }
 
-void adc_configure_trigger_source(uint8_t adc_number, adc_ev_src_t trigger_source)
+void adc_add_channel(uint8_t adc_number, uint8_t channel)
 {
-	/////
-	// Convert to LL constants
+	if ( (adc_number == 0) || (adc_number > NUMBER_OF_ADCS) )
+		return;
 
-	uint32_t trig;
-	switch (trigger_source)
-	{
-	case hrtim_ev1:
-		trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG1;
-		break;
-	case hrtim_ev2:
-		trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG2;
-		break;
-	case hrtim_ev3:
-		trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG3;
-		break;
-	case hrtim_ev4:
-		trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG4;
-		break;
-	case software:
-	default:
-		trig = LL_ADC_REG_TRIG_SOFTWARE;
-		break;
-	}
+	uint8_t adc_index = adc_number-1;
 
-	// Only store configuration: it must be applied after ADC enable
-	if ( (adc_number > 0) && (adc_number <= NUMBER_OF_ADCS) )
-	{
-		adc_trigger_sources[adc_number-1] = trig;
-	}
+	if (enabled_channels_count[adc_index] == NUMBER_OF_CHANNELS_PER_ADC)
+		return;
+
+	enabled_channels[adc_index][enabled_channels_count[adc_index]] = channel;
+	enabled_channels_count[adc_index]++;
 }
 
-void adc_configure_discontinuous_mode(uint8_t adc_number, uint32_t dicontinuous_count)
+void adc_remove_channel(uint8_t adc_number, uint8_t channel)
 {
-	// Only store configuration: it must be applied after ADC enable
-	if ( (adc_number > 0) && (adc_number <= NUMBER_OF_ADCS) )
+	if ( (adc_number == 0) || (adc_number > NUMBER_OF_ADCS) )
+		return;
+
+	uint8_t adc_index = adc_number-1;
+
+	for (int i = 0 ; i < NUMBER_OF_CHANNELS_PER_ADC ; i++)
 	{
-		adc_discontinuous_mode[adc_number-1] = dicontinuous_count;
+		if (enabled_channels[adc_index][i] == channel)
+		{
+			for (int j = i ; j < NUMBER_OF_CHANNELS_PER_ADC-1 ; j++)
+			{
+				enabled_channels[adc_index][i] = enabled_channels[adc_index][i+1];
+			}
+			enabled_channels[adc_index][NUMBER_OF_CHANNELS_PER_ADC-1] = 0;
+
+			enabled_channels_count[adc_index]--;
+
+			break;
+		}
 	}
 }
 
-int8_t adc_configure_adc_channels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count)
+void adc_configure_use_dma(uint8_t adc_number, bool use_dma)
 {
-	return adc_channnels_configure_adc_channels(adc_number, channel_list, channel_count);
+	if ( (adc_number == 0) || (adc_number > NUMBER_OF_ADCS) )
+		return;
+
+	enable_dma[adc_number-1] = use_dma;
 }
 
 void adc_start()
 {
-	uint8_t enabled_channels_count[NUMBER_OF_ADCS];
+	/////
+	// Initialize ADCs
 
-	for (uint8_t i = 0 ; i < NUMBER_OF_ADCS ; i++)
-	{
-		enabled_channels_count[i] = adc_channels_get_enabled_channels_count(i+1);
-	}
+	adc_core_init();
+
+	/////
+	// Pre-enable configuration
+
+	// Nothing here for now.
+
+	// If some channels have to be set as differential,
+	// or ADCs have to be set as dual mode,
+	// this shoud be done here.
 
 	/////
 	// Enable ADCs
-	for (uint8_t i = 0 ; i < NUMBER_OF_ADCS ; i++)
+
+	for (int i = 1 ; i <= NUMBER_OF_ADCS ; i++)
 	{
-		if (enabled_channels_count[i] > 0)
-		{
-			adc_core_enable(i+1);
-		}
+		adc_core_enable(i);
 	}
 
 	/////
-	// Configure ADCs channels
-	for (uint8_t i = 0 ; i < NUMBER_OF_ADCS ; i++)
+	// Post-enable configuration
+
+	for (uint8_t adc_num = 1 ; adc_num <= NUMBER_OF_ADCS ; adc_num++)
 	{
-		if (enabled_channels_count[i] > 0)
+		uint8_t adc_index = adc_num-1;
+		if (enabled_channels_count[adc_index] > 0)
 		{
-			adc_channels_configure(i+1);
+			for (int channel_index = 0 ; channel_index < NUMBER_OF_CHANNELS_PER_ADC ; channel_index++)
+			{
+				if (enabled_channels[adc_index][channel_index] == 0)
+					break;
+
+				adc_core_configure_channel(adc_num, enabled_channels[adc_index][channel_index], channel_index+1);
+			}
 		}
 	}
 
-	/////
-	// Configure ADCs
-	for (uint8_t i = 0 ; i < NUMBER_OF_ADCS ; i++)
+	for (uint8_t adc_num = 1 ; adc_num <= NUMBER_OF_ADCS ; adc_num++)
 	{
-		if (enabled_channels_count[i] > 0)
+		uint8_t adc_index = adc_num-1;
+		if (enabled_channels_count[adc_index] > 0)
 		{
-			adc_core_configure_dma_mode(i+1);
+			adc_core_configure_dma_mode(adc_num, enable_dma[adc_index]);
 		}
 	}
 
-	for (uint8_t i = 0 ; i < NUMBER_OF_ADCS ; i++)
+	for (uint8_t adc_num = 1 ; adc_num <= NUMBER_OF_ADCS ; adc_num++)
 	{
-		if ( (enabled_channels_count[i] > 0) && (adc_discontinuous_mode[i] != 0) )
+		uint8_t adc_index = adc_num-1;
+		if (enabled_channels_count[adc_index] > 0)
 		{
-			adc_core_configure_discontinuous_mode(i+1, adc_discontinuous_mode[i]);
+			adc_core_configure_discontinuous_mode(adc_num, adc_discontinuous_mode[adc_index]);
 		}
 	}
 
-	for (uint8_t i = 0 ; i < NUMBER_OF_ADCS ; i++)
+	for (uint8_t adc_num = 1 ; adc_num <= NUMBER_OF_ADCS ; adc_num++)
 	{
-		if ( (enabled_channels_count[i] > 0) && (adc_trigger_sources[i] != 0) )
+		uint8_t adc_index = adc_num-1;
+		if (enabled_channels_count[adc_index] > 0)
 		{
-			adc_core_configure_trigger_source(i+1, LL_ADC_REG_TRIG_EXT_RISING, adc_trigger_sources[i]);
+			// Convert to LL constants
+			uint32_t trig;
+			switch (adc_trigger_sources[adc_index])
+			{
+			case hrtim_ev1:
+				trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG1;
+				break;
+			case hrtim_ev2:
+				trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG2;
+				break;
+			case hrtim_ev3:
+				trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG3;
+				break;
+			case hrtim_ev4:
+				trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG4;
+				break;
+			case software:
+			default:
+				trig = LL_ADC_REG_TRIG_SOFTWARE;
+				break;
+			}
+
+			adc_core_configure_trigger_source(adc_num, LL_ADC_REG_TRIG_EXT_RISING, trig);
 		}
 	}
 
 	/////
-	// Finally, start ADCs
-	for (uint8_t i = 0 ; i < NUMBER_OF_ADCS ; i++)
+	// Start ADCs
+
+	for (uint8_t adc_num = 1 ; adc_num <= NUMBER_OF_ADCS ; adc_num++)
 	{
-		if (enabled_channels_count[i] > 0)
+		uint8_t adc_index = adc_num-1;
+		if (enabled_channels_count[adc_index] > 0)
 		{
-			adc_core_start(i+1);
+			adc_core_start(adc_num, enabled_channels_count[adc_index]);
 		}
 	}
 }
 
-const char* adc_get_channel_name(uint8_t adc_number, uint8_t channel_rank)
+void adc_stop()
 {
-	return adc_channels_get_channel_name(adc_number, channel_rank);
+	for (uint8_t adc_num = 1 ; adc_num <= NUMBER_OF_ADCS ; adc_num++)
+	{
+		uint8_t adc_index = adc_num-1;
+		if (enabled_channels_count[adc_index] > 0)
+		{
+			adc_core_stop(adc_num);
+		}
+	}
 }
 
-uint8_t adc_get_enabled_channels_count(uint8_t adc_num)
+void adc_trigger_software_conversion(uint8_t adc_number)
 {
-	return adc_channels_get_enabled_channels_count(adc_num);
+	adc_core_start(adc_number, 1);
 }
-
-void adc_software_trigger_conversion(uint8_t adc_number)
-{
-	adc_core_start(adc_number);
-}
\ No newline at end of file
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.h b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.h
index 8f77684e33ae4ece20ddb72fbdb2bd9dfaf93e4a..fe0cfeb4aa3dfcc8ca98cf9d93aef9b72ed3caa3 100644
--- a/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.h
+++ b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.h
@@ -40,6 +40,7 @@
 
 // Stdlib
 #include <stdint.h>
+#include <stdbool.h>
 
 
 #ifdef __cplusplus
@@ -52,11 +53,11 @@ extern "C" {
 
 typedef enum
 {
-	hrtim_ev1,
-	hrtim_ev2,
-	hrtim_ev3,
-	hrtim_ev4,
-	software
+	software  = 0,
+	hrtim_ev1 = 1,
+	hrtim_ev2 = 2,
+	hrtim_ev3 = 3,
+	hrtim_ev4 = 4,
 } adc_ev_src_t;
 
 
@@ -64,24 +65,11 @@ typedef enum
 // Public API
 
 /**
- * @brief Initializes the ADCs. It must be
- * called *before* any configuration is made.
- */
-void adc_init();
-
-/**
- * ADC dual mode: enables ADC 1/ADC 2 synchronization.
- * When ADC 1 acquisition is triggered, it simultaneously
- * triggers an acquisition on ADC 2.
+ * @brief Registers the triger source for an ADC.
  *
- * @param dual_mode true to enable dual moode, false to
- *        disable it. false by default.
- */
-void adc_set_dual_mode(uint8_t dual_mode);
-
-/**
- * Registers the triger source for an ADC.
- * It will be applied when ADC is started.
+ *        This will only be applied when ADC is started.
+ *        If ADC is already started, it must be stopped
+ *        then started again.
  *
  * @param adc_number Number of the ADC to configure.
  * @param triggger_source Source of the trigger.
@@ -89,40 +77,62 @@ void adc_set_dual_mode(uint8_t dual_mode);
 void adc_configure_trigger_source(uint8_t adc_number, adc_ev_src_t trigger_source);
 
 /**
- * Registers the discontinuous count for an ADC.
- * It will be applied when ADC is started.
+ * @brief Registers the discontinuous count for an ADC.
+ *
+ *        This will only be applied when ADC is started.
+ *        If ADC is already started, it must be stopped
+ *        then started again.
  *
  * @param adc_number Number of the ADC to configure.
- * @param dicontinuous_count Number of channels to acquire on each
+ * @param discontinuous_count Number of channels to acquire on each
  *        trigger event. 0 to disable discontinuous mode (default).
  */
-void adc_configure_discontinuous_mode(uint8_t adc_number, uint32_t dicontinuous_count);
+void adc_configure_discontinuous_mode(uint8_t adc_number, uint32_t discontinuous_count);
 
 /**
- * This function is used to configure the channels to be
- * enabled on a given ADC.
- *
- * @param  adc_number Number of the ADC on which channel configuration is
- *         to be done.
- * @param  channel_list List of channels to configure. This is a list of
- *         names as defined in the device tree (field `label`). The order
- *         of the names in the array sets the acquisition ranks (order in
- *         which the channels are acquired).
- * @param  channel_count Number of channels defined in `channel_list`.
- * @return 0 is everything went well,
- *         ECHANNOTFOUND if at least one of the channels
- *           is not available in the given ADC. Available channels are the
- *           ones defined in the device tree.
+ * @brief Adds a channel to the list of channels to be acquired
+ *        for an ADC.
+ *        The order in which channels are added determine
+ *        the order in which they will be acquired.
+ *
+ *        This will only be applied when ADC is started.
+ *        If ADC is already started, it must be stopped
+ *        then started again.
+ *
+ * @param adc_number Number of the ADC to configure.
+ * @param channel Number of the channel to to be acquired.
  */
-int8_t adc_configure_adc_channels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count);
+void adc_add_channel(uint8_t adc_number, uint8_t channel);
 
 /**
- * Get the number of enabled channels for an ADC.
+ * @brief Removes a channel from the list of channels
+ *        that are acquired by an ADC.
+ *        If a channel has been added multiple times,
+ *        then only the first occurence in the list
+ *        will be removed.
+ *
+ *        This will only be applied when ADC is started.
+ *        If ADC is already started, it must be stopped
+ *        then started again.
  *
- * @param  adc_num Number of the ADC.
- * @return Number of enabled channels in this ADC.
+ * @param adc_number Number of the ADC to configure.
+ * @param channel Number of the channel to to no longer be acquired.
  */
-uint8_t adc_get_enabled_channels_count(uint8_t adc_num);
+void adc_remove_channel(uint8_t adc_number, uint8_t channel);
+
+/**
+ * @brief Configures an ADC to use DMA.
+ *
+ *        This will only be applied when ADC is started.
+ *        If ADC is already started, it must be stopped
+ *        then started again.
+ *
+ * @param adc_number Number of the ADC to configure.
+ * @param use_dma Set to true to use DMA for this ADC,
+ *        false to not use it (default).
+ */
+void adc_configure_use_dma(uint8_t adc_number, bool use_dma);
+
 
 /**
  * @brief Starts all configured ADCs.
@@ -130,30 +140,20 @@ uint8_t adc_get_enabled_channels_count(uint8_t adc_num);
 void adc_start();
 
 /**
- * This function returns the name of an enabled channel.
- *
- * This function must only be called after
- * adc_configure_adc_channels has been called.
- *
- * @param  adc_number Number of the ADC.
- * @param  channel_rank Rank of the ADC channel to query.
- *         Rank ranges from 0 to (number of enabled channels)-1
- * @return Name of the channel as defined in the device tree, or
- *         NULL if channel configuration has not been made or
- *         channel_rank is over (number of enabled channels)-1.
+ * @brief Stops all configured ADCs.
  */
-const char* adc_get_channel_name(uint8_t adc_number, uint8_t channel_rank);
-
+void adc_stop();
 
 /**
- * This function triggers a single conversion in the case of a software triggered adc.
+ * @brief This function triggers a single conversion in
+ *        the case of a software triggered ADC.
  *
- * This function must only be called after
- * adc_configure_adc_channels has been called.
+ *        This function must only be called after
+ *        ADC has been started.
  *
  * @param  adc_number Number of the ADC.
  */
-void adc_software_trigger_conversion(uint8_t adc_number);
+void adc_trigger_software_conversion(uint8_t adc_number);
 
 
 #ifdef __cplusplus
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc_error_codes.h b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc_error_codes.h
deleted file mode 100644
index adaa1e170e79b0fe51b67b384658a70e4833ec76..0000000000000000000000000000000000000000
--- a/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc_error_codes.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2022 LAAS-CNRS
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License as published by
- *   the Free Software Foundation, either version 2.1 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- * SPDX-License-Identifier: LGLPV2.1
- */
-
-/**
- * @date   2022
- * @author Clément Foucher <clement.foucher@laas.fr>
- */
-
-
-#ifndef DATAACQUISITONERRORCODES_H_
-#define DATAACQUISITONERRORCODES_H_
-
-
-#define NOERROR          0
-
-#define ECHANNOTFOUND   -1
-
-
-#endif // DATAACQUISITONERRORCODES_H_
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.c b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.c
index bcc19949fd836379e52af240330799f4877b32fa..b778371d3f57142544a4aa22ff281b9d5e5db301 100644
--- a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.c
+++ b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 LAAS-CNRS
+ * Copyright (c) 2021-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -18,6 +18,8 @@
  */
 
 /**
+ * @date 2023
+ *
  * @author Clément Foucher <clement.foucher@laas.fr>
  */
 
@@ -31,8 +33,94 @@
 // STM32 LL
 #include <stm32_ll_bus.h>
 
-// Owntech API
-#include "adc_helper.h"
+
+/////
+// Constants
+
+#define NUMBER_OF_ADCS 4
+
+
+/////
+// Helper functions
+
+ADC_TypeDef* _get_adc_by_number(uint8_t adc_number)
+{
+	ADC_TypeDef* adc = NULL;
+
+	if (adc_number == 1)
+		adc = ADC1;
+	else if (adc_number == 2)
+		adc = ADC2;
+	else if (adc_number == 3)
+		adc = ADC3;
+	else if (adc_number == 4)
+		adc = ADC4;
+
+	return adc;
+}
+/**
+ * Function to convert ADC decimal rank to litteral.
+ * Sadly, there seems to be no equivalent to
+ * __LL_ADC_DECIMAL_NB_TO_CHANNEL() for ranks...
+ */
+uint32_t _adc_decimal_nb_to_rank(uint8_t decimal_rank)
+{
+	uint32_t ll_rank;
+	switch (decimal_rank)
+	{
+		case 1:
+			ll_rank = LL_ADC_REG_RANK_1;
+			break;
+		case 2:
+			ll_rank = LL_ADC_REG_RANK_2;
+			break;
+		case 3:
+			ll_rank = LL_ADC_REG_RANK_3;
+			break;
+		case 4:
+			ll_rank = LL_ADC_REG_RANK_4;
+			break;
+		case 5:
+			ll_rank = LL_ADC_REG_RANK_5;
+			break;
+		case 6:
+			ll_rank = LL_ADC_REG_RANK_6;
+			break;
+		case 7:
+			ll_rank = LL_ADC_REG_RANK_7;
+			break;
+		case 8:
+			ll_rank = LL_ADC_REG_RANK_8;
+			break;
+		case 9:
+			ll_rank = LL_ADC_REG_RANK_9;
+			break;
+		case 10:
+			ll_rank = LL_ADC_REG_RANK_10;
+			break;
+		case 11:
+			ll_rank = LL_ADC_REG_RANK_11;
+			break;
+		case 12:
+			ll_rank = LL_ADC_REG_RANK_12;
+			break;
+		case 13:
+			ll_rank = LL_ADC_REG_RANK_13;
+			break;
+		case 14:
+			ll_rank = LL_ADC_REG_RANK_14;
+			break;
+		case 15:
+			ll_rank = LL_ADC_REG_RANK_15;
+			break;
+		case 16:
+			ll_rank = LL_ADC_REG_RANK_16;
+			break;
+		default:
+			ll_rank = 0;
+	}
+	return ll_rank;
+}
 
 
 /////
@@ -81,18 +169,6 @@ static void _adc_core_calibrate(uint8_t adc_num)
 /////
 // Public API
 
-void adc_core_set_dual_mode(uint8_t dual_mode)
-{
-	if (dual_mode != 0)
-	{
-		LL_ADC_SetMultimode(ADC12_COMMON, LL_ADC_MULTI_DUAL_REG_SIMULT);
-	}
-	else
-	{
-		LL_ADC_SetMultimode(ADC12_COMMON, LL_ADC_MULTI_INDEPENDENT);
-	}
-}
-
 void adc_core_enable(uint8_t adc_num)
 {
 	ADC_TypeDef* adc = _get_adc_by_number(adc_num);
@@ -103,18 +179,36 @@ void adc_core_enable(uint8_t adc_num)
 	while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { /* Wait */ }
 }
 
-void adc_core_start(uint8_t adc_num)
+void adc_core_start(uint8_t adc_num, uint8_t sequence_length)
 {
 	ADC_TypeDef* adc = _get_adc_by_number(adc_num);
 
+	// Set regular sequence length
+	LL_ADC_REG_SetSequencerLength(adc, sequence_length - 1);
+
+	// Go
 	LL_ADC_REG_StartConversion(adc);
 }
 
-void adc_core_configure_dma_mode(uint8_t adc_num)
+void adc_core_stop(uint8_t adc_num)
 {
 	ADC_TypeDef* adc = _get_adc_by_number(adc_num);
 
-	LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
+	LL_ADC_REG_StopConversion(adc);
+}
+
+void adc_core_configure_dma_mode(uint8_t adc_num, bool use_dma)
+{
+	ADC_TypeDef* adc = _get_adc_by_number(adc_num);
+
+	if (use_dma == true)
+	{
+		LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
+	}
+	else
+	{
+		LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_NONE);
+	}
 }
 
 void adc_core_configure_trigger_source(uint8_t adc_num, uint32_t external_trigger_edge, uint32_t trigger_source)
@@ -167,26 +261,104 @@ void adc_core_configure_discontinuous_mode(uint8_t adc_num, uint32_t discontinuo
 	LL_ADC_REG_SetSequencerDiscont(adc, discontinuous_mode);
 }
 
+
+/**
+ * ADC differential channel set-up:
+ * Applies differential mode to specified channel.
+ * Refer to RM 21.4.7
+ */
+void adc_core_set_channel_differential(uint8_t adc_num, uint8_t channel, bool enable_differential)
+{
+	ADC_TypeDef* adc = _get_adc_by_number(adc_num);
+
+	uint32_t diff = (enable_differential == true) ? LL_ADC_DIFFERENTIAL_ENDED : LL_ADC_SINGLE_ENDED;
+	uint32_t ll_channel = __LL_ADC_DECIMAL_NB_TO_CHANNEL(channel);
+
+	LL_ADC_SetChannelSingleDiff(adc, ll_channel, diff);
+}
+
+void adc_core_configure_channel(uint8_t adc_num, uint8_t channel, uint8_t rank)
+{
+	ADC_TypeDef* adc = _get_adc_by_number(adc_num);
+
+	uint32_t ll_channel = __LL_ADC_DECIMAL_NB_TO_CHANNEL(channel);
+	uint32_t ll_rank = _adc_decimal_nb_to_rank(rank);
+
+	// Set regular sequence
+	LL_ADC_REG_SetSequencerRanks(adc, ll_rank, ll_channel);
+
+	// Set channels sampling time
+
+	/* 000: 2.5 ADC clock cycles
+	 * 001: 6.5 ADC clock cycles
+	 * 010: 12.5 ADC clock cycles
+	 * 011: 24.5 ADC clock cycles
+	 * 100: 47.5 ADC clock cycles
+	 * 101: 92.5 ADC clock cycles
+	 * 110: 247.5 ADC clock cycles
+	 * 111: 640.5 ADC clock cycles
+	 */
+	/* Vrefint minimum sampling time : 4us
+	 */
+	/* Vts minimum sampling time : 5us
+	 */
+	/* For 0b110:
+	 * Tadc_clk = 1 / 42.5 MHz = 23.5 ns
+	 * Tsar = 12.5 * Tadc_clk = 293.75 ns
+	 * Tsmpl = 247.5 * Tadc_clk = 5816.25 ns
+	 * Tconv = Tsmpl + Tsar = 6.11 us
+	 * -> Fconv up to 163.6 KSPS for 1 channel per ADC
+	 * Fconv up to 27.2 KSPS with the 6 channels actally
+	 * used on the ADC1
+	 *
+	 * For 0b001 (ok for voltage):
+	 * Tadc_clk = 1 / 42.5 MHz = 23.5 ns
+	 * Tsar = 12.5 * Tadc_clk = 293.75 ns
+	 * Tsmpl = 6.5 * Tadc_clk = 152.75 ns
+	 * Tconv = Tsmpl + Tsar = 446.4 ns
+	 * -> Fconv up to 2239 KSPS for 1 channel per ADC
+	 * Fconv up to 373 KSPS with the 6 channels actally
+	 * used on the ADC1
+	 *
+	 * For 0b101 (ok for current):
+	 * Tadc_clk = 1 / 42.5 MHz = 23.5 ns
+	 * Tsar = 12.5 * Tadc_clk = 293.75 ns
+	 * Tsmpl = 92.5 * Tadc_clk = 2173.75 ns
+	 * Tconv = Tsmpl + Tsar = 2.47 µs
+	 * -> Fconv up to 404 KSPS for 1 channel per ADC
+	 * Fconv up to 134 KSPS for 3 channels actally
+	 * used on each ADC
+	 */
+	LL_ADC_SetChannelSamplingTime(adc, ll_channel, LL_ADC_SAMPLINGTIME_12CYCLES_5);
+}
+
 void adc_core_init()
 {
-	// Enable ADCs clocks
-	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC12);
-	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC345);
-
-	// Wake-up ADCs
-	_adc_core_wakeup(1);
-	_adc_core_wakeup(2);
-	_adc_core_wakeup(3);
-	_adc_core_wakeup(4);
-
-	// Set common clock between ADC 1 and ADC 2
-	// Refer to RM 21.4.3 and 21.7.2
-	LL_ADC_SetCommonClock(ADC12_COMMON, LL_ADC_CLOCK_SYNC_PCLK_DIV4);
-	LL_ADC_SetCommonClock(ADC345_COMMON, LL_ADC_CLOCK_SYNC_PCLK_DIV4);
-
-	// Calibrate ADCs
-	_adc_core_calibrate(1);
-	_adc_core_calibrate(2);
-	_adc_core_calibrate(3);
-	_adc_core_calibrate(4);
+	static bool initialized = false;
+
+	if (initialized == false)
+	{
+		// Enable ADCs clocks
+		LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC12);
+		LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC345);
+
+		// Wake-up ADCs
+		for (int i = 1 ; i <= NUMBER_OF_ADCS ; i++)
+		{
+			_adc_core_wakeup(i);
+		}
+
+		// Set common clock between ADC 1 and ADC 2
+		// Refer to RM 21.4.3 and 21.7.2
+		LL_ADC_SetCommonClock(ADC12_COMMON, LL_ADC_CLOCK_SYNC_PCLK_DIV4);
+		LL_ADC_SetCommonClock(ADC345_COMMON, LL_ADC_CLOCK_SYNC_PCLK_DIV4);
+
+		// Calibrate ADCs
+		for (int i = 1 ; i <= NUMBER_OF_ADCS ; i++)
+		{
+			_adc_core_calibrate(i);
+		}
+
+		initialized = true;
+	}
 }
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.h b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.h
index f83ac863e38c8d378fcd018288278bcc5d688104..0597a12228823c79f75ce99e7e02b88e8114b04f 100644
--- a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.h
+++ b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 LAAS-CNRS
+ * Copyright (c) 2021-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -18,6 +18,8 @@
  */
 
 /**
+ * @date 2023
+ *
  * @author Clément Foucher <clement.foucher@laas.fr>
  *
  * @brief This file implements the core management of the ADCs.
@@ -31,6 +33,7 @@
 
 
 #include <stdint.h>
+#include <stdbool.h>
 
 
 #ifdef __cplusplus
@@ -38,55 +41,55 @@ extern "C" {
 #endif
 
 /////
-// Init, enable, start
+// Init, enable, start, stop
 
 /**
- * ADC initialization procedure for
- * ADC 1, ADC 2 and ADC 3.
+ * @brief ADC initialization procedure for
+ *        ADC 1, ADC 2, ADC 3 and ADC 4.
  */
 void adc_core_init();
 
 /**
- * ADC enable.
- * Refer to RM 21.4.9
+ * @brief ADC enable.
+ *        Refer to RM 21.4.9
  *
  * @param adc_num Number of the ADC to enable.
  */
 void adc_core_enable(uint8_t adc_num);
 
 /**
- * ADC start.
- * Refer to RM 21.4.15
+ * @brief ADC start.
+ *        Refer to RM 21.4.15
  *
  * @param adc_num Number of the ADC to start.
+ * @param sequence_length Length of the sequence configured
+ *        on that ADC.
  */
-void adc_core_start(uint8_t adc_num);
-
-/////
-// Configuration functions
+void adc_core_start(uint8_t adc_num, uint8_t sequence_length);
 
 /**
- * ADC dual mode: enables ADC 1/ADC 2 synchronization.
- * When ADC 1 acquisition is triggered, it simultaneously
- * triggers an acquisition on ADC 2.
- *
- * Refer to RM 21.4.30
+ * @brief ADC stop.
  *
- * @param dual_mode true to enable dual moode, false to
- *        disable it. false by default.
+ * @param adc_num Number of the ADC to stop.
  */
-void adc_core_set_dual_mode(uint8_t dual_mode);
+void adc_core_stop(uint8_t adc_num);
+
+
+/////
+// Configuration functions
 
 /**
- * ADC DMA mode configuration.
- * Enables DMA and circular mode on an ADC.
+ * @brief ADC DMA mode configuration.
+ *        Enables DMA in circular mode on an ADC.
  *
  * @param adc_num Number of the ADC on which to enable DMA.
+ * @param use_dma Set to true to use DMA for this ADC,
+ *        false to not use it (default).
  */
-void adc_core_configure_dma_mode(uint8_t adc_num);
+void adc_core_configure_dma_mode(uint8_t adc_num, bool use_dma);
 
 /**
- * Defines the trigger source for an ADC.
+ * @brief Defines the trigger source for an ADC.
  *
  * @param adc_num Number of the ADC to configure.
  * @param external_trigger_edge Edge of the trigger as defined
@@ -97,7 +100,7 @@ void adc_core_configure_dma_mode(uint8_t adc_num);
 void adc_core_configure_trigger_source(uint8_t adc_num, uint32_t external_trigger_edge, uint32_t trigger_source);
 
 /**
- * Configures the discontinuous mode for an ADC.
+ * @brief  Configures the discontinuous mode for an ADC.
  *
  * @param adc_num Number of the ADC to configure.
  * @param discontinuous_count Number of channels to acquire on each
@@ -105,6 +108,32 @@ void adc_core_configure_trigger_source(uint8_t adc_num, uint32_t external_trigge
  */
 void adc_core_configure_discontinuous_mode(uint8_t adc_num, uint32_t discontinuous_count);
 
+/**
+ * @brief ADC differential channel set-up:
+ *        Applies differential mode to specified channel.
+ *        Refer to RM 21.4.7
+ *
+ * @param adc_num Number of the ADC to configure.
+ * @param channel Number of the channel to configure.
+ * @param enable_differential Set true to enable differential mode,
+ *        false to disable it (default).
+ *
+ */
+void adc_core_set_channel_differential(uint8_t adc_num, uint8_t channel, bool enable_differential);
+
+/**
+ * @brief Configures an ADC channel acquisition.
+ *        Acquisition rank is provided as a parameter.
+ *        Channel sampling time is set to 12.5 cycles.
+ *
+ * @param adc_num Number of the ADC to configure.
+ * @param channel Number of the channel to configure.
+ * @param rank Acquisition rank.
+ *
+ */
+void adc_core_configure_channel(uint8_t adc_num, uint8_t channel, uint8_t rank);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.c b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.c
deleted file mode 100644
index 02d8a964b7c8ab7e9474ade029794c8656ea49b5..0000000000000000000000000000000000000000
--- a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (c) 2021 LAAS-CNRS
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License as published by
- *   the Free Software Foundation, either version 2.1 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- * SPDX-License-Identifier: LGLPV2.1
- */
-
-/**
- * @author Clément Foucher <clement.foucher@laas.fr>
- */
-
-
-// Stdlib
-#include <string.h>
-#include <stdint.h>
-
-// Zephyr
-#include <zephyr.h>
-
-
-/**
- * Helper function to retreive device from name in device tree.
- */
-ADC_TypeDef* _get_adc_by_name(char* name)
-{
-	ADC_TypeDef* adc = NULL;
-
-	if ( strcmp(name, "ADC_1") == 0)
-		adc = ADC1;
-	else if ( strcmp(name, "ADC_2") == 0)
-		adc = ADC2;
-	else if ( strcmp(name, "ADC_3") == 0)
-		adc = ADC3;
-	else if ( strcmp(name, "ADC_4") == 0)
-		adc = ADC4;
-
-	return adc;
-}
-
-ADC_TypeDef* _get_adc_by_number(uint8_t adc_number)
-{
-	ADC_TypeDef* adc = NULL;
-
-	if (adc_number == 1)
-		adc = ADC1;
-	else if (adc_number == 2)
-		adc = ADC2;
-	else if (adc_number == 3)
-		adc = ADC3;
-	else if (adc_number == 4)
-		adc = ADC4;
-
-	return adc;
-}
-
-uint8_t _get_adc_number_by_name(char* name)
-{
-	uint8_t adc_number = 0;
-
-	if ( strcmp(name, "ADC_1") == 0)
-		adc_number = 1;
-	else if ( strcmp(name, "ADC_2") == 0)
-		adc_number = 2;
-	else if ( strcmp(name, "ADC_3") == 0)
-		adc_number = 3;
-	else if ( strcmp(name, "ADC_4") == 0)
-		adc_number = 4;
-
-	return adc_number;
-}
-
-/**
- * Function to convert ADC decimal rank to litteral.
- * Sadly, there seems to be no equivalent to
- * __LL_ADC_DECIMAL_NB_TO_CHANNEL() for ranks...
- */
-uint32_t adc_decimal_nb_to_rank(uint8_t decimal_rank)
-{
-	uint32_t ll_rank;
-	switch (decimal_rank)
-	{
-		case 1:
-			ll_rank = LL_ADC_REG_RANK_1;
-			break;
-		case 2:
-			ll_rank = LL_ADC_REG_RANK_2;
-			break;
-		case 3:
-			ll_rank = LL_ADC_REG_RANK_3;
-			break;
-		case 4:
-			ll_rank = LL_ADC_REG_RANK_4;
-			break;
-		case 5:
-			ll_rank = LL_ADC_REG_RANK_5;
-			break;
-		case 6:
-			ll_rank = LL_ADC_REG_RANK_6;
-			break;
-		case 7:
-			ll_rank = LL_ADC_REG_RANK_7;
-			break;
-		case 8:
-			ll_rank = LL_ADC_REG_RANK_8;
-			break;
-		case 9:
-			ll_rank = LL_ADC_REG_RANK_9;
-			break;
-		case 10:
-			ll_rank = LL_ADC_REG_RANK_10;
-			break;
-		case 11:
-			ll_rank = LL_ADC_REG_RANK_11;
-			break;
-		case 12:
-			ll_rank = LL_ADC_REG_RANK_12;
-			break;
-		case 13:
-			ll_rank = LL_ADC_REG_RANK_13;
-			break;
-		case 14:
-			ll_rank = LL_ADC_REG_RANK_14;
-			break;
-		case 15:
-			ll_rank = LL_ADC_REG_RANK_15;
-			break;
-		case 16:
-			ll_rank = LL_ADC_REG_RANK_16;
-			break;
-		default:
-			ll_rank = 0;
-	}
-	return ll_rank;
-}
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.h b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.h
deleted file mode 100644
index 1dd48015edb796f66fe9ee7342849c17fd5ae300..0000000000000000000000000000000000000000
--- a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2021 LAAS-CNRS
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License as published by
- *   the Free Software Foundation, either version 2.1 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- * SPDX-License-Identifier: LGLPV2.1
- */
-
-/**
- * @author Clément Foucher <clement.foucher@laas.fr>
- *
- * @brief This file provides helper functions for the ADC management.
- *
- * THIS FILE SHOULD NOT BE INCLUDED ANYWHERE OUTSIDE FILES
- * FROM THE SAME FOLDER.
- *
- */
-
-#ifndef ADC_HELPER_H_
-#define ADC_HELPER_H_
-
-
-#include <stdint.h>
-#include <zephyr.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-ADC_TypeDef* _get_adc_by_name(char* name);
-ADC_TypeDef* _get_adc_by_number(uint8_t adc_number);
-uint8_t _get_adc_number_by_name(char* name);
-uint32_t adc_decimal_nb_to_rank(uint8_t decimal_rank);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // ADC_HELPER_H_
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt b/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt
index 6e2db647db2dceaa0df4d24ec3564c19466a534c..aa3576b0878b3732430be12120384a5cb23cc50a 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt
@@ -7,9 +7,10 @@ if(CONFIG_OWNTECH_DATA_ACQUISITION)
 
   # Select source files to be compiled
   zephyr_library_sources(
-    ./adc_to_mem/dma.cpp
-    ./adc_to_mem/data_dispatch.cpp
-    ./data_conversion/data_conversion.cpp
+    ./src/dma.cpp
+    ./src/data_dispatch.cpp
+	./src/adc_channels.cpp
+    ./src/data_conversion.cpp
     ./public_api/DataAcquisition.cpp
    )
 endif()
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/Kconfig b/zephyr/modules/owntech_data_acquisition/zephyr/Kconfig
index 90d0673bcc0ad4cf9877a303ccd8576cffff24cc..5c7d04d19da3f6b68ce2a94dab85c2d184cbe2ca 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/Kconfig
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/Kconfig
@@ -2,8 +2,8 @@ config OWNTECH_DATA_ACQUISITION
 	bool "Enable OwnTech data acquisition using ADCs"
 	default y
 	select DMA
-	depends on OWNTECH_ADC_DRIVER
 	depends on OWNTECH_HRTIM_DRIVER
 	depends on CONSOLE_GETCHAR
+	depends on OWNTECH_HARDWARE_CONFIGURATION
 	# Force-select the following to avoid dependency loop
 	select OWNTECH_SCHEDULING
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.cpp b/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.cpp
index b841d3958a21f82c866877e819cee29ba5a17959..663923f32ff1905ce9251c66870a966a85b3eb32 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.cpp
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.cpp
@@ -33,11 +33,12 @@
 #include "DataAcquisition.h"
 
 // OwnTech Power API
-#include "adc.h"
+#include "HardwareConfiguration.h"
 #include "scheduling_internal.h"
 
 // Current module private functions
-#include "../adc_to_mem/data_dispatch.h"
+#include "../src/data_dispatch.h"
+#include "../src/adc_channels.h"
 
 
 /////
@@ -49,6 +50,16 @@ DataAcquisition dataAcquisition;
 /////
 // Public configuration functions
 
+int8_t DataAcquisition::configureAdcChannels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count)
+{
+	return adc_channels_configure_adc_channels(adc_number, channel_list, channel_count);
+}
+
+void DataAcquisition::configureAdcDefaultAllMeasurements()
+{
+	configure_adc_default_all_measurements();
+}
+
 int8_t DataAcquisition::start(dispatch_method_t dispatch_method)
 {
 	if (this->is_started == true)
@@ -70,7 +81,7 @@ int8_t DataAcquisition::start(dispatch_method_t dispatch_method)
 
 		while (1)
 		{
-			const char* channel_name = adc_get_channel_name(adc_num, channel_rank);
+			const char* channel_name = adc_channels_get_channel_name(adc_num, channel_rank);
 
 			if (channel_name != nullptr)
 			{
@@ -125,7 +136,7 @@ int8_t DataAcquisition::start(dispatch_method_t dispatch_method)
 	data_dispatch_init(dispatch_type);
 
 	// Launch ADC conversion
-	adc_start();
+	hwConfig.adcStart();
 
 	this->is_started = true;
 
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.h b/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.h
index 2df56b31a671eaccab3503e08c6a960e99ce16a7..5f2f3f11695eebc12be9a59c85c0186ae2c20d70 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.h
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.h
@@ -36,7 +36,7 @@
 #include <arm_math.h>
 
 // Current module private functions
-#include "../data_conversion/data_conversion.h"
+#include "../src/data_conversion.h"
 
 
 /////
@@ -62,6 +62,35 @@ class DataAcquisition
 {
 public:
 
+	/**
+	 * This function is used to configure all ADC channels in default configuration.
+	 * Channels will be attributed as follows:
+	 * ADC1 -   V1_LOW      ADC2 -  I1_LOW
+	 *          V2_LOW              I2_LOW
+	 *          V_HIGH              I_HIGH
+	 *
+	 * This function must be called BEFORE ADC is started.
+	 */
+	static int8_t configureAdcChannels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count);
+
+	/**
+	 * @brief  This function is used to configure the channels to be
+	 *         enabled on a given ADC.
+	 *
+	 * @param  adc_number Number of the ADC on which channel configuration is
+	 *         to be done.
+	 * @param  channel_list List of channels to configure. This is a list of
+	 *         names as defined in the device tree (field `label`). The order
+	 *         of the names in the array sets the acquisition ranks (order in
+	 *         which the channels are acquired).
+	 * @param  channel_count Number of channels defined in `channel_list`.
+	 * @return 0 is everything went well,
+	 *         ECHANNOTFOUND if at least one of the channels
+	 *           is not available in the given ADC. Available channels are the
+	 *           ones defined in the device tree.
+	 */
+	static void configureAdcDefaultAllMeasurements();
+
 	/**
 	 * @brief This functions starts the acquisition chain.
 	 *
@@ -271,7 +300,7 @@ public:
 	 * sets these default parameters.
 	 */
 	void setDefaultCalibrationFactors(void);
-	
+
 	/**
 	 * @brief    Retrieve stored parameters from Flash memory and configure ADC parameters
 	 */
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.c b/zephyr/modules/owntech_data_acquisition/zephyr/src/adc_channels.cpp
similarity index 68%
rename from zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.c
rename to zephyr/modules/owntech_data_acquisition/zephyr/src/adc_channels.cpp
index 0d6692d15e75af81a58958e304676ccdba2403eb..05a4a0be7f706c2bbf4fc692506a30d9bed35007 100644
--- a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.c
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/src/adc_channels.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2022 LAAS-CNRS
+ * Copyright (c) 2021-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -18,7 +18,7 @@
  */
 
 /**
- * @date   2022
+ * @date   2023
  *
  * @author Hugues Larrive <hugues.larrive@laas.fr>
  * @author Clément Foucher <clement.foucher@laas.fr>
@@ -28,9 +28,7 @@
 
 
 // Stdlib
-#include <stdlib.h>
 #include <string.h>
-#include <stdint.h>
 
 // Zephyr
 #include <zephyr.h>
@@ -39,8 +37,7 @@
 #include "adc_channels.h"
 
 // OwnTech API
-#include "adc_helper.h"
-#include "adc_error_codes.h"
+#include "HardwareConfiguration.h"
 
 
 /////
@@ -48,10 +45,10 @@
 
 typedef struct
 {
-	char*   name;
-	bool    is_differential;
-	uint8_t number;
-	char*   adc;
+	const char* name;
+	bool        is_differential;
+	uint8_t     number;
+	uint32_t    adc_reg_addr; // ADC addr is used to identify ADC
 } channel_prop_t;
 
 #define ADC_INPUTS_NODELABEL DT_NODELABEL(mychannels)
@@ -60,14 +57,14 @@ typedef struct
 #define CHANNEL_NAME(node_id)    DT_PROP(node_id, label)
 #define CHANNEL_IS_DIFF(node_id) DT_PROP(node_id, differential)
 #define CHANNEL_NUMBER(node_id)  DT_PHA_BY_IDX(node_id, io_channels, 0, input)
-#define CHANNEL_ADC(node_id)     DT_PROP_BY_PHANDLE_IDX(node_id, io_channels, 0, label)
+#define ADC_REG_ADDR(node_id)    DT_REG_ADDR(DT_PHANDLE(node_id, io_channels))
 
 #define CHANNEL_WRITE_PROP(node_id)                \
 	{                                              \
 		.name=CHANNEL_NAME(node_id),               \
 		.is_differential=CHANNEL_IS_DIFF(node_id), \
 		.number=CHANNEL_NUMBER(node_id),           \
-		.adc=CHANNEL_ADC(node_id)                  \
+		.adc_reg_addr=ADC_REG_ADDR(node_id)        \
 	},
 
 // Channel count. This is very dirty!
@@ -111,10 +108,28 @@ static channel_prop_t** adc2_enabled_channels_list;
 static channel_prop_t** adc3_enabled_channels_list;
 static channel_prop_t** adc4_enabled_channels_list;
 
+static bool initialized = false;
+
 
 /////
 // ADC channels private functions
 
+uint8_t _get_adc_number_by_address(uint32_t adc_address)
+{
+	uint8_t adc_number = 0;
+
+	if (adc_address == 0x50000000)
+		adc_number = 1;
+	else if (adc_address == 0x50000100)
+		adc_number = 2;
+	else if (adc_address == 0x50005000)
+		adc_number = 3;
+	else if (adc_address == 0x50005100)
+		adc_number = 4;
+
+	return adc_number;
+}
+
 /**
  * Builds list of device-tree defined channels for each ADC.
  */
@@ -128,7 +143,7 @@ static void _adc_channels_build_available_channels_lists()
 
 	for (int i = 0 ; i < CHANNEL_COUNT ; i++)
 	{
-		uint8_t adc_number = _get_adc_number_by_name(available_channels_props[i].adc);
+		uint8_t adc_number = _get_adc_number_by_address(available_channels_props[i].adc_reg_addr);
 		if (adc_number == 1)
 		{
 			adc1_available_channels_count++;
@@ -148,10 +163,10 @@ static void _adc_channels_build_available_channels_lists()
 	}
 
 	// Build a list of channels by ADC
-	adc1_available_channels_list = k_malloc(sizeof(channel_prop_t*) * adc1_available_channels_count);
-	adc2_available_channels_list = k_malloc(sizeof(channel_prop_t*) * adc2_available_channels_count);
-	adc3_available_channels_list = k_malloc(sizeof(channel_prop_t*) * adc3_available_channels_count);
-	adc4_available_channels_list = k_malloc(sizeof(channel_prop_t*) * adc4_available_channels_count);
+	adc1_available_channels_list = (channel_prop_t**)k_malloc(sizeof(channel_prop_t*) * adc1_available_channels_count);
+	adc2_available_channels_list = (channel_prop_t**)k_malloc(sizeof(channel_prop_t*) * adc2_available_channels_count);
+	adc3_available_channels_list = (channel_prop_t**)k_malloc(sizeof(channel_prop_t*) * adc3_available_channels_count);
+	adc4_available_channels_list = (channel_prop_t**)k_malloc(sizeof(channel_prop_t*) * adc4_available_channels_count);
 
 	int adc1_index = 0;
 	int adc2_index = 0;
@@ -159,7 +174,7 @@ static void _adc_channels_build_available_channels_lists()
 	int adc4_index = 0;
 	for (int i = 0 ; i < CHANNEL_COUNT ; i++)
 	{
-		uint8_t adc_number = _get_adc_number_by_name(available_channels_props[i].adc);
+		uint8_t adc_number = _get_adc_number_by_address(available_channels_props[i].adc_reg_addr);
 		if (adc_number == 1)
 		{
 			adc1_available_channels_list[adc1_index] = &available_channels_props[i];
@@ -181,44 +196,17 @@ static void _adc_channels_build_available_channels_lists()
 			adc4_index++;
 		}
 	}
-}
-
-/**
- * ADC differential channel set-up:
- * Applies differential mode to specified channel.
- * Refer to RM 21.4.7
- */
-static void _adc_channels_set_channel_differential(char* adc_name, uint8_t channel)
-{
-	ADC_TypeDef* adc = _get_adc_by_name(adc_name);
-
-	if (adc != NULL)
-	{
-		LL_ADC_SetChannelSingleDiff(adc,
-		                            __LL_ADC_DECIMAL_NB_TO_CHANNEL(channel),
-		                            LL_ADC_DIFFERENTIAL_ENDED
-		                           );
-	}
 
+	initialized = true;
 }
 
-/**
- * Differential channel setup.
- * Must be done before ADC is enabled.
- */
-static void _adc_channels_differential_setup()
+static channel_prop_t** _adc_channels_get_enabled_channels_list(uint8_t adc_num)
 {
-	for (int i = 0; i < CHANNEL_COUNT; i++)
+	if (initialized == false)
 	{
-		if (available_channels_props[i].is_differential)
-		{
-			_adc_channels_set_channel_differential(available_channels_props[i].adc, available_channels_props[i].number);
-		}
+		_adc_channels_build_available_channels_lists();
 	}
-}
 
-static channel_prop_t** _adc_channels_get_enabled_channels_list(uint8_t adc_num)
-{
 	channel_prop_t** enabled_channels_list = NULL;
 	switch (adc_num)
 	{
@@ -240,6 +228,11 @@ static channel_prop_t** _adc_channels_get_enabled_channels_list(uint8_t adc_num)
 
 static channel_prop_t** _adc_channels_get_available_channels_list(uint8_t adc_num)
 {
+	if (initialized == false)
+	{
+		_adc_channels_build_available_channels_lists();
+	}
+
 	channel_prop_t** available_channels_list = NULL;
 	switch (adc_num)
 	{
@@ -261,6 +254,11 @@ static channel_prop_t** _adc_channels_get_available_channels_list(uint8_t adc_nu
 
 static uint8_t _adc_channels_get_available_channels_count(uint8_t adc_num)
 {
+	if (initialized == false)
+	{
+		_adc_channels_build_available_channels_lists();
+	}
+
 	uint8_t available_channels_count = 0;
 	switch (adc_num)
 	{
@@ -282,6 +280,11 @@ static uint8_t _adc_channels_get_available_channels_count(uint8_t adc_num)
 
 static uint8_t _adc_channels_get_enabled_channels_count(uint8_t adc_num)
 {
+	if (initialized == false)
+	{
+		_adc_channels_build_available_channels_lists();
+	}
+
 	uint8_t enabled_channels_count = 0;
 	switch (adc_num)
 	{
@@ -303,6 +306,11 @@ static uint8_t _adc_channels_get_enabled_channels_count(uint8_t adc_num)
 
 static void _adc_channels_set_enabled_channels(uint8_t adc_num, channel_prop_t** enabled_channels, uint8_t enabled_channels_count)
 {
+	if (initialized == false)
+	{
+		_adc_channels_build_available_channels_lists();
+	}
+
 	switch (adc_num)
 	{
 		case 1:
@@ -326,6 +334,11 @@ static void _adc_channels_set_enabled_channels(uint8_t adc_num, channel_prop_t**
 
 static channel_prop_t* _adc_channels_get_available_channel_by_name(uint8_t adc_num, const char* channel_name)
 {
+	if (initialized == false)
+	{
+		_adc_channels_build_available_channels_lists();
+	}
+
 	channel_prop_t** current_adc_available_channels = _adc_channels_get_available_channels_list(adc_num);
 
 	for (int i = 0 ; i < _adc_channels_get_available_channels_count(adc_num) ; i++)
@@ -343,86 +356,16 @@ static channel_prop_t* _adc_channels_get_available_channel_by_name(uint8_t adc_n
 /////
 // ADC channels public functions
 
-void adc_channels_init()
+int8_t adc_channels_configure_adc_channels(uint8_t adc_num, const char* channel_list[], uint8_t channel_count)
 {
-	_adc_channels_build_available_channels_lists();
-	_adc_channels_differential_setup();
-}
-
-void adc_channels_configure(uint8_t adc_num)
-{
-	ADC_TypeDef* adc = _get_adc_by_number(adc_num);
-	uint8_t enabled_channels_in_this_adc = adc_channels_get_enabled_channels_count(adc_num);
-
-	channel_prop_t** enabled_channels_list = _adc_channels_get_enabled_channels_list(adc_num);
-
-	for (int rank = 0; rank < enabled_channels_in_this_adc; rank++)
+	if (initialized == false)
 	{
-		uint8_t current_channel = enabled_channels_list[rank]->number;
-
-		// Set regular sequence
-		LL_ADC_REG_SetSequencerRanks(adc,
-		                             adc_decimal_nb_to_rank(rank+1), // Indexed from 1 => +1
-		                             __LL_ADC_DECIMAL_NB_TO_CHANNEL(current_channel)
-		                            );
-		// Set channels sampling time
-
-		/* 000: 2.5 ADC clock cycles
-		 * 001: 6.5 ADC clock cycles
-		 * 010: 12.5 ADC clock cycles
-		 * 011: 24.5 ADC clock cycles
-		 * 100: 47.5 ADC clock cycles
-		 * 101: 92.5 ADC clock cycles
-		 * 110: 247.5 ADC clock cycles
-		 * 111: 640.5 ADC clock cycles
-		 */
-		/* Vrefint minimum sampling time : 4us
-		 */
-		/* Vts minimum sampling time : 5us
-		 */
-		/* For 0b110:
-		 * Tadc_clk = 1 / 42.5 MHz = 23.5 ns
-		 * Tsar = 12.5 * Tadc_clk = 293.75 ns
-		 * Tsmpl = 247.5 * Tadc_clk = 5816.25 ns
-		 * Tconv = Tsmpl + Tsar = 6.11 us
-		 * -> Fconv up to 163.6 KSPS for 1 channel per ADC
-		 * Fconv up to 27.2 KSPS with the 6 channels actally
-		 * used on the ADC1
-		 *
-		 * For 0b001 (ok for voltage):
-		 * Tadc_clk = 1 / 42.5 MHz = 23.5 ns
-		 * Tsar = 12.5 * Tadc_clk = 293.75 ns
-		 * Tsmpl = 6.5 * Tadc_clk = 152.75 ns
-		 * Tconv = Tsmpl + Tsar = 446.4 ns
-		 * -> Fconv up to 2239 KSPS for 1 channel per ADC
-		 * Fconv up to 373 KSPS with the 6 channels actally
-		 * used on the ADC1
-		 *
-		 * For 0b101 (ok for current):
-		 * Tadc_clk = 1 / 42.5 MHz = 23.5 ns
-		 * Tsar = 12.5 * Tadc_clk = 293.75 ns
-		 * Tsmpl = 92.5 * Tadc_clk = 2173.75 ns
-		 * Tconv = Tsmpl + Tsar = 2.47 µs
-		 * -> Fconv up to 404 KSPS for 1 channel per ADC
-		 * Fconv up to 134 KSPS for 3 channels actally
-		 * used on each ADC
-		 */
-		LL_ADC_SetChannelSamplingTime(adc,
-		                              __LL_ADC_DECIMAL_NB_TO_CHANNEL(current_channel),
-		                              LL_ADC_SAMPLINGTIME_12CYCLES_5
-		                             );
-
+		_adc_channels_build_available_channels_lists();
 	}
 
-	// Set regular sequence length
-	LL_ADC_REG_SetSequencerLength(adc, (uint32_t)enabled_channels_in_this_adc-1);
-}
-
-int8_t adc_channnels_configure_adc_channels(uint8_t adc_num, const char* channel_list[], uint8_t channel_count)
-{
 	uint8_t result = 0;
 
-	channel_prop_t** current_adc_enabled_channels_list = k_malloc(channel_count * sizeof(channel_prop_t*));
+	channel_prop_t** current_adc_enabled_channels_list = (channel_prop_t**)k_malloc(channel_count * sizeof(channel_prop_t*));
 
 	for (int i = 0 ; i < channel_count ; i++)
 	{
@@ -435,6 +378,9 @@ int8_t adc_channnels_configure_adc_channels(uint8_t adc_num, const char* channel
 		else
 		{
 			current_adc_enabled_channels_list[i] = current_channel;
+
+			hwConfig.adcConfigureDma(adc_num, true);
+			hwConfig.adcAddChannel(adc_num, current_channel->number);
 		}
 	}
 
@@ -458,6 +404,11 @@ int8_t adc_channnels_configure_adc_channels(uint8_t adc_num, const char* channel
 
 const char* adc_channels_get_channel_name(uint8_t adc_num, uint8_t channel_rank)
 {
+	if (initialized == false)
+	{
+		_adc_channels_build_available_channels_lists();
+	}
+
 	channel_prop_t** current_adc_enabled_channels_list = _adc_channels_get_enabled_channels_list(adc_num);
 
 	if ( (current_adc_enabled_channels_list != NULL) && (channel_rank < _adc_channels_get_enabled_channels_count(adc_num)) )
@@ -470,6 +421,11 @@ const char* adc_channels_get_channel_name(uint8_t adc_num, uint8_t channel_rank)
 
 uint8_t adc_channels_get_enabled_channels_count(uint8_t adc_num)
 {
+	if (initialized == false)
+	{
+		_adc_channels_build_available_channels_lists();
+	}
+
 	uint8_t enabled_channels = 0;
 
 	switch (adc_num)
@@ -490,3 +446,31 @@ uint8_t adc_channels_get_enabled_channels_count(uint8_t adc_num)
 
 	return enabled_channels;
 }
+
+void configure_adc_default_all_measurements()
+{
+	if (initialized == false)
+	{
+		_adc_channels_build_available_channels_lists();
+	}
+
+	uint8_t number_of_channels_adc1 = 3;
+	uint8_t number_of_channels_adc2 = 3;
+
+	const char* adc1_channels[] =
+	{
+		"I1_LOW",
+		"V1_LOW",
+		"V_HIGH"
+	};
+
+	const char* adc2_channels[] =
+	{
+		"I2_LOW",
+		"V2_LOW",
+		"I_HIGH"
+	};
+
+	adc_channels_configure_adc_channels(1, adc1_channels, number_of_channels_adc1);
+	adc_channels_configure_adc_channels(2, adc2_channels, number_of_channels_adc2);
+}
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.h b/zephyr/modules/owntech_data_acquisition/zephyr/src/adc_channels.h
similarity index 68%
rename from zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.h
rename to zephyr/modules/owntech_data_acquisition/zephyr/src/adc_channels.h
index 772c20e5525f5fbeedfa006196a5c71672a1a4c3..d3347259c35f13a7c3629b7f8e818fb164a9b478 100644
--- a/zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.h
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/src/adc_channels.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2022 LAAS-CNRS
+ * Copyright (c) 2021-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -18,7 +18,7 @@
  */
 
 /**
- * @date   2022
+ * @date   2023
  *
  * @author Clément Foucher <clement.foucher@laas.fr>
  *
@@ -35,32 +35,12 @@
 #include <stdint.h>
 
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#define ECHANNOTFOUND -1
 
-/**
- * Performs internal data structures initialization
- * and pre-ADC enable init.
- * Must be called before adc_core_enable()
- */
-void adc_channels_init();
 
 /**
- * ADC channel configuration.
- * For each channel enabled by the user, sets its sequencer rank and
- * sampling time, then sets the ADC sequencer length.
- *
- * If must be called only after adc_channnels_configure_adc_channels
- * has been called for this ADC, and ADC is enabled an not running.
- *
- * @param adc_num Number of the adc for which to configure channels.
- */
-void adc_channels_configure(uint8_t adc_num);
-
-/**
- * This function is used to configure the channels to be
- * enabled on a given ADC.
+ * @brief  This function is used to configure the channels to be
+ *         enabled on a given ADC.
  *
  * @param  adc_number Number of the ADC on which channel configuration is
  *         to be done.
@@ -74,13 +54,13 @@ void adc_channels_configure(uint8_t adc_num);
  *           is not available in the given ADC. Available channels are the
  *           ones defined in the device tree.
  */
-int8_t adc_channnels_configure_adc_channels(uint8_t adc_num, const char* channel_list[], uint8_t channel_count);
+int8_t adc_channels_configure_adc_channels(uint8_t adc_num, const char* channel_list[], uint8_t channel_count);
 
 /**
- * This function returns the name of an enabled channel.
+ * @brief  This function returns the name of an enabled channel.
  *
- * This function must onle be called after
- * adc_channnels_configure_adc_channels has been called.
+ *         This function must only be called after
+ *         adc_channels_configure_adc_channels has been called.
  *
  * @param  adc_number Number of the ADC
  * @param  channel_rank Rank of the ADC channel to query.
@@ -92,15 +72,23 @@ int8_t adc_channnels_configure_adc_channels(uint8_t adc_num, const char* channel
 const char* adc_channels_get_channel_name(uint8_t adc_num, uint8_t channel_rank);
 
 /**
- * Get the number of enabled channels for an ADC.
+ * @brief  Get the number of enabled channels for an ADC.
+ *
  * @param  adc_num Number of the ADC
  * @return Number of enabled channels in this ADC.
  */
 uint8_t adc_channels_get_enabled_channels_count(uint8_t adc_num);
 
+/**
+ * This function is used to configure all ADC channels in default configuration.
+ * Channels will be attributed as follows:
+ * ADC1 -   V1_LOW      ADC2 -  I1_LOW
+ *          V2_LOW              I2_LOW
+ *          V_HIGH              I_HIGH
+ *
+ * This function must be called BEFORE ADC is started.
+ */
+void configure_adc_default_all_measurements();
 
-#ifdef __cplusplus
-}
-#endif
 
 #endif // ADC_CHANNELS_H_
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/data_conversion/data_conversion.cpp b/zephyr/modules/owntech_data_acquisition/zephyr/src/data_conversion.cpp
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/data_conversion/data_conversion.cpp
rename to zephyr/modules/owntech_data_acquisition/zephyr/src/data_conversion.cpp
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/data_conversion/data_conversion.h b/zephyr/modules/owntech_data_acquisition/zephyr/src/data_conversion.h
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/data_conversion/data_conversion.h
rename to zephyr/modules/owntech_data_acquisition/zephyr/src/data_conversion.h
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/data_dispatch.cpp b/zephyr/modules/owntech_data_acquisition/zephyr/src/data_dispatch.cpp
similarity index 98%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/data_dispatch.cpp
rename to zephyr/modules/owntech_data_acquisition/zephyr/src/data_dispatch.cpp
index 2c5636e28946835711256058ad096ebae6a65d9d..aee0868a7295bcee6b88110f7df20a782996532b 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/data_dispatch.cpp
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/src/data_dispatch.cpp
@@ -32,7 +32,7 @@
 #include <zephyr.h>
 
 // OwnTech API
-#include "adc.h"
+#include "HardwareConfiguration.h"
 #include "Scheduling.h"
 #include "scheduling_internal.h"
 #include "hrtim.h"
@@ -41,6 +41,7 @@
 // Current module header
 #include "DataAcquisition.h"
 #include "dma.h"
+#include "adc_channels.h"
 
 // Current file header
 #include "data_dispatch.h"
@@ -140,7 +141,7 @@ void data_dispatch_init(dispatch_t dispatch_method)
 	for (uint8_t adc_num = 1 ; adc_num <= ADC_COUNT ; adc_num++)
 	{
 		uint8_t adc_index = adc_num-1;
-		enabled_channels_count[adc_index] = adc_get_enabled_channels_count(adc_num);
+		enabled_channels_count[adc_index] = adc_channels_get_enabled_channels_count(adc_num);
 
 		if (enabled_channels_count[adc_index] > 0)
 		{
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/data_dispatch.h b/zephyr/modules/owntech_data_acquisition/zephyr/src/data_dispatch.h
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/data_dispatch.h
rename to zephyr/modules/owntech_data_acquisition/zephyr/src/data_dispatch.h
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/dma.cpp b/zephyr/modules/owntech_data_acquisition/zephyr/src/dma.cpp
similarity index 98%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/dma.cpp
rename to zephyr/modules/owntech_data_acquisition/zephyr/src/dma.cpp
index f4687c954010fa174beb68547feddd51e57012a5..d30d5405f7005bc09bed2ea26260bb2ee7fe3e65 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/dma.cpp
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/src/dma.cpp
@@ -34,11 +34,9 @@
 // STM32
 #include <stm32_ll_dma.h>
 
-// OwnTech API
-#include "adc.h"
-
 // Current module private functions
 #include "data_dispatch.h"
+#include "adc_channels.h"
 
 
 /////
@@ -99,7 +97,7 @@ void dma_configure_adc_acquisition(uint8_t adc_number, bool disable_interrupts,
 	if (device_is_ready(dma1) == false)
 		return;
 
-	if (adc_get_enabled_channels_count(adc_number) == 0)
+	if (adc_channels_get_enabled_channels_count(adc_number) == 0)
 		return;
 
 	uint8_t dma_index = adc_number - 1;
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/dma.h b/zephyr/modules/owntech_data_acquisition/zephyr/src/dma.h
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc_to_mem/dma.h
rename to zephyr/modules/owntech_data_acquisition/zephyr/src/dma.h
diff --git a/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.cpp b/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.cpp
index 948406a662505a60855e027cb87f57355a94700b..9e92a4009b02498ebb66f9726f516995aed1c6d5 100644
--- a/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.cpp
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 LAAS-CNRS
+ * Copyright (c) 2022-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -420,36 +420,42 @@ void HardwareConfiguration::extraUartWriteChar(char data)
 /////
 // ADC
 
-void HardwareConfiguration::configureAdc12DualMode(uint8_t dual_mode)
+void HardwareConfiguration::adcConfigureTriggerSource(uint8_t adc_number, adc_ev_src_t trigger_source)
 {
-	configure_adc12_dual_mode(dual_mode);
+	configure_adc_trigger_source(adc_number, trigger_source);
 }
 
-int8_t HardwareConfiguration::configureAdcChannels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count)
+void HardwareConfiguration::adcConfigureDiscontinuousMode(uint8_t adc_number, uint32_t dicontinuous_count)
 {
-	return configure_adc_channels(adc_number, channel_list, channel_count);
+	configure_adc_discontinuous_mode(adc_number, dicontinuous_count);
 }
 
-void HardwareConfiguration::configureAdcTriggerSource(uint8_t adc_number, adc_ev_src_t trigger_source)
+void HardwareConfiguration::adcAddChannel(uint8_t adc_number, uint8_t channel)
 {
-	configure_adc_trigger_source(adc_number, trigger_source);
+	configure_adc_add_channel(adc_number, channel);
 }
 
-void HardwareConfiguration::configureAdcDiscontinuousMode(uint8_t adc_number, uint32_t dicontinuous_count)
+void HardwareConfiguration::adcRemoveChannel(uint8_t adc_number, uint8_t channel)
 {
-	configure_adc_discontinuous_mode(adc_number, dicontinuous_count);
+	configure_adc_remove_channel(adc_number, channel);
 }
 
-void HardwareConfiguration::configureAdcDefaultAllMeasurements()
+void HardwareConfiguration::adcConfigureDma(uint8_t adc_number, bool use_dma)
 {
-	configure_adc_default_all_measurements();
+	configure_adc_dma_mode(adc_number, use_dma);
 }
 
-void HardwareConfiguration::configureAdcDefaultAllMeasurementsAndExtra()
+void HardwareConfiguration::adcStart()
 {
-	configure_adc_default_all_measurements_and_extra();
+	start_adcs();
 }
 
+void HardwareConfiguration::adcStop()
+{
+	stop_adcs();
+}
+
+
 
 void HardwareConfiguration::setLeg1DeadTime(uint16_t rise_ns, uint16_t fall_ns)
 {
diff --git a/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.h b/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.h
index 21b5dcf703f75733ceff4092206f9fa6a2d059da..b43ca8694f1dc28c386f1ca45e31e0edbd3681fc 100644
--- a/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.h
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 LAAS-CNRS
+ * Copyright (c) 2022-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -147,12 +147,13 @@ public:
 	static void extraUartWriteChar(char data);
 
 	// ADC
-	static void configureAdc12DualMode(uint8_t dual_mode);
-	static int8_t configureAdcChannels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count);
-	static void configureAdcTriggerSource(uint8_t adc_number, adc_ev_src_t trigger_source);
-	static void configureAdcDiscontinuousMode(uint8_t adc_number, uint32_t dicontinuous_count);
-	static void configureAdcDefaultAllMeasurements();
-	static void configureAdcDefaultAllMeasurementsAndExtra();
+	static void adcConfigureTriggerSource(uint8_t adc_number, adc_ev_src_t trigger_source);
+	static void adcConfigureDiscontinuousMode(uint8_t adc_number, uint32_t dicontinuous_count);
+	static void adcConfigureDma(uint8_t adc_number, bool use_dma);
+	static void adcAddChannel(uint8_t adc_number, uint8_t channel);
+	static void adcRemoveChannel(uint8_t adc_number, uint8_t channel);
+	static void adcStart();
+	static void adcStop();
 
 private:
 	static hardware_version_t hardware_version;
@@ -166,5 +167,4 @@ private:
 extern HardwareConfiguration hwConfig;
 
 
-
 #endif // HARDWARECONFIGURATION_H_
diff --git a/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.cpp b/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.cpp
index 83b574e44d1a78848224ffe9e2f95f8ac7d63257..d5bdd27e3921800ac82e53eb54b42ed3572689ec 100644
--- a/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.cpp
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2022 LAAS-CNRS
+ * Copyright (c) 2021-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -18,7 +18,7 @@
  */
 
 /**
- * @date   2022
+ * @date   2023
  *
  * @author Clément Foucher <clement.foucher@laas.fr>
  * @author Luiz Villa <luiz.villa@laas.fr>
@@ -28,35 +28,31 @@
 // OwnTech Power API
 #include "adc.h"
 
-// Current file headers
+// Current file header
 #include "adc_configuration.h"
-#include "adc_error_codes.h"
 
 
-static uint8_t initialized;
-static uint8_t channels_configured;
+static uint8_t initialized = 0;
 
 
-void _initialize()
+static void _initialize()
 {
 	if (initialized == 0)
 	{
-		// Initialize the ADCs
-		adc_init();
-		initialized = 1;
-
-		// Perform default configration
-		configure_adc_trigger_source(1, hrtim_ev1);
-		configure_adc_trigger_source(2, hrtim_ev3);
-		configure_adc_trigger_source(3, software);
-		configure_adc_trigger_source(4, software);
+		// Perform default configuration
+		adc_configure_trigger_source(1, hrtim_ev1);
+		adc_configure_trigger_source(2, hrtim_ev3);
+		adc_configure_trigger_source(3, software);
+		adc_configure_trigger_source(4, software);
 
 		adc_configure_discontinuous_mode(1, 1);
 		adc_configure_discontinuous_mode(2, 1);
+
+		initialized = 1;
 	}
 }
 
-void configure_adc12_dual_mode(uint8_t dual_mode)
+void configure_adc_trigger_source(uint8_t adc_number, adc_ev_src_t trigger_source)
 {
 	/////
 	// Make sure module is initialized
@@ -69,10 +65,10 @@ void configure_adc12_dual_mode(uint8_t dual_mode)
 	/////
 	// Proceed
 
-	adc_set_dual_mode(dual_mode);
+	adc_configure_trigger_source(adc_number, trigger_source);
 }
 
-int8_t configure_adc_channels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count)
+void configure_adc_discontinuous_mode(uint8_t adc_number, uint32_t discontinuous_count)
 {
 	/////
 	// Make sure module is initialized
@@ -85,19 +81,26 @@ int8_t configure_adc_channels(uint8_t adc_number, const char* channel_list[], ui
 	/////
 	// Proceed
 
-	int8_t result = adc_configure_adc_channels(adc_number, channel_list, channel_count);
+	adc_configure_discontinuous_mode(adc_number, discontinuous_count);
+}
+
+void configure_adc_add_channel(uint8_t adc_num, uint8_t channel)
+{
+	/////
+	// Make sure module is initialized
 
-	if (result != NOERROR)
+	if (initialized == 0)
 	{
-		return result;
+		_initialize();
 	}
 
-	channels_configured = 1;
+	/////
+	// Proceed
 
-	return NOERROR;
+	adc_add_channel(adc_num, channel);
 }
 
-void configure_adc_trigger_source(uint8_t adc_number, adc_ev_src_t trigger_source)
+void configure_adc_remove_channel(uint8_t adc_num, uint8_t channel)
 {
 	/////
 	// Make sure module is initialized
@@ -110,10 +113,10 @@ void configure_adc_trigger_source(uint8_t adc_number, adc_ev_src_t trigger_sourc
 	/////
 	// Proceed
 
-	adc_configure_trigger_source(adc_number, trigger_source);
+	adc_remove_channel(adc_num, channel);
 }
 
-void configure_adc_discontinuous_mode(uint8_t adc_number, uint32_t dicontinuous_count)
+void configure_adc_dma_mode(uint8_t adc_num, bool use_dma)
 {
 	/////
 	// Make sure module is initialized
@@ -126,53 +129,38 @@ void configure_adc_discontinuous_mode(uint8_t adc_number, uint32_t dicontinuous_
 	/////
 	// Proceed
 
-	adc_configure_discontinuous_mode(adc_number, dicontinuous_count);
+	adc_configure_use_dma(adc_num, use_dma);
 }
 
-void configure_adc_default_all_measurements()
+void start_adcs()
 {
-	uint8_t number_of_channels_adc1 = 3;
-	uint8_t number_of_channels_adc2 = 3;
+	/////
+	// Make sure module is initialized
 
-	const char* adc1_channels[] =
+	if (initialized == 0)
 	{
-		"I1_LOW",
-		"V1_LOW",
-		"V_HIGH"
-	};
+		_initialize();
+	}
 
-	const char* adc2_channels[] =
-	{
-		"I2_LOW",
-		"V2_LOW",
-		"I_HIGH"
-	};
+	/////
+	// Proceed
 
-	configure_adc_channels(1, adc1_channels, number_of_channels_adc1);
-	configure_adc_channels(2, adc2_channels, number_of_channels_adc2);
+	adc_start();
 }
 
-
-void configure_adc_default_all_measurements_and_extra()
+void stop_adcs()
 {
-	uint8_t number_of_channels_adc1 = 3;
-	uint8_t number_of_channels_adc2 = 4;
+	/////
+	// Make sure module is initialized
 
-	const char* adc1_channels[] =
+	if (initialized == 0)
 	{
-		"I1_LOW",
-		"V1_LOW",
-		"V_HIGH"
-	};
+		_initialize();
+	}
 
-	const char* adc2_channels[] =
-	{
-		"I2_LOW",
-		"V2_LOW",
-		"I_HIGH",
-		"EXTRA_MEAS"
-	};
-
-	configure_adc_channels(1, adc1_channels, number_of_channels_adc1);
-	configure_adc_channels(2, adc2_channels, number_of_channels_adc2);
+	/////
+	// Proceed
+
+	adc_stop();
 }
+
diff --git a/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.h b/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.h
index 4a72905f9ba8d51b734813ec7a0a0da12a1167cf..43c1aff9984448b24845e79c9c6d64bf4f3a12b9 100644
--- a/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.h
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 LAAS-CNRS
+ * Copyright (c) 2022-2023 LAAS-CNRS
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published by
@@ -18,7 +18,7 @@
  */
 
 /**
- * @date   2022
+ * @date   2023
  *
  * @author Clément Foucher <clement.foucher@laas.fr>
  */
@@ -39,82 +39,69 @@
 // Public API
 
 /**
- * Use this function to set ADC 1 and ADC 2 in dual mode.
- * By default, ADC 1 and 2 are not in dual mode.
+ * @brief This function is used to change the trigger source of an ADC.
+ *        By default, triggger source for ADC 1 and ADC 2 is on HRTIM1,
+ *        and ADC 3 is software-triggered.
  *
- * This function must be called BEFORE ADC is started.
+ *        This function must be called BEFORE ADC is started.
  *
- * @param  dual_mode Status of the dual mode:
- *         true to enable,
- *         false to disable.
+ * @param  adc_number Number of the ADC to configure
+ * @param  trigger_source Source of the trigger
  */
-void configure_adc12_dual_mode(uint8_t dual_mode);
+void configure_adc_trigger_source(uint8_t adc_number, adc_ev_src_t trigger_source);
 
 /**
- * This function is used to configure the channels to be
- * enabled on a given ADC.
- *
- * This function must be called BEFORE ADC is started.
+ * @brief Register the discontinuous count for an ADC.
+ *        It will be applied when ADC is started.
  *
- * @param  adc_number Number of the ADC on which channel configuration is
- *         to be done.
- * @param  channel_list List of channels to configure. This is a list of
- *         names as defined in the device tree (field `label`). The order
- *         of the names in the array sets the acquisition ranks (order in
- *         which the channels are acquired).
- * @param  channel_count Number of channels defined in `channel_list`.
- * @return 0 is everything went well,
- *         ECHANNOTFOUND if at least one of the channels
- *           is not available in the given ADC. Available channels are the
- *           ones defined in the device tree.
+ * @param adc_number Number of the ADC to configure.
+ * @param discontinuous_count Number of channels to acquire on each
+ *        trigger event. 0 to disable discontinuous mode (default).
  */
-int8_t configure_adc_channels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count);
+void configure_adc_discontinuous_mode(uint8_t adc_number, uint32_t discontinuous_count);
 
 /**
- * This function is used to change the trigger source of an ADC.
- * By default, triggger source for ADC 1 and ADC 2 is on HRTIM1,
- * and ADC 3 is software-triggered.
+ * @brief Adds a channel to the list of channels to be acquired
+ *        for an ADC.
+ *        The order in which channels are added determine
+ *        the order in which they will be acquired.
  *
- * This function must be called BEFORE ADC is started.
- *
- * @param  adc_number Number of the ADC to configure
- * @param  trigger_source Source of the trigger
+ * @param adc_number Number of the ADC to configure.
+ * @param channel Number of the channel to to be acquired.
  */
-void configure_adc_trigger_source(uint8_t adc_number, adc_ev_src_t trigger_source);
+void configure_adc_add_channel(uint8_t adc_num, uint8_t channel);
 
 /**
- * Registers the discontinuous count for an ADC.
- * It will be applied when ADC is started.
+ * @brief Removes a channel from the list of channels
+ *        that are acquired by an ADC.
+ *        If a channel has been added multiple times,
+ *        then only the first occurence in the list
+ *        will be removed.
  *
  * @param adc_number Number of the ADC to configure.
- * @param dicontinuous_count Number of channels to acquire on each
- *        trigger event. 0 to disable discontinuous mode (default).
+ * @param channel Number of the channel to to no longer be acquired.
  */
-void configure_adc_discontinuous_mode(uint8_t adc_number, uint32_t dicontinuous_count);
+void configure_adc_remove_channel(uint8_t adc_num, uint8_t channel);
 
 /**
- * This function is used to configure all ADC channels in default configuration.
- * Channels will be attributed as follows:
- * ADC1 -   V1_LOW      ADC2 -  I1_LOW
- *          V2_LOW              I2_LOW
- *          V_HIGH              I_HIGH
+ * @brief ADC DMA mode configuration.
+ *        Enables DMA and circular mode on an ADC.
  *
- * This function must be called BEFORE ADC is started.
+ * @param adc_num Number of the ADC on which to enable DMA.
+ * @param use_dma Set to true to use DMA for this ADC,
+ *        false to not use it (default).
  */
-void configure_adc_default_all_measurements();
+void configure_adc_dma_mode(uint8_t adc_num, bool use_dma);
 
+/**
+ * @brief Starts all configured ADCs.
+ */
+void start_adcs();
 
 /**
- * This function is used to configure all ADC channels in default configuration.
- * Channels will be attributed as follows:
- * ADC1 -   V1_LOW      ADC2 -  I1_LOW
- *          V2_LOW              I2_LOW
- *          V_HIGH              I_HIGH
- *                              EXTRA_MEAS
- *
- * This function must be called BEFORE ADC is started.
+ * @brief Stops all configured ADCs.
  */
-void configure_adc_default_all_measurements_and_extra();
+void stop_adcs();
 
 
 #endif // ADC_CONFIGURATION_H_