changeset 2582:4b00ee508a41

* LPC24xx ADC driver package created * cdl/adc_lpc24xx.cdl * src/adc_lpc24xx.c * tests/lpc24xx_adc_test.c
author asl
date Tue, 04 Nov 2008 16:16:19 +0000
parents ea9df9d39af9
children a75fc899d9d1
files packages/devs/adc/arm/lpc24xx/current/ChangeLog packages/devs/adc/arm/lpc24xx/current/cdl/adc_lpc24xx.cdl packages/devs/adc/arm/lpc24xx/current/src/adc_lpc24xx.c packages/devs/adc/arm/lpc24xx/current/tests/lpc24xx_adc_test.c
diffstat 4 files changed, 1001 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/arm/lpc24xx/current/ChangeLog
@@ -0,0 +1,38 @@
+2008-11-01  Uwe Kindler  <uwe_kindler@web.de>
+
+	* LPC24xx ADC driver package created
+	* cdl/adc_lpc24xx.cdl
+	* src/adc_lpc24xx.c
+	* tests/lpc24xx_adc_test.c
+
+//===========================================================================
+//####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.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+//
+// 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####
+//===========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/arm/lpc24xx/current/cdl/adc_lpc24xx.cdl
@@ -0,0 +1,158 @@
+# ====================================================================
+#
+#      adc_lpc24xx.cdl
+#
+#      eCos LPC24xx 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.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+##
+## 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>
+# Contributors:   
+# Date:           2008-09-24
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+
+cdl_package CYGPKG_DEVS_ADC_ARM_LPC24XX {
+    display     "ADC hardware device driver for LPC24xx family of ARM controllers"
+    
+    parent      CYGPKG_IO_ADC_DEVICES
+    active_if   CYGPKG_IO_ADC_DEVICES
+    active_if   CYGPKG_HAL_ARM_LPC24XX
+    requires    {CYGNUM_IO_ADC_SAMPLE_SIZE <= 10}
+    requires    {CYGNUM_IO_ADC_SAMPLE_SIZE >= 3}
+    description " 
+           This package provides a generic ADC device driver for the on-chip
+           ADC peripherals in LPX24xx processors."
+           
+    include_dir cyg/io
+    compile     -library=libextras.a adc_lpc24xx.c
+    
+    cdl_interface CYGINT_DEVS_ADC_ARM_LPC24XX_CHANNELS {
+        display "Number of ADC channels"
+    }  
+   
+    cdl_option CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL {
+         display "Driver debug output level"
+         flavor  data
+         legal_values {0 1 2}
+         default_value 0
+         description   "
+             This option specifies the level of debug data output by
+             the LPC24XX 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_option CYGNUM_DEVS_ADC_ARM_LPC24XX_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 1 is used for generating the sample
+            clock. So this option configures the interrupt priority
+            for timer 1. 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_LPC24XX_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_LPC24XX_CHANNEL[set ::channel] {
+            display        "Access ADC channel [set ::channel]"
+            flavor          bool
+            default_value   [set ::channel] == 0
+            implements      CYGINT_DEVS_ADC_ARM_LPC24XX_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_LPC24XX_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_LPC24XX_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_LPC24XX_TESTS {
+        display "Tests for LPC24xx ADC driver"
+        flavor  data
+        no_define
+        calculated { "tests/lpc24xx_adc_test" }
+        description   "
+            This option specifies the set of tests for the LPC24xx 
+            ADC device driver."
+    }
+
+}
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/arm/lpc24xx/current/src/adc_lpc24xx.c
@@ -0,0 +1,507 @@
+//==========================================================================
+//
+//      adc_lpc24xx.c
+//
+//      ADC driver for LPC24xx 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.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+//
+// 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>
+// Contributors:
+// Date:         2008-09-21
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+
+//==========================================================================
+//                                 INCLUDES
+//==========================================================================
+#include <pkgconf/system.h>
+#include <pkgconf/devs_adc_arm_lpc24xx.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>
+
+
+
+//==========================================================================
+//                                DEFINES
+//==========================================================================
+
+//--------------------------------------------------------------------------
+// Register definition
+//
+#define ADC_BASE        CYGARC_HAL_LPC24XX_REG_AD_BASE
+#define ADC_CR         (ADC_BASE + 0x0000)
+#define ADC_GDR        (ADC_BASE + 0x0004)
+#define ADC_INTEN      (ADC_BASE + 0x000C)
+#define ADC_DR(_chan_) (ADC_BASE + 0x0010 + ((_chan_) << 2))
+#define ADC_STAT       (ADC_BASE + 0x0030)
+
+#define DR_OVR         (0x01 << 30)
+#define DR_DONE        (0x01 << 31)
+#define CR_BURST       (0x01 << 16)
+#define CR_PDN         (0x01 << 21)
+
+
+#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 0
+   #define debug1_printf(args...) diag_printf(args)
+#else
+   #define debug1_printf(args...)
+#endif
+
+#define LPC2XXX_CHAN_CNT 8 // maximum number of channels for LPC2xxx device
+
+
+//==========================================================================
+//                                  DATA TYPES
+//==========================================================================
+typedef struct lpc2xxx_adc_info
+{
+    cyg_uint32              base;       // base address of ADC peripheral
+    cyg_vector_t            vector;     // interrupt vector number
+    int                     intprio;    // interrupt priority of ADC interrupt
+    cyg_handle_t            int_handle; // For initializing the interrupt
+    cyg_interrupt           int_data;
+    struct cyg_adc_channel* channel[LPC2XXX_CHAN_CNT]; // stores references to 
+                                                       // channel objects
+#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 1
+    cyg_uint32              isr_cnt;     // number of ISR = number of samples
+    cyg_uint32              zero_time;
+#endif // CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 1
+    cyg_uint8               chan_mask;  // mask that indicates channels used 
+                                        // by ADC driver
+} lpc2xxx_adc_info;
+
+
+//==========================================================================
+//                               DECLARATIONS
+//==========================================================================
+static bool lpc2xxx_adc_init(struct cyg_devtab_entry *tab);
+static Cyg_ErrNo lpc2xxx_adc_lookup(struct cyg_devtab_entry **tab,
+                                    struct cyg_devtab_entry  *sub_tab,
+                                    const char               *name);
+static void lpc2xxx_adc_enable( cyg_adc_channel *chan );
+static void lpc2xxx_adc_disable( cyg_adc_channel *chan );
+static void lpc2xxx_adc_set_rate( cyg_adc_channel *chan, cyg_uint32 rate );
+static cyg_uint32 lpc2xxx_adc_isr(cyg_vector_t vector, cyg_addrword_t data);
+static void lpc2xxx_adc_dsr(cyg_vector_t vector,
+                            cyg_ucount32 count,
+                            cyg_addrword_t data);
+
+
+//==========================================================================
+// Instantiate data structures
+
+// -------------------------------------------------------------------------
+// Driver functions:
+CYG_ADC_FUNCTIONS( lpc2xxx_adc_funs,
+                   lpc2xxx_adc_enable,
+                   lpc2xxx_adc_disable,
+                   lpc2xxx_adc_set_rate );
+
+// -------------------------------------------------------------------------
+// Device instance:
+static lpc2xxx_adc_info lpc2xxx_adc_info0 =
+{
+    .base               = CYGARC_HAL_LPC2XXX_REG_AD_BASE,
+    .vector             = CYGNUM_HAL_INTERRUPT_TIMER1,
+    .intprio            = CYGNUM_DEVS_ADC_ARM_LPC24XX_INTPRIO,
+    .int_handle         = 0,
+#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 0
+    .isr_cnt            = 0,
+#endif
+    .chan_mask          = 0
+};
+
+CYG_ADC_DEVICE( lpc2xxx_adc_device,
+                &lpc2xxx_adc_funs,
+                &lpc2xxx_adc_info0,
+                CYGNUM_DEVS_ADC_ARM_LPC24XX_DEFAULT_RATE);
+
+// -------------------------------------------------------------------------
+// Channel instances:
+
+#define LPC2XXX_ADC_CHANNEL( __chan )                                    \
+CYG_ADC_CHANNEL( lpc2xxx_adc_channel##__chan,                            \
+                 __chan,                                                 \
+                 CYGDAT_DEVS_ADC_ARM_LPC24XX_CHANNEL##__chan##_BUFSIZE,  \
+                 &lpc2xxx_adc_device );                                  \
+                                                                         \
+DEVTAB_ENTRY( lpc2xxx_adc_channel##__chan##_device,                      \
+              CYGDAT_DEVS_ADC_ARM_LPC24XX_CHANNEL##__chan##_NAME,        \
+              0,                                                         \
+              &cyg_io_adc_devio,                                         \
+              lpc2xxx_adc_init,                                          \
+              lpc2xxx_adc_lookup,                                        \
+              &lpc2xxx_adc_channel##__chan );
+
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL0
+LPC2XXX_ADC_CHANNEL(0);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL1
+LPC2XXX_ADC_CHANNEL(1);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL2
+LPC2XXX_ADC_CHANNEL(2);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL3
+LPC2XXX_ADC_CHANNEL(3);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL4
+LPC2XXX_ADC_CHANNEL(4);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL5
+LPC2XXX_ADC_CHANNEL(5);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL6
+LPC2XXX_ADC_CHANNEL(6);
+#endif
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL7
+LPC2XXX_ADC_CHANNEL(7);
+#endif
+
+//==========================================================================
+// 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 lpc2xxx_adc_init(struct cyg_devtab_entry *tab)
+{
+    cyg_adc_channel  *chan   = (cyg_adc_channel *)tab->priv;
+    cyg_adc_device   *device = chan->device;
+    lpc2xxx_adc_info *info   = device->dev_priv;
+
+    if (!info->int_handle)
+    {
+        cyg_drv_interrupt_create(info->vector,
+                                 info->intprio,
+                                (cyg_addrword_t)device,
+                                &lpc2xxx_adc_isr,
+                                &lpc2xxx_adc_dsr,
+                                &(info->int_handle),
+                                &(info->int_data));
+        cyg_drv_interrupt_attach(info->int_handle);
+        cyg_drv_interrupt_unmask(info->vector);
+
+        //
+        // The APB clock (PCLK) is divided by (this value plus one) to produce
+        // the clock for the A/D converter, which should be less than or equal
+        // to 4.5 MHz. Typically, software should program the smallest value in
+        // this field that yields a clock of 4.5 MHz or slightly less, but in
+        // certain cases (such as a high-impedance analog source) a slower
+        // clock may be desirable.
+        // Set clock division factor so ADC clock is <= 4.5 MHz
+        //
+        cyg_uint8 clkdiv = CYGNUM_HAL_ARM_LPC24XX_ADC_CLK / 4500001;
+
+        //
+        // Enable A/D converter and setup the configured sample size
+        // The eCos ADC I/O manual says: Channels are initialized in a disabled
+        // state and generate no samples - let's do this now
+        // We initialize the device to operate in burst mode and we enable
+        // conversion for all channels here
+        //
+        HAL_WRITE_UINT32(ADC_INTEN, 0);         // disables all interrupts
+        HAL_WRITE_UINT32(ADC_CR, CR_BURST       // burst mode
+                               | CR_PDN         // A/D converter is operational
+                               | 0xFF           // enable all channels
+                               | ((10 - CYGNUM_IO_ADC_SAMPLE_SIZE) << 17)
+                               | (clkdiv << 8));// set clock divider
+
+        //
+        // setup the default sample rate
+        //
+        lpc2xxx_adc_set_rate(chan, chan->device->config.rate);
+    } // 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 lpc2xxx_adc_lookup(struct cyg_devtab_entry **tab,
+                                    struct cyg_devtab_entry  *sub_tab,
+                                    const char               *name)
+{
+    typedef struct adc_pin_cfg_st
+    {
+        cyg_uint8 port;
+        cyg_uint8 pin;
+        cyg_uint8 func;
+    } adc_pin_cfg_t;
+    static const adc_pin_cfg_t acd_pin_cfg_tbl[] =
+    {
+        {0, 23, 1},
+        {0, 24, 1},
+        {0, 25, 1},
+        {0, 26, 1},
+        {1, 30, 3},
+        {1, 31, 3},
+        {0, 12, 3},
+        {0, 13, 3},
+    };
+    cyg_adc_channel  *chan     = (cyg_adc_channel *)(*tab)->priv;
+    lpc2xxx_adc_info *info     = chan->device->dev_priv;
+    adc_pin_cfg_t    *pin_cfg  = (adc_pin_cfg_t *)&acd_pin_cfg_tbl[chan->channel];
+
+    //
+    // This ADC driver is quite LP24xx specific. The pin function of each pin
+    // is well defined in the LP24xx specification. Therefore we can setup
+    // the pin function here. If someone decides that this driver can be used 
+    // by other LPC2xxx or LPC3xxx variants too and that the driver should 
+    // become more generic, then we might need to move the pin configuration 
+    // out of this driver an into the variant / platform HAL
+    //
+    CYG_HAL_ARM_LPC24XX_PIN_CFG(pin_cfg->port, pin_cfg->pin, pin_cfg->func);
+    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;
+    lpc2xxx_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 lpc2xxx_adc_enable(cyg_adc_channel *chan)
+{
+    cyg_uint32        regval;
+    lpc2xxx_adc_info *info      = chan->device->dev_priv;
+
+    //
+    // Enable interrupts for timer to start generation of samples in timer
+    // ISR if this is the first channel that is enabled. If there are
+    // already some channels enabled, then the interrupt is already enabled
+    //
+    if (!info->chan_mask)
+    {
+        HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                        CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
+#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 0
+        info->zero_time = cyg_current_time() * 10;
+#endif
+        regval |= CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_INT;
+        HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                        CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
+    }
+   
+    info->chan_mask |= (0x01 << 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 lpc2xxx_adc_disable(cyg_adc_channel *chan)
+{
+    cyg_uint32        regval;
+    lpc2xxx_adc_info *info  = chan->device->dev_priv;
+
+    info->chan_mask &= ~(0x01 << chan->channel);
+    
+    //
+    // If no channel is enabled the we disable interrupts now
+    //
+    if (!info->chan_mask)
+    {
+        HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                        CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
+        regval &= ~CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_INT;
+        HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                        CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
+    }
+}
+
+
+//==========================================================================
+// 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 lpc2xxx_adc_set_rate( cyg_adc_channel *chan, cyg_uint32 rate)
+{
+    cyg_adc_device   *device = chan->device;
+    cyg_uint32        regval;
+
+    cyg_uint32 tmr_period = hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER1) /
+                            rate;
+    device->config.rate = rate;
+
+    //
+    // Disable and reset counter, set prescale register to 0 and
+    // Set up match register
+    //
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                     CYGARC_HAL_LPC24XX_REG_TxTCR,
+                     CYGARC_HAL_LPC24XX_REG_TxTCR_CTR_RESET);
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                     CYGARC_HAL_LPC24XX_REG_TxPR, 0);
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                     CYGARC_HAL_LPC24XX_REG_TxMR0, tmr_period);
+    //
+    // Reset on match and Enable counter
+    //
+    HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                    CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
+    regval |= CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_RESET; // reset on match
+    regval &= ~CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_STOP; // do not stop on match
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                     CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                     CYGARC_HAL_LPC24XX_REG_TxTCR,
+                     CYGARC_HAL_LPC24XX_REG_TxTCR_CTR_ENABLE);
+}
+
+
+//==========================================================================
+// 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 lpc2xxx_adc_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+    cyg_adc_device   *device = (cyg_adc_device *) data;
+    lpc2xxx_adc_info *info   = (lpc2xxx_adc_info *)device->dev_priv;
+    cyg_uint32        regval;
+    cyg_uint32        res = 0;
+    cyg_adc_sample_t  adcdata;
+
+#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 1
+    //
+    // Print debug information for channel 1 - this is the channel that
+    // triggers the interrupt and that is used for measuring lost samples
+    //
+    if (!(++info->isr_cnt % device->config.rate))
+    {
+        cyg_uint32 current_time_ms = cyg_current_time() * 10;
+        debug1_printf("ms %d smpl. %d\n",
+                      current_time_ms - info->zero_time, info->isr_cnt);
+        info->zero_time = current_time_ms;
+    } // if (!(info->isr_count % device->config.rate))
+#endif // CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 1
+
+    cyg_uint8 active_channels = info->chan_mask;
+    cyg_uint8 channel_no = 0;
+    while (active_channels)
+    {
+        if (active_channels & 0x01)
+        {
+            HAL_READ_UINT32(ADC_DR(channel_no), regval);
+            adcdata = (regval >> 6) & 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)
+
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
+                     CYGARC_HAL_LPC24XX_REG_TxIR,
+                     CYGARC_HAL_LPC24XX_REG_TxIR_MR0);  // Clear interrupt
+    cyg_drv_interrupt_acknowledge(info->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 lpc2xxx_adc_dsr(cyg_vector_t vector,
+                            cyg_ucount32 count,
+                            cyg_addrword_t data)
+{
+    cyg_adc_device   *device          = (cyg_adc_device *) data;
+    lpc2xxx_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_lpc24xx.c
new file mode 100644
--- /dev/null
+++ b/packages/devs/adc/arm/lpc24xx/current/tests/lpc24xx_adc_test.c
@@ -0,0 +1,298 @@
+//==========================================================================
+//
+//        lpc24xx_adc_test.c
+//
+//        ADC performance test for LPC24xxx
+//
+//==========================================================================
+//####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.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+//
+// 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
+// Contributors:
+// Date:          2008-11-01
+// Description:   ADC performance test for LPC24xxx
+//####DESCRIPTIONEND####
+
+
+//===========================================================================
+//                                INCLUDES
+//===========================================================================
+#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_lpc24xx.h>
+
+// Package option requirements
+#if defined(CYGFUN_KERNEL_API_C)
+
+#include <cyg/kernel/kapi.h>
+
+#if CYGINT_DEVS_ADC_ARM_LPC24XX_CHANNELS > 0
+
+//===========================================================================
+//                               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 1 - 8
+    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]);
+    res = cyg_io_lookup( "/dev/adc04", &handle[4]);
+    res = cyg_io_lookup( "/dev/adc05", &handle[5]);
+    res = cyg_io_lookup( "/dev/adc06", &handle[6]);
+    res = cyg_io_lookup( "/dev/adc07", &handle[7]);
+
+    //
+    // switch all channels to non blocking
+    //
+    for (i = 0; i < 8; ++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;
+        } // if (handle[i])
+    } // for (i = 0; i < 8; ++i)
+
+    start_time = cyg_current_time();
+    do
+    {
+        for (i = 0; i < 8; ++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\t %d\t %d\t %d\t %d\n",
+                        sample_cnt[0],
+                        sample_cnt[1],
+                        sample_cnt[2],
+                        sample_cnt[3],
+                        sample_cnt[4],
+                        sample_cnt[5],
+                        sample_cnt[6],
+                        sample_cnt[7]);
+            seconds++;
+        } // if ((end_time - start_time) >= 100)
+    } while (seconds < 10);
+
+    //
+    // Now stop all channels
+    //
+    for (i = 0; i < 8; ++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 < 8; ++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_LPC24XX_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\t %d\t %d\t %d\t %d\n",
+                sample_cnt[0],
+                sample_cnt[1],
+                sample_cnt[2],
+                sample_cnt[3],
+                sample_cnt[4],
+                sample_cnt[5],
+                sample_cnt[6],
+                sample_cnt[7]);
+
+    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,
+                      "lpc24xx_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_LPC24XX_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 i2c_test.c
+