Commit 6cf292ed authored by Clément Foucher's avatar Clément Foucher
Browse files

Extract ADC configuration functions as an independent module.

parent 2618dd27
......@@ -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.
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()
config OWNTECH_ADC_DRIVER
bool "Enable OwnTech ADC driver for STM32"
default y
depends on !ADC
name: owntech_adc_driver
build:
cmake: zephyr
kconfig: zephyr/Kconfig
......@@ -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);
}
......@@ -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.
*/
......
......@@ -30,8 +30,6 @@
#define NOERROR 0
#define ECHANNOTFOUND -1
#define EALREADYSTARTED -2
#define ECHANUNCONF -3
#endif // DATAACQUISITONERRORCODES_H_
......@@ -40,7 +40,7 @@
// OwnTech API
#include "adc_helper.h"
#include "data_acquisition_error_codes.h"
#include "adc_error_codes.h"
/////
......
......@@ -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
......
......@@ -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
/*
* 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
......
/*
* 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);
......
......@@ -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);
......
......@@ -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