diff --git a/platformio.ini b/platformio.ini index 040aa5f736256f4b46772c1def8b9a3027d11591..5f90dae9621cfe1e22fce37b7b58305212680b5e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,7 +17,7 @@ extra_configs = src/owntech.ini framework = zephyr -platform = ststm32@14.1.0 +platform = ststm32@14.2.0 # Serial monitor baud rate monitor_speed = 115200 diff --git a/zephyr/dts/adc-channels.dtsi b/zephyr/dts/adc-channels.dtsi index b2727ceba18e85f205be9a5922a509e7fdefcc63..b7b5acd452e495766773ab9af86a9921035b67d8 100644 --- a/zephyr/dts/adc-channels.dtsi +++ b/zephyr/dts/adc-channels.dtsi @@ -1,34 +1,80 @@ / { mychannels: adc-inputs { compatible = "adc-inputs"; - v1-low { + + /* Voltage channels */ + + v1-low-adc1 { + io-channels = <&adc1 1>; + label = "V1_LOW"; + }; + + v1-low-adc2 { io-channels = <&adc2 1>; label = "V1_LOW"; }; - i1-low { - io-channels = <&adc1 2>; - label = "I1_LOW"; + v2-low-adc1 { + io-channels = <&adc1 6>; + label = "V2_LOW"; }; - v2-low { + v2-low-adc2 { io-channels = <&adc2 6>; label = "V2_LOW"; }; - i2-low { - io-channels = <&adc1 7>; - label = "I2_LOW"; + v-high-adc1 { + + io-channels = <&adc1 9>; + label = "V_HIGH"; }; - v-high { + v-high-adc2 { io-channels = <&adc2 9>; label = "V_HIGH"; }; - i-high { + /* Current channels */ + + i1-low-adc1 { + io-channels = <&adc1 2>; + label = "I1_LOW"; + }; + + i1-low-adc2 { + io-channels = <&adc2 2>; + label = "I1_LOW"; + }; + + i2-low-adc1 { + io-channels = <&adc1 7>; + label = "I2_LOW"; + }; + + i2-low-adc2 { + io-channels = <&adc2 7>; + label = "I2_LOW"; + }; + + i-high-adc1 { io-channels = <&adc1 8>; label = "I_HIGH"; }; + + i-high-adc2 { + io-channels = <&adc2 8>; + label = "I_HIGH"; + }; + + /* Temperature channel */ + + /* + temp-sensor { + io-channels = <&adc3 1>; + label = "TEMP_SENSOR"; + }; + */ + }; }; diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt b/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt index 5c9d9cb90d5624b6768cfe5b05a0da76af60164a..a49b0624d96360eb8cce77994eaa7ccd79bbc8c4 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt +++ b/zephyr/modules/owntech_data_acquisition/zephyr/CMakeLists.txt @@ -1,6 +1,6 @@ if(CONFIG_OWNTECH_DATA_ACQUISITION) - zephyr_include_directories(.) + zephyr_include_directories(./public_include) zephyr_library() zephyr_library_sources( diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.c b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.c index bde6cb59e09088d8c404e702b8236918a42829c5..fdf683f4aeea4ae4eb35ea1783756235bf034c9a 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.c +++ b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.c @@ -22,6 +22,9 @@ */ +// Stdlib +#include <stdint.h> + // STM32 LL #include <stm32g4xx_ll_adc.h> @@ -29,87 +32,86 @@ #include "adc_channels.h" #include "adc_core.h" - ///// -// Private functions - -/** - * ADC 1 OwnTech's specific configuration. - */ -static void _adc_configure_adc_1() -{ - // Set regular sequence length - LL_ADC_REG_SetSequencerLength(ADC1, adc_channels_get_channels_count(1)-1); - - // TO TEST - // Set discontinuous mode: first event triggers first channel conversion, - // next event will convert the next channel in the sequence, and so on - // until all channels are converted, then restart from fisrt channel. - // RM: 21.4.20 - //LL_ADC_REG_SetSequencerDiscont(ADC1, LL_ADC_REG_SEQ_DISCONT_1RANK); - - // Enable dma and circular mode - LL_ADC_REG_SetDMATransfer(ADC1, LL_ADC_REG_DMA_TRANSFER_UNLIMITED); - - ///// - // Set trigger source: only for ADC 1 as we operate in dual mode - // (ADC 2 triggered by ADC 1) - - // Enable external trigger on hrtim_adc_trg1 - LL_ADC_REG_SetTriggerEdge(ADC1, LL_ADC_REG_TRIG_EXT_RISING); - - // RM Table 163. adc_ext_trg21 hrtim_adc_trg1 EXTSEL = 0x10101 - LL_ADC_REG_SetTriggerSource(ADC1, LL_ADC_REG_TRIG_EXT_HRTIM_TRG1); -} - -/** - * ADC 2 OwnTech's specific configuration. - */ -static void _adc_configure_adc_2() -{ - // Set regular sequence length - LL_ADC_REG_SetSequencerLength(ADC2, adc_channels_get_channels_count(2)-1); - - // TO TEST - // Set discontinuous mode: first event triggers first channel conversion, - // next event will convert the next channel in the sequence, and so on - // until all channels are converted, then restart from fisrt channel. - // RM: 21.4.20 - //LL_ADC_REG_SetSequencerDiscont(ADC2, LL_ADC_REG_SEQ_DISCONT_1RANK); - - // Enable dma and circular mode - LL_ADC_REG_SetDMATransfer(ADC2, LL_ADC_REG_DMA_TRANSFER_UNLIMITED); -} +// Local variables +static uint32_t adc_trigger_sources[3]; ///// // Public API -/** - * Configure ADC and DMA according to OwnTech - * board requirements. - */ void adc_init() { - // Initialize ADC - adc_core_init(); - adc_core_set_dual_mode(); + for (int i = 0 ; i < 3 ; i++) + { + adc_trigger_sources[i] = 0; + } - // Initialize channels - adc_channels_init(); + adc_core_init(); + adc_channels_init(); +} - // Enable ADC - adc_core_enable(ADC1); - adc_core_enable(ADC2); +void adc_set_dual_mode(uint8_t dual_mode) +{ + adc_core_set_dual_mode(dual_mode); +} - // Perform post-enable ADC configuration - adc_channels_configure(ADC1); - adc_channels_configure(ADC2); +void adc_configure_trigger_source(uint8_t adc_number, uint32_t trigger_source) +{ + // Only store configuration: it must be applied after ADC enable + if (adc_number < 3) + adc_trigger_sources[adc_number-1] = trigger_source; +} - _adc_configure_adc_1(); - _adc_configure_adc_2(); +int8_t adc_configure_adc_channels(uint8_t adc_number, char* channel_list[], uint8_t channel_count) +{ + return adc_channnels_configure_adc_channels(adc_number, channel_list, channel_count); +} - // Finally, start ADCs - adc_core_start(ADC1); - adc_core_start(ADC2); +void adc_start() +{ + uint8_t enabled_channels_count[3]; + + for (uint8_t i = 0 ; i < 3 ; i++) + { + enabled_channels_count[i] = adc_channels_get_enabled_channels_count(i+1); + } + + ///// + // Enable ADCs + for (uint8_t i = 0 ; i < 3 ; i++) + { + if (enabled_channels_count[i] > 0) + adc_core_enable(i+1); + } + + ///// + // Configure ADCs channels + for (uint8_t i = 0 ; i < 3 ; i++) + { + if (enabled_channels_count[i] > 0) + adc_channels_configure(i+1); + } + + ///// + // Configure ADCs + 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]); + } + + ///// + // Finally, start ADCs + for (uint8_t i = 0 ; i < 3 ; i++) + { + if (enabled_channels_count[i] > 0) + adc_core_start(i+1); + } } diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.h b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.h index a06013a7d91b3866b13a3d85aa58eb601abd160a..506061dfdb63f0383201af1ed1d4732e52d17047 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.h +++ b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc.h @@ -19,22 +19,79 @@ /** * @author Clément Foucher <clement.foucher@laas.fr> - * @brief This is the main include for ADC configuration. + * + * @brief This is an ad-hoc ADC driver for OwnTech's + * application. It supports differential channel setup + * unlike Zephyr's STM32 driver. + * It configures ADC 1 and ADC 2, using a common clock + * which is AHB clock with a prescaler division by 4. + * ADC 3 is also enabled independently. + * + * To use this driver, first call adc_init(), then call + * required configuration functions, then call adc_start(). */ + #ifndef ADC_H_ #define ADC_H_ + +#include <stdint.h> + + #ifdef __cplusplus extern "C" { #endif /** - * @brief Initializes ADC1 and ADC2 driver. + * @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. + * + * @param dual_mode true to enable dual moode, false to + * disable it. false by default. + */ +void adc_set_dual_mode(uint8_t dual_mode); + +/** + * Regsters the triger source for an ADC. + * It will be applied when ADC is started. + * + * @param adc_number Number of the ADC to configure + * @param triggger_source Source of the trigger as defined + * in stm32gxx_ll_adc.h (LL_ADC_REG_TRIG_***) + */ +void adc_configure_trigger_source(uint8_t adc_number, uint32_t trigger_source); + +/** + * 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. + */ +int8_t adc_configure_adc_channels(uint8_t adc_number, char* channel_list[], uint8_t channel_count); + +/** + * @brief Starts all configured ADCs. + */ +void adc_start(); #ifdef __cplusplus } diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.c b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.c index 0e0f9357719ac8a52617a8f7916118b27034f416..ce458cc75d824ca646bde24e88793f3e9eb1c416 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.c +++ b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.c @@ -27,75 +27,161 @@ // Stdlib #include <stdlib.h> +#include <string.h> +#include <stdint.h> + +// Zephyr +#include <zephyr.h> // Current file header -#include "adc_channels_private.h" +#include "adc_channels.h" // OwnTech API +#include "data_acquisition.h" #include "adc_helper.h" -#include "adc_core.h" + + +///// +// Device-tree related defines + +typedef struct +{ + char* name; + bool is_differential; + uint8_t number; + char* adc; +} channel_prop_t; + +#define ADC_INPUTS_NODELABEL DT_NODELABEL(mychannels) + +// Channel properties +#define CHANNEL_NAME(node_id) DT_LABEL(node_id) +#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 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) \ + }, + +// Channel count. This is very dirty! +#define CHANNEL_COUNTER(node_id) +1 +#define CHANNEL_COUNT (DT_FOREACH_CHILD(ADC_INPUTS_NODELABEL, CHANNEL_COUNTER)) ///// // Variables -static channel_prop_t channels_props[] = +static channel_prop_t available_channels_props[] = { - DT_FOREACH_CHILD(ADC_INPUTS_NODELABEL, CHANNEL_WRITE_PROP) + DT_FOREACH_CHILD(ADC_INPUTS_NODELABEL, CHANNEL_WRITE_PROP) }; -static uint8_t channels_in_adc1_count; -static uint8_t channels_in_adc2_count; +// Number of available channels defined in device tree +static uint8_t adc1_available_channels_count; +static uint8_t adc2_available_channels_count; +static uint8_t adc3_available_channels_count; + +// List of available channels as defined in device tree. +// These are arrays (range 0 to adcX_available_channels_count-1) +// of pointers to channel definition in available_channels_props array. +static channel_prop_t** adc1_available_channels_list; +static channel_prop_t** adc2_available_channels_list; +static channel_prop_t** adc3_available_channels_list; -static channel_prop_t** adc1_channels_list; -static channel_prop_t** adc2_channels_list; +// Number of enabled channels defined by the user configuration +static uint8_t adc1_enabled_channels_count; +static uint8_t adc2_enabled_channels_count; +static uint8_t adc3_enabled_channels_count; + +// List of channels enabled by user configuration. +// These are arrays (range 0 to adcX_enabled_channels_count-1) +// of pointers to channel definition in available_channels_props array. +static channel_prop_t** adc1_enabled_channels_list; +static channel_prop_t** adc2_enabled_channels_list; +static channel_prop_t** adc3_enabled_channels_list; ///// // ADC channels private functions /** - * Counts device-tree configured channels in each ADC. + * Builds list of device-tree defined channels for each ADC. + */ +static void _adc_channels_build_available_channels_lists() +{ + // Count total number of channels + adc1_available_channels_count = 0; + adc2_available_channels_count = 0; + adc3_available_channels_count = 0; + + for (int i = 0 ; i < CHANNEL_COUNT ; i++) + { + uint8_t adc_number = _get_adc_number_by_name(available_channels_props[i].adc); + if (adc_number == 1) + { + adc1_available_channels_count++; + } + else if (adc_number == 2) + { + adc2_available_channels_count++; + } + else if (adc_number == 3) + { + adc3_available_channels_count++; + } + } + + // 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); + + int adc1_index = 0; + int adc2_index = 0; + int adc3_index = 0; + for (int i = 0 ; i < CHANNEL_COUNT ; i++) + { + uint8_t adc_number = _get_adc_number_by_name(available_channels_props[i].adc); + if (adc_number == 1) + { + adc1_available_channels_list[adc1_index] = &available_channels_props[i]; + adc1_index++; + } + else if (adc_number == 2) + { + adc2_available_channels_list[adc2_index] = &available_channels_props[i]; + adc2_index++; + } + else if (adc_number == 3) + { + adc3_available_channels_list[adc3_index] = &available_channels_props[i]; + adc3_index++; + } + } +} + +/** + * ADC differential channel set-up: + * Applies differential mode to specified channel. + * Refer to RM 21.4.7 */ -static void _adc_channels_count() -{ - // Count total number of channels - channels_in_adc1_count = 0; - channels_in_adc2_count = 0; - - for (int i = 0 ; i < CHANNEL_COUNT ; i++) - { - ADC_TypeDef* adc = _get_adc_by_name(channels_props[i].adc); - if (adc == ADC1) - { - channels_in_adc1_count++; - } - else if (adc == ADC2) - { - channels_in_adc2_count++; - } - } - - // Build a list of channels by ADC - adc1_channels_list = malloc(sizeof(channel_prop_t*) * channels_in_adc1_count); - adc2_channels_list = malloc(sizeof(channel_prop_t*) * channels_in_adc2_count); - - int adc1_index = 0; - int adc2_index = 0; - for (int i = 0 ; i < CHANNEL_COUNT ; i++) - { - ADC_TypeDef* adc = _get_adc_by_name(channels_props[i].adc); - if (adc == ADC1) - { - adc1_channels_list[adc1_index] = &channels_props[i]; - adc1_index++; - } - else if (adc == ADC2) - { - adc2_channels_list[adc2_index] = &channels_props[i]; - adc2_index++; - } - } +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 + ); + } + } /** @@ -104,148 +190,266 @@ static void _adc_channels_count() */ static void _adc_channels_differential_setup() { - for (int i = 0; i < CHANNEL_COUNT; i++) - { - if (channels_props[i].is_differential) - { - ADC_TypeDef* adc = _get_adc_by_name(channels_props[i].adc); - if (adc != NULL) - { - adc_core_set_channel_differential(adc, channels_props[i].number); - } - } - } + for (int i = 0; i < CHANNEL_COUNT; i++) + { + if (available_channels_props[i].is_differential) + { + _adc_channels_set_channel_differential(available_channels_props[i].adc, available_channels_props[i].number); + } + } } -/** - * Internal path setup. - * Currently done before ADC is enabled, - * but is is correct? No hint in RM on this. - */ -void _adc_channels_internal_path_setup() -{ - uint8_t vts = 0; - uint8_t vbat = 0; - uint8_t vref = 0; - - for (int i = 0 ; i < CHANNEL_COUNT ; i++) - { - if (channels_props[i].number == __LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_CHANNEL_TEMPSENSOR_ADC1)) - vts = 1; - if (channels_props[i].number == __LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_CHANNEL_VBAT)) - vbat = 1; - if (channels_props[i].number == __LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_CHANNEL_VREFINT)) - vref = 1; - } - - adc_core_configure_internal_paths(vts, vbat, vref); +static channel_prop_t** _adc_channels_get_enabled_channels_list(uint8_t adc_num) +{ + channel_prop_t** enabled_channels_list = NULL; + switch (adc_num) + { + case 1: + enabled_channels_list = adc1_enabled_channels_list; + break; + case 2: + enabled_channels_list = adc2_enabled_channels_list; + break; + case 3: + enabled_channels_list = adc3_enabled_channels_list; + break; + } + return enabled_channels_list; +} + +static channel_prop_t** _adc_channels_get_available_channels_list(uint8_t adc_num) +{ + channel_prop_t** available_channels_list = NULL; + switch (adc_num) + { + case 1: + available_channels_list = adc1_available_channels_list; + break; + case 2: + available_channels_list = adc2_available_channels_list; + break; + case 3: + available_channels_list = adc3_available_channels_list; + break; + } + return available_channels_list; +} + +static uint8_t _adc_channels_get_available_channels_count(uint8_t adc_num) +{ + uint8_t available_channels_count = 0; + switch (adc_num) + { + case 1: + available_channels_count = adc1_available_channels_count; + break; + case 2: + available_channels_count = adc2_available_channels_count; + break; + case 3: + available_channels_count = adc3_available_channels_count; + break; + } + return available_channels_count; +} + +static uint8_t _adc_channels_get_enabled_channels_count(uint8_t adc_num) +{ + uint8_t enabled_channels_count = 0; + switch (adc_num) + { + case 1: + enabled_channels_count = adc1_enabled_channels_count; + break; + case 2: + enabled_channels_count = adc2_enabled_channels_count; + break; + case 3: + enabled_channels_count = adc3_enabled_channels_count; + break; + } + return enabled_channels_count; +} + +static void _adc_channels_set_enabled_channels(uint8_t adc_num, channel_prop_t** enabled_channels, uint8_t enabled_channels_count) +{ + switch (adc_num) + { + case 1: + adc1_enabled_channels_list = enabled_channels; + adc1_enabled_channels_count = enabled_channels_count; + break; + case 2: + adc2_enabled_channels_list = enabled_channels; + adc2_enabled_channels_count = enabled_channels_count; + break; + case 3: + adc3_enabled_channels_list = enabled_channels; + adc3_enabled_channels_count = enabled_channels_count; + break; + } +} + +static channel_prop_t* _adc_channels_get_available_channel_by_name(uint8_t adc_num, char* channel_name) +{ + 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++) + { + if (strcmp(current_adc_available_channels[i]->name, channel_name) == 0) + { + return current_adc_available_channels[i]; + } + } + + return NULL; } ///// -// ADC channls public functions +// ADC channels public functions -/** - * Performs internal data structures initialization - * and pre-ADC enable init. - * Must be called before adc_core_enable() - */ void adc_channels_init() { - _adc_channels_count(); - _adc_channels_differential_setup(); - _adc_channels_internal_path_setup(); + _adc_channels_build_available_channels_lists(); + _adc_channels_differential_setup(); } -/** - * ADC channel configuration. - * Sets sequencer ranks and channels sampling time. - */ -void adc_channels_configure(ADC_TypeDef* adc) -{ - uint8_t channel; - uint8_t rank = 1; - ADC_TypeDef* channel_adc; - - for (int i = 0; i < CHANNEL_COUNT; i++) - { - channel = channels_props[i].number; - channel_adc = _get_adc_by_name(channels_props[i].adc); - // Regular sequencer - if (channel_adc == adc) - { - LL_ADC_REG_SetSequencerRanks(adc, - adc_decimal_nb_to_rank(rank), - __LL_ADC_DECIMAL_NB_TO_CHANNEL(channel) - ); - rank++; - - // 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(channel), - LL_ADC_SAMPLINGTIME_92CYCLES_5 - ); - } - } +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++) + { + 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_92CYCLES_5 + ); + + } + + // 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, 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*)); + + for (int i = 0 ; i < channel_count ; i++) + { + channel_prop_t* current_channel = _adc_channels_get_available_channel_by_name(adc_num, channel_list[i]); + if (current_channel == NULL) + { + result = ECHANNOTFOUND; + break; + } + else + { + current_adc_enabled_channels_list[i] = current_channel; + } + } + + if (result == 0) + { + channel_prop_t** previous_adc_enabled_channels_list = _adc_channels_get_enabled_channels_list(adc_num); + if (previous_adc_enabled_channels_list != NULL) + { + k_free(previous_adc_enabled_channels_list); + } + + _adc_channels_set_enabled_channels(adc_num, current_adc_enabled_channels_list, channel_count); + } + else + { + k_free(current_adc_enabled_channels_list); + } + + return result; } char* adc_channels_get_channel_name(uint8_t adc_num, uint8_t channel_rank) { - if (adc_num == 1) - return adc1_channels_list[channel_rank]->name; - else if (adc_num == 2) - return adc2_channels_list[channel_rank]->name; - else - return NULL; + 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)) ) + { + return current_adc_enabled_channels_list[channel_rank]->name; + } + + return NULL; } -uint8_t adc_channels_get_channels_count(uint8_t adc_num) +uint8_t adc_channels_get_enabled_channels_count(uint8_t adc_num) { - if (adc_num == 1) - return channels_in_adc1_count; - else if (adc_num == 2) - return channels_in_adc2_count; - else - return 0xFF; -} \ No newline at end of file + uint8_t enabled_channels = 0; + + switch (adc_num) + { + case 1: + enabled_channels = adc1_enabled_channels_count; + break; + case 2: + enabled_channels = adc2_enabled_channels_count; + break; + case 3: + enabled_channels = adc3_enabled_channels_count; + break; + } + + return enabled_channels; +} diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.h b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.h index 72bc11f3d8054b891320787fdaf6df9551e7c3a3..90a5b550c6f97674dc10ac6f965da30484a1222b 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.h +++ b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels.h @@ -18,8 +18,6 @@ */ /** - * @brief This is the public include for adc_channels.h - * * @author Clément Foucher <clement.foucher@laas.fr> */ @@ -27,20 +25,71 @@ #define ADC_CHANNELS_H_ -// Zephyr -#include <zephyr.h> +#include <stdint.h> #ifdef __cplusplus extern "C" { #endif +/** + * Performs internal data structures initialization + * and pre-ADC enable init. + * Must be called before adc_core_enable() + */ void adc_channels_init(); -void adc_channels_configure(ADC_TypeDef* adc); +/** + * 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. + * + * @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 adc_channnels_configure_adc_channels(uint8_t adc_num, char* channel_list[], uint8_t channel_count); + +/** + * This function returns the name of an enabled channel. + * + * This function must onle be called after + * adc_channnels_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. + */ char* adc_channels_get_channel_name(uint8_t adc_num, uint8_t channel_rank); -uint8_t adc_channels_get_channels_count(uint8_t adc_num); +/** + * 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); #ifdef __cplusplus diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels_private.h b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels_private.h deleted file mode 100644 index 20ae8dc05de071a704bdd7318b2aaca23a0536a5..0000000000000000000000000000000000000000 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_channels_private.h +++ /dev/null @@ -1,72 +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 is the private include file for adc_channels.c. - * It should only be included in C files from the current folder. - */ - -#ifndef ADC_CHANNELS_PRIVATE_H_ -#define ADC_CHANNELS_PRIVATE_H_ - - -// Zephyr -#include <zephyr.h> - - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef struct -{ - char* name; - bool is_differential; - uint8_t number; - char* adc; -} channel_prop_t; - -#define ADC_INPUTS_NODELABEL DT_NODELABEL(mychannels) - -// Channel properties -#define CHANNEL_NAME(node_id) DT_LABEL(node_id) -#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 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) \ - }, - -// Channel count -#define CHANNEL_COUNTER(node_id) +1 -#define CHANNEL_COUNT DT_FOREACH_CHILD(ADC_INPUTS_NODELABEL, CHANNEL_COUNTER) - - -#ifdef __cplusplus -} -#endif - -#endif // ADC_CHANNELS_PRIVATE_H_ diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.c b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.c index 7336c3f94539f08f81c03c77a555535f85e6ecd2..b9935bf656975900be04399e0d91388ba6e361ef 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.c +++ b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.c @@ -19,35 +19,21 @@ /** * @author Clément Foucher <clement.foucher@laas.fr> - * - * @brief This is an ad-hoc ADC driver for OwnTech's - * application. It supports differential channel setup - * unlike Zephyr's STM32 driver. - * It configures ADC 1 and ADC 2, using a common clock - * which is AHB clock with a prescaler division by 4. - * - * ** Summary ** - * - * To use this driver, first call adc_init(), then call - * required configuration functions, then call adc_enable(), - * and finally adc_start(). - * - * ** Call order ** - * - * All configuration functions provided by this driver must - * be called (if required) before calling adc_enable(). - * If addtionnal configuration not provided by this driver - * is required, this must be done after calling adc_enable(), - * but before calling adc_start(). */ -// Current file header -#include "adc_core.h" +// Stdlib +#include <stdint.h> + +// Zephyr +#include <zephyr.h> // STM32 LL #include <stm32g4xx_ll_bus.h> +// Owntech API +#include "adc_helper.h" + ///// // Private functions @@ -56,124 +42,110 @@ * ADC wake-up. * Refer to RM 21.4.6 */ -static void _adc_core_wakeup(ADC_TypeDef* adc) +static void _adc_core_wakeup(uint8_t adc_num) { - // Disable deep power down - LL_ADC_DisableDeepPowerDown(adc); + ADC_TypeDef* adc = _get_adc_by_number(adc_num); + + // Disable deep power down + LL_ADC_DisableDeepPowerDown(adc); - // Enable internal regulator - LL_ADC_EnableInternalRegulator(adc); + // Enable internal regulator + LL_ADC_EnableInternalRegulator(adc); - // Wait for ADC voltage regulator start-up time (20us for g474) - // See also constant LL_ADC_DELAY_INTERNAL_REGUL_STAB_US - k_busy_wait(30); + // Wait for ADC voltage regulator start-up time + k_busy_wait(LL_ADC_DELAY_INTERNAL_REGUL_STAB_US); } /** * ADC calibration. * Refer to RM 21.4.8 */ -static void _adc_core_calibrate(ADC_TypeDef* adc) +static void _adc_core_calibrate(uint8_t adc_num) { - // Single ended calibration - LL_ADC_StartCalibration(adc, LL_ADC_SINGLE_ENDED); - while ( LL_ADC_IsCalibrationOnGoing(adc) ) { /* Wait */ } + ADC_TypeDef* adc = _get_adc_by_number(adc_num); - // Seems to require an additionnal delay between calibrations - // TODO: undocumented??? - k_busy_wait(10); + // Single ended calibration + LL_ADC_StartCalibration(adc, LL_ADC_SINGLE_ENDED); + while ( LL_ADC_IsCalibrationOnGoing(adc) ) { /* Wait */ } - // Differential ended calibration - LL_ADC_StartCalibration(adc, LL_ADC_DIFFERENTIAL_ENDED); - while ( LL_ADC_IsCalibrationOnGoing(adc) ) { /* Wait */ } + // Seems to require an additionnal delay between calibrations + // TODO: undocumented??? + k_busy_wait(10); + + // Differential ended calibration + LL_ADC_StartCalibration(adc, LL_ADC_DIFFERENTIAL_ENDED); + while ( LL_ADC_IsCalibrationOnGoing(adc) ) { /* Wait */ } } ///// // Public API -/** - * ADC differential channel set-up: - * Applies differential mode to specified channel. - * Must be done *before* enabling ADC. - * Refer to RM 21.4.7 - */ -void adc_core_set_channel_differential(ADC_TypeDef* adc, uint8_t channel) +void adc_core_set_dual_mode(uint8_t dual_mode) { - LL_ADC_SetChannelSingleDiff(adc, - __LL_ADC_DECIMAL_NB_TO_CHANNEL(channel), - LL_ADC_DIFFERENTIAL_ENDED - ); + 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); + } } -/** - * ADC internal paths configuration. - * Enables VTS, VBAT and VREF. - * Refer to RM 21.4.31 to 21.4.33 - */ -void adc_core_configure_internal_paths(uint8_t vts, uint8_t vbat, uint8_t vref) +void adc_core_enable(uint8_t adc_num) { - uint32_t path = LL_ADC_PATH_INTERNAL_NONE; - if (vts == 1) - path |= LL_ADC_PATH_INTERNAL_TEMPSENSOR; - if (vbat == 1) - path |= LL_ADC_PATH_INTERNAL_VBAT; - if (vref == 1) - path |= LL_ADC_PATH_INTERNAL_VREFINT; - - LL_ADC_SetCommonPathInternalCh(ADC12_COMMON, path); -} + ADC_TypeDef* adc = _get_adc_by_number(adc_num); -/** - * 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 - */ -void adc_core_set_dual_mode() -{ - LL_ADC_SetMultimode(ADC12_COMMON, LL_ADC_MULTI_DUAL_REG_SIMULT); + // Enable ADC and wait for it to be ready + LL_ADC_ClearFlag_ADRDY(adc); + LL_ADC_Enable(adc); + while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { /* Wait */ } } -/** - * ADC enable. - * Refer to RM 21.4.9 - */ -void adc_core_enable(ADC_TypeDef* adc) +void adc_core_start(uint8_t adc_num) { - // Enable ADC and wait for it to be ready - LL_ADC_ClearFlag_ADRDY(adc); - LL_ADC_Enable(adc); - while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { /* Wait */ } + ADC_TypeDef* adc = _get_adc_by_number(adc_num); + + LL_ADC_REG_StartConversion(adc); } -/** - * ADC start. - * Refer to RM 21.4.15 - */ -void adc_core_start(ADC_TypeDef* adc) +void adc_core_configure_dma_mode(uint8_t adc_num) { - LL_ADC_REG_StartConversion(adc); + ADC_TypeDef* adc = _get_adc_by_number(adc_num); + + LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_UNLIMITED); } -/** - * ADC initialization procedure for - * both ADC 1 and ADC 2. - */ -void adc_core_init() +void adc_core_configure_trigger_source(uint8_t adc_num, uint32_t ExternalTriggerEdge, uint32_t TriggerSource) { - // Enable ADC1/2 clock - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC12); + ADC_TypeDef* adc = _get_adc_by_number(adc_num); - // Wake-up ADCs - _adc_core_wakeup(ADC1); - _adc_core_wakeup(ADC2); + // Set trigger edge + LL_ADC_REG_SetTriggerEdge(adc, ExternalTriggerEdge); - // Set common clock - // Refer to RM 21.4.3 and 21.7.2 - LL_ADC_SetCommonClock(ADC12_COMMON, LL_ADC_CLOCK_SYNC_PCLK_DIV4); + // Set trigger source + LL_ADC_REG_SetTriggerSource(adc, TriggerSource); +} - // Calibrate ADCs - _adc_core_calibrate(ADC1); - _adc_core_calibrate(ADC2); +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); + + // 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); } diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.h b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.h index 98adc3278d053dd5fdef43343251cff74b508caa..d1c5da2955a80e6932248ff31bcdcb881e6f649f 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.h +++ b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_core.h @@ -19,32 +19,77 @@ /** * @author Clément Foucher <clement.foucher@laas.fr> - * @brief This is the public include for adc_cores.h - * It should only be included in C files from the current folder. */ #ifndef ADC_CORE_H_ #define ADC_CORE_H_ -// Zephyr -#include <zephyr.h> +#include <stdint.h> #ifdef __cplusplus extern "C" { #endif - +///// // Init, enable, start + +/** + * ADC initialization procedure for + * ADC 1, ADC 2 and ADC 3. + */ void adc_core_init(); -void adc_core_enable(ADC_TypeDef* adc); -void adc_core_start(ADC_TypeDef* adc); +/** + * 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 + * + * @param adc_num Number of the ADC to start. + */ +void adc_core_start(uint8_t adc_num); + +///// // Configuration functions -void adc_core_set_channel_differential(ADC_TypeDef* adc, uint8_t channel); -void adc_core_configure_internal_paths(uint8_t vts, uint8_t vbat, uint8_t vref); -void adc_core_set_dual_mode(); + +/** + * 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 + * + * @param dual_mode true to enable dual moode, false to + * disable it. false by default. + */ +void adc_core_set_dual_mode(uint8_t dual_mode); + +/** + * ADC DMA mode configuration. + * Enables DMA and circular mode on an ADC. + * + * @param adc_num Number of the ADC on which to enable DMA. + */ +void adc_core_configure_dma_mode(uint8_t adc_num); + +/** + * Defines the trigger source for an ADC. + * + * @param adc_num Number of the ADC to configure. + * @param ExternalTriggerEdge Edge of the trigger as defined + * in stm32gxx_ll_adc.h (LL_ADC_REG_TRIG_***). + * @param trigger_source Source of the trigger as defined + * in stm32gxx_ll_adc.h (LL_ADC_REG_TRIG_***). + */ +void adc_core_configure_trigger_source(uint8_t adc_num, uint32_t ExternalTriggerEdge, uint32_t TriggerSource); #ifdef __cplusplus diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.c b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.c index 22a48d586e1a0b7dda29389bc05762ef39d4fb0e..1b06cb1c806f79ee311aca73643913d04f29f847 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.c +++ b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.c @@ -24,9 +24,10 @@ // Stdlib #include <string.h> +#include <stdint.h> -// Current file header -#include "adc_helper.h" +// Zephyr +#include <zephyr.h> /** @@ -34,14 +35,44 @@ */ ADC_TypeDef* _get_adc_by_name(char* name) { - ADC_TypeDef* adc = NULL; + ADC_TypeDef* adc = NULL; - if ( strcmp(name, "ADC_1") == 0) - adc = ADC1; - else if ( strcmp(name, "ADC_2") == 0) - adc = ADC2; + 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; - return adc; + 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; + + 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; + + return adc_number; } /** @@ -51,59 +82,59 @@ ADC_TypeDef* _get_adc_by_name(char* name) */ 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; + 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_data_acquisition/zephyr/adc/adc_helper.h b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.h index f1990442d1ef5222c76359eb297851cc91370221..efdc71365fe6144ba57f2e63530b44416afd84f2 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.h +++ b/zephyr/modules/owntech_data_acquisition/zephyr/adc/adc_helper.h @@ -19,15 +19,13 @@ /** * @author Clément Foucher <clement.foucher@laas.fr> - * @brief This is the public include for adc_helper.h - * It should only be included in C files from the current folder. */ #ifndef ADC_HELPER_H_ #define ADC_HELPER_H_ -// Zephyr +#include <stdint.h> #include <zephyr.h> @@ -37,6 +35,8 @@ extern "C" { 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); diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/data_acquisition.c b/zephyr/modules/owntech_data_acquisition/zephyr/data_acquisition.c index 13fe0876dc75ae7ec108298ceea6866dc01fdbbd..d4cd294b67de84065ce7a8c4db220d51bae4006f 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/data_acquisition.c +++ b/zephyr/modules/owntech_data_acquisition/zephyr/data_acquisition.c @@ -22,52 +22,217 @@ */ -///// -// OwnTech Power API includes +// Stdlib +#include <string.h> +#include <stdint.h> -#include "timer.h" +// OwnTech Power API #include "dma/dma.h" #include "adc/adc.h" +#include "adc/adc_channels.h" #include "data_dispatch/data_dispatch.h" +#include "data_acquisition.h" + ///// -// Timer +// Local types -#define TIMER7_LABEL DT_PROP(DT_NODELABEL(timers7), label) -static const struct device* timer7; +typedef struct +{ + uint8_t adc_number; + uint8_t channel_rank; +} channel_assignment_t; ///// -// Private functions +// Local variables + +static uint8_t data_acquisition_initialized = 0; +static uint8_t data_acquisition_started = 0; + +static channel_assignment_t v1_low_assignement = {0}; +static channel_assignment_t v2_low_assignement = {0}; +static channel_assignment_t v_high_assignement = {0}; +static channel_assignment_t i1_low_assignement = {0}; +static channel_assignment_t i2_low_assignement = {0}; +static channel_assignment_t i_high_assignement = {0}; +static channel_assignment_t temp_sensor_assignement = {0}; ///// // Public API -void data_acquisition_init() +int8_t data_acquisition_init() +{ + if (data_acquisition_initialized == 0) + { + adc_init(); + data_acquisition_initialized = 1; + return 0; + } + else + { + return EALREADYINIT; + } +} + +int8_t data_acquisition_set_adc12_dual_mode(uint8_t dual_mode) { - ///// - // Initialize peripherals + if ( (data_acquisition_initialized == 1) && (data_acquisition_started == 0) ) + { + adc_set_dual_mode(dual_mode); + return 0; + } + else if (data_acquisition_initialized == 0) + { + return EUNITITIALIZED; + } + else + { + return EALREADYSTARTED; + } +} - // ADC - adc_init(); +int8_t data_acquisition_configure_adc_channels(uint8_t adc_number, char* channel_list[], uint8_t channel_count) +{ + if ( (data_acquisition_initialized == 1) && (data_acquisition_started == 0) ) + { + int8_t result = adc_configure_adc_channels(adc_number, channel_list, channel_count); + if (result == 0) + { + for (int i = 0 ; i < channel_count ; i++) + { + if (strcmp(channel_list[i], "V1_LOW") == 0) + { + v1_low_assignement.adc_number = adc_number; + v1_low_assignement.channel_rank = i; + } + else if (strcmp(channel_list[i], "V2_LOW") == 0) + { + v2_low_assignement.adc_number = adc_number; + v2_low_assignement.channel_rank = i; + } + else if (strcmp(channel_list[i], "V_HIGH") == 0) + { + v_high_assignement.adc_number = adc_number; + v_high_assignement.channel_rank = i; + } + else if (strcmp(channel_list[i], "I1_LOW") == 0) + { + i1_low_assignement.adc_number = adc_number; + i1_low_assignement.channel_rank = i; + } + else if (strcmp(channel_list[i], "I2_LOW") == 0) + { + i2_low_assignement.adc_number = adc_number; + i2_low_assignement.channel_rank = i; + } + else if (strcmp(channel_list[i], "I_HIGH") == 0) + { + i_high_assignement.adc_number = adc_number; + i_high_assignement.channel_rank = i; + } + else if (strcmp(channel_list[i], "TEMP_SENSOR") == 0) + { + temp_sensor_assignement.adc_number = adc_number; + temp_sensor_assignement.channel_rank = i; + } + } + } + return result; + } + else if (data_acquisition_initialized == 0) + { + return EUNITITIALIZED; + } + else + { + return EALREADYSTARTED; + } +} - // DMA - dma_init(); +int8_t data_acquisition_configure_adc_trigger_source(uint8_t adc_number, uint32_t trigger_source) +{ + if ( (data_acquisition_initialized == 1) && (data_acquisition_started == 0) ) + { + adc_configure_trigger_source(adc_number, trigger_source); + return 0; + } + else if (data_acquisition_initialized == 0) + { + return EUNITITIALIZED; + } + else + { + return EALREADYSTARTED; + } +} - ///// - // Initialize data dispatch - data_dispatch_init(); - ///// - // Configure timer for background data dispatch - timer7 = device_get_binding(TIMER7_LABEL); - struct timer_config_t timer_cfg = +int8_t data_acquisition_start() +{ + if ( (data_acquisition_initialized == 1) && (data_acquisition_started == 0) ) { - .timer_enable_irq = 1, - .timer_callback = data_dispatch_do_dispatch - }; - timer_config(timer7, &timer_cfg); - timer_start(timer7, 25); + // DMAs + dma_configure_and_start(); + + // Initialize data dispatch + data_dispatch_init(); + + // Launch ADC conversion + adc_start(); + + data_acquisition_started = 1; + + return 0; + } + else if (data_acquisition_initialized == 0) + { + return EUNITITIALIZED; + } + else + { + return EALREADYSTARTED; + } +} + +char* data_acquisition_get_channel_name(uint8_t adc_number, uint8_t channel_rank) +{ + return adc_channels_get_channel_name(adc_number, channel_rank); +} + +uint16_t* data_acquisition_get_v1_low_values(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); +} + +uint16_t* data_acquisition_get_v2_low_values(uint32_t* number_of_values_acquired) +{ + return data_dispatch_get_acquired_values(v2_low_assignement.adc_number, v2_low_assignement.channel_rank, number_of_values_acquired); +} + +uint16_t* data_acquisition_get_v_high_values(uint32_t* number_of_values_acquired) +{ + return data_dispatch_get_acquired_values(v_high_assignement.adc_number, v_high_assignement.channel_rank, number_of_values_acquired); +} + +uint16_t* data_acquisition_get_i1_low_values(uint32_t* number_of_values_acquired) +{ + return data_dispatch_get_acquired_values(i1_low_assignement.adc_number, i1_low_assignement.channel_rank, number_of_values_acquired); +} + +uint16_t* data_acquisition_get_i2_low_values(uint32_t* number_of_values_acquired) +{ + return data_dispatch_get_acquired_values(i2_low_assignement.adc_number, i2_low_assignement.channel_rank, number_of_values_acquired); +} + +uint16_t* data_acquisition_get_i_high_values(uint32_t* number_of_values_acquired) +{ + return data_dispatch_get_acquired_values(i_high_assignement.adc_number, i_high_assignement.channel_rank, number_of_values_acquired); +} + +uint16_t* data_acquisition_get_temp_sensor_values(uint32_t* number_of_values_acquired) +{ + return data_dispatch_get_acquired_values(temp_sensor_assignement.adc_number, temp_sensor_assignement.channel_rank, number_of_values_acquired); } diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/data_acquisition.h b/zephyr/modules/owntech_data_acquisition/zephyr/data_acquisition.h deleted file mode 100644 index 5aff6d03d50ecddf5cac53c92f1b70779a3b982d..0000000000000000000000000000000000000000 --- a/zephyr/modules/owntech_data_acquisition/zephyr/data_acquisition.h +++ /dev/null @@ -1,45 +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> - */ - -#ifndef DATA_ACQUISITION_H_ -#define DATA_ACQUISITION_H_ - -// Indirect public headers -#include "adc/adc_channels.h" -#include "data_dispatch/data_dispatch.h" -#include "dma/dma.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -// Current file public function -void data_acquisition_init(); - - -#ifdef __cplusplus -} -#endif - -#endif // DATA_ACQUISITION_H_ 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 2f67b8f1e8d28ba27dcd0a1b8db181175ba87d59..89c4404d3d0359c14b8aa3c2c4407bea8a2dcc71 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 @@ -31,7 +31,6 @@ #include <zephyr.h> // OwnTech API -#include "../dma/dma.h" #include "../adc/adc_channels.h" @@ -40,84 +39,56 @@ #define CHANNELS_BUFFERS_SIZE 32 -// Number of channels in each ADC -static uint8_t channels_in_adc1_count; -static uint8_t channels_in_adc2_count; +// Number of channels in each ADC (cell i is ADC number i+1) +static uint8_t enabled_channels_count[3]; -// Number of readings a DMA buffer can handle -static size_t dma1_buffer_size; -static size_t dma2_buffer_size; - -// Number of readings a *half-buffer* can handle -static size_t dma1_half_buffer_size; -static size_t dma2_half_buffer_size; - -// Number of *per-channel* readings a *half-buffer* can handle -static uint32_t dma1_half_buffer_capacity; -static uint32_t dma2_half_buffer_capacity; - -///// -// DMA buffers (in) - -static uint16_t* dma1_buffer = NULL; -static uint16_t* dma2_buffer = NULL; - -static uint32_t dma1_next_read_index = 0; -static uint32_t dma2_next_read_index = 0; ///// -// Per-channel buffers (out) +// Per-channel buffers // Bidimentionnal arrays: each of these variables is an array // of per-channel arrays holding the readings static uint16_t** adc1_channels_buffers = NULL; static uint16_t** adc2_channels_buffers = NULL; -// Arrays to store the latest and next indexes in each channel array +// Arrays to store the read and write indexes in each channel array static uint32_t* adc1_next_read_indexes = NULL; static uint32_t* adc2_next_read_indexes = NULL; static uint32_t* adc1_next_write_indexes = NULL; static uint32_t* adc2_next_write_indexes = NULL; -///// -// Meta-data -static uint32_t readings_missed_in_adc1 = 0; -static uint32_t readings_missed_in_adc2 = 0; - +static uint16_t** adc1_user_buffers = NULL; +static uint16_t** adc2_user_buffers = NULL; ///// // Private functions -void _increment_circular_index(uint32_t* buffer_index, uint32_t buffer_size) +__STATIC_INLINE void _increment_circular_index(uint32_t* buffer_index, uint32_t buffer_size) { - (*buffer_index) = ( (*buffer_index) < (buffer_size-1) ) ? ( (*buffer_index) + 1 ) : 0; + (*buffer_index) = ( (*buffer_index) < (buffer_size-1) ) ? ( (*buffer_index) + 1 ) : 0; } -void _circular_buffer_copy(uint16_t* src_buffer, uint16_t* dest_buffer, - uint32_t* src_buffer_next_read_index, uint32_t* dest_buffer_next_write_index, - uint32_t src_buffer_size, uint32_t dest_buffer_size - ) +__STATIC_INLINE void _circular_buffer_copy(uint16_t* src_buffer, uint16_t* dest_buffer, + uint32_t src_buffer_next_read_index, uint32_t dest_buffer_next_write_index + ) { - dest_buffer[*dest_buffer_next_write_index] = src_buffer[*src_buffer_next_read_index]; - - _increment_circular_index(src_buffer_next_read_index, src_buffer_size); - _increment_circular_index(dest_buffer_next_write_index, dest_buffer_size); + dest_buffer[dest_buffer_next_write_index] = src_buffer[src_buffer_next_read_index]; } -uint32_t _get_values_available_count_in_buffer(uint32_t next_read_index, uint32_t next_write_index, uint32_t buffer_size) +static uint32_t _get_values_available_count_in_buffer(uint32_t next_read_index, uint32_t next_write_index, uint32_t buffer_size) { - if (next_read_index == next_write_index) - return 0; + if (next_read_index == next_write_index) + return 0; - uint32_t i_next_write_index = (next_write_index < next_read_index) ? (next_write_index + buffer_size) : next_write_index; - return i_next_write_index - next_read_index; + uint32_t i_next_write_index = (next_write_index < next_read_index) ? (next_write_index + buffer_size) : next_write_index; + return i_next_write_index - next_read_index; } -uint16_t _get_next_value_from_buffer(uint16_t* buffer, uint32_t* next_read_index, uint32_t buffer_size) +static uint16_t _get_next_value_from_buffer(uint16_t* buffer, uint32_t* next_read_index, uint32_t buffer_size) { - uint16_t value = buffer[*next_read_index]; - _increment_circular_index(next_read_index, buffer_size); - return value; + uint16_t value = buffer[*next_read_index]; + _increment_circular_index(next_read_index, buffer_size); + return value; } @@ -126,175 +97,112 @@ uint16_t _get_next_value_from_buffer(uint16_t* buffer, uint32_t* next_read_index void data_dispatch_init() { - dma1_buffer = dma_get_dma1_buffer(); - dma2_buffer = dma_get_dma2_buffer(); - - dma1_buffer_size = dma_get_dma1_buffer_size(); - dma2_buffer_size = dma_get_dma2_buffer_size(); - - dma1_half_buffer_size = dma1_buffer_size/2; - dma2_half_buffer_size = dma2_buffer_size/2; - - channels_in_adc1_count = adc_channels_get_channels_count(1); - channels_in_adc2_count = adc_channels_get_channels_count(2); - - dma1_half_buffer_capacity = dma1_half_buffer_size/channels_in_adc1_count; - dma2_half_buffer_capacity = dma2_half_buffer_size/channels_in_adc2_count; - - adc1_channels_buffers = malloc(sizeof(uint16_t*) * channels_in_adc1_count); - adc1_next_read_indexes = malloc(sizeof(uint32_t) * channels_in_adc1_count); - adc1_next_write_indexes = malloc(sizeof(uint32_t) * channels_in_adc1_count); - for (int i = 0 ; i < channels_in_adc1_count ; i++) - { - adc1_channels_buffers[i] = malloc(sizeof(uint16_t) * CHANNELS_BUFFERS_SIZE); - adc1_next_read_indexes[i] = 0; - adc1_next_write_indexes[i] = 0; - } - - adc2_channels_buffers = malloc(sizeof(uint16_t*) * channels_in_adc2_count); - adc2_next_read_indexes = malloc(sizeof(uint32_t) * channels_in_adc2_count); - adc2_next_write_indexes = malloc(sizeof(uint32_t) * channels_in_adc2_count); - for (int i = 0 ; i < channels_in_adc2_count ; i++) - { - adc2_channels_buffers[i] = malloc(sizeof(uint16_t) * CHANNELS_BUFFERS_SIZE); - adc2_next_read_indexes[i] = 0; - adc2_next_write_indexes[i] = 0; - } + enabled_channels_count[0] = adc_channels_get_enabled_channels_count(1); + if (enabled_channels_count[0] > 0) + { + adc1_channels_buffers = k_malloc(sizeof(uint16_t*) * enabled_channels_count[0]); + adc1_next_read_indexes = k_malloc(sizeof(uint32_t) * enabled_channels_count[0]); + adc1_next_write_indexes = k_malloc(sizeof(uint32_t) * enabled_channels_count[0]); + adc1_user_buffers = k_malloc(sizeof(uint16_t*) * enabled_channels_count[0]); + for (int i = 0 ; i < enabled_channels_count[0] ; i++) + { + adc1_channels_buffers[i] = k_malloc(sizeof(uint16_t) * CHANNELS_BUFFERS_SIZE); + adc1_next_read_indexes[i] = 0; + adc1_next_write_indexes[i] = 0; + adc1_user_buffers[i] = k_malloc(sizeof(uint16_t) * CHANNELS_BUFFERS_SIZE); + } + } + + enabled_channels_count[1] = adc_channels_get_enabled_channels_count(2); + if (enabled_channels_count[1] > 0) + { + adc2_channels_buffers = k_malloc(sizeof(uint16_t*) * enabled_channels_count[1]); + adc2_next_read_indexes = k_malloc(sizeof(uint32_t) * enabled_channels_count[1]); + adc2_next_write_indexes = k_malloc(sizeof(uint32_t) * enabled_channels_count[1]); + adc2_user_buffers = k_malloc(sizeof(uint16_t*) * enabled_channels_count[1]); + for (int i = 0 ; i < enabled_channels_count[1] ; i++) + { + adc2_channels_buffers[i] = k_malloc(sizeof(uint16_t) * CHANNELS_BUFFERS_SIZE); + adc2_next_read_indexes[i] = 0; + adc2_next_write_indexes[i] = 0; + adc2_user_buffers[i] = k_malloc(sizeof(uint16_t) * CHANNELS_BUFFERS_SIZE); + } + } } -/** - * This function gets the values from ADC buffers - * and place them in arrays depending on their origin. - */ -void data_dispatch_do_dispatch() +void data_dispatch_do_dispatch(uint8_t adc_num, uint16_t* dma_buffer) { - // DMA 1 - uint32_t _dma1_count = atomic_set(&dma1_readings_count, 0); - - if (_dma1_count > 1) - { - uint32_t readings_missed = _dma1_count - 1; - readings_missed_in_adc1 += readings_missed*dma1_half_buffer_capacity; - // Catch up to the latest written half-buffer - if ( (readings_missed % 2) == 1) - { - dma1_next_read_index = (dma1_next_read_index + dma1_half_buffer_size) % dma1_buffer_size; - } - } - - if (_dma1_count >= 1) - { - for (int readings_count = 0 ; readings_count < dma1_half_buffer_capacity ; readings_count++) - { - for (int channel_count = 0 ; channel_count < channels_in_adc1_count ; channel_count++) - { - _circular_buffer_copy(dma1_buffer, adc1_channels_buffers[channel_count], - &dma1_next_read_index, &adc1_next_write_indexes[channel_count], - dma1_buffer_size, CHANNELS_BUFFERS_SIZE - ); - } - } - } - - // DMA 2 - uint32_t _dma2_count = atomic_set(&dma2_readings_count, 0); - - if (_dma2_count > 1) - { - uint32_t readings_missed = _dma2_count - 1; - readings_missed_in_adc2 += readings_missed*dma2_half_buffer_capacity; - // Catch up to the latest written half-buffer - if ( (readings_missed % 2) == 1) - { - dma2_next_read_index = (dma2_next_read_index + dma2_half_buffer_size) % dma2_buffer_size; - } - } - - if (_dma2_count >= 1) - { - for (int readings_count = 0 ; readings_count < dma2_half_buffer_capacity ; readings_count++) - { - for (int channel_count = 0 ; channel_count < channels_in_adc2_count ; channel_count++) - { - _circular_buffer_copy(dma2_buffer, adc2_channels_buffers[channel_count], - &dma2_next_read_index, &adc2_next_write_indexes[channel_count], - dma2_buffer_size, CHANNELS_BUFFERS_SIZE - ); - } - } - } + if (adc_num == 1) + { + for (int current_channel = 0 ; current_channel < enabled_channels_count[0] ; current_channel++) + { + _circular_buffer_copy(dma_buffer, adc1_channels_buffers[current_channel], + current_channel, adc1_next_write_indexes[current_channel] + ); + + _increment_circular_index(&adc1_next_write_indexes[current_channel], CHANNELS_BUFFERS_SIZE); + } + } + else if (adc_num == 2) + { + for (int current_channel = 0 ; current_channel < enabled_channels_count[1] ; current_channel++) + { + _circular_buffer_copy(dma_buffer, adc2_channels_buffers[current_channel], + current_channel, adc2_next_write_indexes[current_channel] + ); + + _increment_circular_index(&adc2_next_write_indexes[current_channel], CHANNELS_BUFFERS_SIZE); + } + } } ///// // Accessors -char* data_dispatch_get_adc1_channel_name(uint8_t channel_rank) -{ - return adc_channels_get_channel_name(1, channel_rank); -} - -char* data_dispatch_get_adc2_channel_name(uint8_t channel_rank) -{ - return adc_channels_get_channel_name(2, channel_rank); -} - -uint32_t data_dispatch_get_values_available_in_adc1_channel(uint8_t channel_rank) -{ - return _get_values_available_count_in_buffer(adc1_next_read_indexes[channel_rank], - adc1_next_write_indexes[channel_rank], - CHANNELS_BUFFERS_SIZE - ); -} - -uint32_t data_dispatch_get_values_available_in_adc2_channel(uint8_t channel_rank) -{ - return _get_values_available_count_in_buffer(adc2_next_read_indexes[channel_rank], - adc2_next_write_indexes[channel_rank], - CHANNELS_BUFFERS_SIZE - ); -} - -uint16_t data_dispatch_get_next_value_from_adc1_channel(uint8_t channel_rank) -{ - return _get_next_value_from_buffer(adc1_channels_buffers[channel_rank], - &adc1_next_read_indexes[channel_rank], - CHANNELS_BUFFERS_SIZE - ); -} - -uint16_t data_dispatch_get_next_value_from_adc2_channel(uint8_t channel_rank) -{ - return _get_next_value_from_buffer(adc2_channels_buffers[channel_rank], - &adc2_next_read_indexes[channel_rank], - CHANNELS_BUFFERS_SIZE - ); -} - -uint32_t data_dispatch_how_many_adc1_reading_been_lost() -{ - if (readings_missed_in_adc1 > 0) - { - uint32_t error_count = readings_missed_in_adc1; - readings_missed_in_adc1 = 0; - return error_count; - } - else - { - return 0; - } -} - -uint32_t data_dispatch_how_many_adc2_reading_been_lost() +uint16_t* data_dispatch_get_acquired_values(uint8_t adc_number, uint8_t channel_rank, uint32_t* number_of_values_acquired) { - if (readings_missed_in_adc2 > 0) - { - uint32_t error_count = readings_missed_in_adc2; - readings_missed_in_adc2 = 0; - return error_count; - } - else - { - return 0; - } + if (adc_number == 1) + { + // Get number of available values + uint32_t number_of_values = _get_values_available_count_in_buffer(adc1_next_read_indexes[channel_rank], + adc1_next_write_indexes[channel_rank], + CHANNELS_BUFFERS_SIZE + ); + + for (uint32_t i = 0 ; i < number_of_values ; i++) + { + adc1_user_buffers[channel_rank][i] = _get_next_value_from_buffer(adc1_channels_buffers[channel_rank], + &adc1_next_read_indexes[channel_rank], + CHANNELS_BUFFERS_SIZE + ); + } + + *number_of_values_acquired = number_of_values; + return adc1_user_buffers[channel_rank]; + } + else if (adc_number == 2) + { + // Get number of available values + uint32_t number_of_values = _get_values_available_count_in_buffer(adc2_next_read_indexes[channel_rank], + adc2_next_write_indexes[channel_rank], + CHANNELS_BUFFERS_SIZE + ); + + for (uint32_t i = 0 ; i < number_of_values ; i++) + { + adc2_user_buffers[channel_rank][i] = _get_next_value_from_buffer(adc2_channels_buffers[channel_rank], + &adc2_next_read_indexes[channel_rank], + CHANNELS_BUFFERS_SIZE + ); + } + + *number_of_values_acquired = number_of_values; + return adc2_user_buffers[channel_rank]; + } + else + { + *number_of_values_acquired = 0; + return NULL; + } } diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/data_dispatch/data_dispatch.h b/zephyr/modules/owntech_data_acquisition/zephyr/data_dispatch/data_dispatch.h index 7a0bde076bd2c96a859fd8cb5f176c0fc5a0b236..4fce83103813de1ba84be3e11eaea0f16f099618 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/data_dispatch/data_dispatch.h +++ b/zephyr/modules/owntech_data_acquisition/zephyr/data_dispatch/data_dispatch.h @@ -28,7 +28,6 @@ #define DATA_DISPATCH_H_ -// Stdlib #include <stdint.h> @@ -41,27 +40,10 @@ extern "C" { void data_dispatch_init(); // Dispatch function: gets the readings and store them in per-channel arrays -void data_dispatch_do_dispatch(); - -// Get the name of a specific channel -char* data_dispatch_get_adc1_channel_name(uint8_t channel_rank); -char* data_dispatch_get_adc2_channel_name(uint8_t channel_rank); - -// Get number of readings available for a specific channel -uint32_t data_dispatch_get_values_available_in_adc1_channel(uint8_t channel_rank); -uint32_t data_dispatch_get_values_available_in_adc2_channel(uint8_t channel_rank); - -// Pop next value from the buffer of a specific channel -// WARNING: calling one of these function when values_available is 0 -// will break the behavior by desynchronizing the buffer indexes -uint16_t data_dispatch_get_next_value_from_adc1_channel(uint8_t channel_rank); -uint16_t data_dispatch_get_next_value_from_adc2_channel(uint8_t channel_rank); - -// Error function: tells how many values have been missed since -// last call of the function (error count is reset at each call) -uint32_t data_dispatch_how_many_adc1_reading_been_lost(); -uint32_t data_dispatch_how_many_adc2_reading_been_lost(); +void data_dispatch_do_dispatch(uint8_t adc_num, uint16_t* dma_buffer); +// Obtain buffer for a specific channel +uint16_t* data_dispatch_get_acquired_values(uint8_t adc_number, uint8_t channel_rank, uint32_t* number_of_values_acquired); #ifdef __cplusplus } diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.c b/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.c index b2e48c96dd86ddb46748885c2bf261682ac5ba43..041a572f1ace49a0e98a05ca3636a2d7b322b79f 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.c +++ b/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.c @@ -18,181 +18,149 @@ */ /** - * @brief DMA configuration for OwnTech application + * @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), + * which is subdivised in two half-buffers, so that when + * the DMA is filling one half-buffer, the other one + * 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> */ + // Stdlib -#include <stdlib.h> +#include <stdint.h> // Zephyr +#include <zephyr.h> #include <drivers/dma.h> // STM32 #include <stm32g4xx_ll_dma.h> // OwnTech API +#include "../data_dispatch/data_dispatch.h" #include "../adc/adc_channels.h" -// Current file header -#include "dma.h" - ///// // DT definitions #define DMA1_NODELABEL DT_NODELABEL(dma1) #define DMA1_LABEL DT_PROP(DMA1_NODELABEL, label) -#define DMA2_NODELABEL DT_NODELABEL(dma2) -#define DMA2_LABEL DT_PROP(DMA2_NODELABEL, label) - -// This is the size of the buffer, in terms of readings -// *per channel*. E.g. if 3 channels in an ADC, -// the size of the buffer will be 3*DMA_BUFFER_SIZE -// This value *must be* a multiple of 2 to allow -// half-transfer interrupts correct handling. -#define DMA_BUFFER_SIZE 2 +const struct device* _dma1; ///// -// Variables -atomic_t dma1_readings_count = ATOMIC_INIT(0); -atomic_t dma2_readings_count = ATOMIC_INIT(0); - -static uint16_t* dma1_buffer = NULL; -static uint16_t* dma2_buffer = NULL; - -static size_t buffer1_size; -static size_t buffer2_size; +// Arrays of buffers: +// half_buffer_*[i][] is an array whose size matches +// the number of enabled channels in ADC(i+1). +static uint16_t* half_buffer_1[3]; +static uint16_t* half_buffer_2[3]; ///// -// DMA callbacks -// These callbacks are called twice per buffer filling: -// when buffer is half-filled and when buffer is filled. - -void _dma1_callback(const struct device* dev, void* user_data, uint32_t channel, int status) -{ - atomic_inc(&dma1_readings_count); -} +// Private API -void _dma2_callback(const struct device* dev, void* user_data, uint32_t channel, int status) -{ - atomic_inc(&dma2_readings_count); -} - - -///// -// DMA inits - -static void _dma1_init() +/** + * DMA callback + * This callback is called twice per buffer filling: + * when buffer is half-filled and when buffer is filled. + */ +static void _dma_callback(const struct device* dev, void* user_data, uint32_t channel, int status) { - // Prepare buffers - buffer1_size = adc_channels_get_channels_count(1) * DMA_BUFFER_SIZE; - dma1_buffer = malloc(sizeof(uint16_t) * buffer1_size); - - // Configure DMA - struct dma_block_config dma1_block_config = {0}; - struct dma_config dma1_config = {0}; - - dma1_block_config.source_address = (uint32_t)(&(ADC1->DR)); // Source: ADC 1 - dma1_block_config.dest_address = (uint32_t)dma1_buffer; // Dest: array in mem - dma1_block_config.block_size = 2 * buffer1_size; // Buffer size in bytes - dma1_block_config.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; // Source: no increment in DMA register - dma1_block_config.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; // Dest: increment in memory - dma1_block_config.source_reload_en = 1; // Reload initial address after block - dma1_block_config.dest_reload_en = 1; // Reload initial address after block - - dma1_config.dma_slot = LL_DMAMUX_REQ_ADC1; // Source: ADC 1 - dma1_config.channel_direction = PERIPHERAL_TO_MEMORY; // From periph to mem - dma1_config.source_data_size = 2; // 2 bytes - dma1_config.dest_data_size = 2; // 2 bytes - dma1_config.source_burst_length = 1; // No burst - dma1_config.dest_burst_length = 1; // No burst - dma1_config.block_count = 1; // 1 block - dma1_config.head_block = &dma1_block_config; // Above block config - dma1_config.dma_callback = _dma1_callback; // Callback - - const struct device* _dma1 = device_get_binding(DMA1_LABEL); - dma_config(_dma1, 1, &dma1_config); - // Half-transfer interrupt is not handled by Zephyr driver: - // enable it manually. - LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); + static uint8_t current_half_buffer[3] = {0}; + + if (current_half_buffer[channel] == 0) + { + data_dispatch_do_dispatch(channel+1, half_buffer_1[channel]); + current_half_buffer[channel] = 1; + } + else + { + data_dispatch_do_dispatch(channel+1, half_buffer_2[channel]); + current_half_buffer[channel] = 0; + } } -static void _dma2_init() +/** + * DMA init function for one channel + */ +static void _dma_channel_init(uint8_t adc_num, uint32_t source_address, uint32_t source_trigger) { - // Prepare buffers - buffer2_size = adc_channels_get_channels_count(2) * DMA_BUFFER_SIZE; - dma2_buffer = malloc(sizeof(uint16_t) * buffer2_size); - - // Configure DMA - struct dma_block_config dma2_block_config = {0}; - struct dma_config dma2_config = {0}; - - dma2_block_config.source_address = (uint32_t)(&(ADC2->DR)); // Source: ADC 2 - dma2_block_config.dest_address = (uint32_t)dma2_buffer; // Dest: array in mem - dma2_block_config.block_size = 2 * buffer2_size; // Buffer size in bytes - dma2_block_config.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; // Source: no increment in DMA register - dma2_block_config.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; // Dest: increment in memory - dma2_block_config.source_reload_en = 1; // Reload initial address after block - dma2_block_config.dest_reload_en = 1; // Reload initial address after block - - dma2_config.dma_slot = LL_DMAMUX_REQ_ADC2; // Source: ADC 2 - dma2_config.channel_direction = PERIPHERAL_TO_MEMORY; // From periph to mem - dma2_config.source_data_size = 2; // 2 bytes - dma2_config.dest_data_size = 2; // 2 bytes - dma2_config.source_burst_length = 1; // No burst - dma2_config.dest_burst_length = 1; // No burst - dma2_config.block_count = 1; // 1 block - dma2_config.head_block = &dma2_block_config; // Above block config - dma2_config.dma_callback = _dma2_callback; // Callback - - const struct device* _dma2 = device_get_binding(DMA2_LABEL); - dma_config(_dma2, 1, &dma2_config); - // Half-transfer interrupt is not handled by Zephyr driver: - // enable it manually. - LL_DMA_EnableIT_HT(DMA2, LL_DMA_CHANNEL_1); + // Prepare buffers + uint8_t enabled_channels = adc_channels_get_enabled_channels_count(adc_num); + size_t dma_buffer_size = enabled_channels * sizeof(uint16_t) * 2; + uint8_t adc_index = adc_num - 1; + + uint16_t* dma_buffer = k_malloc(dma_buffer_size); + half_buffer_1[adc_index] = dma_buffer; + half_buffer_2[adc_index] = dma_buffer + enabled_channels; + + // Configure DMA + struct dma_block_config dma_block_config_s = {0}; + struct dma_config dma_config_s = {0}; + + dma_block_config_s.source_address = source_address; // Source: ADC DR register + dma_block_config_s.dest_address = (uint32_t)dma_buffer; // Dest: buffer in memory + dma_block_config_s.block_size = dma_buffer_size; // Buffer size in bytes + dma_block_config_s.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; // Source: no increment in ADC register + dma_block_config_s.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; // Dest: increment in memory + dma_block_config_s.source_reload_en = 1; // Reload initial address after block; Enables Half-transfer interrupt + dma_block_config_s.dest_reload_en = 1; // Reload initial address after block + + dma_config_s.dma_slot = source_trigger; // Source: triggered from ADC + dma_config_s.channel_direction = PERIPHERAL_TO_MEMORY; // From periph to mem + dma_config_s.source_data_size = 2; // 2 bytes + dma_config_s.dest_data_size = 2; // 2 bytes + dma_config_s.source_burst_length = 1; // No burst + dma_config_s.dest_burst_length = 1; // No burst + dma_config_s.block_count = 1; // 1 block + dma_config_s.head_block = &dma_block_config_s; // Above block config + dma_config_s.dma_callback = _dma_callback; // Callback + + dma_config(_dma1, adc_num, &dma_config_s); } ///// // Public API -/** - * DMA initialization procedure. - */ -void dma_init() +void dma_configure_and_start() { - __ASSERT( (DMA_BUFFER_SIZE%2 == 0), "WARNING: DMA_BUFFER_SIZE macro must be an even value."); - - // DMA1 - _dma1_init(); - const struct device* _dma1 = device_get_binding(DMA1_LABEL); - dma_start(_dma1, 1); - - // DMA2 - _dma2_init(); - const struct device* _dma2 = device_get_binding(DMA2_LABEL); - dma_start(_dma2, 1); + _dma1 = device_get_binding(DMA1_LABEL); + + // ADC 1 + if (adc_channels_get_enabled_channels_count(1) > 0) + { + _dma_channel_init(1, (uint32_t)(&(ADC1->DR)), LL_DMAMUX_REQ_ADC1); + dma_start(_dma1, 1); + } + + // ADC 2 + if (adc_channels_get_enabled_channels_count(2) > 0) + { + _dma_channel_init(2, (uint32_t)(&(ADC2->DR)), LL_DMAMUX_REQ_ADC2); + dma_start(_dma1, 2); + } + + // ADC 3 + if (adc_channels_get_enabled_channels_count(3) > 0) + { + _dma_channel_init(3, (uint32_t)(&(ADC3->DR)), LL_DMAMUX_REQ_ADC3); + dma_start(_dma1, 3); + } } + uint16_t* dma_get_dma1_buffer() { - return dma1_buffer; + return half_buffer_1[0]; } uint16_t* dma_get_dma2_buffer() { - return dma2_buffer; -} - -size_t dma_get_dma1_buffer_size() -{ - return buffer1_size; -} - -size_t dma_get_dma2_buffer_size() -{ - return buffer2_size; + return half_buffer_1[1]; } diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.h b/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.h index 321160290ade277f184413e14a7506403b6fc0cc..70e6c7d03c477316a55d0ab8046f57e5f2124c9b 100644 --- a/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.h +++ b/zephyr/modules/owntech_data_acquisition/zephyr/dma/dma.h @@ -25,8 +25,7 @@ #define DMA_H_ -// Zephyr -#include <zephyr.h> +#include <stdint.h> #ifdef __cplusplus @@ -34,26 +33,20 @@ extern "C" { #endif -// Public functions -void dma_init(); +/** + * This function configures and starts + * the DMA. It must only be called after + * all the ADCs configuration has been + * carried out, as it uses its channels + * configuration to determine the size + * of the buffers. + */ +void dma_configure_and_start(); +// For debug purpose uint16_t* dma_get_dma1_buffer(); uint16_t* dma_get_dma2_buffer(); -size_t dma_get_dma1_buffer_size(); -size_t dma_get_dma2_buffer_size(); - -// Public variables: these variables handle -// the number of readings stored in the -// buffer at a specific time. They are -// incremented by 1 by the DMA transfer -// interrupts and can be decremented by -// a task reading the buffers. -// Each unit in these counts represent -// a half-buffer amount of readings. -extern atomic_t dma1_readings_count; -extern atomic_t dma2_readings_count; - #ifdef __cplusplus } diff --git a/zephyr/modules/owntech_data_acquisition/zephyr/public_include/data_acquisition.h b/zephyr/modules/owntech_data_acquisition/zephyr/public_include/data_acquisition.h new file mode 100644 index 0000000000000000000000000000000000000000..e9287984caf20f8b867826cbdf2cc27bd10e66c1 --- /dev/null +++ b/zephyr/modules/owntech_data_acquisition/zephyr/public_include/data_acquisition.h @@ -0,0 +1,176 @@ +/* + * 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> + */ + +#ifndef DATA_ACQUISITION_H_ +#define DATA_ACQUISITION_H_ + + +#include <stdint.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +///// +// Error codes + +#define ECHANNOTFOUND -1 +#define EUNITITIALIZED -2 +#define ESTARTED -3 +#define EALREADYSTARTED -4 +#define EALREADYINIT -5 + + +///// +// Configuration API + +/** + * This function initializes the Data Acquisition module. + * It must be called prior to any other function in this module. + * @return 0 if initialization went well, + * EALREADYINIT is already initialized. + */ +int8_t data_acquisition_init(); + +/** + * Use this function to set ADC 1 and ADC 2 in dual mode. + * + * This function must be called AFTER data_acquisition_init() + * and BEFORE data_acquisition_start(). + * + * @param dual_mode Status of the dual mode: true to enable, + * false to disable. false by default. + * @return 0 is everything went well, + * EUNITITIALIZED if the module has not been initialized, + * EALREADYSTARTED if the module has already been started. + */ +int8_t data_acquisition_set_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 AFTER data_acquisition_init() + * and BEFORE data_acquisition_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. + * EUNITITIALIZED if the module has not been initialized, + * EALREADYSTARTED if the module has already been started. + */ +int8_t data_acquisition_configure_adc_channels(uint8_t adc_number, char* channel_list[], uint8_t channel_count); + +/** + * This function is used to configure the trigger source of an ADC. + * + * This function must be called AFTER data_acquisition_init() + * and BEFORE data_acquisition_start(). + * + * TODO: Use an enumeration instead of LL constants for source. + * + * @param adc_number Number of the ADC to configure + * @param trigger_source Source of the trigger as defined + * in stm32gxx_ll_adc.h (LL_ADC_REG_TRIG_***) + * @return 0 is everything went well, + * EUNITITIALIZED if the module has not been initialized, + * EALREADYSTARTED if the module has already been started. + */ +int8_t data_acquisition_configure_adc_trigger_source(uint8_t adc_number, uint32_t trigger_source); + +/** + * This functions starts the acquisition chain. It must be called + * after all module configuration has been carried out. No + * 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. + */ +int8_t data_acquisition_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. + */ +char* data_acquisition_get_channel_name(uint8_t adc_number, uint8_t channel_rank); + +/** + * Function to access the acquired data for each channel. + * Each function provides a buffer in which all data that + * have been acquired since last call are stored. The count + * of these values is returned as an output parameter: the + * user has to define a variable and pass a pointer to this + * variable as the parameter of the function. The variable + * will be updated with the number of values that are available + * in the buffer. + * + * NOTE 1: When calling one of these functions, it invalidates + * the buffer returned by a previous call to the same function. + * NOTE 2: All function buffers are independent. + * + * @param number_of_values_acquired Pass a pointer to an uint32_t variable. + * This variable will be updated with the number of values that + * have been acquired for this channel. + * @return Pointer to a buffer in which the acquired values are stored. + * If number_of_values_acquired is 0, do not try to access the + * buffer as it may be NULL. + */ +uint16_t* data_acquisition_get_v1_low_values(uint32_t* number_of_values_acquired); +uint16_t* data_acquisition_get_v2_low_values(uint32_t* number_of_values_acquired); +uint16_t* data_acquisition_get_v_high_values(uint32_t* number_of_values_acquired); +uint16_t* data_acquisition_get_i1_low_values(uint32_t* number_of_values_acquired); +uint16_t* data_acquisition_get_i2_low_values(uint32_t* number_of_values_acquired); +uint16_t* data_acquisition_get_i_high_values(uint32_t* number_of_values_acquired); +uint16_t* data_acquisition_get_temp_sensor_values(uint32_t* number_of_values_acquired); + + +#ifdef __cplusplus +} +#endif + +#endif // DATA_ACQUISITION_H_ diff --git a/zephyr/nucleo_g474re.overlay b/zephyr/nucleo_g474re.overlay index 04b45dd36af941884d76a260ddc216e496bf4edc..780a9fce859cd5216c6600641671091f5a53e6e1 100644 --- a/zephyr/nucleo_g474re.overlay +++ b/zephyr/nucleo_g474re.overlay @@ -16,6 +16,13 @@ status = "okay"; }; +/* +&adc3 { + pinctrl-0 = <&adc3_in1_pb1 >; + status = "okay"; +}; +*/ + /*******/ /* SPI */ /*******/ @@ -77,10 +84,6 @@ status = "okay"; }; -&dma2 { - status = "okay"; -}; - &dmamux1 { status = "okay"; }; diff --git a/zephyr/prj.conf b/zephyr/prj.conf index aff1b3e1faa651a268243c7f639dbbc790973107..4165d53541877708f1cd2204de9cae25b43e49a3 100644 --- a/zephyr/prj.conf +++ b/zephyr/prj.conf @@ -1,7 +1,6 @@ # Main application configuration (overrides board-specific settings) -# only very small heap necessary for malloc in printf statements with %f -CONFIG_HEAP_MEM_POOL_SIZE=256 +CONFIG_HEAP_MEM_POOL_SIZE=2048 CONFIG_CPLUSPLUS=y @@ -28,7 +27,7 @@ CONFIG_HWINFO=y # Buses CONFIG_GPIO=y CONFIG_SERIAL=y -CONFIG_I2C=y +#CONFIG_SPI=y # Console CONFIG_CONSOLE_SUBSYS=y