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

Added OwnTech's Zephyr modules to the tree.

parent fa005f4d
# Macro to list all subdirectories in a specified directory
MACRO(SUBDIRLIST result curdir)
FILE(GLOB children RELATIVE ${curdir} ${curdir}/*)
SET(dirlist "")
FOREACH(child ${children})
IF(IS_DIRECTORY ${curdir}/${child})
LIST(APPEND dirlist ${curdir}/${child})
ENDIF()
ENDFOREACH()
SET(${result} ${dirlist})
ENDMACRO()
# Define SUBDIRS as the list of all subdirectories of the modules directory
SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}/modules)
# Append found modules to zephyr extra modules variable
list(APPEND ZEPHYR_EXTRA_MODULES ${SUBDIRS})
# Configure Zephyr
cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
......
if(CONFIG_OWNTECH_DATA_ACQUISITION)
zephyr_include_directories(.)
zephyr_library()
zephyr_library_sources(
./adc/adc.c
./adc/adc_channels.c
./adc/adc_core.c
./adc/adc_helper.c
./dma/dma.c
./data_dispatch/data_dispatch.c
./data_acquisition.c
)
endif()
config OWNTECH_DATA_ACQUISITION
bool "Enable OwnTech data acquisition using ADCs"
default y
select DMA
/*
* 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>
*/
// STM32 LL
#include <stm32g4xx_ll_adc.h>
// OwnTech API
#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);
}
/////
// Public API
/**
* Configure ADC and DMA according to OwnTech
* board requirements.
*/
void adc_init()
{
// Initialize ADC
adc_core_init();
adc_core_set_dual_mode();
// Initialize channels
adc_channels_init();
// Enable ADC
adc_core_enable(ADC1);
adc_core_enable(ADC2);
// Perform post-enable ADC configuration
adc_channels_configure(ADC1);
adc_channels_configure(ADC2);
_adc_configure_adc_1();
_adc_configure_adc_2();
// Finally, start ADCs
adc_core_start(ADC1);
adc_core_start(ADC2);
}
/*
* 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 main include for ADC configuration.
*/
#ifndef ADC_H_
#define ADC_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes ADC1 and ADC2 driver.
*/
void adc_init();
#ifdef __cplusplus
}
#endif
#endif // ADC_H_
/*
* 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
*/
/**
* @brief ADC driver for stm32g474re
*
* @author Hugues Larrive <hugues.larrive@laas.fr>
* @author Clément Foucher <clement.foucher@laas.fr>
*/
// Stdlib
#include <stdlib.h>
// Current file header
#include "adc_channels_private.h"
// OwnTech API
#include "adc_helper.h"
#include "adc_core.h"
/////
// Variables
static channel_prop_t channels_props[] =
{
DT_FOREACH_CHILD(ADC_INPUTS_NODELABEL, CHANNEL_WRITE_PROP)
};
static uint8_t channels_in_adc1_count;
static uint8_t channels_in_adc2_count;
static channel_prop_t** adc1_channels_list;
static channel_prop_t** adc2_channels_list;
/////
// ADC channels private functions
/**
* Counts device-tree configured channels in each ADC.
*/
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++;
}
}
}
/**
* Differential channel setup.
* Must be done before ADC is enabled.
*/
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);
}
}
}
}
/**
* 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);
}
/////
// ADC channls 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 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
);
}
}
}
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;
}
uint8_t adc_channels_get_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
/*
* 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
*/
/**
* @brief This is the public include for adc_channels.h
*
* @author Clément Foucher <clement.foucher@laas.fr>
*/
#ifndef ADC_CHANNELS_H_
#define ADC_CHANNELS_H_
// Zephyr
#include <zephyr.h>
#ifdef __cplusplus
extern "C" {
#endif
void adc_channels_init();
void adc_channels_configure(ADC_TypeDef* adc);
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);
#ifdef __cplusplus
}
#endif
#endif // ADC_CHANNELS_H_
/*
* 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_
/*
* 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>