From 6cf292ed476c32090ad813d04bdfcf59f3d2b7d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Foucher?= <cfoucher@laas.fr>
Date: Tue, 8 Mar 2022 10:42:34 +0000
Subject: [PATCH] Extract ADC configuration functions as an independent module.

---
 README.md                                     |   8 +-
 .../owntech_adc_driver/zephyr/CMakeLists.txt  |  15 ++
 .../modules/owntech_adc_driver/zephyr/Kconfig |   4 +
 .../owntech_adc_driver/zephyr/module.yml      |   4 +
 .../zephyr/public_api}/adc.c                  |  25 ++-
 .../zephyr/public_api}/adc.h                  |  13 +-
 .../zephyr/public_api/adc_error_codes.h}      |   2 -
 .../zephyr/src}/adc_channels.c                |   2 +-
 .../zephyr/src}/adc_channels.h                |   0
 .../zephyr/src}/adc_core.c                    |   0
 .../zephyr/src}/adc_core.h                    |   0
 .../zephyr/src}/adc_helper.c                  |   0
 .../zephyr/src}/adc_helper.h                  |   0
 .../zephyr/CMakeLists.txt                     |   4 -
 .../owntech_data_acquisition/zephyr/Kconfig   |   2 +-
 .../zephyr/data_dispatch/data_dispatch.c      |   8 +-
 .../owntech_data_acquisition/zephyr/dma/dma.c |  14 +-
 .../zephyr/public_api/DataAcquisition.cpp     | 209 ++----------------
 .../zephyr/public_api/DataAcquisition.h       | 112 +---------
 .../zephyr/CMakeLists.txt                     |   1 +
 .../zephyr/Kconfig                            |   2 +
 .../public_api/HardwareConfiguration.cpp      |  25 +++
 .../zephyr/public_api/HardwareConfiguration.h |  77 ++++---
 .../zephyr/src/adc_configuration.cpp          | 145 ++++++++++++
 .../zephyr/src/adc_configuration.h            | 102 +++++++++
 zephyr/prj.conf                               |  16 +-
 26 files changed, 432 insertions(+), 358 deletions(-)
 create mode 100644 zephyr/modules/owntech_adc_driver/zephyr/CMakeLists.txt
 create mode 100644 zephyr/modules/owntech_adc_driver/zephyr/Kconfig
 create mode 100644 zephyr/modules/owntech_adc_driver/zephyr/module.yml
 rename zephyr/modules/{owntech_data_acquisition/zephyr/adc => owntech_adc_driver/zephyr/public_api}/adc.c (91%)
 rename zephyr/modules/{owntech_data_acquisition/zephyr/adc => owntech_adc_driver/zephyr/public_api}/adc.h (94%)
 rename zephyr/modules/{owntech_data_acquisition/zephyr/public_api/data_acquisition_error_codes.h => owntech_adc_driver/zephyr/public_api/adc_error_codes.h} (94%)
 rename zephyr/modules/{owntech_data_acquisition/zephyr/adc => owntech_adc_driver/zephyr/src}/adc_channels.c (99%)
 rename zephyr/modules/{owntech_data_acquisition/zephyr/adc => owntech_adc_driver/zephyr/src}/adc_channels.h (100%)
 rename zephyr/modules/{owntech_data_acquisition/zephyr/adc => owntech_adc_driver/zephyr/src}/adc_core.c (100%)
 rename zephyr/modules/{owntech_data_acquisition/zephyr/adc => owntech_adc_driver/zephyr/src}/adc_core.h (100%)
 rename zephyr/modules/{owntech_data_acquisition/zephyr/adc => owntech_adc_driver/zephyr/src}/adc_helper.c (100%)
 rename zephyr/modules/{owntech_data_acquisition/zephyr/adc => owntech_adc_driver/zephyr/src}/adc_helper.h (100%)
 create mode 100644 zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.cpp
 create mode 100644 zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.h

diff --git a/README.md b/README.md
index c3d4ceb..060143b 100644
--- a/README.md
+++ b/README.md
@@ -25,20 +25,19 @@ The hierarchy of the project is as follows:
 
 ```
 owntech_power_api
-└─ boards
-|  └─ nucleo_g474re.json
 └─ src
 |  └─ main.cpp
 |  └─ owntech.ini
 └─ zephyr
-|  └─ dts
+|  └─ boards
 |  └─ modules
 |  └─ [...]
 └─ LICENSE
+└─ README.md
 └─ [...]
 ```
 
-You will want to work in the `src` folder, other folders and files are used to configure the underlying Zephyr OS.
+You will want to work in the `src` folder, other folders and files are used to configure the underlying Zephyr OS and PlatformIO.
 Power users may want to tweak them too. Is so, please checkout the [Zephyr documentation](https://docs.zephyrproject.org/latest/).
 
 In the `src` folder, the file `main.cpp` is the entry point of the application.
@@ -50,3 +49,4 @@ The file `owntech.ini` is used to configure the Power API Libraries you want to
 To enable a Power API Library, edit the `src/owntech.ini` file.
 In this file, you'll find various commented libraries references.
 Simply uncomment a line to enable the corresponding library.
+You can also add any PlatformIO library in this file.
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/CMakeLists.txt b/zephyr/modules/owntech_adc_driver/zephyr/CMakeLists.txt
new file mode 100644
index 0000000..114e0ad
--- /dev/null
+++ b/zephyr/modules/owntech_adc_driver/zephyr/CMakeLists.txt
@@ -0,0 +1,15 @@
+if(CONFIG_OWNTECH_ADC_DRIVER)
+  # Select directory to add to the include path
+  zephyr_include_directories(./public_api)
+
+  # Define the current folder as a Zephyr library
+  zephyr_library()
+
+  # 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/Kconfig b/zephyr/modules/owntech_adc_driver/zephyr/Kconfig
new file mode 100644
index 0000000..56e382a
--- /dev/null
+++ b/zephyr/modules/owntech_adc_driver/zephyr/Kconfig
@@ -0,0 +1,4 @@
+config OWNTECH_ADC_DRIVER
+	bool "Enable OwnTech ADC driver for STM32"
+	default y
+	depends on !ADC
diff --git a/zephyr/modules/owntech_adc_driver/zephyr/module.yml b/zephyr/modules/owntech_adc_driver/zephyr/module.yml
new file mode 100644
index 0000000..a228308
--- /dev/null
+++ b/zephyr/modules/owntech_adc_driver/zephyr/module.yml
@@ -0,0 +1,4 @@
+name: owntech_adc_driver
+build:
+  cmake: zephyr
+  kconfig: zephyr/Kconfig
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.c b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.c
similarity index 91%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.c
rename to zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.c
index 630f393..a6d702f 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.c
+++ b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.c
@@ -24,15 +24,15 @@
  */
 
 
-// Stdlib
-#include <stdint.h>
-
 // STM32 LL
 #include <stm32g4xx_ll_adc.h>
 
 // OwnTech API
-#include "adc_channels.h"
-#include "adc_core.h"
+#include "../src/adc_channels.h"
+#include "../src/adc_core.h"
+
+// Current file header
+#include "adc.h"
 
 
 /////
@@ -81,7 +81,9 @@ void adc_start()
 	for (uint8_t i = 0 ; i < 3 ; i++)
 	{
 		if (enabled_channels_count[i] > 0)
+		{
 			adc_core_enable(i+1);
+		}
 	}
 
 	/////
@@ -89,7 +91,9 @@ void adc_start()
 	for (uint8_t i = 0 ; i < 3 ; i++)
 	{
 		if (enabled_channels_count[i] > 0)
+		{
 			adc_channels_configure(i+1);
+		}
 	}
 
 	/////
@@ -97,13 +101,17 @@ void adc_start()
 	for (uint8_t i = 0 ; i < 3 ; i++)
 	{
 		if (enabled_channels_count[i] > 0)
+		{
 			adc_core_configure_dma_mode(i+1);
+		}
 	}
 
 	for (uint8_t i = 0 ; i < 3 ; i++)
 	{
 		if ( (enabled_channels_count[i] > 0) && (adc_trigger_sources[i] != 0) )
+		{
 			adc_core_configure_trigger_source(i+1, LL_ADC_REG_TRIG_EXT_RISING, adc_trigger_sources[i]);
+		}
 	}
 
 	/////
@@ -111,7 +119,9 @@ void adc_start()
 	for (uint8_t i = 0 ; i < 3 ; i++)
 	{
 		if (enabled_channels_count[i] > 0)
+		{
 			adc_core_start(i+1);
+		}
 	}
 }
 
@@ -119,3 +129,8 @@ const char* adc_get_channel_name(uint8_t adc_number, uint8_t channel_rank)
 {
 	return adc_channels_get_channel_name(adc_number, channel_rank);
 }
+
+uint8_t adc_get_enabled_channels_count(uint8_t adc_num)
+{
+	return adc_channels_get_enabled_channels_count(adc_num);
+}
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.h b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.h
similarity index 94%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.h
rename to zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.h
index 31fea1f..a7d6a7c 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.h
+++ b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc.h
@@ -31,11 +31,6 @@
  *
  * To use this driver, first call adc_init(), then call
  * required configuration functions, then call adc_start().
- *
- * This file is the entry point of the ADC management.
- * Only this header file provides public functions for the
- * ADC. No other header from this folder should be included
- * in files outside this folder.
  */
 
 
@@ -43,6 +38,7 @@
 #define ADC_H_
 
 
+// Stdlib
 #include <stdint.h>
 
 
@@ -95,6 +91,13 @@ void adc_configure_trigger_source(uint8_t adc_number, uint32_t trigger_source);
  */
 int8_t adc_configure_adc_channels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count);
 
+/**
+ * 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_get_enabled_channels_count(uint8_t adc_num);
+
 /**
  * @brief Starts all configured ADCs.
  */
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/public_api/data_acquisition_error_codes.h b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc_error_codes.h
similarity index 94%
rename from zephyr/modules/owntech_data_acquisition/zephyr/public_api/data_acquisition_error_codes.h
rename to zephyr/modules/owntech_adc_driver/zephyr/public_api/adc_error_codes.h
index f8058c5..adaa1e1 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/public_api/data_acquisition_error_codes.h
+++ b/zephyr/modules/owntech_adc_driver/zephyr/public_api/adc_error_codes.h
@@ -30,8 +30,6 @@
 #define NOERROR          0
 
 #define ECHANNOTFOUND   -1
-#define EALREADYSTARTED -2
-#define ECHANUNCONF     -3
 
 
 #endif // DATAACQUISITONERRORCODES_H_
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.c b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.c
similarity index 99%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.c
rename to zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.c
index b082249..3f25f13 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.c
+++ b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.c
@@ -40,7 +40,7 @@
 
 // OwnTech API
 #include "adc_helper.h"
-#include "data_acquisition_error_codes.h"
+#include "adc_error_codes.h"
 
 
 /////
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.h b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.h
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.h
rename to zephyr/modules/owntech_adc_driver/zephyr/src/adc_channels.h
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.c b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.c
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.c
rename to zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.c
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.h b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.h
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.h
rename to zephyr/modules/owntech_adc_driver/zephyr/src/adc_core.h
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.c b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.c
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.c
rename to zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.c
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.h b/zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.h
similarity index 100%
rename from zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.h
rename to zephyr/modules/owntech_adc_driver/zephyr/src/adc_helper.h
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt b/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt
index 862d127..def8f47 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt
@@ -7,10 +7,6 @@ if(CONFIG_OWNTECH_DATA_ACQUISITION)
 
   # Select source files to be compiled
   zephyr_library_sources(
-    ./adc/adc.c
-    ./adc/adc_channels.c
-    ./adc/adc_core.c
-    ./adc/adc_helper.c
     ./dma/dma.c
     ./data_dispatch/data_dispatch.c
 	./data_conversion/data_conversion.c
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/Kconfig b/zephyr/modules/owntech_data_acquisition/zephyr/Kconfig
index 3265b02..e4c6765 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/Kconfig
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/Kconfig
@@ -2,4 +2,4 @@ config OWNTECH_DATA_ACQUISITION
 	bool "Enable OwnTech data acquisition using ADCs"
 	default y
 	select DMA
-	depends on !ADC
+	depends on OWNTECH_ADC_DRIVER
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/data_dispatch/data_dispatch.c b/zephyr/modules/owntech_data_acquisition/zephyr/data_dispatch/data_dispatch.c
index bfa26fb..3c672b7 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/data_dispatch/data_dispatch.c
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/data_dispatch/data_dispatch.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 LAAS-CNRS
+ * Copyright (c) 2021-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
@@ -18,6 +18,8 @@
  */
 
 /**
+ * @date   2022
+ *
  * @author Clément Foucher <clement.foucher@laas.fr>
  */
 
@@ -30,7 +32,7 @@
 #include <zephyr.h>
 
 // OwnTech API
-#include "../adc/adc_channels.h"
+#include "adc.h"
 
 
 /////
@@ -105,7 +107,7 @@ void data_dispatch_init(uint8_t adc_count)
 
 	for (int adc_index = 0 ; adc_index < number_of_adcs ; adc_index++)
 	{
-		enabled_channels_count[adc_index] = adc_channels_get_enabled_channels_count(adc_index+1);
+		enabled_channels_count[adc_index] = adc_get_enabled_channels_count(adc_index+1);
 		if (enabled_channels_count[adc_index] > 0)
 		{
 			// Prepare arrays for each channel
diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.c b/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.c
index 59fcf45..6a446c9 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.c
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 LAAS-CNRS
+ * Copyright (c) 2021-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
@@ -18,6 +18,10 @@
  */
 
 /**
+ * @date   2022
+ *
+ * @author Clément Foucher <clement.foucher@laas.fr>
+ *
  * @brief  DMA configuration for OwnTech application.
  * One DMA channel is assigned per ADC. For each ADC, the DMA
  * has a buffer sized 2*(number of enabled channels in ADC),
@@ -26,8 +30,6 @@
  * is available to data dispatch.
  * DMA 1 is used for all acquisitions, with channel i
  * acquiring values from ADC i.
- *
- * @author Clément Foucher <clement.foucher@laas.fr>
  */
 
 
@@ -42,8 +44,8 @@
 #include <stm32g4xx_ll_dma.h>
 
 // OwnTech API
+#include "adc.h"
 #include "../data_dispatch/data_dispatch.h"
-#include "../adc/adc_channels.h"
 
 
 /////
@@ -113,7 +115,7 @@ static void _dma_callback(const struct device* dev, void* user_data, uint32_t ch
 static void _dma_channel_init(uint8_t adc_num, uint32_t source_address, uint32_t source_trigger)
 {
 	// Prepare buffers
-	uint8_t enabled_channels = adc_channels_get_enabled_channels_count(adc_num);
+	uint8_t enabled_channels = adc_get_enabled_channels_count(adc_num);
 	size_t dma_buffer_size = enabled_channels * sizeof(uint16_t) * 2;
 	uint8_t adc_index = adc_num - 1;
 
@@ -160,7 +162,7 @@ void dma_configure_and_start(uint8_t adc_count)
 	for (uint8_t adc_index = 0 ; adc_index < adc_count ; adc_index++)
 	{
 		uint8_t adc_num = adc_index +1;
-		if (adc_channels_get_enabled_channels_count(adc_num) > 0)
+		if (adc_get_enabled_channels_count(adc_num) > 0)
 		{
 			_dma_channel_init(adc_num, source_registers[adc_index], source_triggers[adc_index]);
 			dma_start(dma1, adc_num);
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 aac77f1..3b4dea8 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.cpp
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.cpp
@@ -19,6 +19,7 @@
 
 /**
  * @date   2022
+ *
  * @author Clément Foucher <clement.foucher@laas.fr>
  * @author Luiz Villa <luiz.villa@laas.fr>
  */
@@ -27,15 +28,11 @@
 // Stdlib
 #include <string.h>
 
-// STM32 LL
-#include <stm32g4xx_ll_adc.h>
-
 // OwnTech Power API
-#include "../adc/adc.h"
+#include "adc.h"
 #include "../dma/dma.h"
 #include "../data_dispatch/data_dispatch.h"
 #include "../data_conversion/data_conversion.h"
-#include "data_acquisition_error_codes.h"
 
 // Current class header
 #include "DataAcquisition.h"
@@ -50,10 +47,6 @@ DataAcquisition dataAcquisition;
 /////
 // Initialize static members
 
-uint8_t DataAcquisition::initialized         = 0;
-uint8_t DataAcquisition::channels_configured = 0;
-uint8_t DataAcquisition::started             = 0;
-
 DataAcquisition::channel_assignment_t DataAcquisition::v1_low_assignement      = {0};
 DataAcquisition::channel_assignment_t DataAcquisition::v2_low_assignement      = {0};
 DataAcquisition::channel_assignment_t DataAcquisition::v_high_assignement      = {0};
@@ -64,22 +57,7 @@ DataAcquisition::channel_assignment_t DataAcquisition::temp_sensor_assignement =
 
 
 /////
-// Private members
-
-void DataAcquisition::initialize()
-{
-	if (initialized == 0)
-	{
-		// Initialize the ADCs
-		adc_init();
-		initialized = 1;
-
-		// Perform default configration
-		configureAdcTriggerSource(1, hrtim1);
-		configureAdcTriggerSource(2, hrtim1);
-		configureAdcTriggerSource(3, software);
-	}
-}
+// Public static configuration functions
 
 void  DataAcquisition::setChannnelAssignment(uint8_t adc_number, const char* channel_name, uint8_t channel_rank)
 {
@@ -120,184 +98,45 @@ void  DataAcquisition::setChannnelAssignment(uint8_t adc_number, const char* cha
 	}
 }
 
-
-/////
-// Public static configuration functions
-
-int8_t DataAcquisition::configureAdc12DualMode(uint8_t dual_mode)
-{
-	/////
-	// Guard
-
-	if (started == 1)
-	{
-		return EALREADYSTARTED;
-	}
-
-	/////
-	// Make sure module is initialized
-
-	if (initialized == 0)
-	{
-		initialize();
-	}
-
-	/////
-	// Proceed
-
-	adc_set_dual_mode(dual_mode);
-
-	return NOERROR;
-}
-
-int8_t DataAcquisition::configureAdcChannels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count)
-{
-	/////
-	// Guard
-
-	if (started == 1)
-	{
-		return EALREADYSTARTED;
-	}
-
-	/////
-	// Make sure module is initialized
-
-	if (initialized == 0)
-	{
-		initialize();
-	}
-
-	/////
-	// Proceed
-
-	int8_t result = adc_configure_adc_channels(adc_number, channel_list, channel_count);
-
-	if (result != 0)
-	{
-		return result;
-	}
-
-	for (int rank = 0 ; rank < channel_count ; rank++)
-	{
-		setChannnelAssignment(adc_number, channel_list[rank], rank);
-	}
-
-	channels_configured = 1;
-
-	return NOERROR;
-}
-
-int8_t DataAcquisition::configureAdcTriggerSource(uint8_t adc_number, adc_src_t trigger_source)
+void DataAcquisition::start()
 {
-	/////
-	// Guard
+	uint8_t number_of_adcs = 2;
 
-	if (started == 1)
+	for (uint8_t adc_num = 1 ; adc_num <= number_of_adcs ; adc_num++)
 	{
-		return EALREADYSTARTED;
-	}
+		uint8_t channel_rank = 0;
+
+		while (1)
+		{
+			const char* channel_name = adc_get_channel_name(adc_num, channel_rank);
+
+			if (channel_name != NULL)
+			{
+				setChannnelAssignment(adc_num, channel_name, channel_rank);
+				channel_rank++;
+			}
+			else
+			{
+				break;
+			}
+		}
 
-	/////
-	// Make sure module is initialized
-
-	if (initialized == 0)
-	{
-		initialize();
-	}
-
-	/////
-	// Proceed
-	uint32_t trig;
-	switch (trigger_source)
-	{
-	case hrtim1:
-		trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG1;
-		break;
-	case software:
-	default:
-		trig = LL_ADC_REG_TRIG_SOFTWARE;
-		break;
 	}
 
-	adc_configure_trigger_source(adc_number, trig);
-
-	return NOERROR;
-}
-
-int8_t DataAcquisition::configureAdcDefaultAllMeasurements()
-{
-	uint8_t init_status;
-
-	uint8_t number_of_channels_adc1 = 3;
-	uint8_t number_of_channels_adc2 = 3;
-
-	const char* adc1_channels[] =
-	{
-		"V1_LOW",
-		"V2_LOW",
-		"V_HIGH"
-	};
-
-	const char* adc2_channels[] =
-	{
-		"I1_LOW",
-		"I2_LOW",
-		"I_HIGH"
-	};
-
-	init_status = dataAcquisition.configureAdcChannels(1, adc1_channels, number_of_channels_adc1);
-
-	if (init_status != NOERROR)
-	{
-		return init_status;
-	}
-
-	init_status = dataAcquisition.configureAdcChannels(2, adc2_channels, number_of_channels_adc2);
-
-	return NOERROR;
-}
-
-int8_t DataAcquisition::start()
-{
-	/////
-	// Guards
-
-	if (channels_configured == 0)
-	{
-		return ECHANUNCONF;
-	}
-	else if (started == 1)
-	{
-		return EALREADYSTARTED;
-	}
-
-	/////
-	// Proceed
-
 	// DMAs
-	dma_configure_and_start(2);
+	dma_configure_and_start(number_of_adcs);
 
 	// Initialize data dispatch
-	data_dispatch_init(2);
+	data_dispatch_init(number_of_adcs);
 
 	// Launch ADC conversion
 	adc_start();
-
-	started = 1;
-
-	return NOERROR;
 }
 
 
 /////
 // Public static accessors
 
-const char* DataAcquisition::getChannelName(uint8_t adc_number, uint8_t channel_rank)
-{
-	return adc_get_channel_name(adc_number, channel_rank);
-}
-
 uint16_t* DataAcquisition::getV1LowRawValues(uint32_t& number_of_values_acquired)
 {
 	return data_dispatch_get_acquired_values(v1_low_assignement.adc_number, v1_low_assignement.channel_rank, &number_of_values_acquired);
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 06a4722..4085967 100644
--- a/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.h
+++ b/zephyr/modules/owntech_data_acquisition/zephyr/public_api/DataAcquisition.h
@@ -19,6 +19,7 @@
 
 /**
  * @date   2022
+ *
  * @author Clément Foucher <clement.foucher@laas.fr>
  */
 
@@ -34,13 +35,6 @@
 #include <arm_math.h>
 
 
-/////
-// Public enums
-typedef enum
-{
-	hrtim1,
-	software
-} adc_src_t;
 
 
 /////
@@ -48,116 +42,30 @@ typedef enum
 
 class DataAcquisition
 {
-
 private:
-
-	/**
-	 * This function initializes the Data Acquisition module.
-	 */
-	static void initialize();
-
 	/**
+	 * This function is used to indicate to the DataAcquisition module
+	 * what the underlying ADC channel configuration is.
 	 *
+	 * @param adc_number ADC number
+	 * @param channel_name Channel name
+	 * @param channel_rannk Channel rank
 	 */
 	static void setChannnelAssignment(uint8_t adc_number, const char* channel_name, uint8_t channel_rank);
 
 public:
 
-	/**
-	 * Use this function to set ADC 1 and ADC 2 in dual mode.
-	 * By default, ADC 1 and 2 are not in dual mode.
-	 *
-	 * This function must be called BEFORE dataAcquisition.start().
-	 *
-	 * @param  dual_mode Status of the dual mode:
-	 *         true to enable,
-	 *         false to disable.
-	 * @return 0 is everything went well,
-	 *         EALREADYSTARTED if the module has already been started.
-	 */
-	static int8_t configureAdc12DualMode(uint8_t dual_mode);
-
-	/**
-	 * This function is used to configure the channels to be
-	 * enabled on a given ADC.
-	 *
-	 * This function must be called BEFORE dataAcquisition.start().
-	 *
-	 * @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.
-	 *         EALREADYSTARTED if the module has already been started.
-	 */
-	static int8_t configureAdcChannels(uint8_t adc_number, const char* channel_list[], uint8_t channel_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.
-	 *
-	 * This function must be called BEFORE dataAcquisition.start().
-	 *
-	 * @param  adc_number Number of the ADC to configure
-	 * @param  trigger_source Source of the trigger
-	 * @return 0 is everything went well,
-	 *         EALREADYSTARTED if the module has already been started.
-	 */
-	static int8_t configureAdcTriggerSource(uint8_t adc_number, adc_src_t trigger_source);
-
-	/**
-	 * 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 dataAcquisition.start().
-	 *
-	 * @return 0 is everything went well,
-	 *         EALREADYSTARTED if the module has already been started.
-	 */
-	static int8_t configureAdcDefaultAllMeasurements();
-
 	/**
 	 * This functions starts the acquisition chain. It must be called
-	 * after all module configuration has been carried out. No
+	 * after all module configuration has been carried out. No ADC
 	 * configuration change is allowed after module has been started.
-	 *
-	 * @return 0 is everything went well,
-	 *         EUNITITIALIZED if the module has not been initialized,
-	 *         EALREADYSTARTED if the module has already been started,
-	 *         ECHANUNCONF if the channel configuration has not been done.
 	 */
-	static int8_t start();
+	static void start();
 
 
 	/////
 	// Accessor API
 
-	/**
-	 * This function returns the name of an enabled channel.
-	 *
-	 * This function must be called AFTER data_acquisition_init()
-	 * and AFTER data_acquisition_configure_adc_channels() function
-	 * has been called for this channel.
-	 *
-	 * @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.
-	 */
-	static const char* getChannelName(uint8_t adc_number, uint8_t channel_rank);
-
 	/**
 	 * Functions to access the acquired data for each channel.
 	 * Each function provides a buffer in which all data that
@@ -245,9 +153,7 @@ private:
 	} channel_assignment_t;
 
 private:
-	static uint8_t initialized;
-	static uint8_t channels_configured;
-	static uint8_t started;
+
 
 	static channel_assignment_t v1_low_assignement;
 	static channel_assignment_t v2_low_assignement;
diff --git a/zephyr/modules/owntech_hardware_configuration/zephyr/CMakeLists.txt b/zephyr/modules/owntech_hardware_configuration/zephyr/CMakeLists.txt
index 4a51bbb..6565eb7 100644
--- a/zephyr/modules/owntech_hardware_configuration/zephyr/CMakeLists.txt
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/CMakeLists.txt
@@ -14,6 +14,7 @@ if(CONFIG_OWNTECH_HARDWARE_CONFIGURATION)
 	src/timer_configuration.cpp
 	src/hrtim_configuration.cpp
 	src/uart_configuration.cpp
+	src/adc_configuration.cpp
 	public_api/HardwareConfiguration.cpp
     )
 endif()
diff --git a/zephyr/modules/owntech_hardware_configuration/zephyr/Kconfig b/zephyr/modules/owntech_hardware_configuration/zephyr/Kconfig
index 5793393..ae5ec6b 100644
--- a/zephyr/modules/owntech_hardware_configuration/zephyr/Kconfig
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/Kconfig
@@ -1,6 +1,8 @@
 config OWNTECH_HARDWARE_CONFIGURATION
 	bool "Enable OwnTech hardware configuration module"
 	default y
+	depends on OWNTECH_ADC_DRIVER
 	depends on OWNTECH_DAC_DRIVER
+	depends on OWNTECH_HRTIM_DRIVER
 	depends on OWNTECH_NGND_DRIVER
 	depends on OWNTECH_TIMER_DRIVER
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 2f431ae..19de4f2 100644
--- a/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.cpp
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.cpp
@@ -30,6 +30,7 @@
 #include "../src/timer_configuration.h"
 #include "../src/hrtim_configuration.h"
 #include "../src/uart_configuration.h"
+#include "../src/adc_configuration.h"
 
 // Current class header
 #include "HardwareConfiguration.h"
@@ -225,3 +226,27 @@ void HardwareConfiguration::extraUartWriteChar(char data)
 {
 	uart_usart1_write_single(data);
 }
+
+
+/////
+// ADC
+
+void HardwareConfiguration::configureAdc12DualMode(uint8_t dual_mode)
+{
+	configure_adc12_dual_mode(dual_mode);
+}
+
+int8_t HardwareConfiguration::configureAdcChannels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count)
+{
+	return configure_adc_channels(adc_number, channel_list, channel_count);
+}
+
+void HardwareConfiguration::configureAdcTriggerSource(uint8_t adc_number, adc_src_t trigger_source)
+{
+	configure_adc_trigger_source(adc_number, trigger_source);
+}
+
+void HardwareConfiguration::configureAdcDefaultAllMeasurements()
+{
+	configure_adc_default_all_measurements();
+}
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 7688385..4a66b41 100644
--- a/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.h
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/public_api/HardwareConfiguration.h
@@ -26,10 +26,15 @@
 #ifndef HARDWARECONFIGURATION_H_
 #define HARDWARECONFIGURATION_H_
 
-
+// Std lib
 #include <stdint.h>
+
+// ARM lib
 #include <arm_math.h>
 
+// OwnTech API
+#include "../src/adc_configuration.h"
+
 
 /** Hardware version. See
  *  https://gitlab.laas.fr/owntech/1leg/-/wikis/Releases
@@ -51,50 +56,56 @@ class HardwareConfiguration
 
 public:
 	// Common
-	void setBoardVersion(hardware_version_t hardware_version);
+	static void setBoardVersion(hardware_version_t hardware_version);
 
 	// DAC
-	void initDac1Dac3CurrentMode();
+	static void initDac1Dac3CurrentMode();
 
 	// NGND
-	void setNgndOn();
-	void setNgndOff();
+	static void setNgndOn();
+	static void setNgndOff();
 
 	// LED
-	void setLedOn();
-	void setLedOff();
-	void setLedToggle();
+	static void setLedOn();
+	static void setLedOff();
+	static void setLedToggle();
 
 	// Incremental encoder
-	void startLoggingIncrementalEncoder();
-	uint32_t getIncrementalEncoderValue();
+	static void startLoggingIncrementalEncoder();
+	static uint32_t getIncrementalEncoderValue();
 
 	// Power converter
-	void initInterleavedBuckMode();
-	void initInterleavedBoostMode();
-	void initFullBridgeBuckMode();
-	void initFullBridgeBoostMode();
-	void initIndependentMode(bool leg1_buck_mode, bool leg2_buck_mode);
-
-	void setInterleavedDutyCycle(float32_t duty_cycle);
-	void setFullBridgeDutyCycle(float32_t duty_cycle);
-	void setLeg1DutyCycle(float32_t duty_cycle);
-	void setLeg2DutyCycle(float32_t duty_cycle);
-
-	void setInterleavedOn();
-	void setFullBridgeOn();
-	void setLeg1On();
-	void setLeg2On();
-
-	void setInterleavedOff();
-	void setFullBridgeOff();
-	void setLeg1Off();
-	void setLeg2Off();
+	static void initInterleavedBuckMode();
+	static void initInterleavedBoostMode();
+	static void initFullBridgeBuckMode();
+	static void initFullBridgeBoostMode();
+	static void initIndependentMode(bool leg1_buck_mode, bool leg2_buck_mode);
+
+	static void setInterleavedDutyCycle(float32_t duty_cycle);
+	static void setFullBridgeDutyCycle(float32_t duty_cycle);
+	static void setLeg1DutyCycle(float32_t duty_cycle);
+	static void setLeg2DutyCycle(float32_t duty_cycle);
+
+	static void setInterleavedOn();
+	static void setFullBridgeOn();
+	static void setLeg1On();
+	static void setLeg2On();
+
+	static void setInterleavedOff();
+	static void setFullBridgeOff();
+	static void setLeg1Off();
+	static void setLeg2Off();
 
 	// Extra UART
-	void extraUartInit();
-	char extraUartReadChar();
-	void extraUartWriteChar(char data);
+	static void extraUartInit();
+	static char extraUartReadChar();
+	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_src_t trigger_source);
+	static void configureAdcDefaultAllMeasurements();
 
 };
 
diff --git a/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.cpp b/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.cpp
new file mode 100644
index 0000000..0c1b3e8
--- /dev/null
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2021-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>
+ */
+
+
+// STM32 LL
+#include <stm32g4xx_ll_adc.h>
+
+// OwnTech Power API
+#include "adc.h"
+
+// Current file headers
+#include "adc_configuration.h"
+#include "adc_error_codes.h"
+
+
+static uint8_t initialized;
+static uint8_t channels_configured;
+
+
+void _initialize()
+{
+	if (initialized == 0)
+	{
+		// Initialize the ADCs
+		adc_init();
+		initialized = 1;
+
+		// Perform default configration
+		configure_adc_trigger_source(1, hrtim1);
+		configure_adc_trigger_source(2, hrtim1);
+		configure_adc_trigger_source(3, software);
+	}
+}
+
+void configure_adc12_dual_mode(uint8_t dual_mode)
+{
+	/////
+	// Make sure module is initialized
+
+	if (initialized == 0)
+	{
+		_initialize();
+	}
+
+	/////
+	// Proceed
+
+	adc_set_dual_mode(dual_mode);
+}
+
+int8_t configure_adc_channels(uint8_t adc_number, const char* channel_list[], uint8_t channel_count)
+{
+	/////
+	// Make sure module is initialized
+
+	if (initialized == 0)
+	{
+		_initialize();
+	}
+
+	/////
+	// Proceed
+
+	int8_t result = adc_configure_adc_channels(adc_number, channel_list, channel_count);
+
+	if (result != NOERROR)
+	{
+		return result;
+	}
+
+	channels_configured = 1;
+
+	return NOERROR;
+}
+
+void configure_adc_trigger_source(uint8_t adc_number, adc_src_t trigger_source)
+{
+	/////
+	// Make sure module is initialized
+
+	if (initialized == 0)
+	{
+		_initialize();
+	}
+
+	/////
+	// Proceed
+	uint32_t trig;
+	switch (trigger_source)
+	{
+	case hrtim1:
+		trig = LL_ADC_REG_TRIG_EXT_HRTIM_TRG1;
+		break;
+	case software:
+	default:
+		trig = LL_ADC_REG_TRIG_SOFTWARE;
+		break;
+	}
+
+	adc_configure_trigger_source(adc_number, trig);
+}
+
+void configure_adc_default_all_measurements()
+{
+	uint8_t number_of_channels_adc1 = 3;
+	uint8_t number_of_channels_adc2 = 3;
+
+	const char* adc1_channels[] =
+	{
+		"V1_LOW",
+		"V2_LOW",
+		"V_HIGH"
+	};
+
+	const char* adc2_channels[] =
+	{
+		"I1_LOW",
+		"I2_LOW",
+		"I_HIGH"
+	};
+
+	configure_adc_channels(1, adc1_channels, number_of_channels_adc1);
+	configure_adc_channels(2, adc2_channels, number_of_channels_adc2);
+}
diff --git a/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.h b/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.h
new file mode 100644
index 0000000..d08e852
--- /dev/null
+++ b/zephyr/modules/owntech_hardware_configuration/zephyr/src/adc_configuration.h
@@ -0,0 +1,102 @@
+/*
+ * 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 ADC_CONFIGURATION_H_
+#define ADC_CONFIGURATION_H_
+
+
+// Stdlib
+#include <stdint.h>
+
+
+/////
+// Public enums
+typedef enum
+{
+	hrtim1,
+	software
+} adc_src_t;
+
+
+/////
+// 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.
+ *
+ * This function must be called BEFORE ADC is started.
+ *
+ * @param  dual_mode Status of the dual mode:
+ *         true to enable,
+ *         false to disable.
+ */
+void configure_adc12_dual_mode(uint8_t dual_mode);
+
+/**
+ * This function is used to configure the channels to be
+ * enabled on a given ADC.
+ *
+ * This function must be called BEFORE 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.
+ */
+int8_t configure_adc_channels(uint8_t adc_number, const char* channel_list[], uint8_t channel_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.
+ *
+ * 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
+ */
+void configure_adc_trigger_source(uint8_t adc_number, adc_src_t trigger_source);
+
+/**
+ * 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();
+
+
+#endif // ADC_CONFIGURATION_H_
diff --git a/zephyr/prj.conf b/zephyr/prj.conf
index cc7241c..b59eb39 100644
--- a/zephyr/prj.conf
+++ b/zephyr/prj.conf
@@ -31,12 +31,16 @@ CONFIG_LOG=y
 # Enable assertions for debug purpose
 CONFIG_ASSERT=y
 
-# OwnTech modules: uncomment a line to exclude a module
-#CONFIG_OWNTECH_TIMER_DRIVER=n
-#CONFIG_OWNTECH_HRTIM_DRIVER=n
-#CONFIG_OWNTECH_NGND_DRIVER=n
+# OwnTech user API modules: uncomment a line to exclude a module
 #CONFIG_OWNTECH_DATA_ACQUISITION=n
-#CONFIG_OWNTECH_DAC_DRIVER=n
-#CONFIG_OWNTECH_COMPARATOR_DRIVER=n
 #CONFIG_OWNTECH_HARDWARE_CONFIGURATION=n
 #CONFIG_OWNTECH_SCHEDULING=n
+
+# OwnTech driver modules: uncomment a line to exclude a module
+# Warning: most driver modules are mandatory when user API modules are activated
+#CONFIG_OWNTECH_ADC_DRIVER=n
+#CONFIG_OWNTECH_COMPARATOR_DRIVER=n
+#CONFIG_OWNTECH_DAC_DRIVER=n
+#CONFIG_OWNTECH_HRTIM_DRIVER=n
+#CONFIG_OWNTECH_NGND_DRIVER=n
+#CONFIG_OWNTECH_TIMER_DRIVER=n
-- 
GitLab