diff --git a/packages/devs/adc/cortexm/stm32/current/ChangeLog b/packages/devs/adc/cortexm/stm32/current/ChangeLog new file mode 100755 index 0000000..c416579 --- /dev/null +++ b/packages/devs/adc/cortexm/stm32/current/ChangeLog @@ -0,0 +1,30 @@ +2009-02-24 Simon Kallweit + + * STM32 ADC driver package created + * cdl/adc_stm32.cdl + * src/adc_stm32.c + * tests/stm32_adc_test.c + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 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 +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/packages/devs/adc/cortexm/stm32/current/cdl/adc_stm32.cdl b/packages/devs/adc/cortexm/stm32/current/cdl/adc_stm32.cdl new file mode 100755 index 0000000..19f54b5 --- /dev/null +++ b/packages/devs/adc/cortexm/stm32/current/cdl/adc_stm32.cdl @@ -0,0 +1,254 @@ +# ==================================================================== +# +# adc_stm32.cdl +# +# eCos STM32 ADC configuration data +# +# ==================================================================== +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2009 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos 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 General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): Simon Kallweit +# Contributors: +# Date: 2009-02-24 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + + +cdl_package CYGPKG_DEVS_ADC_CORTEXM_STM32 { + display "ST STM32 ADC device driver" + + parent CYGPKG_IO_ADC_DEVICES + active_if CYGPKG_IO_ADC_DEVICES + active_if CYGPKG_HAL_CORTEXM_STM32 + requires {CYGNUM_IO_ADC_SAMPLE_SIZE >= 12} + description " + This option enables the ADC device drivers for the ST STM32. The STM32 + has up to 3 ADC devices. The driver supports both ADC1 and ADC3. ADC2 + is not supported as it does cover the same inputs as ADC2 and does not + support DMA directly." + + include_dir cyg/io + compile -library=libextras.a adc_stm32.c + + cdl_option CYGNUM_DEVS_ADC_CORTEXM_STM32_CLOCK_DIV { + display "ADC clock divider" + flavor data + legal_values { 2 4 6 8 } + default_value 8 + description " + This option specifies the level of debug data output by + the STM32 ADC device driver. A value of 0 signifies + no debug data output; 1 signifies normal debug data + output. If an overrun occurred then this can only be + detected by debug output messages." + } + + cdl_component CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1 { + display "ADC1" + description " + ADC1 supports 16 analog input channels as well as additional + channels for CPU temperature and internal VREF. This is a total of + 18 channels. Note that only 16 channels may be active at once! + ADC1 uses TIM3 to generate scan events and DMA1 channel 1 for data + transmission." + + cdl_interface CYGINT_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNELS { + display "Number of ADC channels" + } + + cdl_option CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC1_SAMPLE_TIME { + display "Sample time" + flavor data + legal_values 1 to 1000 + default_value 20 + description " + Sampling time in us. When sampling the internal temperatur, + this needs to be at least 17.1 us." + } + + cdl_option CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC1_DEFAULT_RATE { + display "Default sample rate" + flavor data + legal_values 1 to 10000 + default_value 100 + description " + The driver will be initialized with the default sample rate. + If you raise the default sample rate you might need to increase + the buffer size for each channel." + } + + cdl_option CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC1_DMA_INT_PRI { + display "DMA interrupt priority" + flavor data + default_value 0x80 + description " + Priority of the DMA request interrupt." + } + + # ADC1 supports 16 analog inputs + 2 additional channels (temperature/vref) + for { set ::channel 0 } { $::channel < 18 } { incr ::channel } { + + cdl_component CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL[set ::channel] { + display "ADC channel [set ::channel]" + flavor bool + default_value [set ::channel] == 0 + implements CYGINT_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNELS + description " + If the application needs to access the on-chip ADC + channel [set ::channel] via an eCos ADC driver then + this option should be enabled." + + cdl_option CYGDAT_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL[set ::channel]_NAME { + display "Device name" + flavor data + default_value [format {"\"/dev/adc0%d\""} $::channel] + description " + This option controls the name that an eCos application + should use to access this device via cyg_io_lookup(), + open(), or similar calls." + } + + cdl_option CYGDAT_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL[set ::channel]_BUFSIZE { + display "Size of data buffer" + flavor data + legal_values 1 to 65536 + default_value 128 + description " + This option controls the number of samples the + buffer can store. The required RAM is = size of + data buffer * 2." + } + } + } + } + + cdl_component CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3 { + display "ADC3" + description " + ADC3 supports 16 analog input channels. All channels may be active + at once. ADC3 uses TIM8 to generate scan events and DMA2 channel 5 + for data transmission." + + cdl_interface CYGINT_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNELS { + display "Number of ADC channels" + } + + cdl_option CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC3_SAMPLE_TIME { + display "Sample time" + flavor data + legal_values 1 to 1000 + default_value 20 + description " + Sampling time in us. When sampling the internal temperatur, + this needs to be at least 17.1 us." + } + + cdl_option CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC3_DEFAULT_RATE { + display "Default sample rate" + flavor data + legal_values 1 to 10000 + default_value 100 + description " + The driver will be initialized with the default sample rate. + If you raise the default sample rate you might need to increase + the buffer size for each channel." + } + + cdl_option CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC3_DMA_INT_PRI { + display "DMA interrupt priority" + flavor data + default_value 0x80 + description " + Priority of the DMA request interrupt." + } + + # ADC3 supports 16 analog inputs + for { set ::channel 0 } { $::channel < 16 } { incr ::channel } { + + cdl_component CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL[set ::channel] { + display "ADC channel [set ::channel]" + flavor bool + default_value [set ::channel] == 0 + implements CYGINT_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNELS + description " + If the application needs to access the on-chip ADC + channel [set ::channel] via an eCos ADC driver then + this option should be enabled." + + cdl_option CYGDAT_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL[set ::channel]_NAME { + display "Device name" + flavor data + default_value [format {"\"/dev/adc1%d\""} $::channel] + description " + This option controls the name that an eCos application + should use to access this device via cyg_io_lookup(), + open(), or similar calls." + } + + cdl_option CYGDAT_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL[set ::channel]_BUFSIZE { + display "Size of data buffer" + flavor data + legal_values 1 to 65536 + default_value 128 + description " + This option controls the number of samples the + buffer can store. The required RAM is = size of + data buffer * 2." + } + } + } + } + + cdl_component CYGPKG_DEVS_ADC_CORTEXM_STM32_TESTS { + display "Tests for STM32 ADC driver" + flavor data + no_define + calculated { "tests/stm32_adc_test" } + description " + This option specifies the set of tests for the STM32 + ADC device driver." + + cdl_option CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC_TEST_RATE { + display "Test sample rate" + flavor data + legal_values 1 to 10000 + default_value 100 + description " + Sample rate to use for adc test." + } + } +} diff --git a/packages/devs/adc/cortexm/stm32/current/src/adc1.inl b/packages/devs/adc/cortexm/stm32/current/src/adc1.inl new file mode 100644 index 0000000..5219c57 --- /dev/null +++ b/packages/devs/adc/cortexm/stm32/current/src/adc1.inl @@ -0,0 +1,108 @@ + +// ADC input pins +static const cyg_uint32 stm32_adc_pins1[] = { + CYGHWR_HAL_STM32_ADC1_IN0, + CYGHWR_HAL_STM32_ADC1_IN1, + CYGHWR_HAL_STM32_ADC1_IN2, + CYGHWR_HAL_STM32_ADC1_IN3, + CYGHWR_HAL_STM32_ADC1_IN4, + CYGHWR_HAL_STM32_ADC1_IN5, + CYGHWR_HAL_STM32_ADC1_IN6, + CYGHWR_HAL_STM32_ADC1_IN7, + CYGHWR_HAL_STM32_ADC1_IN8, + CYGHWR_HAL_STM32_ADC1_IN9, + CYGHWR_HAL_STM32_ADC1_IN10, + CYGHWR_HAL_STM32_ADC1_IN11, + CYGHWR_HAL_STM32_ADC1_IN12, + CYGHWR_HAL_STM32_ADC1_IN13, + CYGHWR_HAL_STM32_ADC1_IN14, + CYGHWR_HAL_STM32_ADC1_IN15, + CYGHWR_HAL_STM32_GPIO_NONE, + CYGHWR_HAL_STM32_GPIO_NONE, +}; + +// ADC setup +static const stm32_adc_setup stm32_adc_setup1 = { + .adc_base = CYGHWR_HAL_STM32_ADC1, + .dma_base = CYGHWR_HAL_STM32_DMA1, + .dma_int_vector = CYGNUM_HAL_INTERRUPT_DMA1_CH1, + .dma_int_pri = CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC1_DMA_INT_PRI, + .dma_channel = 1, + .tim_base = CYGHWR_HAL_STM32_TIM3, + .pins = stm32_adc_pins1, + .extsel = 4, + .sample_time = CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC1_SAMPLE_TIME, +}; + +// ADC DMA buffer +static cyg_uint16 + stm32_adc_dma_buf1[CYGINT_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNELS] + __attribute__((aligned(2), section(".sram"))); + +// ADC device info +static stm32_adc_info stm32_adc_info1 = { + .setup = &stm32_adc_setup1, + .dma_buf = stm32_adc_dma_buf1, +}; + +// ADC device instance +CYG_ADC_DEVICE(stm32_adc_device1, + &stm32_adc_funs, + &stm32_adc_info1, + CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC1_DEFAULT_RATE); + +// ADC channels +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL0 +STM32_ADC_CHANNEL(1, 0) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL1 +STM32_ADC_CHANNEL(1, 1) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL2 +STM32_ADC_CHANNEL(1, 2) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL3 +STM32_ADC_CHANNEL(1, 3) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL4 +STM32_ADC_CHANNEL(1, 4) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL5 +STM32_ADC_CHANNEL(1, 5) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL6 +STM32_ADC_CHANNEL(1, 6) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL7 +STM32_ADC_CHANNEL(1, 7) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL8 +STM32_ADC_CHANNEL(1, 8) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL9 +STM32_ADC_CHANNEL(1, 9) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL10 +STM32_ADC_CHANNEL(1, 10) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL11 +STM32_ADC_CHANNEL(1, 11) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL12 +STM32_ADC_CHANNEL(1, 12) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL13 +STM32_ADC_CHANNEL(1, 13) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL14 +STM32_ADC_CHANNEL(1, 14) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL15 +STM32_ADC_CHANNEL(1, 15) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL16 +STM32_ADC_CHANNEL(1, 16) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1_CHANNEL17 +STM32_ADC_CHANNEL(1, 17) +#endif diff --git a/packages/devs/adc/cortexm/stm32/current/src/adc3.inl b/packages/devs/adc/cortexm/stm32/current/src/adc3.inl new file mode 100644 index 0000000..afcc151 --- /dev/null +++ b/packages/devs/adc/cortexm/stm32/current/src/adc3.inl @@ -0,0 +1,100 @@ + +// ADC input pins +static const cyg_uint32 stm32_adc_pins3[] = { + CYGHWR_HAL_STM32_ADC3_IN0, + CYGHWR_HAL_STM32_ADC3_IN1, + CYGHWR_HAL_STM32_ADC3_IN2, + CYGHWR_HAL_STM32_ADC3_IN3, + CYGHWR_HAL_STM32_ADC3_IN4, + CYGHWR_HAL_STM32_ADC3_IN5, + CYGHWR_HAL_STM32_ADC3_IN6, + CYGHWR_HAL_STM32_ADC3_IN7, + CYGHWR_HAL_STM32_ADC3_IN8, + CYGHWR_HAL_STM32_ADC3_IN9, + CYGHWR_HAL_STM32_ADC3_IN10, + CYGHWR_HAL_STM32_ADC3_IN11, + CYGHWR_HAL_STM32_ADC3_IN12, + CYGHWR_HAL_STM32_ADC3_IN13, + CYGHWR_HAL_STM32_ADC3_IN14, + CYGHWR_HAL_STM32_ADC3_IN15, +}; + +// ADC setup +static const stm32_adc_setup stm32_adc_setup3 = { + .adc_base = CYGHWR_HAL_STM32_ADC3, + .dma_base = CYGHWR_HAL_STM32_DMA2, + .dma_int_vector = CYGNUM_HAL_INTERRUPT_DMA2_CH4_5, + .dma_int_pri = 0x80, + .dma_channel = 5, + .tim_base = CYGHWR_HAL_STM32_TIM8, + .pins = stm32_adc_pins3, + .extsel = 4, + .sample_time = CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC3_SAMPLE_TIME, +}; + +// ADC DMA buffer +static cyg_uint16 + stm32_adc_dma_buf3[CYGINT_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNELS] + __attribute__((aligned(2), section(".sram"))); + +// ADC device info +static stm32_adc_info stm32_adc_info3 = { + .setup = &stm32_adc_setup3, + .dma_buf = stm32_adc_dma_buf3, +}; + +// ADC device instance +CYG_ADC_DEVICE(stm32_adc_device3, + &stm32_adc_funs, + &stm32_adc_info3, + CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC3_DEFAULT_RATE); + +// ADC channels +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL0 +STM32_ADC_CHANNEL(3, 0) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL1 +STM32_ADC_CHANNEL(3, 1) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL2 +STM32_ADC_CHANNEL(3, 2) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL3 +STM32_ADC_CHANNEL(3, 3) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL4 +STM32_ADC_CHANNEL(3, 4) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL5 +STM32_ADC_CHANNEL(3, 5) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL6 +STM32_ADC_CHANNEL(3, 6) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL7 +STM32_ADC_CHANNEL(3, 7) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL8 +STM32_ADC_CHANNEL(3, 8) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL9 +STM32_ADC_CHANNEL(3, 9) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL10 +STM32_ADC_CHANNEL(3, 10) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL11 +STM32_ADC_CHANNEL(3, 11) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL12 +STM32_ADC_CHANNEL(3, 12) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL13 +STM32_ADC_CHANNEL(3, 13) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL14 +STM32_ADC_CHANNEL(3, 14) +#endif +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3_CHANNEL15 +STM32_ADC_CHANNEL(3, 15) +#endif diff --git a/packages/devs/adc/cortexm/stm32/current/src/adc_stm32.c b/packages/devs/adc/cortexm/stm32/current/src/adc_stm32.c new file mode 100755 index 0000000..e4848e7 --- /dev/null +++ b/packages/devs/adc/cortexm/stm32/current/src/adc_stm32.c @@ -0,0 +1,611 @@ +//========================================================================== +// +// adc_stm32.c +// +// ADC driver for STM32 on chip ADC +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos 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 General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Simon Kallweit +// Contributors: +// Date: 2009-02-24 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +// Diagnostic support +// Switch the #if to 1 to generate some diagnostic messages. + +#if 0 +#include +#define adc_diag( __fmt, ... ) diag_printf("ADC: %30s[%4d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ ); +#else +#define adc_diag( __fmt, ... ) +#endif + + +//----------------------------------------------------------------------------- +// STM32 ADC device setup + +typedef struct stm32_adc_setup { + CYG_ADDRESS adc_base; // ADC registers base address + CYG_ADDRESS dma_base; // DMA registers base address + cyg_vector_t dma_int_vector; // DMA interrupt vector + cyg_priority_t dma_int_pri; // DMA interrupt priority + cyg_uint8 dma_channel; // DMA channel to use + CYG_ADDRESS tim_base; // Timer registers base address + const cyg_uint32 *pins; // ADC associated GPIO pins + cyg_uint8 extsel; // ADC EXTSEL value (timer event) + cyg_uint32 sample_time; // ADC sampling time in us +} stm32_adc_setup; + +//----------------------------------------------------------------------------- +// STM32 ADC device + +typedef struct stm32_adc_info { + const stm32_adc_setup *setup; // ADC setup + cyg_handle_t dma_int_handle; // DMA interrupt handle + cyg_interrupt dma_int_data; // DMA interrupt data + cyg_uint16 *dma_buf; // DMA buffer + cyg_adc_channel *chan[18]; // Channel references by channel no + cyg_uint32 chan_mask; // Channel mask +} stm32_adc_info; + +//----------------------------------------------------------------------------- +// API function call forward references + +static bool stm32_adc_init(struct cyg_devtab_entry *tab); +static Cyg_ErrNo stm32_adc_lookup(struct cyg_devtab_entry **tab, + struct cyg_devtab_entry *sub_tab, + const char *name); + +static void stm32_adc_enable(cyg_adc_channel *chan); +static void stm32_adc_disable(cyg_adc_channel *chan); +static void stm32_adc_set_rate(cyg_adc_channel *chan, cyg_uint32 rate); + +static cyg_uint32 stm32_dma_isr(cyg_vector_t vector, cyg_addrword_t data); +static void stm32_dma_dsr(cyg_vector_t vector, cyg_ucount32 count, + cyg_addrword_t data); + +static void stm32_adc_init_clock(void); +static void stm32_adc_init_device(cyg_adc_device *device); +static void stm32_adc_update_sequence(cyg_adc_device *device); + +CYG_ADC_FUNCTIONS(stm32_adc_funs, + stm32_adc_enable, + stm32_adc_disable, + stm32_adc_set_rate); + +//----------------------------------------------------------------------------- +// STM32 ADC channel instance macro + +#define STM32_ADC_CHANNEL(_device_, _chan_) \ +CYG_ADC_CHANNEL( \ + stm32_adc##_device_##_channel##_chan_, \ + _chan_, \ + CYGDAT_DEVS_ADC_CORTEXM_STM32_ADC##_device_##_CHANNEL##_chan_##_BUFSIZE,\ + &stm32_adc_device##_device_ \ +); \ +DEVTAB_ENTRY( \ + stm32_adc##_device_##_channel##_chan_##_device, \ + CYGDAT_DEVS_ADC_CORTEXM_STM32_ADC##_device_##_CHANNEL##_chan_##_NAME, \ + 0, \ + &cyg_io_adc_devio, \ + stm32_adc_init, \ + stm32_adc_lookup, \ + &stm32_adc##_device_##_channel##_chan_ \ +); + +//----------------------------------------------------------------------------- +// STM32 ADC device instances + +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC1 +#include "adc1.inl" +#endif + +#ifdef CYGHWR_DEVS_ADC_CORTEXM_STM32_ADC3 +#include "adc3.inl" +#endif + +static cyg_bool initialized; +static cyg_uint32 adc_clock; + +__externC cyg_uint32 hal_stm32_pclk1; +__externC cyg_uint32 hal_stm32_pclk2; + +//----------------------------------------------------------------------------- +// This function is called from the device IO infrastructure to initialize the +// device. It should perform any work needed to start up the device, short of +// actually starting the generation of samples. This function will be called +// for each channel, so if there is initialization that only needs to be done +// once, such as creating and interrupt object, then care should be taken to do +// this. This function should also call cyg_adc_device_init() to initialize the +// generic parts of the driver. + +static bool +stm32_adc_init(struct cyg_devtab_entry *tab) +{ + cyg_adc_channel *chan = (cyg_adc_channel *) tab->priv; + cyg_adc_device *device = chan->device; + stm32_adc_info *info = device->dev_priv; + + adc_diag("Initializing device\n"); + + // Initialize ADC clock + if (!initialized) { + stm32_adc_init_clock(); + initialized = true; + } + + // Keep reference to channel + info->chan[chan->channel] = chan; + + if (!info->dma_int_handle) { + // Initialize ADC device + stm32_adc_init_device(device); + + // Set default rate + stm32_adc_set_rate(chan, chan->device->config.rate); + + // Initialize DMA interrupt + cyg_drv_interrupt_create(info->setup->dma_int_vector, + info->setup->dma_int_pri, + (cyg_addrword_t) device, + &stm32_dma_isr, + &stm32_dma_dsr, + &info->dma_int_handle, + &info->dma_int_data); + cyg_drv_interrupt_attach(info->dma_int_handle); + cyg_drv_interrupt_unmask(info->setup->dma_int_vector); + } + + // Initialize generic parts of ADC device + cyg_adc_device_init(device); + + return true; +} + +//----------------------------------------------------------------------------- +// This function is called when a client looks up or opens a channel. It should +// call cyg_adc_channel_init() to initialize the generic part of the channel. +// It should also perform any operations needed to start the channel generating +// samples. + +static Cyg_ErrNo +stm32_adc_lookup(struct cyg_devtab_entry **tab, + struct cyg_devtab_entry *sub_tab, + const char *name) +{ + cyg_adc_channel *chan = (cyg_adc_channel *) (*tab)->priv; + stm32_adc_info *info = chan->device->dev_priv; + cyg_uint32 cr; + + adc_diag("Opening device\n"); + + // Configure the input pin, if available + if (info->setup->pins[chan->channel] != CYGHWR_HAL_STM32_GPIO_NONE) + CYGHWR_HAL_STM32_GPIO_SET(info->setup->pins[chan->channel]); + + // Activate temperature and VREF if necessary + if (chan->channel >= 16) { + HAL_READ_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + cr |= CYGHWR_HAL_STM32_ADC_CR2_TSVREFE; + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + } + + // Initialize generic parts of the channel + cyg_adc_channel_init(chan); + + // The generic ADC manual says: When a channel is first looked up or + // opened, then it is automatically enabled and samples start to + // accumulate - so we start the channel now + chan->enabled = true; + stm32_adc_enable(chan); + + return ENOERR; +} + +//----------------------------------------------------------------------------- +// This function is called from the generic ADC package to enable the channel +// in response to a CYG_IO_SET_CONFIG_ADC_ENABLE config operation. It should +// take any steps needed to start the channel generating samples + +static void +stm32_adc_enable(cyg_adc_channel *chan) +{ + stm32_adc_info *info = chan->device->dev_priv; + cyg_uint32 cr; + cyg_bool start; + + adc_diag("Enabling channel\n"); + + start = !info->chan_mask; + + // Update the scanning sequence + info->chan_mask |= (1 << chan->channel); + stm32_adc_update_sequence(chan->device); + + // Start scanning when first channel was activated + if (start) { + // Enable timer + adc_diag("Starting scanning\n"); + HAL_READ_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_CR1, cr); + cr |= CYGHWR_HAL_STM32_TIM_CR1_CEN; + HAL_WRITE_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_CR1, cr); + } +} + +//----------------------------------------------------------------------------- +// This function is called from the generic ADC package to enable the channel +// in response to a CYG_IO_SET_CONFIG_ADC_DISABLE config operation. It should +// take any steps needed to stop the channel generating samples. + +static void +stm32_adc_disable(cyg_adc_channel *chan) +{ + stm32_adc_info *info = chan->device->dev_priv; + cyg_uint32 cr; + + adc_diag("Disabling channel\n"); + + // Update scanning sequence + info->chan_mask &= ~(1 << chan->channel); + stm32_adc_update_sequence(chan->device); + + // Stop scanning when no channel is active + if (!info->chan_mask) { + // Disable timer + adc_diag("Stopping scanning\n"); + HAL_READ_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_CR1, cr); + cr &= ~CYGHWR_HAL_STM32_TIM_CR1_CEN; + HAL_WRITE_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_CR1, cr); + } +} + +//----------------------------------------------------------------------------- +// This function is called from the generic ADC package to enable the channel +// in response to a CYG_IO_SET_CONFIG_ADC_RATE config operation. It should take +// any steps needed to change the sample rate of the channel, or of the entire +// device. We use a timer channel to generate the interrupts for sampling the +// analog channels + +static void +stm32_adc_set_rate( cyg_adc_channel *chan, cyg_uint32 rate) +{ + cyg_adc_device *device = chan->device; + stm32_adc_info *info = device->dev_priv; + cyg_uint32 clock; + cyg_uint32 period, prescaler; + cyg_uint32 cr; + + adc_diag("Setting rate to %d\n", rate); + + device->config.rate = rate; + + clock = hal_stm32_timer_clock(info->setup->tim_base); + + period = clock / rate; + prescaler = (period / 0x10000) + 1; + period = period / prescaler; + + HAL_WRITE_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_PSC, + prescaler - 1); + HAL_WRITE_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_ARR, + period - 1); + + // Set direction = down, clock divider = 1 + cr = CYGHWR_HAL_STM32_TIM_CR1_DIR | CYGHWR_HAL_STM32_TIM_CR1_CKD_1; + HAL_WRITE_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_CR1, cr); + + // Reinitialize timer + cr = CYGHWR_HAL_STM32_TIM_EGR_UG; + HAL_WRITE_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_EGR, cr); + + // Enable generation of TRGO event + cr = CYGHWR_HAL_STM32_TIM_CR2_MMS_UPDATE; + HAL_WRITE_UINT32(info->setup->tim_base + CYGHWR_HAL_STM32_TIM_CR2, cr); +} + +//----------------------------------------------------------------------------- +// This function is the ISR attached to the ADC device's DMA channel interrupt +// vector. It is responsible for reading samples from the DMA buffer and +// passing them on to the generic layer. + +static cyg_uint32 +stm32_dma_isr(cyg_vector_t vector, cyg_addrword_t data) +{ + cyg_adc_device *device = (cyg_adc_device *) data; + stm32_adc_info *info = (stm32_adc_info *) device->dev_priv; + cyg_uint32 chan_active = info->chan_mask; + cyg_uint16 *sample = info->dma_buf; + cyg_adc_channel **chan = info->chan; + cyg_uint32 res = 0; + + while (chan_active) { + if (chan_active & 0x1) + res |= (CYG_ISR_HANDLED | + cyg_adc_receive_sample(*chan, *sample++ & 0xfff)); + chan_active >>= 1; + chan++; + } + + HAL_WRITE_UINT32(info->setup->dma_base + CYGHWR_HAL_STM32_DMA_IFCR, + CYGHWR_HAL_STM32_DMA_IFCR_MASK(info->setup->dma_channel)); + + cyg_drv_interrupt_acknowledge(vector); + + return res; +} + +//----------------------------------------------------------------------------- +// This function is the DSR attached to the ADC device's DMA channel interrupt +// vector. It is called by the kernel if the ISR return value contains the +// CYG_ISR_CALL_DSR bit. It needs to call cyg_adc_wakeup() for each channel +// that has its wakeup field set. + +static void +stm32_dma_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + cyg_adc_device *device = (cyg_adc_device *) data; + stm32_adc_info *info = (stm32_adc_info *) device->dev_priv; + cyg_uint32 chan_active = info->chan_mask; + cyg_adc_channel **chan = info->chan; + + while (chan_active) { + if (chan_active & 0x1) + if ((*chan)->wakeup) + cyg_adc_wakeup(*chan); + chan_active >>= 1; + chan++; + } +} + +//----------------------------------------------------------------------------- +// Initializes the ADC system clock. + +static void +stm32_adc_init_clock(void) +{ + CYG_ADDRESS rcc = CYGHWR_HAL_STM32_RCC; + cyg_uint32 cfgr; + + adc_diag("Initializing ADC system clock\n"); + + HAL_READ_UINT32(rcc + CYGHWR_HAL_STM32_RCC_CFGR, cfgr); + cfgr &= ~CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_XXX; + +#if CYGNUM_DEVS_ADC_CORTEXM_STM32_CLOCK_DIV == 2 + cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_2; + adc_clock = hal_stm32_pclk2 / 2; +#elif CYGNUM_DEVS_ADC_CORTEXM_STM32_CLOCK_DIV == 4 + cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_4; + adc_clock = hal_stm32_pclk2 / 4; +#elif CYGNUM_DEVS_ADC_CORTEXM_STM32_CLOCK_DIV == 6 + cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_6; + adc_clock = hal_stm32_pclk2 / 6; +#elif CYGNUM_DEVS_ADC_CORTEXM_STM32_CLOCK_DIV == 8 + cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_8; + adc_clock = hal_stm32_pclk2 / 8; +#endif + + HAL_READ_UINT32(rcc + CYGHWR_HAL_STM32_RCC_CFGR, cfgr); +} + +//----------------------------------------------------------------------------- +// Initializes an ADC device. + +static void +stm32_adc_init_device(cyg_adc_device *device) +{ + stm32_adc_info *info = device->dev_priv; + cyg_uint32 cr; + cyg_uint64 tmp; + cyg_uint32 cycles; + cyg_uint32 smpr; + int i; + + static const cyg_uint32 cycles_table[] = + { 15, 75, 135, 285, 415, 555, 715, 2395 }; + + // Make sure ADC is powered on + cr = CYGHWR_HAL_STM32_ADC_CR2_ADON; + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + + // Reset calibration + cr |= CYGHWR_HAL_STM32_ADC_CR2_RSTCAL; + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + do { + HAL_READ_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + } while (cr & CYGHWR_HAL_STM32_ADC_CR2_RSTCAL); + + // Do calibration + cr |= CYGHWR_HAL_STM32_ADC_CR2_CAL; + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + do { + HAL_READ_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + } while (cr & CYGHWR_HAL_STM32_ADC_CR2_CAL); + + // Power off ADC + cr &= CYGHWR_HAL_STM32_ADC_CR2_ADON; + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + + // Enable external triggering and DMA + cr |= CYGHWR_HAL_STM32_ADC_CR2_DMA | + CYGHWR_HAL_STM32_ADC_CR2_EXTTRIG | + CYGHWR_HAL_STM32_ADC_CR2_EXTSEL(info->setup->extsel); + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + + // Enable scanning + cr = CYGHWR_HAL_STM32_ADC_CR1_SCAN; + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR1, cr); + + // Setup DMA channel + HAL_WRITE_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CPAR(info->setup->dma_channel), + info->setup->adc_base + CYGHWR_HAL_STM32_ADC_DR); + HAL_WRITE_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CMAR(info->setup->dma_channel), + (CYG_ADDRESS) info->dma_buf); + HAL_WRITE_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CNDTR(info->setup->dma_channel), + 0); + HAL_WRITE_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CCR(info->setup->dma_channel), + CYGHWR_HAL_STM32_DMA_CCR_TCIE | + CYGHWR_HAL_STM32_DMA_CCR_TEIE | + CYGHWR_HAL_STM32_DMA_CCR_CIRC | + CYGHWR_HAL_STM32_DMA_CCR_MINC | + CYGHWR_HAL_STM32_DMA_CCR_PSIZE16 | + CYGHWR_HAL_STM32_DMA_CCR_MSIZE16); + + // Compute duration of a single cycle in pico-seconds + tmp = 1000000000000LL / adc_clock; + // Compute tenths of cycles for target sample time + tmp = (info->setup->sample_time * 1000000 * 10) / tmp; + cycles = tmp; + + adc_diag("Setting ADC sample time to %d us (%d.%d cycles)\n", + info->setup->sample_time, cycles / 10, cycles % 10); + + // Find best matching SMPR value + if (cycles > cycles_table[7]) { + adc_diag("ADC sample time too long\n"); + smpr = 7; + } else { + for (smpr = 7; smpr > 0; smpr--) + if (cycles > cycles_table[smpr]) + break; + } + + // Expand SMPR value to all channels + for (i = 0; i < 10; i++) + smpr |= smpr << 3; + + // Set sampling time + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_SMPR1, smpr); + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_SMPR2, smpr); +} + +//----------------------------------------------------------------------------- +// Updates the sequence for the regular group. ADC and DMA are disabled during +// the update. The sequence registers and DMA count registers are rewritten. +// Note: As the regular group consists of 16 channels max, we cannot activate +// the theoretical maximum of 18 channels (analog ins + temperature/VREF). + +static void +stm32_adc_update_sequence(cyg_adc_device *device) +{ + stm32_adc_info *info = device->dev_priv; + int i; + int count = 0; + cyg_uint32 cr; + cyg_uint32 sqr1 = 0; + cyg_uint32 sqr2 = 0; + cyg_uint32 sqr3 = 0; + + adc_diag("Updateing regular group\n"); + + // Disable ADC + HAL_READ_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + cr &= ~CYGHWR_HAL_STM32_ADC_CR2_ADON; + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + + // Disable DMA + HAL_READ_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CCR(info->setup->dma_channel), cr); + cr &= ~CYGHWR_HAL_STM32_DMA_CCR_EN; + HAL_WRITE_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CCR(info->setup->dma_channel), cr); + + // Initialize scanning sequence (regular group) + for (i = 0; i < 18; i++) { + if (!(info->chan_mask & (1 << i))) + continue; + + if (count < 6) { + sqr3 |= CYGHWR_HAL_STM32_ADC_SQRx_SQ(count, i); + } else if (count < 12) { + sqr2 |= CYGHWR_HAL_STM32_ADC_SQRx_SQ(count - 6, i); + } else if (count < 16) { + sqr1 |= CYGHWR_HAL_STM32_ADC_SQRx_SQ(count - 12, i); + } else { + CYG_FAIL("Too many active channels\n"); + } + count++; + } + + sqr1 |= CYGHWR_HAL_STM32_ADC_SQR1_L(count - 1); + + adc_diag("sqr1: %p sqr2: %p sqr3: %p\n", + (void *) sqr1, (void *) sqr2, (void *) sqr3); + + // Write sequence registers + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_SQR1, sqr1); + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_SQR2, sqr2); + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_SQR3, sqr3); + + // Update DMA + HAL_WRITE_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CNDTR(info->setup->dma_channel), + count); + + // Enable DMA + HAL_READ_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CCR(info->setup->dma_channel), cr); + cr |= CYGHWR_HAL_STM32_DMA_CCR_EN; + HAL_WRITE_UINT32(info->setup->dma_base + + CYGHWR_HAL_STM32_DMA_CCR(info->setup->dma_channel), cr); + + // Enable ADC + HAL_READ_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); + cr |= CYGHWR_HAL_STM32_ADC_CR2_ADON; + HAL_WRITE_UINT32(info->setup->adc_base + CYGHWR_HAL_STM32_ADC_CR2, cr); +} diff --git a/packages/devs/adc/cortexm/stm32/current/tests/stm32_adc_test.c b/packages/devs/adc/cortexm/stm32/current/tests/stm32_adc_test.c new file mode 100755 index 0000000..d25afb3 --- /dev/null +++ b/packages/devs/adc/cortexm/stm32/current/tests/stm32_adc_test.c @@ -0,0 +1,264 @@ +//========================================================================== +// +// stmp32_adc_test.c +// +// ADC performance test for STM32 +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos 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 General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Simon Kallweit +// Contributors: +// Date: 2009-02-24 +// Description: ADC performance test for STM32 +//####DESCRIPTIONEND#### + +#include + +#include +#include +#include +#include +#include + +// Package requirements +#if defined(CYGPKG_IO_ADC) && defined(CYGPKG_KERNEL) + +#include +#include +#include +#include + +// Package option requirements +#if defined(CYGFUN_KERNEL_API_C) + +#include + +#define MAX_DEVICES 2 +#define MAX_CHANNELS_PER_DEVICE 18 +#define MAX_CHANNELS (MAX_DEVICES * MAX_CHANNELS_PER_DEVICE) + +// Test channel +typedef struct test_channel { + int device; + int channel; + cyg_io_handle_t handle; + cyg_uint32 count; + cyg_adc_sample_t sample; +} test_channel; + +// Test channels +static test_channel channels[MAX_CHANNELS]; + +// Thread data +cyg_handle_t thread_handle; +cyg_thread thread_data; +cyg_uint8 thread_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL]; + + +void +adc_thread(cyg_addrword_t data) +{ + cyg_uint32 num = 0; + char dev[] = "/dev/adcXXX"; + test_channel *chan; + cyg_adc_sample_t sample; + int res; + cyg_uint32 cfg_data; + cyg_uint32 len; + cyg_uint32 start_time; + cyg_uint32 end_time; + int i, j; + cyg_uint8 seconds = 0; + float final_seconds; + cyg_uint32 samples_expected; + + diag_printf("\n\nThis test reads samples from all enabled ADC channels.\n" + "Each second the number of already acquired samples\n" + "will be printed. After 10 seconds all ADC channels\n" + "will be stopped and each ADC buffer will be read until\n" + "it is empty. If the number of acquired samples is much\n" + "smaller than the number of expected samples, then you\n" + "should lower the sample rate.\n\n"); + + // Open available channels + for (i = 0; i < MAX_DEVICES; i++) { + for (j = 0; j < MAX_CHANNELS_PER_DEVICE; j++) { + chan = &channels[num]; + chan->device = i; + chan->channel = j; + chan->count = 0; + + dev[8] = '0' + i; + if (j < 10) { + dev[9] = '0' + j; + dev[10] = '\0'; + } else { + dev[9] = '0' + (j / 10); + dev[10] = '0' + (j % 10); + } + + if (cyg_io_lookup(dev, &chan->handle) == ENOERR) { + diag_printf("Opened ADC channel '%s'\n", dev); + num++; + } + } + } + + // Make channels non-blocking + for (i = 0; i < num; i++) { + chan = &channels[i]; + cfg_data = 0; + len = sizeof(cfg_data); + res = cyg_io_set_config(chan->handle, + CYG_IO_SET_CONFIG_READ_BLOCKING, + &cfg_data, &len); + if (res != ENOERR) + CYG_TEST_FAIL_FINISH("Error switching ADC channel to non blocking"); + + chan->count = 0; + } + + start_time = cyg_current_time(); + do { + for (i = 0; i < num; i++) { + chan = &channels[i]; + + // Read a samples from the channel + do { + cyg_uint32 len = sizeof(sample); + res = cyg_io_read(chan->handle, &sample, &len); + if (res == ENOERR) { + chan->count++; + chan->sample = sample; + } + } while (res == ENOERR); + } + + // Print number of acquired samples - if one second is expired. We + // expect that the number of acquired samples is nearly the sample rate + end_time = cyg_current_time(); + if ((end_time - start_time) >= 100) { + start_time = end_time; + diag_printf("\n"); + for (i = 0; i < num; i++) { + chan = &channels[i]; + diag_printf("adc%d%d\t= %d\n", chan->device, chan->channel, chan->count); + } + seconds++; + } + } while (seconds < 10); + + // Now stop all channels + for (i = 0; i < num; i++) { + chan = &channels[i]; + res = cyg_io_set_config(chan->handle, CYG_IO_SET_CONFIG_ADC_DISABLE, 0, 0); + if (res != ENOERR) + CYG_TEST_FAIL_FINISH("Error disabling ADC channel"); + } + + end_time = cyg_current_time(); + end_time = seconds * 1000 + (end_time - start_time) * 10; + final_seconds = end_time / 1000.0; + + // Now read all remaining samples from buffer and disable the channels + for (i = 0; i < num; i++) { + chan = &channels[i]; + do { + len = sizeof(sample); + res = cyg_io_read(chan->handle, &sample, &len); + if (res == ENOERR) + chan->count++; + } while (res == ENOERR); + } + + diag_printf("\n\n----------------------------------------\n"); + + samples_expected = final_seconds * CYGNUM_DEVS_ADC_CORTEXM_STM32_ADC_TEST_RATE; + diag_printf("Samples expected after %d milliseconds: %d\n", + end_time, samples_expected); + + diag_printf("Samples read (per channel):\n"); + for (i = 0; i < num; i++) { + chan = &channels[i]; + diag_printf("adc%d%d\t= %d\n", chan->device, chan->channel, chan->count); + } + + diag_printf("Last read sample (per channel):\n"); + for (i = 0; i < num; i++) { + chan = &channels[i]; + diag_printf("adc%d%d\t= %d\n", chan->device, chan->channel, chan->sample); + } + + CYG_TEST_PASS_FINISH("ADC test OK"); +} + + +void +cyg_start(void) +{ + CYG_TEST_INIT(); + + // Create the main ADC test thread + cyg_thread_create( + 4, + adc_thread, + (cyg_addrword_t) 0, + "stm32_adc_thread", + thread_stack, + sizeof(thread_stack), + &thread_handle, + &thread_data + ); + cyg_thread_resume(thread_handle); + cyg_scheduler_start(); +} + +#else // CYGFUN_KERNEL_API_C +#define N_A_MSG "Needs kernel C API" +#endif + +#else // CYGPKG_IO_ADC && CYGPKG_KERNEL +#define N_A_MSG "Needs Kernel and ADC support" +#endif + +#ifdef N_A_MSG +void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA(N_A_MSG); +} +#endif // N_A_MSG diff --git a/packages/ecos.db b/packages/ecos.db index b8b2613..ce7282d 100644 --- a/packages/ecos.db +++ b/packages/ecos.db @@ -6848,6 +6848,16 @@ package CYGPKG_DEVS_WALLCLOCK_STM32 { STM32 controller and compatibles" } +package CYGPKG_DEVS_ADC_CORTEXM_STM32 { + alias { "STM32 ADC driver" adc_stm32 } + hardware + directory devs/adc/cortexm/stm32 + script adc_stm32.cdl + description " + This package provides a driver for the ADC interfaces found on the + ST STM32 microcontroller family." +} + target stm3210e_eval { alias { "ST STM3210E EVAL board" stm3210e } packages { CYGPKG_HAL_CORTEXM