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_