changeset 2956:ae92e99547f4

* ecos.db: Add AT91 ADC driver. * devs/adc/arm/at91/*: Initial check-in ADC driver for AT91 contributed by Christophe Coutand.
author sergeig
date Sun, 30 May 2010 10:24:56 +0000
parents f3e242061dd3
children e382c7388162
files packages/ChangeLog packages/NEWS packages/devs/adc/arm/at91/current/ChangeLog packages/devs/adc/arm/at91/current/cdl/adc_at91.cdl packages/devs/adc/arm/at91/current/include/adc_at91.inl packages/devs/adc/arm/at91/current/src/adc_at91.c packages/devs/adc/arm/at91/current/tests/at91_adc_test.c packages/ecos.db
diffstat 8 files changed, 1348 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/packages/ChangeLog
+++ b/packages/ChangeLog
@@ -1,3 +1,7 @@
+2010-05-30  Christophe Coutand  <ccoutand@stmi.com>
+
+	* ecos.db: Add AT91 ADC driver.
+
 2009-11-13  John Dallaway  <john@dallaway.org.uk>
 
 	* ecosadmin.tcl: Keep target records containing removed packages
--- a/packages/NEWS
+++ b/packages/NEWS
@@ -1,3 +1,4 @@
+* ADC device driver for AT91 by Christophe Coutand 
 * Major update of lwIP stack to v1.3.2 by Simon Kallweit
 * Port of uSTL 1.3 by Uwe Kindler
 * Port of PDCurses 3.4 by Sergei Gavrikov
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/arm/at91/current/ChangeLog
@@ -0,0 +1,31 @@
+2010-05-18  ccoutand  <ccoutand@stmi.com>
+
+        * AT91 ADC driver package created
+        * cdl/adc_at91.cdl
+        * src/adc_at91.c
+        * include/adc_at91.inl
+        * tests/at91_adc_test.c
+
+//===========================================================================
+// ####GPLCOPYRIGHTBEGIN####                                                
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2010 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/arm/at91/current/cdl/adc_at91.cdl
@@ -0,0 +1,355 @@
+# ====================================================================
+#
+#      adc_at91.cdl
+#
+#      eCos AT91 ADC configuration data
+#
+# ====================================================================
+## ####ECOSGPLCOPYRIGHTBEGIN####                                            
+## -------------------------------------------                              
+## This file is part of eCos, the Embedded Configurable Operating System.   
+## Copyright (C) 2008 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):      ccoutand@stmi.com
+# Contributors:   
+# Date:           2010-02-12
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+
+cdl_package CYGPKG_DEVS_ADC_ARM_AT91 {
+    display     "ADC hardware device driver for AT91 family of ARM controllers"
+    
+    parent      CYGPKG_IO_ADC_DEVICES
+    active_if   CYGPKG_IO_ADC_DEVICES
+    active_if   CYGPKG_HAL_ARM_AT91
+    description " 
+           This package provides a generic ADC device driver for the on-chip
+           ADC peripherals in AT91 processors."
+           
+    include_dir cyg/io
+    compile     -library=libextras.a adc_at91.c
+    
+    define_proc {
+      puts $::cdl_system_header "#define CYGDAT_DEVS_ADC_ARM_AT91_INL <cyg/io/adc_at91.inl>"
+    }
+    
+    # 
+    # Primary ADC ( ADC0 )
+    #
+    cdl_component CYGPKG_DEVS_ADC_ARM_AT91_ADC0 {
+       display       "Atmel AT91 ADC port 0 driver"
+       flavor        bool
+       default_value 1
+       description "
+           This option includes the device driver for the on-chip ADC 0 of the
+           AT91 processors"
+    
+    
+       cdl_interface CYGINT_DEVS_ADC_ARM_AT91_ADC0_CHANNELS {
+          display "Number of ADC0 channels"
+       }  
+   
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC0_SELECT_TIMER {
+          display       "Interrupt priority"
+          flavor        data
+          legal_values {0 1 2}
+          default_value 1
+          description   "
+              This option selects the timer channel to be used for 
+              generating the sampling interval. Timer channel 0 can 
+              be assigned as Real Time Kernel clock so timer channel 
+              1 is set to be the default value."
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC0_PRESCAL {
+           display       "ADC clock setting"
+           flavor        data
+           legal_values  0 to 255
+           default_value 128
+           description   "
+               This option sets the AT91 ADC PRESCAL value. 
+               ADCClock = MCK / ((PRESCAL + 1) * 2)"
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC0_STARTUP_TIME {
+           display       "ADC start-up time"
+           flavor        data
+           legal_values  0 to 255
+           default_value 128
+           description   "
+               This option sets the AT91 ADC start-up time value. 
+               ADC start-up time = (STARTUP+1) * 8 / ADCClock"
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC0_SHTIM {
+           display       "ADC start up time"
+           flavor        data
+           legal_values  0 to 15
+           default_value 7
+           description   "
+               This option sets the AT91 ADC Sample and Hold Time. 
+               Sample and Hold Time = SHTIM / ADCClock"
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC0_INTPRIO {
+           display       "Interrupt priority"
+           flavor        data
+           legal_values  0 to 15
+           default_value 15
+           description   "
+               This option selects the interrupt priority for the ADC
+               interrupts.  Timer x is used for generating the sample
+               clock. So this option configures the interrupt priority
+               for timer x. There are 16 priority levels corresponding to
+               the values 0 through 15 decimal, of which 15 is the lowest
+               priority. The reset value of these registers defaults all
+               interrupts to the lowest priority, allowing a single write
+               to elevate the priority of an individual interrupt."
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC0_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 up to 8 ADC channels
+       for { set ::channel 0 } { $::channel < 8 } { incr ::channel } {  
+    
+           cdl_component CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL[set ::channel] {
+               display        "Access ADC channel [set ::channel]"
+               flavor          bool
+               default_value   [set ::channel] == 0
+               implements      CYGINT_DEVS_ADC_ARM_AT91_ADC0_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_ARM_AT91_ADC0_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_ARM_AT91_ADC0_CHANNEL[set ::channel]_BUFSIZE {
+                   display "Size of data buffer"
+                   flavor  data
+                   legal_values  0x01 to 0x2000000
+                   default_value 512
+                   description "
+                       This option controls the number of samples the
+                       buffer can store. The required RAM depends on the
+                       sample size and on the number of samples. If the
+                       sample size is <= 8 bit the the required RAM =
+                       size of data buffer. If the sample size is 9 or 10
+                       bit then required RAM = size of data buffer * 2."
+               } 
+           } 
+        }
+     }
+     
+    # 
+    # ADC1
+    #
+    cdl_component CYGPKG_DEVS_ADC_ARM_AT91_ADC1 {
+       display       "Atmel AT91 ADC port 1 driver"
+       flavor        bool
+       default_value 0
+       
+       requires      { CYGHWR_HAL_ARM_AT91 == "M55800A" }
+       
+       description "
+           This option includes the device driver for the on-chip ADC 1 of the
+           AT91 processors"
+    
+    
+       cdl_interface CYGINT_DEVS_ADC_ARM_AT91_ADC1_CHANNELS {
+          display "Number of ADC1 channels"
+       }  
+   
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC1_SELECT_TIMER {
+          display       "Interrupt priority"
+          flavor        data
+          legal_values {0 1 2}
+          default_value 2
+          description   "
+              This option selects the timer channel to be used for 
+              generating the sampling interval. Timer channel 0 can 
+              be assigned as Real Time Kernel clock so timer channel 
+              1 is set to be the default value."
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC1_PRESCAL {
+           display       "ADC clock setting"
+           flavor        data
+           legal_values  0 to 255
+           default_value 128
+           description   "
+               This option sets the AT91 ADC PRESCAL value. 
+               ADCClock = MCK / ((PRESCAL + 1) * 2)"
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC1_STARTUP_TIME {
+           display       "ADC start-up time"
+           flavor        data
+           legal_values  0 to 255
+           default_value 128
+           description   "
+               This option sets the AT91 ADC start-up time value. 
+               ADC start-up time = (STARTUP+1) * 8 / ADCClock"
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC1_SHTIM {
+           display       "ADC start up time"
+           flavor        data
+           legal_values  0 to 15
+           default_value 7
+           description   "
+               This option sets the AT91 ADC Sample and Hold Time. 
+               Sample and Hold Time = SHTIM / ADCClock"
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_ADC1_INTPRIO {
+           display       "Interrupt priority"
+           flavor        data
+           legal_values  0 to 15
+           default_value 15
+           description   "
+               This option selects the interrupt priority for the ADC
+               interrupts.  Timer x is used for generating the sample
+               clock. So this option configures the interrupt priority
+               for timer x. There are 16 priority levels corresponding to
+               the values 0 through 15 decimal, of which 15 is the lowest
+               priority. The reset value of these registers defaults all
+               interrupts to the lowest priority, allowing a single write
+               to elevate the priority of an individual interrupt."
+       }
+
+       cdl_option CYGNUM_DEVS_ADC_ARM_AT91_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."
+       }
+                
+       # Support up to 8 ADC channels
+       for { set ::channel 0 } { $::channel < 8 } { incr ::channel } {  
+    
+           cdl_component CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL[set ::channel] {
+               display        "Access ADC channel [set ::channel]"
+               flavor          bool
+               default_value   [set ::channel] == 0
+               implements      CYGINT_DEVS_ADC_ARM_AT91_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_ARM_AT91_ADC1_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_ARM_AT91_ADC1_CHANNEL[set ::channel]_BUFSIZE {
+                   display "Size of data buffer"
+                   flavor  data
+                   legal_values  0x01 to 0x2000000
+                   default_value 512
+                   description "
+                       This option controls the number of samples the
+                       buffer can store. The required RAM depends on the
+                       sample size and on the number of samples. If the
+                       sample size is <= 8 bit the the required RAM =
+                       size of data buffer. If the sample size is 9 or 10
+                       bit then required RAM = size of data buffer * 2."
+               } 
+           } 
+        }
+     }     
+     
+     cdl_option CYGPKG_DEVS_ADC_ARM_AT91_DEBUG_LEVEL {
+         display "Driver debug output level"
+         flavor  data
+         legal_values {0 1}
+         default_value 0
+         description   "
+              This option specifies the level of debug data output by
+              the AT91 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 CYGSEM_DEVS_ADC_ARM_AT91_SAMPLE_SIZE_LIMIT {
+         display       "Sample size limit"
+         flavor          bool
+         calculated    1
+         requires      { ( CYGNUM_IO_ADC_SAMPLE_SIZE == 8 )
+                            || ( CYGNUM_IO_ADC_SAMPLE_SIZE == 10 ) }
+         description   "
+             This component forces a limit (or rounds) the sample
+             size for AT91 ADC channels which in the most are 10-bit."
+     }
+
+    cdl_option CYGPKG_DEVS_ADC_ARM_AT91_TESTS {
+        display "Tests for AT91 ADC driver"
+        flavor  data
+        no_define
+        calculated { "tests/at91_adc_test" }
+        description   "
+            This option specifies the set of tests for the AT91
+            ADC device driver."
+    }
+
+}
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/arm/at91/current/include/adc_at91.inl
@@ -0,0 +1,200 @@
+//==========================================================================
+//
+//      adc_at91.inl
+//
+//      ADC driver for AT91 on chip ADC
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 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):    Atmel AT91 on-chip ADC device driver, ccoutand
+//              
+// Contributors:
+// Date:         2010-05-27
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef CYGONCE_DEVS_ADC_ARM_AT91_INL
+#define CYGONCE_DEVS_ADC_ARM_AT91_INL
+
+// Some AT91 HAL are defining the timer 0 vector as TC0 and other as TIMER0
+#ifndef CYGNUM_HAL_INTERRUPT_TC0
+#define CYGNUM_HAL_INTERRUPT_TC0 CYGNUM_HAL_INTERRUPT_TIMER0
+#endif
+
+// Declare ADC0
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0
+
+static at91_adc_info at91_adc0_info =
+{
+    .adc_base         = AT91_ADC,
+    .timer_base       = AT91_TC,
+    .tc_base          = AT91_TC + (AT91_TC_TC_SIZE * CYGNUM_DEVS_ADC_ARM_AT91_ADC0_SELECT_TIMER),
+    .timer_vector     = CYGNUM_HAL_INTERRUPT_TC0 + CYGNUM_DEVS_ADC_ARM_AT91_ADC0_SELECT_TIMER,
+    .timer_intprio    = CYGNUM_DEVS_ADC_ARM_AT91_ADC0_INTPRIO,
+    .timer_id         = CYGNUM_DEVS_ADC_ARM_AT91_ADC0_SELECT_TIMER,
+    .int_handle       = 0,
+    .adc_prescal      = CYGNUM_DEVS_ADC_ARM_AT91_ADC0_PRESCAL,
+    .adc_startup_time = CYGNUM_DEVS_ADC_ARM_AT91_ADC0_STARTUP_TIME,
+    .adc_shtim        = CYGNUM_DEVS_ADC_ARM_AT91_ADC0_SHTIM,
+#if CYGNUM_IO_ADC_SAMPLE_SIZE > 8
+     .resolution      = AT91_ADC_MR_LOWREC_10BITS,
+#else
+     .resolution      = AT91_ADC_MR_LOWRES_8BITS,
+#endif
+    .chan_mask        = 0
+};
+
+CYG_ADC_DEVICE( at91_adc0_device,
+                &at91_adc_funs,
+                &at91_adc0_info,
+                CYGNUM_DEVS_ADC_ARM_AT91_ADC0_DEFAULT_RATE);
+
+#define AT91_ADC0_CHANNEL( __chan )                                        \
+CYG_ADC_CHANNEL( at91_adc0_channel##__chan,                                \
+                 __chan,                                                   \
+                 CYGDAT_DEVS_ADC_ARM_AT91_ADC0_CHANNEL##__chan##_BUFSIZE,  \
+                 &at91_adc0_device );                                       \
+                                                                           \
+DEVTAB_ENTRY( at91_adc0_channel##__chan##_device,                          \
+              CYGDAT_DEVS_ADC_ARM_AT91_ADC0_CHANNEL##__chan##_NAME,        \
+              0,                                                           \
+              &cyg_io_adc_devio,                                           \
+              at91_adc_init,                                               \
+              at91_adc_lookup,                                             \
+              &at91_adc0_channel##__chan );
+
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL0
+AT91_ADC0_CHANNEL(0);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL1
+AT91_ADC0_CHANNEL(1);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL2
+AT91_ADC0_CHANNEL(2);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL3
+AT91_ADC0_CHANNEL(3);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL4
+AT91_ADC0_CHANNEL(4);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL5
+AT91_ADC0_CHANNEL(5);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL6
+AT91_ADC0_CHANNEL(6);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC0_CHANNEL7
+AT91_ADC0_CHANNEL(7);
+#endif
+
+#endif // CYGPKG_DEVS_ADC_ARM_AT91_ADC0
+
+
+
+// Declare ADC1
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1
+
+static at91_adc_info at91_adc1_info =
+{
+    .adc_base         = AT91_ADC1,
+    .timer_base       = AT91_TC,
+    .tc_base          = AT91_TC + (AT91_TC_TC_SIZE * CYGNUM_DEVS_ADC_ARM_AT91_ADC1_SELECT_TIMER),
+    .timer_vector     = CYGNUM_HAL_INTERRUPT_TC0 + CYGNUM_DEVS_ADC_ARM_AT91_ADC1_SELECT_TIMER,
+    .timer_intprio    = CYGNUM_DEVS_ADC_ARM_AT91_ADC1_INTPRIO,
+    .timer_id         = CYGNUM_DEVS_ADC_ARM_AT91_ADC1_SELECT_TIMER,
+    .int_handle       = 0,
+    .adc_prescal      = CYGNUM_DEVS_ADC_ARM_AT91_ADC1_PRESCAL,
+    .adc_startup_time = CYGNUM_DEVS_ADC_ARM_AT91_ADC1_STARTUP_TIME,
+    .adc_shtim        = CYGNUM_DEVS_ADC_ARM_AT91_ADC1_SHTIM,
+#if CYGNUM_IO_ADC_SAMPLE_SIZE > 8
+     .resolution      = AT91_ADC_MR_LOWREC_10BITS,
+#else
+     .resolution      = AT91_ADC_MR_LOWRES_8BITS,
+#endif
+    .chan_mask        = 0
+};
+CYG_ADC_DEVICE( at91_adc1_device,
+                &at91_adc_funs,
+                &at91_adc1_info,
+                CYGNUM_DEVS_ADC_ARM_AT91_ADC1_DEFAULT_RATE);
+
+#define AT91_ADC1_CHANNEL( __chan )                                        \
+CYG_ADC_CHANNEL( at91_adc1_channel##__chan,                                \
+                 __chan,                                                   \
+                 CYGDAT_DEVS_ADC_ARM_AT91_ADC1_CHANNEL##__chan##_BUFSIZE,  \
+                 &at91_adc1_device );                                       \
+                                                                           \
+DEVTAB_ENTRY( at91_adc1_channel##__chan##_device,                          \
+              CYGDAT_DEVS_ADC_ARM_AT91_ADC1_CHANNEL##__chan##_NAME,        \
+              0,                                                           \
+              &cyg_io_adc_devio,                                           \
+              at91_adc_init,                                               \
+              at91_adc_lookup,                                             \
+              &at91_adc1_channel##__chan );
+
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL0
+AT91_ADC1_CHANNEL(0);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL1
+AT91_ADC1_CHANNEL(1);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL2
+AT91_ADC1_CHANNEL(2);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL3
+AT91_ADC1_CHANNEL(3);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL4
+AT91_ADC1_CHANNEL(4);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL5
+AT91_ADC1_CHANNEL(5);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL6
+AT91_ADC1_CHANNEL(6);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_AT91_ADC1_CHANNEL7
+AT91_ADC1_CHANNEL(7);
+#endif
+
+#endif // CYGPKG_DEVS_ADC_ARM_AT91_ADC1
+
+#endif // CYGONCE_DEVS_ADC_ARM_AT91_INL
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/arm/at91/current/src/adc_at91.c
@@ -0,0 +1,457 @@
+//==========================================================================
+//
+//      adc_at91.c
+//
+//      ADC driver for AT91 on chip ADC
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 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):   Uwe Kindler <uwe_kindler@web.de>
+//              Updated for Atmel AT91 device, ccoutand <ccoutand@stmi.com>
+// Contributors:
+// Date:         2010-02-15
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+
+//==========================================================================
+//                                 INCLUDES
+//==========================================================================
+#include <pkgconf/system.h>
+#include <pkgconf/devs_adc_arm_at91.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.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>
+
+#if CYGPKG_DEVS_ADC_ARM_AT91_DEBUG_LEVEL > 0
+   #define at91_adc_printf(args...) diag_printf(args)
+#else
+   #define at91_adc_printf(args...)
+#endif
+
+#define AT91_ADC_CHER_CHx(_ch_)  (0x1 << _ch_)
+#define AT91_ADC_CHER_CDRx(_ch_) (_ch_ << 2)
+
+//==========================================================================
+//                                  DATA TYPES
+//==========================================================================
+typedef struct at91_adc_info
+{
+    cyg_uint32              adc_base;          // base address of ADC peripheral
+    cyg_uint8               adc_prescal;       // ADC prescal value
+    cyg_uint8               adc_startup_time;  // ADC Startup Time value
+    cyg_uint8               adc_shtim;         // ADC SHTIM value
+    cyg_uint8               timer_id;          // select timer
+    cyg_uint32              timer_base;        // base address of Timer peripheral
+    cyg_uint32              tc_base;           // base address of Timer channel
+    cyg_vector_t            timer_vector;      // interrupt vector number
+    int                     timer_intprio;     // interrupt priority of ADC interrupt
+    cyg_uint32              timer_cnt;         // Timer value
+    cyg_uint8               timer_clk;         // Timer clock setting
+    cyg_uint32              resolution;
+    cyg_handle_t            int_handle;        // For initializing the interrupt
+    cyg_interrupt           int_data;
+    struct cyg_adc_channel *channel[AT91_MAX_ADC_CHAN]; // stores references to channel objects
+    cyg_uint8               chan_mask;         // mask that indicates channels used
+                                               // by ADC driver
+} at91_adc_info;
+
+
+//==========================================================================
+//                               DECLARATIONS
+//==========================================================================
+static bool at91_adc_init(struct cyg_devtab_entry *tab);
+static Cyg_ErrNo at91_adc_lookup(struct cyg_devtab_entry **tab,
+                                    struct cyg_devtab_entry  *sub_tab,
+                                    const char               *name);
+static void at91_adc_enable( cyg_adc_channel *chan );
+static void at91_adc_disable( cyg_adc_channel *chan );
+static void at91_adc_set_rate( cyg_adc_channel *chan, cyg_uint32 rate );
+static cyg_uint32 at91_adc_isr(cyg_vector_t vector, cyg_addrword_t data);
+static void at91_adc_dsr(cyg_vector_t vector,
+                            cyg_ucount32 count,
+                            cyg_addrword_t data);
+
+// -------------------------------------------------------------------------
+// Driver functions:
+CYG_ADC_FUNCTIONS( at91_adc_funs,
+                   at91_adc_enable,
+                   at91_adc_disable,
+                   at91_adc_set_rate );
+
+
+#include CYGDAT_DEVS_ADC_ARM_AT91_INL // Instantiate ADCs
+
+//==========================================================================
+// 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 at91_adc_init(struct cyg_devtab_entry *tab)
+{
+    cyg_adc_channel *chan   = (cyg_adc_channel *)tab->priv;
+    cyg_adc_device *device  = chan->device;
+    at91_adc_info *info     = device->dev_priv;
+    cyg_uint32 regval;
+
+    if (!info->int_handle)
+    {
+       cyg_drv_interrupt_create(info->timer_vector,
+                                 info->timer_intprio,
+                                (cyg_addrword_t)device,
+                                &at91_adc_isr,
+                                &at91_adc_dsr,
+                                &(info->int_handle),
+                                &(info->int_data));
+       cyg_drv_interrupt_attach(info->int_handle);
+       cyg_drv_interrupt_mask(info->timer_vector);
+
+       // Reset ADC
+       HAL_WRITE_UINT32((info->adc_base + AT91_ADC_CR), AT91_ADC_CR_SWRST);
+
+       // Disable counter interrupts
+       HAL_WRITE_UINT32(info->tc_base+AT91_TC_CCR, AT91_TC_CCR_CLKDIS);
+       HAL_WRITE_UINT32(info->tc_base+AT91_TC_IDR, 0xffffffff);
+
+       // Clear status bit
+       HAL_READ_UINT32(info->tc_base + AT91_TC_SR, regval);
+
+       // Enable peripheral clocks for TC
+       HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCER,  \
+             ((AT91_PMC_PCER_TC0) << info->timer_id));
+
+       //
+       // Disable all interrupts, all channels
+       //
+       HAL_WRITE_UINT32((info->adc_base + AT91_ADC_CHDR), \
+                     AT91_ADC_CHER_CH0  |\
+                     AT91_ADC_CHER_CH1  |\
+                     AT91_ADC_CHER_CH2  |\
+                     AT91_ADC_CHER_CH3  |\
+                     AT91_ADC_CHER_CH4  |\
+                     AT91_ADC_CHER_CH5  |\
+                     AT91_ADC_CHER_CH6  |\
+                     AT91_ADC_CHER_CH7);
+       HAL_WRITE_UINT32((info->adc_base + AT91_ADC_IDR), \
+                     AT91_ADC_CHER_CH0  |\
+                     AT91_ADC_CHER_CH1  |\
+                     AT91_ADC_CHER_CH2  |\
+                     AT91_ADC_CHER_CH3  |\
+                     AT91_ADC_CHER_CH4  |\
+                     AT91_ADC_CHER_CH5  |\
+                     AT91_ADC_CHER_CH6  |\
+                     AT91_ADC_CHER_CH7);
+
+       //
+       // setup the default sample rate
+       //
+       at91_adc_set_rate(chan, chan->device->config.rate);
+
+       // setup ADC mode
+       HAL_WRITE_UINT32((info->adc_base + AT91_ADC_MR), \
+                    ( ( info->adc_prescal  << AT91_ADC_MR_PRESCAL_SHIFT ) & \
+                        AT91_ADC_MR_PRESCAL_MASK ) | \
+                    ( ( info->adc_startup_time   << AT91_ADC_MR_STARTUP_SHIFT ) & \
+                        AT91_ADC_MR_STARTUP_MASK ) | \
+                    ( (  info->adc_shtim << AT91_ADC_MR_SHTIM_SHIFT ) & \
+                        AT91_ADC_MR_SHTIM_MASK ) | \
+                        AT91_ADC_MR_TRGSEL_TIOA0  | \
+                        info->resolution);
+
+
+    } // if (!info->int_handle)
+
+    cyg_adc_device_init(device); // initialize generic parts of driver
+
+    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 at91_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;
+    at91_adc_info *info     = chan->device->dev_priv;
+
+    info->channel[chan->channel] = chan;
+    cyg_adc_channel_init(chan); // initialize generic parts of channel
+
+    //
+    // 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;
+    at91_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 at91_adc_enable(cyg_adc_channel *chan)
+{
+    at91_adc_info *info      = chan->device->dev_priv;
+
+    // Enable the channel
+    HAL_WRITE_UINT32((info->adc_base + AT91_ADC_CHER), \
+                      AT91_ADC_CHER_CHx(chan->channel));
+
+    //
+    // Unmask interrupt as soon as 1 channel is enable
+    //
+    if (!info->chan_mask)
+    {
+       cyg_drv_interrupt_unmask(info->timer_vector);
+
+       // Enable timer interrupt
+       HAL_WRITE_UINT32(info->tc_base+AT91_TC_IER, AT91_TC_IER_CPC);
+
+       // Enable the clock
+       HAL_WRITE_UINT32(info->tc_base+AT91_TC_CCR, AT91_TC_CCR_TRIG | AT91_TC_CCR_CLKEN);
+
+       // Start timer
+       HAL_WRITE_UINT32(info->tc_base+AT91_TC_CCR,  AT91_TC_CCR_TRIG);
+
+       // Start ADC sampling
+       HAL_WRITE_UINT32((info->adc_base + AT91_ADC_CR), AT91_ADC_CR_START);
+
+    }
+
+    info->chan_mask |= AT91_ADC_CHER_CHx(chan->channel);
+
+}
+
+
+//==========================================================================
+// 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 at91_adc_disable(cyg_adc_channel *chan)
+{
+    at91_adc_info *info  = chan->device->dev_priv;
+    cyg_uint32 sr;
+
+    info->chan_mask &= ~ AT91_ADC_CHER_CHx(chan->channel);
+
+    // Disable the channel
+    HAL_WRITE_UINT32((info->adc_base + AT91_ADC_CHDR), \
+                      AT91_ADC_CHER_CHx(chan->channel));
+
+    //
+    // If no channel is enabled the we disable interrupts now
+    //
+    if (!info->chan_mask)
+    {
+       cyg_drv_interrupt_mask(info->timer_vector);
+
+       // Clear interrupt
+       HAL_READ_UINT32(info->tc_base+AT91_TC_SR, sr);
+
+       // Disable  timer interrupt
+       HAL_WRITE_UINT32(info->tc_base+AT91_TC_IDR, AT91_TC_IER_CPC);
+
+       // Disable the clock
+       HAL_WRITE_UINT32(info->tc_base+AT91_TC_CCR, AT91_TC_CCR_CLKDIS);
+
+    }
+}
+
+
+//==========================================================================
+// 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 at91_adc_set_rate( cyg_adc_channel *chan, cyg_uint32 rate)
+{
+    cyg_adc_device   *device = chan->device;
+    at91_adc_info *info   = (at91_adc_info *)device->dev_priv;
+    cyg_uint8 timer_clk   = AT91_TC_CMR_CLKS_MCK2;
+    cyg_uint32 tmr_period = CYGNUM_HAL_ARM_AT91_CLOCK_SPEED / ( rate << 1);
+
+    if( tmr_period > 0xffff )
+    {
+       tmr_period = CYGNUM_HAL_ARM_AT91_CLOCK_SPEED / ( rate << 5);
+       timer_clk  = AT91_TC_CMR_CLKS_MCK32;
+    }
+
+    if( tmr_period > 0xffff )
+    {
+       tmr_period = CYGNUM_HAL_ARM_AT91_CLOCK_SPEED / ( rate << 7);
+       timer_clk  = AT91_TC_CMR_CLKS_MCK128;
+    }
+
+    if( tmr_period > 0xffff )
+    {
+       tmr_period = CYGNUM_HAL_ARM_AT91_CLOCK_SPEED / ( rate << 10);
+       timer_clk  = AT91_TC_CMR_CLKS_MCK1024;
+    }
+
+    if( tmr_period > 0xffff )
+    {
+       tmr_period = 0xffff;
+       timer_clk  = AT91_TC_CMR_CLKS_MCK1024;
+       at91_adc_printf("AT91 ADC timer, rate too high!");
+    }
+
+    device->config.rate = rate;
+    info->timer_clk = timer_clk;
+    info->timer_cnt = tmr_period;
+
+    // Set timer values
+    HAL_WRITE_UINT32(info->tc_base+AT91_TC_CMR,  AT91_TC_CMR_CPCTRG | info->timer_clk);
+    HAL_WRITE_UINT32(info->tc_base+AT91_TC_RC,  info->timer_cnt);
+
+    at91_adc_printf("AT91 ADC Timer settings %d, %d", info->timer_clk, info->timer_cnt);
+
+    return;
+}
+
+
+//==========================================================================
+// This function is the ISR attached to the ADC device's interrupt vector.
+// It is responsible for reading samples from the channels and passing them
+// on to the generic layer. It needs to check each channel for data, and call
+// cyg_adc_receive_sample() for each new sample available, and then ready the
+// device for the next interrupt.
+//==========================================================================
+static cyg_uint32 at91_adc_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+    cyg_adc_device   *device = (cyg_adc_device *) data;
+    at91_adc_info *info   = (at91_adc_info *)device->dev_priv;
+    cyg_uint32        regval,  adc_status;
+    cyg_uint32        res = 0;
+    cyg_adc_sample_t  adcdata;
+    cyg_uint32 sr;
+
+    cyg_uint8 active_channels = info->chan_mask;
+    cyg_uint8 channel_no = 0;
+
+    // Clear timer interrupt
+    HAL_READ_UINT32(info->tc_base+AT91_TC_SR, sr);
+
+    // Check on channel conversion done
+    HAL_READ_UINT32(info->adc_base + AT91_ADC_SR, adc_status);
+
+    while (active_channels)
+    {
+        if (active_channels & 0x01)
+        {
+            // If ADC conversion done, save sample
+            if(adc_status & AT91_ADC_CHER_CHx(channel_no))
+            {
+              HAL_READ_UINT32((info->adc_base + AT91_ADC_CDR0 + AT91_ADC_CHER_CDRx(channel_no)), regval);
+              adcdata = regval & 0x3FF;
+              res |= CYG_ISR_HANDLED
+                |  cyg_adc_receive_sample(info->channel[channel_no],
+                                          adcdata);
+            }
+        } // if (active_channels & 0x01)
+        active_channels >>= 1;
+        channel_no++;
+    } // while (active_channels)
+
+    // Restart sampling
+    HAL_WRITE_UINT32((info->adc_base + AT91_ADC_CR), AT91_ADC_CR_START);
+
+    cyg_drv_interrupt_acknowledge(info->timer_vector);
+
+    return res;
+}
+
+
+//==========================================================================
+// This function is the DSR attached to the ADC device's interrupt vector.
+// It is called by the kernel if the ISR return value contains the
+// CYG_ISR_HANDLED bit. It needs to call cyg_adc_wakeup() for each channel
+// that has its wakeup field set.
+//==========================================================================
+static void at91_adc_dsr(cyg_vector_t vector,
+                            cyg_ucount32 count,
+                            cyg_addrword_t data)
+{
+    cyg_adc_device   *device          = (cyg_adc_device *) data;
+    at91_adc_info *info            = device->dev_priv;
+    cyg_uint8         active_channels = info->chan_mask;
+    cyg_uint8         chan_no         = 0;
+
+    while (active_channels)
+    {
+        if (active_channels & 0x01)
+        {
+            if(info->channel[chan_no]->wakeup)
+            {
+                cyg_adc_wakeup(info->channel[chan_no]);
+            }
+        }
+        chan_no++;
+        active_channels >>= 1;
+    }
+}
+
+
+//---------------------------------------------------------------------------
+// eof adc_at91.c
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/arm/at91/current/tests/at91_adc_test.c
@@ -0,0 +1,290 @@
+//==========================================================================
+//
+//      at91_adc_test.c
+//
+//      ADC driver for AT91 on chip ADC
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 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):  Uwe Kindler <uwe_kindler@web.de>
+//             Updated for Atmel AT91 device, ccoutand <ccoutand@stmi.com>
+// Contributors:
+// Date:         2010-02-15
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+
+#include <cyg/infra/testcase.h>         // test macros
+#include <cyg/infra/cyg_ass.h>          // assertion macros
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_diag.h>
+#include <cyg/hal/hal_arch.h>           // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+// Package requirements
+#if defined(CYGPKG_IO_ADC) && defined(CYGPKG_KERNEL)
+
+#include <pkgconf/kernel.h>
+#include <cyg/io/io.h>
+#include <cyg/io/adc.h>
+#include <pkgconf/devs_adc_arm_at91.h>
+
+// Package option requirements
+#if defined(CYGFUN_KERNEL_API_C)
+
+#include <cyg/kernel/kapi.h>
+
+#if CYGINT_DEVS_ADC_ARM_AT91_ADC0_CHANNELS > 0
+
+#define MAX_ADC_CHANNEL_TO_TEST 4
+
+//===========================================================================
+//                               DATA TYPES
+//===========================================================================
+typedef struct st_thread_data
+{
+    cyg_thread   obj;
+    long         stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
+    cyg_handle_t hdl;
+} thread_data_t;
+
+
+//===========================================================================
+//                              LOCAL DATA
+//===========================================================================
+cyg_thread_entry_t adc_thread;
+thread_data_t      adc_thread_data;
+
+
+//===========================================================================
+//                             ADC THREAD
+//===========================================================================
+void adc_thread(cyg_addrword_t data)
+{
+    int             res;
+    cyg_io_handle_t handle[8]     = {0, 0, 0, 0, 0, 0, 0, 0};
+    cyg_uint32      sample_cnt[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+    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;
+
+
+    diag_printf("This test reads samples from all enabled ADC channels.\n"
+                "Each second the number of already acquired samples\n"
+                "will be printed. After 10 seconds all ADC channels\n"
+                "will be stopped and each ADC buffer will be read until\n"
+                "it is empty. If the number of acquired samples is much\n"
+                "smaller than the number of expected samples, then you\n"
+                "should lower the sample rate.\n\n");
+
+    // Get a handle for ADC device 0 channel 0 - 3 (lookup also trigger a channel enable)
+    res = cyg_io_lookup( "/dev/adc00", &handle[0]);
+    res = cyg_io_lookup( "/dev/adc01", &handle[1]);
+    res = cyg_io_lookup( "/dev/adc02", &handle[2]);
+    res = cyg_io_lookup( "/dev/adc03", &handle[3]);
+
+    //
+    // switch all channels to non blocking
+    //
+    for (i = 0; i < MAX_ADC_CHANNEL_TO_TEST; ++i)
+    {
+        if (handle[i])
+        {
+            cfg_data = 0;
+            len = sizeof(cfg_data);
+            res = cyg_io_set_config(handle[i],
+                                    CYG_IO_SET_CONFIG_READ_BLOCKING,
+                                    &cfg_data,
+                                    &len);
+            if (ENOERR != res)
+            {
+                CYG_TEST_FAIL_FINISH("Error switching ADC channel to non blocking");
+            }
+            sample_cnt[i] = 0;
+        }
+    }
+
+    start_time = cyg_current_time();
+    do
+    {
+        for (i = 0; i < MAX_ADC_CHANNEL_TO_TEST; ++i)
+        {
+            if (handle[i])
+            {
+                cyg_adc_sample_t sample;
+
+                // read a sample from the channel
+                do
+                {
+                    cyg_uint32 len = sizeof(sample);
+                    res = cyg_io_read( handle[i], &sample, &len );
+                }
+                while (-EAGAIN == res);
+                if (ENOERR == res)
+                {
+                    sample_cnt[i]++;
+                }
+            } // if (handle[i])
+        }
+        //
+        // print number of acquired samples - if one second is expired.
+        // we expect that the number of acquired samples is nearly the
+        // sample rate
+        //
+        end_time = cyg_current_time();
+        if ((end_time - start_time) >= 100)
+        {
+            start_time = end_time;
+            diag_printf("%d\t %d\t %d\t %d\n",
+                        sample_cnt[0],
+                        sample_cnt[1],
+                        sample_cnt[2],
+                        sample_cnt[3]);
+            seconds++;
+        } // if ((end_time - start_time) >= 100)
+    } while (seconds < 10);
+
+    //
+    // Now stop all channels
+    //
+    for (i = 0; i < MAX_ADC_CHANNEL_TO_TEST; ++i)
+    {
+        if (handle[i])
+        {
+            res = cyg_io_set_config(handle[i],
+                                    CYG_IO_SET_CONFIG_ADC_DISABLE,
+                                    0,
+                                    0);
+            if (ENOERR != res)
+            {
+                CYG_TEST_FAIL_FINISH("Error disabling ADC channel");
+            }
+        } // if (handle[i])
+    }
+    end_time = cyg_current_time();
+    end_time = seconds * 1000 + (end_time - start_time) * 10;
+    final_seconds = end_time / 1000.0;
+
+    //
+    // Now read all remaining samples from buffer
+    //
+    for (i = 0; i < MAX_ADC_CHANNEL_TO_TEST; ++i)
+    {
+        if (handle[i])
+        {
+            do
+            {
+                cyg_adc_sample_t sample;
+                cyg_uint32 len = sizeof(sample);
+                res = cyg_io_read( handle[i], &sample, &len );
+                if (ENOERR == res)
+                {
+                    sample_cnt[i]++;
+                }
+            } while (ENOERR == res);
+        } // if (handle[i])
+    }
+
+    diag_printf("\n\n----------------------------------------\n");
+    samples_expected = final_seconds * CYGNUM_DEVS_ADC_ARM_AT91_ADC0_DEFAULT_RATE;
+    diag_printf("Samples expected after %d milliseconds: %d\n",
+                end_time, samples_expected);
+    diag_printf("Samples read (per channel):\n");
+    diag_printf("%d\t %d\t %d\t %d\n",
+                sample_cnt[0],
+                sample_cnt[1],
+                sample_cnt[2],
+                sample_cnt[3]);
+
+    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,
+                      "at91_adc_thread",
+                      (void *) adc_thread_data.stack,
+                      1024 * sizeof(long),
+                      &adc_thread_data.hdl,
+                      &adc_thread_data.obj);
+
+    cyg_thread_resume(adc_thread_data.hdl);
+
+    cyg_scheduler_start();
+}
+#else // CYGINT_DEVS_ADC_ARM_AT91_CHANNELS > 0
+#define N_A_MSG "Needs at least one enabled ADC channel"
+#endif
+
+#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
+
+
+// EOF can_tx.c
+
+//---------------------------------------------------------------------------
+// eof at91_adc_test.c
--- a/packages/ecos.db
+++ b/packages/ecos.db
@@ -2421,6 +2421,16 @@ package CYGPKG_DEVS_ADC_ARM_LPC24XX {
             ADC provided by the LPC24xx processor family."
 }
 
+package CYGPKG_DEVS_ADC_ARM_AT91 {
+    alias           { "AT91 ADC driver" }
+    hardware
+    directory       devs/adc/arm/at91
+    script          adc_at91.cdl
+    description "
+            This packages provides an ADC driver for the on-chip
+            ADC provided by the Atmel AT91 processor family."
+}
+
 package CYGPKG_DEVS_ADC_SYNTH {
     alias         { "Synthethic ADC driver" adc_synth }
     hardware