changeset 2842:8fe6d83b6d48

Add STM32 and synthetic target ADC drivers. Also, some changes in Cortex-M and STM32 HALs. See ChangeLogs for details.
author nickg
date Wed, 04 Mar 2009 16:29:54 +0000
parents 7552237440b4
children 6a5b18d2c1be
files packages/ChangeLog packages/devs/adc/cortexm/stm32/current/ChangeLog packages/devs/adc/cortexm/stm32/current/cdl/adc_stm32.cdl packages/devs/adc/cortexm/stm32/current/src/adc1.inl packages/devs/adc/cortexm/stm32/current/src/adc3.inl packages/devs/adc/cortexm/stm32/current/src/adc_stm32.c packages/devs/adc/synth/current/ChangeLog packages/devs/adc/synth/current/cdl/adc_synth.cdl packages/devs/adc/synth/current/src/adc_synth.c packages/ecos.db packages/hal/cortexm/arch/current/ChangeLog packages/hal/cortexm/arch/current/include/hal_io.h packages/hal/cortexm/stm32/var/current/ChangeLog packages/hal/cortexm/stm32/var/current/include/var_io.h packages/hal/cortexm/stm32/var/current/src/stm32_misc.c packages/io/adc/current/ChangeLog packages/io/adc/current/cdl/io_adc.cdl packages/io/adc/current/tests/adc1.c packages/io/adc/current/tests/adc2.c
diffstat 19 files changed, 2703 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/packages/ChangeLog
+++ b/packages/ChangeLog
@@ -1,3 +1,7 @@
+2009-03-04  Nick Garnett  <nickg@ecoscentric.com>
+
+	* ecos.db: Add ADC synthetic driver. Add STM32 ADC driver.
+
 2009-02-12  John Dallaway  <john@dallaway.org.uk>
 
 	* ecos.db: Make CYGPKG_DEVS_FLASH_SPI_M25PXX a hardware package.
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/cortexm/stm32/current/ChangeLog
@@ -0,0 +1,31 @@
+2009-02-24  Simon Kallweit  <simon.kallweit@intefo.ch>
+
+	* cdl/adc_stm32.cdl:
+	* src/adc_stm32.c:
+	* src/adc1.inl:
+	* src/adc3.inl:
+	STM32 ADC driver package created.
+
+//===========================================================================
+// ####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####                                                  
+//===========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/cortexm/stm32/current/cdl/adc_stm32.cdl
@@ -0,0 +1,237 @@
+# ====================================================================
+#
+#      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 <simon.kallweit@intefo.ch>
+# 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"
+        default_value   0
+        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"
+        default_value   0        
+        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."
+                } 
+            }
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/cortexm/stm32/current/src/adc1.inl
@@ -0,0 +1,161 @@
+//==========================================================================
+//
+//      adc1.inl
+//
+//      Parameters for ADC device 1
+//
+//==========================================================================
+// ####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 <simon.kallweit@intefo.ch>
+// Contributors:
+// Date:         2009-02-24
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// 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
+
+//-----------------------------------------------------------------------------
+// End of adc1.inl
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/cortexm/stm32/current/src/adc3.inl
@@ -0,0 +1,153 @@
+//==========================================================================
+//
+//      adc3.inl
+//
+//      Parameters for ADC device 3
+//
+//==========================================================================
+// ####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 <simon.kallweit@intefo.ch>
+// Contributors:
+// Date:         2009-02-24
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// 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
+
+//-----------------------------------------------------------------------------
+// End of adc3.inl
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/cortexm/stm32/current/src/adc_stm32.c
@@ -0,0 +1,614 @@
+//==========================================================================
+//
+//      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 <simon.kallweit@intefo.ch>
+// Contributors:
+// Date:         2009-02-24
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/devs_adc_cortexm_stm32.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/io/adc.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/drv_api.h>
+
+//-----------------------------------------------------------------------------
+// Diagnostic support
+// Switch the #if to 1 to generate some diagnostic messages.
+
+#if 0
+#include <cyg/infra/diag.h>
+#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);
+}
+
+//-----------------------------------------------------------------------------
+// End of adc_stm32.c
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/synth/current/ChangeLog
@@ -0,0 +1,29 @@
+2009-02-27  Simon Kallweit  <simon.kallweit@intefo.ch>
+
+	* Synthethic ADC driver package created
+	* cdl/adc_synth.cdl
+	* src/adc_synth.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####                                                  
+//===========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/synth/current/cdl/adc_synth.cdl
@@ -0,0 +1,158 @@
+# ====================================================================
+#
+#      adc_synth.cdl
+#
+#      eCos Synthethic 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 <simon.kallweit@intefo.ch>
+# Contributors:   
+# Date:           2009-02-27
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+
+cdl_package CYGPKG_DEVS_ADC_SYNTH {
+    display     "Synthetic ADC device driver"
+    
+    parent      CYGPKG_IO_ADC_DEVICES
+    active_if   CYGPKG_IO_ADC_DEVICES
+    active_if   CYGPKG_HAL_SYNTH
+    requires    {CYGNUM_IO_ADC_SAMPLE_SIZE >= CYGNUM_DEVS_ADC_SYNTH_SAMPLE_SIZE}
+    description "
+        This option enables the ADC device drivers for Synthetic target."
+           
+    include_dir cyg/io
+    compile     -library=libextras.a adc_synth.c
+    
+    cdl_interface CYGINT_DEVS_ADC_SYNTH_CHANNELS {
+        display         "Number of ADC channels"
+    }
+            
+    cdl_option CYGNUM_DEVS_ADC_SYNTH_SAMPLE_SIZE {
+        display         "Sample size"
+        flavor          data
+        legal_values    1 to 32
+        default_value   16
+        description     "
+            Sample size provided by the ADC channels."
+    }
+        
+    cdl_option CYGNUM_DEVS_ADC_SYNTH_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."
+    }
+        
+    # Support 16 channels
+    for { set ::channel 0 } { $::channel < 16 } { incr ::channel } {
+    
+        cdl_component CYGHWR_DEVS_ADC_SYNTH_CHANNEL[set ::channel] {
+            display         "ADC channel [set ::channel]"
+            flavor          none
+            implements      CYGINT_DEVS_ADC_SYNTH_CHANNELS
+            description     "
+                If the application needs to access the ADC
+                channel [set ::channel] via an eCos ADC driver then
+                this option should be enabled."
+     
+            cdl_option CYGDAT_DEVS_ADC_SYNTH_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 CYGNUM_DEVS_ADC_SYNTH_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 * size of sample."
+            }
+            
+            cdl_option CYGDAT_DEVS_ADC_SYNTH_CHANNEL[set ::channel]_SOURCE {
+                display         "Channel source"
+                flavor          data
+                legal_values    { "CONST" "RANDOM" "FILE" }
+                default_value   { "CONST" }
+                description     "
+                    This option controls the sample source of the virtual ADC
+                    channel. CONST mode always returns a constant sample value.
+                    RANDOM mode returns random samples. FILE returns samples as
+                    read by a file on the host." 
+            }
+        
+            cdl_option CYGNUM_DEVS_ADC_SYNTH_CHANNEL[set ::channel]_CONST_VALUE {
+                display         "Constant sample value"
+                flavor          data
+                default_value   0
+                description     "
+                    Constant sample value returned when CONST mode is selected."
+            }
+            
+            cdl_option CYGDAT_DEVS_ADC_SYNTH_CHANNEL[set ::channel]_FILENAME {
+                display         "Sample data filename"
+                flavor          data
+                default_value   [format {"\"adc0%d\""} $::channel]
+                description     "
+                    Filename of sample data file used in FILE mode."
+            }
+            
+            cdl_option CYGNUM_DEVS_ADC_SYNTH_CHANNEL[set ::channel]_MODE {
+                display         "Channel mode"
+                flavor          data
+                calculated      CYGDAT_DEVS_ADC_SYNTH_CHANNEL[set ::channel]_SOURCE == { "CONST" } ? 0 : \
+                                CYGDAT_DEVS_ADC_SYNTH_CHANNEL[set ::channel]_SOURCE == { "RANDOM" } ? 1 : \
+                                CYGDAT_DEVS_ADC_SYNTH_CHANNEL[set ::channel]_SOURCE == { "FILE" } ? 2 : -1
+            }
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/synth/current/src/adc_synth.c
@@ -0,0 +1,482 @@
+//==========================================================================
+//
+//      adc_synth.c
+//
+//      ADC driver for Synthethic 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 <simon.kallweit@intefo.ch>
+// Contributors:
+// Date:         2009-02-27
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/devs_adc_synth.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/io/adc.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/drv_api.h>
+
+//-----------------------------------------------------------------------------
+// Diagnostic support
+// Switch the #if to 1 to generate some diagnostic messages.
+
+#if 0
+#include <cyg/infra/diag.h>
+#define adc_diag( __fmt, ... ) diag_printf("ADC: %30s[%4d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ );
+#else
+#define adc_diag( __fmt, ... ) 
+#endif
+
+#define NUM_CHANNELS    16
+
+#define MODE_CONST      0
+#define MODE_RANDOM     1
+#define MODE_FILE       2
+
+#define SAMPLE_BITS     ((1 << CYGNUM_DEVS_ADC_SYNTH_SAMPLE_SIZE) - 1)
+
+//-----------------------------------------------------------------------------
+// Synthetic ADC channel
+
+typedef struct synth_adc_channel_info {
+    cyg_uint32 mode;            // Channel mode
+    cyg_uint32 const_value;     // Const sample value
+    char *filename;             // Sampling data filename
+
+    int fd;                     // File descriptor of sample file
+    cyg_uint32 num_samples;     // Number of samples in the file
+    cyg_adc_sample_t *base;     // Base address of mapped sample file
+    cyg_adc_sample_t *sample;   // Current sample
+    
+    cyg_adc_sample_t (*get_sample)(cyg_adc_channel *chan);
+} synth_adc_channel_info;
+
+//-----------------------------------------------------------------------------
+// Synthethic ADC device
+
+typedef struct synth_adc_info {
+    synth_adc_channel_info  *chan_info;     // Channel infos
+    cyg_adc_channel *chan[NUM_CHANNELS];    // Channel references
+    cyg_uint32 chan_mask;                   // Active channels
+    cyg_handle_t alarm_handle;              // Alarm handle
+    cyg_alarm alarm_data;                   // Alarm data
+    cyg_tick_count_t alarm_interval;        // Alarm interval in ticks
+    cyg_uint32 alarm_samples;               // Number of samples per tick
+} synth_adc_info;
+
+//-----------------------------------------------------------------------------
+// API function call forward references
+
+static bool synth_adc_init(struct cyg_devtab_entry *tab);
+static Cyg_ErrNo synth_adc_lookup(struct cyg_devtab_entry **tab,
+                                  struct cyg_devtab_entry *sub_tab,
+                                  const char *name);
+
+static void synth_adc_enable(cyg_adc_channel *chan);
+static void synth_adc_disable(cyg_adc_channel *chan);
+static void synth_adc_set_rate(cyg_adc_channel *chan, cyg_uint32 rate);
+
+static void alarm_handler(cyg_handle_t alarm, cyg_addrword_t data);
+
+static cyg_adc_sample_t synth_adc_get_sample_const(cyg_adc_channel *chan);
+static cyg_adc_sample_t synth_adc_get_sample_random(cyg_adc_channel *chan);
+static cyg_adc_sample_t synth_adc_get_sample_file(cyg_adc_channel *chan);
+
+static cyg_uint32 rand(void);
+
+CYG_ADC_FUNCTIONS(synth_adc_funs,
+                  synth_adc_enable,
+                  synth_adc_disable,
+                  synth_adc_set_rate);
+
+//-----------------------------------------------------------------------------
+// Synthethic ADC channel info macro
+
+#define SYNTH_ADC_CHANNEL_INFO(_chan_)                                      \
+{                                                                           \
+    .mode           = CYGNUM_DEVS_ADC_SYNTH_CHANNEL##_chan_##_MODE,         \
+    .const_value    = CYGNUM_DEVS_ADC_SYNTH_CHANNEL##_chan_##_CONST_VALUE,  \
+    .filename       = CYGDAT_DEVS_ADC_SYNTH_CHANNEL##_chan_##_FILENAME,     \
+}
+
+//-----------------------------------------------------------------------------
+// Synthethic ADC channel instance macro
+
+#define SYNTH_ADC_CHANNEL(_chan_)                                           \
+CYG_ADC_CHANNEL(                                                            \
+    synth_adc_channel##_chan_,                                              \
+    _chan_,                                                                 \
+    CYGNUM_DEVS_ADC_SYNTH_CHANNEL##_chan_##_BUFSIZE,                        \
+    &synth_adc_device                                                       \
+);                                                                          \
+DEVTAB_ENTRY(                                                               \
+    synth_adc_channel##_chan_##_device,                                     \
+    CYGDAT_DEVS_ADC_SYNTH_CHANNEL##_chan_##_NAME,                           \
+    0,                                                                      \
+    &cyg_io_adc_devio,                                                      \
+    synth_adc_init,                                                         \
+    synth_adc_lookup,                                                       \
+    &synth_adc_channel##_chan_                                              \
+);
+
+//-----------------------------------------------------------------------------
+// Synthethic ADC device instance
+
+static synth_adc_channel_info synth_adc_channel_infos[NUM_CHANNELS] = {
+    SYNTH_ADC_CHANNEL_INFO(0),
+    SYNTH_ADC_CHANNEL_INFO(1),
+    SYNTH_ADC_CHANNEL_INFO(2),
+    SYNTH_ADC_CHANNEL_INFO(3),
+    SYNTH_ADC_CHANNEL_INFO(4),
+    SYNTH_ADC_CHANNEL_INFO(5),
+    SYNTH_ADC_CHANNEL_INFO(6),
+    SYNTH_ADC_CHANNEL_INFO(7),
+    SYNTH_ADC_CHANNEL_INFO(8),
+    SYNTH_ADC_CHANNEL_INFO(9),
+    SYNTH_ADC_CHANNEL_INFO(10),
+    SYNTH_ADC_CHANNEL_INFO(11),
+    SYNTH_ADC_CHANNEL_INFO(12),
+    SYNTH_ADC_CHANNEL_INFO(13),
+    SYNTH_ADC_CHANNEL_INFO(14),
+    SYNTH_ADC_CHANNEL_INFO(15),
+};
+
+static synth_adc_info synth_adc_info0 = {
+    .chan_info = synth_adc_channel_infos,
+};
+
+CYG_ADC_DEVICE(synth_adc_device,
+               &synth_adc_funs,
+               &synth_adc_info0,
+               CYGNUM_DEVS_ADC_SYNTH_DEFAULT_RATE);
+
+SYNTH_ADC_CHANNEL(0)
+SYNTH_ADC_CHANNEL(1)
+SYNTH_ADC_CHANNEL(2)
+SYNTH_ADC_CHANNEL(3)
+SYNTH_ADC_CHANNEL(4)
+SYNTH_ADC_CHANNEL(5)
+SYNTH_ADC_CHANNEL(6)
+SYNTH_ADC_CHANNEL(7)
+SYNTH_ADC_CHANNEL(8)
+SYNTH_ADC_CHANNEL(9)
+SYNTH_ADC_CHANNEL(10)
+SYNTH_ADC_CHANNEL(11)
+SYNTH_ADC_CHANNEL(12)
+SYNTH_ADC_CHANNEL(13)
+SYNTH_ADC_CHANNEL(14)
+SYNTH_ADC_CHANNEL(15)
+
+
+//-----------------------------------------------------------------------------
+// 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
+synth_adc_init(struct cyg_devtab_entry *tab)
+{
+    static cyg_bool initialized = false;
+    cyg_adc_channel *chan = (cyg_adc_channel *) tab->priv;
+    cyg_adc_device *device = chan->device;
+    synth_adc_info *info = device->dev_priv;
+    synth_adc_channel_info *chan_info = &info->chan_info[chan->channel];
+    cyg_handle_t counter;
+    
+    adc_diag("Initializing device\n");
+    
+    // Initialize channel
+    info->chan[chan->channel] = chan;
+    switch (chan_info->mode) {
+    case MODE_CONST:
+        chan_info->get_sample = synth_adc_get_sample_const;
+        break;
+    case MODE_RANDOM:
+        chan_info->get_sample = synth_adc_get_sample_random;
+        break;
+    case MODE_FILE:
+        chan_info->get_sample = synth_adc_get_sample_file;
+        break;
+    }
+
+    // Set default rate
+    if (!initialized) {
+        // Initialize alarm
+        cyg_clock_to_counter(cyg_real_time_clock(), &counter);
+        cyg_alarm_create(counter, alarm_handler, (cyg_addrword_t) device,
+                         &info->alarm_handle, &info->alarm_data);
+        
+        synth_adc_set_rate(chan, chan->device->config.rate);
+        initialized = true;
+    }
+        
+    // 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
+synth_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;
+    synth_adc_info *info = chan->device->dev_priv;
+    synth_adc_channel_info *chan_info = &info->chan_info[chan->channel];
+
+    adc_diag("Opening device\n");
+    
+    // When this channel is in file mode, initialize file access
+    if (chan_info->mode == MODE_FILE) {
+        struct cyg_hal_sys_new_stat stat;
+        
+        // Open the file
+        chan_info->fd = cyg_hal_sys_open(chan_info->filename,
+                                         CYG_HAL_SYS_O_RDONLY, 0);
+        if (chan_info->fd == -ENOENT) {
+            adc_diag("Cannot open sampling file '%s' for channel '%s'\n", 
+                     chan_info->filename, (*tab)->name);
+            CYG_FAIL("Cannot open sampling file\n");
+        }
+        
+        // Get file size
+        if (cyg_hal_sys_newfstat(chan_info->fd, &stat) != 0) {
+            CYG_FAIL("Cannot stat sampling file\n");
+        }
+        chan_info->num_samples = stat.st_size / sizeof(cyg_adc_sample_t);
+        if (chan_info->num_samples <= 0)
+            CYG_FAIL("Sampling file too small\n");
+        
+        // Memory map
+        chan_info->base = (cyg_adc_sample_t *) cyg_hal_sys_mmap(
+            NULL,
+            chan_info->num_samples * sizeof(cyg_adc_sample_t),
+            CYG_HAL_SYS_PROT_READ,
+            CYG_HAL_SYS_MAP_SHARED,
+            chan_info->fd,
+            0);
+        if (chan_info->base == (void *) -1)
+            CYG_FAIL("Cannot memory map sampling file\n");
+        chan_info->sample = chan_info->base;
+
+        adc_diag("Mapped to %p\n", chan_info->base);
+    }
+    
+    // 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;
+    synth_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
+synth_adc_enable(cyg_adc_channel *chan)
+{
+    synth_adc_info *info = chan->device->dev_priv;
+    cyg_bool start;
+    
+    adc_diag("Enabling channel\n");
+
+    start = !info->chan_mask;
+    info->chan_mask |= (1 << chan->channel);
+    
+    // Start scanning when first channel was activated
+    if (start) {
+        // Enable timer
+        adc_diag("Starting scanning\n");
+        cyg_alarm_initialize(info->alarm_handle,
+                             cyg_current_time() + info->alarm_interval,
+                             info->alarm_interval);
+    }
+}
+
+//-----------------------------------------------------------------------------
+// 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
+synth_adc_disable(cyg_adc_channel *chan)
+{
+    synth_adc_info *info = chan->device->dev_priv;
+    
+    adc_diag("Disabling channel\n");
+    
+    info->chan_mask &= ~(1 << chan->channel);
+    
+    // Stop scanning when no channel is active
+    if (!info->chan_mask) {
+        // Disable timer
+        adc_diag("Stopping scanning\n");
+        cyg_alarm_disable(info->alarm_handle);
+    }
+}
+
+//-----------------------------------------------------------------------------
+// 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
+synth_adc_set_rate(cyg_adc_channel *chan, cyg_uint32 rate)
+{
+    cyg_adc_device *device = chan->device;
+    synth_adc_info *info = device->dev_priv;
+    cyg_uint64 interval;
+    
+    adc_diag("Setting rate to %d\n", rate);
+        
+    interval = 1000000000000LL / rate;
+    interval /= (CYGNUM_HAL_RTC_NUMERATOR / CYGNUM_HAL_RTC_DENOMINATOR);
+    
+    if (interval > 1000) {
+        info->alarm_interval = interval / 1000;
+        info->alarm_samples = 1;
+    } else {
+        info->alarm_interval = 1;
+        info->alarm_samples = 1000 / interval;
+    }
+    
+    if (info->chan_mask)
+        cyg_alarm_initialize(info->alarm_handle,
+                             cyg_current_time() + info->alarm_interval,
+                             info->alarm_interval);
+
+    device->config.rate = rate;
+}
+
+static void
+alarm_handler(cyg_handle_t alarm, cyg_addrword_t data)
+{
+    cyg_adc_device *device = (cyg_adc_device *) data;
+    synth_adc_info *info = device->dev_priv;
+    cyg_adc_channel *chan;
+    synth_adc_channel_info *chan_info;
+    cyg_uint32 active_mask;
+    int i, j;
+   
+    if (!info->chan_mask)
+        return;
+    
+    active_mask = info->chan_mask;
+    
+    for (i = 0; i < NUM_CHANNELS; i++) {
+        if (active_mask & 0x01) {
+            chan = info->chan[i];
+            chan_info = &info->chan_info[chan->channel];
+            for (j = 0; j < info->alarm_samples; j++)
+                cyg_adc_receive_sample(chan, chan_info->get_sample(chan));
+            cyg_adc_wakeup(info->chan[i]);
+        }
+        active_mask >>= 1;
+    }
+}
+
+static cyg_adc_sample_t
+synth_adc_get_sample_const(cyg_adc_channel *chan)
+{
+    synth_adc_info *info = chan->device->dev_priv;
+    synth_adc_channel_info *chan_info = &info->chan_info[chan->channel];
+    
+    return chan_info->const_value;
+}
+
+static cyg_adc_sample_t
+synth_adc_get_sample_random(cyg_adc_channel *chan)
+{
+    return rand() & SAMPLE_BITS;
+}
+
+static cyg_adc_sample_t
+synth_adc_get_sample_file(cyg_adc_channel *chan)
+{
+    synth_adc_info *info = chan->device->dev_priv;
+    synth_adc_channel_info *chan_info = &info->chan_info[chan->channel];
+    cyg_adc_sample_t sample;
+    
+    sample = *chan_info->sample++;
+    if (chan_info->sample >= chan_info->base + chan_info->num_samples)
+        chan_info->sample = chan_info->base;
+    
+    return sample;
+}
+
+//-----------------------------------------------------------------------------
+// Simple random number generator
+
+static cyg_uint32 rand(void)
+{
+    static cyg_uint32 seed;
+    
+    seed = (seed * 1103515245) + 12345; // permutate seed
+    
+    return seed;
+}
+ 
--- a/packages/ecos.db
+++ b/packages/ecos.db
@@ -2421,6 +2421,15 @@ package CYGPKG_DEVS_ADC_ARM_LPC24XX {
             ADC provided by the LPC24xx processor family."
 }
 
+package CYGPKG_DEVS_ADC_SYNTH {
+    alias         { "Synthethic ADC driver" adc_synth }
+    hardware
+    directory     devs/adc/synth
+    script        adc_synth.cdl
+    description "
+            This package provides an ADC driver for the Synthethic target."
+}
+
 package CYGPKG_IO_ADC {
 	alias 		{ "Generic ADC support" adc io_adc }
 	directory	io/adc
@@ -5630,7 +5639,8 @@ target linux {
                       CYGPKG_DEVS_ETH_ECOSYNTH
                       CYGPKG_DEVS_WATCHDOG_SYNTH
                       CYGPKG_DEVS_WALLCLOCK_SYNTH      
-	                  CYGPKG_DEVS_FRAMEBUF_SYNTH
+                      CYGPKG_DEVS_FRAMEBUF_SYNTH
+                      CYGPKG_DEVS_ADC_SYNTH
         }
         description "
     	    The linux target provides the 
@@ -6848,6 +6858,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
@@ -6860,6 +6880,7 @@ target stm3210e_eval {
                    CYGPKG_DEVS_WALLCLOCK_STM32
                    CYGPKG_IO_SPI
                    CYGPKG_DEVS_SPI_CORTEXM_STM32
+                   CYGPKG_DEVS_ADC_CORTEXM_STM32
                  }
         description "The stm3210e_eval target provides the packages needed
         to run eCos on the STM3210E EVAL board."
--- a/packages/hal/cortexm/arch/current/ChangeLog
+++ b/packages/hal/cortexm/arch/current/ChangeLog
@@ -1,3 +1,7 @@
+2009-02-27  Simon Kallweit  <simon.kallweit@intefo.ch>
+
+	* include/hal_io.h: Added system control register definitions 
+
 2009-02-13  Nick Garnett  <nickg@ecoscentric.com>
 
 	* include/hal_arch.h: Add include for var_arch.h.
--- a/packages/hal/cortexm/arch/current/include/hal_io.h
+++ b/packages/hal/cortexm/arch/current/include/hal_io.h
@@ -190,6 +190,12 @@
 #define CYGARC_REG_NVIC_AIRCR_VECTCLRACTIVE     BIT_(1)
 #define CYGARC_REG_NVIC_AIRCR_VECTRESET         BIT_(0)
 
+// SCR
+
+#define CYGARC_REG_NVIC_SCR_SLEEPONEXIT         BIT_(1)
+#define CYGARC_REG_NVIC_SCR_DEEPSLEEP           BIT_(2)
+#define CYGARC_REG_NVIC_SCR_SEVONPEND           BIT_(4)
+
 // SHCSR
 
 #define CYGARC_REG_NVIC_SHCSR_USGFAULTENA       BIT_(18)
--- a/packages/hal/cortexm/stm32/var/current/ChangeLog
+++ b/packages/hal/cortexm/stm32/var/current/ChangeLog
@@ -1,3 +1,15 @@
+2009-02-27  Simon Kallweit  <simon.kallweit@intefo.ch>
+
+	* include/var_io.h:
+	Add mask for CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE.
+	Fixed CYGHWR_HAL_STM32_RTC_CRL_ALRF.
+	Add register definitions for ADC.
+	Add additional timer registers.
+	* src/stm32_mis.c:
+	Moved system clock initialization into it's own function, so it can
+	be called after wakeup from sleep modes.
+	Added hal_stm32_timer_clock() to get current clock of timers.
+
 2009-02-10  Chris Holgate  <chris@zynaptic.com>
 
 	* include/var_io.h: Add mask for CYGHWR_HAL_STM32_AFIO_MAPR_SWJ.
--- a/packages/hal/cortexm/stm32/var/current/include/var_io.h
+++ b/packages/hal/cortexm/stm32/var/current/include/var_io.h
@@ -177,6 +177,7 @@
 #define CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_4      VALUE_(14,1)
 #define CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_6      VALUE_(14,2)
 #define CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_8      VALUE_(14,3)
+#define CYGHWR_HAL_STM32_RCC_CFGR_ADCPRE_XXX    VALUE_(14,3)
 #define CYGHWR_HAL_STM32_RCC_CFGR_PLLSRC_HSI    0
 #define CYGHWR_HAL_STM32_RCC_CFGR_PLLSRC_HSE    BIT_(16)
 #define CYGHWR_HAL_STM32_RCC_CFGR_PLLXTPRE      BIT_(17)
@@ -279,7 +280,7 @@
 // CRL fields
 
 #define CYGHWR_HAL_STM32_RTC_CRL_SECF           BIT_(0)
-#define CYGHWR_HAL_STM32_RTC_CRL_ALRCF          BIT_(1)
+#define CYGHWR_HAL_STM32_RTC_CRL_ALRF           BIT_(1)
 #define CYGHWR_HAL_STM32_RTC_CRL_OWF            BIT_(2)
 #define CYGHWR_HAL_STM32_RTC_CRL_RSF            BIT_(3)
 #define CYGHWR_HAL_STM32_RTC_CRL_CNF            BIT_(4)
@@ -607,6 +608,159 @@
 #endif
 
 //=============================================================================
+// ADCs
+
+#define CYGHWR_HAL_STM32_ADC_SR                 0x00
+#define CYGHWR_HAL_STM32_ADC_CR1                0x04
+#define CYGHWR_HAL_STM32_ADC_CR2                0x08
+#define CYGHWR_HAL_STM32_ADC_SMPR1              0x0C
+#define CYGHWR_HAL_STM32_ADC_SMPR2              0x10
+#define CYGHWR_HAL_STM32_ADC_JOFR(__x)          0x14 + ((__x) << 2)
+#define CYGHWR_HAL_STM32_ADC_HTR                0x24
+#define CYGHWR_HAL_STM32_ADC_LTR                0x28
+#define CYGHWR_HAL_STM32_ADC_SQR1               0x2C
+#define CYGHWR_HAL_STM32_ADC_SQR2               0x30
+#define CYGHWR_HAL_STM32_ADC_SQR3               0x34
+#define CYGHWR_HAL_STM32_ADC_JSQR               0x38
+#define CYGHWR_HAL_STM32_ADC_JDR(__x)           0x3C + ((__x) << 2)
+#define CYGHWR_HAL_STM32_ADC_DR                 0x4C
+
+// SR fields
+
+#define CYGHWR_HAL_STM32_ADC_SR_AWD             BIT_(0)
+#define CYGHWR_HAL_STM32_ADC_SR_EOC             BIT_(1)
+#define CYGHWR_HAL_STM32_ADC_SR_JEOC            BIT_(2)
+#define CYGHWR_HAL_STM32_ADC_SR_JSTRT           BIT_(3)
+#define CYGHWR_HAL_STM32_ADC_SR_STRT            BIT_(4)
+
+// CR1 fields
+
+#define CYGHWR_HAL_STM32_ADC_CR1_AWDCH(__x)     VALUE_(0,(__x))
+#define CYGHWR_HAL_STM32_ADC_CR1_EOCIE          BIT_(5)
+#define CYGHWR_HAL_STM32_ADC_CR1_AWDIE          BIT_(6)
+#define CYGHWR_HAL_STM32_ADC_CR1_JEOCIE         BIT_(7)
+#define CYGHWR_HAL_STM32_ADC_CR1_SCAN           BIT_(8)
+#define CYGHWR_HAL_STM32_ADC_CR1_AWDSGL         BIT_(9)
+#define CYGHWR_HAL_STM32_ADC_CR1_JAUTO          BIT_(10)
+#define CYGHWR_HAL_STM32_ADC_CR1_DISCEN         BIT_(11)
+#define CYGHWR_HAL_STM32_ADC_CR1_JDISCEN        BIT_(12)
+#define CYGHWR_HAL_STM32_ADC_CR1_DISCNUM(__x)   VALUE_(13,(__x))
+#define CYGHWR_HAL_STM32_ADC_CR1_DUALMODE(__x)  VALUE_(16,(__x))
+#define CYGHWR_HAL_STM32_ADC_CR1_JAWDEN         BIT_(22)
+#define CYGHWR_HAL_STM32_ADC_CR1_AWDEN          BIT_(23)
+
+// CR2 fields
+
+#define CYGHWR_HAL_STM32_ADC_CR2_ADON           BIT_(0)
+#define CYGHWR_HAL_STM32_ADC_CR2_CONT           BIT_(1)
+#define CYGHWR_HAL_STM32_ADC_CR2_CAL            BIT_(2)
+#define CYGHWR_HAL_STM32_ADC_CR2_RSTCAL         BIT_(3)
+#define CYGHWR_HAL_STM32_ADC_CR2_DMA            BIT_(8)
+#define CYGHWR_HAL_STM32_ADC_CR2_ALIGN          BIT_(11)
+#define CYGHWR_HAL_STM32_ADC_CR2_JEXTSEL(__x)   VALUE_(12,(__x))
+#define CYGHWR_HAL_STM32_ADC_CR2_JEXTTRIG       BIT_(15)
+#define CYGHWR_HAL_STM32_ADC_CR2_EXTSEL(__x)    VALUE_(17,(__x))
+#define CYGHWR_HAL_STM32_ADC_CR2_EXTTRIG        BIT_(20)
+#define CYGHWR_HAL_STM32_ADC_CR2_JSWSTART       BIT_(21)
+#define CYGHWR_HAL_STM32_ADC_CR2_SWSTART        BIT_(22)
+#define CYGHWR_HAL_STM32_ADC_CR2_TSVREFE        BIT_(23)
+
+// SMPRx fields
+
+#define CYGHWR_HAL_STM32_ADC_SMPRx_SMP(__x, __y) VALUE_((__x) * 3, (__y))
+
+// SQRx fields
+
+#define CYGHWR_HAL_STM32_ADC_SQR1_L(__x)        VALUE_(20, (__x))
+#define CYGHWR_HAL_STM32_ADC_SQRx_SQ(__x, __y)  VALUE_((__x) * 5, (__y))
+
+// JSQR fields
+
+#define CYGHWR_HAL_STM32_ADC_JSQR_SQ(__x, __y)  VALUE_((__x) * 5, (__y))
+
+// ADC GPIO pins
+
+#define CYGHWR_HAL_STM32_ADC123_IN0             CYGHWR_HAL_STM32_GPIO( A, 0,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC123_IN1             CYGHWR_HAL_STM32_GPIO( A, 1,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC123_IN2             CYGHWR_HAL_STM32_GPIO( A, 2,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC123_IN3             CYGHWR_HAL_STM32_GPIO( A, 3,  IN, ANALOG )
+
+#define CYGHWR_HAL_STM32_ADC12_IN4              CYGHWR_HAL_STM32_GPIO( A, 4,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC12_IN5              CYGHWR_HAL_STM32_GPIO( A, 5,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC12_IN6              CYGHWR_HAL_STM32_GPIO( A, 6,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC12_IN7              CYGHWR_HAL_STM32_GPIO( A, 7,  IN, ANALOG )
+
+#define CYGHWR_HAL_STM32_ADC12_IN8              CYGHWR_HAL_STM32_GPIO( B, 0,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC12_IN9              CYGHWR_HAL_STM32_GPIO( B, 1,  IN, ANALOG )
+
+#define CYGHWR_HAL_STM32_ADC3_IN4               CYGHWR_HAL_STM32_GPIO( F, 6,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC3_IN5               CYGHWR_HAL_STM32_GPIO( F, 7,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC3_IN6               CYGHWR_HAL_STM32_GPIO( F, 8,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC3_IN7               CYGHWR_HAL_STM32_GPIO( F, 9,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC3_IN8               CYGHWR_HAL_STM32_GPIO( F, 10, IN, ANALOG )
+
+#define CYGHWR_HAL_STM32_ADC123_IN10            CYGHWR_HAL_STM32_GPIO( C, 0,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC123_IN11            CYGHWR_HAL_STM32_GPIO( C, 1,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC123_IN12            CYGHWR_HAL_STM32_GPIO( C, 2,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC123_IN13            CYGHWR_HAL_STM32_GPIO( C, 3,  IN, ANALOG )
+
+#define CYGHWR_HAL_STM32_ADC12_IN14             CYGHWR_HAL_STM32_GPIO( C, 4,  IN, ANALOG )
+#define CYGHWR_HAL_STM32_ADC12_IN15             CYGHWR_HAL_STM32_GPIO( C, 5,  IN, ANALOG )
+
+// ADC1 GPIO pin aliases
+
+#define CYGHWR_HAL_STM32_ADC1_IN0               CYGHWR_HAL_STM32_ADC123_IN0
+#define CYGHWR_HAL_STM32_ADC1_IN1               CYGHWR_HAL_STM32_ADC123_IN1
+#define CYGHWR_HAL_STM32_ADC1_IN2               CYGHWR_HAL_STM32_ADC123_IN2
+#define CYGHWR_HAL_STM32_ADC1_IN3               CYGHWR_HAL_STM32_ADC123_IN3
+#define CYGHWR_HAL_STM32_ADC1_IN4               CYGHWR_HAL_STM32_ADC12_IN4
+#define CYGHWR_HAL_STM32_ADC1_IN5               CYGHWR_HAL_STM32_ADC12_IN5
+#define CYGHWR_HAL_STM32_ADC1_IN6               CYGHWR_HAL_STM32_ADC12_IN6
+#define CYGHWR_HAL_STM32_ADC1_IN7               CYGHWR_HAL_STM32_ADC12_IN7
+#define CYGHWR_HAL_STM32_ADC1_IN8               CYGHWR_HAL_STM32_ADC12_IN8
+#define CYGHWR_HAL_STM32_ADC1_IN9               CYGHWR_HAL_STM32_ADC12_IN9
+#define CYGHWR_HAL_STM32_ADC1_IN10              CYGHWR_HAL_STM32_ADC123_IN10
+#define CYGHWR_HAL_STM32_ADC1_IN11              CYGHWR_HAL_STM32_ADC123_IN11
+#define CYGHWR_HAL_STM32_ADC1_IN12              CYGHWR_HAL_STM32_ADC123_IN12
+#define CYGHWR_HAL_STM32_ADC1_IN13              CYGHWR_HAL_STM32_ADC123_IN13
+#define CYGHWR_HAL_STM32_ADC1_IN14              CYGHWR_HAL_STM32_ADC12_IN14
+#define CYGHWR_HAL_STM32_ADC1_IN15              CYGHWR_HAL_STM32_ADC12_IN15
+
+// ADC2 GPIO pin aliases
+
+#define CYGHWR_HAL_STM32_ADC2_IN0               CYGHWR_HAL_STM32_ADC123_IN0
+#define CYGHWR_HAL_STM32_ADC2_IN1               CYGHWR_HAL_STM32_ADC123_IN1
+#define CYGHWR_HAL_STM32_ADC2_IN2               CYGHWR_HAL_STM32_ADC123_IN2
+#define CYGHWR_HAL_STM32_ADC2_IN3               CYGHWR_HAL_STM32_ADC123_IN3
+#define CYGHWR_HAL_STM32_ADC2_IN4               CYGHWR_HAL_STM32_ADC12_IN4
+#define CYGHWR_HAL_STM32_ADC2_IN5               CYGHWR_HAL_STM32_ADC12_IN5
+#define CYGHWR_HAL_STM32_ADC2_IN6               CYGHWR_HAL_STM32_ADC12_IN6
+#define CYGHWR_HAL_STM32_ADC2_IN7               CYGHWR_HAL_STM32_ADC12_IN7
+#define CYGHWR_HAL_STM32_ADC2_IN8               CYGHWR_HAL_STM32_ADC12_IN8
+#define CYGHWR_HAL_STM32_ADC2_IN9               CYGHWR_HAL_STM32_ADC12_IN9
+#define CYGHWR_HAL_STM32_ADC2_IN10              CYGHWR_HAL_STM32_ADC123_IN10
+#define CYGHWR_HAL_STM32_ADC2_IN11              CYGHWR_HAL_STM32_ADC123_IN11
+#define CYGHWR_HAL_STM32_ADC2_IN12              CYGHWR_HAL_STM32_ADC123_IN12
+#define CYGHWR_HAL_STM32_ADC2_IN13              CYGHWR_HAL_STM32_ADC123_IN13
+#define CYGHWR_HAL_STM32_ADC2_IN14              CYGHWR_HAL_STM32_ADC12_IN14
+#define CYGHWR_HAL_STM32_ADC2_IN15              CYGHWR_HAL_STM32_ADC12_IN15
+
+// ADC3 GPIO pin aliases
+
+#define CYGHWR_HAL_STM32_ADC3_IN0               CYGHWR_HAL_STM32_ADC123_IN0
+#define CYGHWR_HAL_STM32_ADC3_IN1               CYGHWR_HAL_STM32_ADC123_IN1
+#define CYGHWR_HAL_STM32_ADC3_IN2               CYGHWR_HAL_STM32_ADC123_IN2
+#define CYGHWR_HAL_STM32_ADC3_IN3               CYGHWR_HAL_STM32_ADC123_IN3
+// Inputs 4 - 8 are already defined
+#define CYGHWR_HAL_STM32_ADC3_IN9               CYGHWR_HAL_STM32_GPIO_NONE
+#define CYGHWR_HAL_STM32_ADC3_IN10              CYGHWR_HAL_STM32_ADC123_IN10
+#define CYGHWR_HAL_STM32_ADC3_IN11              CYGHWR_HAL_STM32_ADC123_IN11
+#define CYGHWR_HAL_STM32_ADC3_IN12              CYGHWR_HAL_STM32_ADC123_IN12
+#define CYGHWR_HAL_STM32_ADC3_IN13              CYGHWR_HAL_STM32_ADC123_IN13
+#define CYGHWR_HAL_STM32_ADC3_IN14              CYGHWR_HAL_STM32_GPIO_NONE
+#define CYGHWR_HAL_STM32_ADC3_IN15              CYGHWR_HAL_STM32_GPIO_NONE
+
+//=============================================================================
 // SPI interface register definitions.
 
 #define CYGHWR_HAL_STM32_SPI_CR1                0x00
@@ -768,15 +922,27 @@
 #define CYGHWR_HAL_STM32_TIM_DIER               0x0C
 #define CYGHWR_HAL_STM32_TIM_SR                 0x10
 #define CYGHWR_HAL_STM32_TIM_EGR                0x14
+#define CYGHWR_HAL_STM32_TIM_CCMR1              0x18
+#define CYGHWR_HAL_STM32_TIM_CCMR2              0x1C
+#define CYGHWR_HAL_STM32_TIM_CCER               0x20
 #define CYGHWR_HAL_STM32_TIM_CNT                0x24
 #define CYGHWR_HAL_STM32_TIM_PSC                0x28
 #define CYGHWR_HAL_STM32_TIM_ARR                0x2C
+#define CYGHWR_HAL_STM32_TIM_CCR1               0x34
+#define CYGHWR_HAL_STM32_TIM_CCR2               0x38
+#define CYGHWR_HAL_STM32_TIM_CCR3               0x3C
+#define CYGHWR_HAL_STM32_TIM_CCR4               0x40
 
 #define CYGHWR_HAL_STM32_TIM_CR1_CEN            BIT_(0)
 #define CYGHWR_HAL_STM32_TIM_CR1_UDIS           BIT_(1)
 #define CYGHWR_HAL_STM32_TIM_CR1_URS            BIT_(2)
 #define CYGHWR_HAL_STM32_TIM_CR1_OPM            BIT_(3)
+#define CYGHWR_HAL_STM32_TIM_CR1_DIR            BIT_(4)
 #define CYGHWR_HAL_STM32_TIM_CR1_ARPE           BIT_(7)
+#define CYGHWR_HAL_STM32_TIM_CR1_CKD_1          VALUE_(8,0)
+#define CYGHWR_HAL_STM32_TIM_CR1_CKD_2          VALUE_(8,1)
+#define CYGHWR_HAL_STM32_TIM_CR1_CKD_4          VALUE_(8,2)
+#define CYGHWR_HAL_STM32_TIM_CR1_CKD_XXX        VALUE_(8,3)
 
 #define CYGHWR_HAL_STM32_TIM_CR2_MMS_RESET      VALUE_(4,0)
 #define CYGHWR_HAL_STM32_TIM_CR2_MMS_ENABLE     VALUE_(4,1)
@@ -789,6 +955,12 @@
 
 #define CYGHWR_HAL_STM32_TIM_EGR_UG             BIT_(0)
 
+#ifndef __ASSEMBLER__
+
+__externC cyg_uint32 hal_stm32_timer_clock( CYG_ADDRESS base );
+
+#endif
+
 //=============================================================================
 // Flash controller
 
@@ -867,8 +1039,12 @@
 // Functions and macros to reset the backup domain as well as
 // enable/disable backup domain write protection.
 
+#ifndef __ASSEMBLER__
+
 __externC void hal_stm32_bd_protect( int protect );
 
+#endif
+
 #define CYGHWR_HAL_STM32_BD_RESET()                                         \
     CYG_MACRO_START                                                         \
     HAL_WRITE_UINT32(CYGHWR_HAL_STM32_RCC+CYGHWR_HAL_STM32_RCC_BDCR,        \
--- a/packages/hal/cortexm/stm32/var/current/src/stm32_misc.c
+++ b/packages/hal/cortexm/stm32/var/current/src/stm32_misc.c
@@ -122,6 +122,7 @@ cyg_uint32 hal_stm32_pclk1;
 cyg_uint32 hal_stm32_pclk2;
 cyg_uint32 hal_cortexm_systick_clock;
 
+void hal_start_clocks( void );
 cyg_uint32 hal_exti_isr( cyg_uint32 vector, CYG_ADDRWORD data );
 
 //==========================================================================
@@ -131,93 +132,16 @@ void hal_variant_init( void )
     CYG_ADDRESS rcc = CYGHWR_HAL_STM32_RCC;
 
     // Enable all devices in RCC
-    {
-        HAL_WRITE_UINT32( CYGHWR_HAL_STM32_RCC+CYGHWR_HAL_STM32_RCC_APB2ENR, 0xFFFFFFFF );
-        HAL_WRITE_UINT32( CYGHWR_HAL_STM32_RCC+CYGHWR_HAL_STM32_RCC_APB1ENR, 0xFFFFFFFF );
-    }
-
+    HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_APB2ENR, 0xFFFFFFFF );
+    HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_APB1ENR, 0xFFFFFFFF );
 
 #if 1 //!defined(CYG_HAL_STARTUP_RAM)
-    // Set up clocks from configuration. In the future this should be moved to a
-    // function so that clock rates can be changed at runtime.
-    {
-        cyg_uint32 cr, cfgr;
-
-        // Reset RCC
-
-        HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, 0x00000001 );
-        
-        // Start up HSE clock
-
-        HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
-        cr &= CYGHWR_HAL_STM32_RCC_CR_HSEON|CYGHWR_HAL_STM32_RCC_CR_HSEBYP;
-        HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
-
-        HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
-        cr |= CYGHWR_HAL_STM32_RCC_CR_HSEON;
-        HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
-        
-        // Wait for HSE clock to startup
-        do
-        {
-            HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
-        } while( !(cr & CYGHWR_HAL_STM32_RCC_CR_HSERDY) );
-
-//        HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CFGR, cfgr );
-
-        // Configure clocks
-
-        hal_stm32_sysclk = CYGARC_HAL_CORTEXM_STM32_INPUT_CLOCK;
-        
-        cfgr = 0;
-
-#if defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSE)
-        cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PLLSRC_HSE;
-#elif defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSE_HALF)
-        cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PLLSRC_HSE |
-                CYGHWR_HAL_STM32_RCC_CFGR_PLLXTPRE;
-        hal_stm32_sysclk /= 2;
-#elif defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSI_HALF)
-        hal_stm32_sysclk /= 2;
-#endif
-        
-        cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PLLMUL(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_MUL);
-        cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_HPRE;
-        cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PPRE1;
-        cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PPRE2;
-
-        HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CFGR, cfgr );        
-
-        // Enable the PLL and wait for it to lock
-
-        cr |= CYGHWR_HAL_STM32_RCC_CR_PLLON;
-
-        HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
-        do
-        {
-            HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
-        } while( !(cr & CYGHWR_HAL_STM32_RCC_CR_PLLRDY) );
-
-        // Now switch to use PLL as SYSCLK
-
-        cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_SW_PLL;
-
-        HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CFGR, cfgr );        
-
-        // Calculate clocks from configuration
-
-        hal_stm32_sysclk *= CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_MUL;
-        hal_stm32_hclk = hal_stm32_sysclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_HCLK_DIV;
-        hal_stm32_pclk1 = hal_stm32_hclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_PCLK1_DIV;
-        hal_stm32_pclk2 = hal_stm32_hclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_PCLK2_DIV;
-        hal_cortexm_systick_clock = hal_stm32_hclk / 8;
-    }
+    hal_start_clocks();
 #endif
 
     // Attach EXTI springboard to interrupt vectors
     HAL_INTERRUPT_ATTACH( CYGNUM_HAL_INTERRUPT_EXTI9_5,   hal_exti_isr, 0, 0 );
     HAL_INTERRUPT_ATTACH( CYGNUM_HAL_INTERRUPT_EXTI15_10, hal_exti_isr, 0, 0 );
-
     
 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
     hal_if_init();
@@ -225,6 +149,91 @@ void hal_variant_init( void )
 }
 
 //==========================================================================
+// Setup up system clocks
+//
+// Set up clocks from configuration. In the future this should be extended so
+// that clock rates can be changed at runtime.
+
+void hal_start_clocks( void )
+{
+    CYG_ADDRESS rcc = CYGHWR_HAL_STM32_RCC;
+    cyg_uint32 cr, cfgr;
+    
+    // Reset RCC
+
+    HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, 0x00000001 );
+    
+    // Start up HSE clock
+    
+    HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+    cr &= CYGHWR_HAL_STM32_RCC_CR_HSEON|CYGHWR_HAL_STM32_RCC_CR_HSEBYP;
+    HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+
+    HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+    cr |= CYGHWR_HAL_STM32_RCC_CR_HSEON;
+    HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+    
+    // Wait for HSE clock to startup
+    
+    do
+    {
+        HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+    } while( !(cr & CYGHWR_HAL_STM32_RCC_CR_HSERDY) );
+
+    // Configure clocks
+    
+    hal_stm32_sysclk = CYGARC_HAL_CORTEXM_STM32_INPUT_CLOCK;
+    
+    cfgr = 0;
+
+#if defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSE)
+    cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PLLSRC_HSE;
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSE_HALF)
+    cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PLLSRC_HSE |
+            CYGHWR_HAL_STM32_RCC_CFGR_PLLXTPRE;
+    hal_stm32_sysclk /= 2;
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSI_HALF)
+    hal_stm32_sysclk /= 2;
+#endif
+    
+    cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PLLMUL(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_MUL);
+    cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_HPRE;
+    cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PPRE1;
+    cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PPRE2;
+
+    HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CFGR, cfgr );
+
+    // Enable the PLL and wait for it to lock
+    
+    cr |= CYGHWR_HAL_STM32_RCC_CR_PLLON;
+
+    HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+    do
+    {
+        HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+    } while( !(cr & CYGHWR_HAL_STM32_RCC_CR_PLLRDY) );
+
+    // Now switch to use PLL as SYSCLK
+    
+    cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_SW_PLL;
+
+    HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CFGR, cfgr );
+    do
+    {
+        HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CFGR, cfgr );
+    } while( (cfgr & CYGHWR_HAL_STM32_RCC_CFGR_SWS_XXX) != 
+             CYGHWR_HAL_STM32_RCC_CFGR_SWS_PLL );
+
+    // Calculate clocks from configuration
+
+    hal_stm32_sysclk *= CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_MUL;
+    hal_stm32_hclk = hal_stm32_sysclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_HCLK_DIV;
+    hal_stm32_pclk1 = hal_stm32_hclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_PCLK1_DIV;
+    hal_stm32_pclk2 = hal_stm32_hclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_PCLK2_DIV;
+    hal_cortexm_systick_clock = hal_stm32_hclk / 8;
+}
+
+//==========================================================================
 // ISR springboard
 //
 // This is attached to the ISR table entries for EXTI9_5 and EXTI15_10
@@ -354,4 +363,28 @@ void hal_stm32_uart_setbaud( cyg_uint32 
 }
 
 //==========================================================================
+// Timer clock rate
+//
+// Returns the current timer clock rate of a timer.
+
+cyg_uint32 hal_stm32_timer_clock( CYG_ADDRESS base )
+{
+    if( base == CYGHWR_HAL_STM32_TIM1 ||
+        base == CYGHWR_HAL_STM32_TIM8 )
+    {
+#if CYGHWR_HAL_CORTEXM_STM32_CLOCK_PCLK2_DIV == 1
+        return hal_stm32_pclk2;
+#else
+        return hal_stm32_pclk2 << 1;
+#endif
+    } else {
+#if CYGHWR_HAL_CORTEXM_STM32_CLOCK_PCLK1_DIV == 1
+        return hal_stm32_pclk1;
+#else
+        return hal_stm32_pclk1 << 1;
+#endif
+    }
+}
+
+//==========================================================================
 // EOF stm32_misc.c
--- a/packages/io/adc/current/ChangeLog
+++ b/packages/io/adc/current/ChangeLog
@@ -1,3 +1,10 @@
+2009-03-02  Simon Kallweit  <simon.kallweit@intefo.ch>
+
+	* cdl/io_adc.cdl:
+	* tests/adc1.c:
+	* tests/adc2.c:
+	Added generic ADC device driver tests.
+
 2008-12-30  John Dallaway  <john@dallaway.org.uk>
 
 	* cdl/io_adc.cdl: Reference per-package documentation.
--- a/packages/io/adc/current/cdl/io_adc.cdl
+++ b/packages/io/adc/current/cdl/io_adc.cdl
@@ -92,4 +92,23 @@ cdl_package CYGPKG_IO_ADC {
 	    ADC devices."
     }
     
+    cdl_component CYGPKG_IO_ADC_TESTS {
+        display     "ADC device driver tests"
+        flavor      data
+        no_define
+        calculated  { "tests/adc1 tests/adc2" }
+        description "
+            This option specifies the set of tests for the ADC device drivers."
+            
+            
+        cdl_option CYGNUM_IO_ADC_PERFORMANCE_TEST_RATE {
+            display         "ADC performance test rate"
+            flavor          data
+            legal_values    1 to 10000
+            default_value   1000
+            description     "
+                This option specifies the sampling rate used for the ADC device
+                driver performance test."
+        }
+    }
 }    
new file mode 100644
--- /dev/null
+++ b/packages/io/adc/current/tests/adc1.c
@@ -0,0 +1,194 @@
+//==========================================================================
+//
+//        adc1.c
+//
+//        ADC test
+//
+//==========================================================================
+// ####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 <simon.kallweit@intefo.ch>
+// Contributors:
+// Date:          2009-03-02
+// Description:   ADC test
+//####DESCRIPTIONEND####
+
+#include <pkgconf/system.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_diag.h>
+#include <cyg/hal/hal_arch.h>
+
+// Package requirements
+#if defined(CYGPKG_IO_ADC) && defined(CYGPKG_KERNEL)
+
+#include <pkgconf/kernel.h>
+#include <cyg/io/io.h>
+#include <cyg/io/devtab.h>
+#include <cyg/io/adc.h>
+
+// Package option requirements
+#if defined(CYGFUN_KERNEL_API_C)
+
+#include <cyg/kernel/kapi.h>
+
+#define TEST_RATE                   100 // Data acquisition rate for test
+#define TEST_SAMPLES                10  // Number of samples to acquire
+
+// Thread data
+cyg_handle_t thread_handle;
+cyg_thread thread_data;
+cyg_uint8 thread_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
+
+static void
+test_channel(const char *dev, cyg_io_handle_t channel)
+{
+    Cyg_ErrNo res;
+    cyg_uint32 cfg_data;
+    cyg_uint32 len;
+    cyg_adc_sample_t sample;
+    int count;
+    
+    diag_printf("\nTesting ADC channel '%s'\n", dev);
+    
+    // Disable channel
+    res = cyg_io_set_config(channel, CYG_IO_SET_CONFIG_ADC_DISABLE, 0, 0);
+    if (res != ENOERR)
+        CYG_TEST_FAIL_FINISH("Failed to disable ADC channel");
+    
+    // Make channel non-blocking
+    cfg_data = 0;
+    len = sizeof(cfg_data);
+    res = cyg_io_set_config(channel, CYG_IO_SET_CONFIG_READ_BLOCKING,
+                            &cfg_data, &len);
+    if (res != ENOERR)
+        CYG_TEST_FAIL_FINISH("Failed to make ADC channel non-blocking");
+
+    // Set channel sampling rate
+    cfg_data = TEST_RATE;
+    len = sizeof(cfg_data);
+    res = cyg_io_set_config(channel, CYG_IO_SET_CONFIG_ADC_RATE,
+                            &cfg_data, &len);
+    if (res != ENOERR)
+        CYG_TEST_FAIL_FINISH("Failed to set ADC channel sampling rate");
+    
+    // Flush channel
+    do {
+        len = sizeof(sample);
+        res = cyg_io_read(channel, &sample, &len);
+    } while (res == ENOERR);
+    
+    // Enable channel
+    res = cyg_io_set_config(channel, CYG_IO_SET_CONFIG_ADC_ENABLE, 0, 0);
+    if (res != ENOERR)
+        CYG_TEST_FAIL_FINISH("Failed to enable ADC channel");
+    
+    // Read from channel
+    count = 0;
+    while (count < TEST_SAMPLES) {
+        len = sizeof(sample);
+        res = cyg_io_read(channel, &sample, &len);
+        if (res == ENOERR) {
+            diag_printf("%d\n", sample);
+            count++;
+        }
+    }
+    
+    // Disable channel
+    res = cyg_io_set_config(channel, CYG_IO_SET_CONFIG_ADC_DISABLE, 0, 0);
+    if (res != ENOERR)
+        CYG_TEST_FAIL_FINISH("Failed to disable ADC channel");
+}
+
+static void
+adc_thread(cyg_addrword_t data)
+{
+    cyg_io_handle_t channel;
+    cyg_devtab_entry_t *t;
+    
+    CYG_TEST_INFO("ADC test");
+    
+    for (t = &__DEVTAB__[0]; t != &__DEVTAB_END__; t++) {
+        if (t->handlers != &cyg_io_adc_devio)
+            continue;
+        if (cyg_io_lookup(t->name, &channel) == ENOERR) {
+            test_channel(t->name, channel);
+        } else {
+            CYG_TEST_FAIL_FINISH("Cannot open ADC channel");
+        }
+    }
+    
+    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,
+        "adc1",
+        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
new file mode 100644
--- /dev/null
+++ b/packages/io/adc/current/tests/adc2.c
@@ -0,0 +1,280 @@
+//==========================================================================
+//
+//        adc2.c
+//
+//        ADC performance test
+//
+//==========================================================================
+// ####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 <simon.kallweit@intefo.ch>
+// Contributors:
+// Date:          2009-03-02
+// Description:   ADC performance test
+//####DESCRIPTIONEND####
+
+#include <pkgconf/system.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_diag.h>
+#include <cyg/hal/hal_arch.h>
+
+// Package requirements
+#if defined(CYGPKG_IO_ADC) && defined(CYGPKG_KERNEL)
+
+#include <pkgconf/kernel.h>
+#include <cyg/io/io.h>
+#include <cyg/io/devtab.h>
+#include <cyg/io/adc.h>
+
+// Package option requirements
+#if defined(CYGFUN_KERNEL_API_C)
+
+#include <cyg/kernel/kapi.h>
+
+#define MAX_CHANNELS                64  // Max channels to test
+
+#define TICKS_PER_SECOND            \
+    (1000000000 / (CYGNUM_HAL_RTC_NUMERATOR / CYGNUM_HAL_RTC_DENOMINATOR))
+
+// ADC test channel
+typedef struct test_channel {
+    const char *dev;            // ADC channel device name
+    cyg_io_handle_t handle;     // ADC channel handle
+    cyg_uint32 count;           // Sample counter
+} test_channel;
+
+// ADC test channels
+static test_channel test_channels[MAX_CHANNELS];
+
+// Thread data
+cyg_handle_t thread_handle;
+cyg_thread thread_data;
+cyg_uint8 thread_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
+
+static void
+adc_thread(cyg_addrword_t data)
+{
+    cyg_uint32 num = 0;
+    cyg_devtab_entry_t *t;
+    test_channel *chan;
+    cyg_adc_sample_t sample;
+    Cyg_ErrNo res;
+    cyg_uint32 cfg_data;
+    cyg_uint32 len;
+    cyg_uint32 start_time;
+    cyg_uint32 end_time;
+    int i;
+    cyg_uint8 seconds = 0;
+    float final_seconds;
+    cyg_uint32 samples_expected;
+    
+    CYG_TEST_INFO("ADC performance test");
+    
+    // This test reads samples from all enabled ADC channels. Each second, the
+    // number of already acquired samples is printed. After 10 seconds, all ADC
+    // channels are stpped and each ADC buffer is read until empty. If the
+    // number of acquired samples is much smaller than the number of expected
+    // samples, the rate is too high.
+
+    CYG_TEST_INFO("Opening available ADC channels");
+    
+    for (t = &__DEVTAB__[0]; t != &__DEVTAB_END__; t++) {
+        if (t->handlers != &cyg_io_adc_devio)
+            continue;
+        chan = &test_channels[num++];
+        chan->dev = t->name;
+        if (cyg_io_lookup(chan->dev, &chan->handle) != ENOERR)
+            CYG_TEST_FAIL_FINISH("Cannot open ADC channel");
+    }
+    
+    diag_printf("Opened %d ADC channels\n", num);
+    
+    CYG_TEST_INFO("Preparing ADC channels for test");
+    
+    for (i = 0; i < num; i++) {
+        chan = &test_channels[i];
+        
+        // Disable channel
+        res = cyg_io_set_config(chan->handle, CYG_IO_SET_CONFIG_ADC_DISABLE, 0, 0);
+        if (res != ENOERR)
+            CYG_TEST_FAIL_FINISH("Failed to disable ADC channel");
+        
+        // Make channel non-blocking
+        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("Failed to make ADC channel non-blocking");
+
+        // Set channel sampling rate
+        cfg_data = CYGNUM_IO_ADC_PERFORMANCE_TEST_RATE;
+        len = sizeof(cfg_data);
+        res = cyg_io_set_config(chan->handle,
+                                CYG_IO_SET_CONFIG_ADC_RATE,
+                                &cfg_data, &len);
+        if (res != ENOERR)
+            CYG_TEST_FAIL_FINISH("Failed to set ADC channel sampling rate");
+        
+        // Flush channel
+        do {
+            len = sizeof(sample);
+            res = cyg_io_read(chan->handle, &sample, &len);
+        } while (res == ENOERR);
+        chan->count = 0;
+    }
+    
+    CYG_TEST_INFO("Starting measurement");
+    
+    for (i = 0; i < num; i++) {
+        chan = &test_channels[i];
+        
+        // Enable channel
+        res = cyg_io_set_config(chan->handle, CYG_IO_SET_CONFIG_ADC_ENABLE, 0, 0);
+        if (res != ENOERR)
+            CYG_TEST_FAIL_FINISH("Failed to enabled ADC channel");
+    }
+
+    start_time = cyg_current_time();
+    do {
+        for (i = 0; i < num; i++) {
+            chan = &test_channels[i];
+            
+            // Read & count samples
+            do {
+                cyg_uint32 len = sizeof(sample);
+                res = cyg_io_read(chan->handle, &sample, &len);
+                if (res == ENOERR)
+                    chan->count++;
+            } 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) >= TICKS_PER_SECOND) {
+            start_time = end_time;
+            diag_printf("\n");
+            for (i = 0; i < num; i++) {
+                chan = &test_channels[i];
+                diag_printf("%-20s\t= %d\n", chan->dev, chan->count);
+            }
+            seconds++;
+        }
+    } while (seconds < 10);
+
+    for (i = 0; i < num; i++) {
+        chan = &test_channels[i];
+        
+        // Disable channel
+        res = cyg_io_set_config(chan->handle, CYG_IO_SET_CONFIG_ADC_DISABLE, 0, 0);
+        if (res != ENOERR)
+            CYG_TEST_FAIL_FINISH("Failed to disable ADC channel");
+    }
+    
+    end_time = cyg_current_time();
+    
+    for (i = 0; i < num; i++) {
+        chan = &test_channels[i];
+        
+        // Count remainding samples
+        do {
+            len = sizeof(sample);
+            res = cyg_io_read(chan->handle, &sample, &len);
+            if (res == ENOERR)
+                chan->count++;
+        } while (res == ENOERR);
+    }
+    
+    CYG_TEST_INFO("Finished measurement");
+    
+    diag_printf("\n\n----------------------------------------\n");
+    
+    final_seconds = (end_time - start_time) + (seconds * TICKS_PER_SECOND);
+    final_seconds /= TICKS_PER_SECOND;
+    samples_expected = final_seconds * CYGNUM_IO_ADC_PERFORMANCE_TEST_RATE;
+    diag_printf("Samples expected after %d milliseconds: %d\n",
+                (unsigned int) (final_seconds * 1000), samples_expected);
+    
+    diag_printf("Samples read (per channel):\n");
+    for (i = 0; i < num; i++) {
+        chan = &test_channels[i];
+        diag_printf("%-20s\t= %d\n", chan->dev, chan->count);
+    }
+
+    CYG_TEST_PASS_FINISH("ADC performance 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,
+        "adc2",
+        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