diff options
Diffstat (limited to 'ecos/packages/devs/adc/arm/lpc24xx/current')
4 files changed, 999 insertions, 0 deletions
diff --git a/ecos/packages/devs/adc/arm/lpc24xx/current/ChangeLog b/ecos/packages/devs/adc/arm/lpc24xx/current/ChangeLog new file mode 100755 index 0000000..b2b727f --- /dev/null +++ b/ecos/packages/devs/adc/arm/lpc24xx/current/ChangeLog @@ -0,0 +1,30 @@ +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 + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2008 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/ecos/packages/devs/adc/arm/lpc24xx/current/cdl/adc_lpc24xx.cdl b/ecos/packages/devs/adc/arm/lpc24xx/current/cdl/adc_lpc24xx.cdl new file mode 100755 index 0000000..75c737d --- /dev/null +++ b/ecos/packages/devs/adc/arm/lpc24xx/current/cdl/adc_lpc24xx.cdl @@ -0,0 +1,160 @@ +# ==================================================================== +# +# 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., +## 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> +# 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." + } + +} diff --git a/ecos/packages/devs/adc/arm/lpc24xx/current/src/adc_lpc24xx.c b/ecos/packages/devs/adc/arm/lpc24xx/current/src/adc_lpc24xx.c new file mode 100755 index 0000000..5f8863f --- /dev/null +++ b/ecos/packages/devs/adc/arm/lpc24xx/current/src/adc_lpc24xx.c @@ -0,0 +1,509 @@ +//========================================================================== +// +// 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., +// 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> +// 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 diff --git a/ecos/packages/devs/adc/arm/lpc24xx/current/tests/lpc24xx_adc_test.c b/ecos/packages/devs/adc/arm/lpc24xx/current/tests/lpc24xx_adc_test.c new file mode 100755 index 0000000..dae9531 --- /dev/null +++ b/ecos/packages/devs/adc/arm/lpc24xx/current/tests/lpc24xx_adc_test.c @@ -0,0 +1,300 @@ +//========================================================================== +// +// 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., +// 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 +// 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 + |