diff -r ae816c83f082 packages/devs/adc/arm/at91/current/ChangeLog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/packages/devs/adc/arm/at91/current/ChangeLog Tue May 25 23:10:09 2010 +0200 @@ -0,0 +1,30 @@ +2010-05-18 ccoutand + + * AT91 ADC driver package created + * cdl/adc_at91.cdl + * src/adc_at91.c + * 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#### +//=========================================================================== diff -r ae816c83f082 packages/devs/adc/arm/at91/current/cdl/adc_at91.cdl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/packages/devs/adc/arm/at91/current/cdl/adc_at91.cdl Tue May 25 23:10:17 2010 +0200 @@ -0,0 +1,209 @@ +# ==================================================================== +# +# 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 + + cdl_interface CYGINT_DEVS_ADC_ARM_AT91_CHANNELS { + display "Number of ADC channels" + } + + 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_option CYGNUM_DEVS_ADC_ARM_AT91_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_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_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_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_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_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_CHANNEL[set ::channel] { + display "Access ADC channel [set ::channel]" + flavor bool + default_value [set ::channel] == 0 + implements CYGINT_DEVS_ADC_ARM_AT91_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_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_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_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 " + Tell user about AT91 ADC sample size limitation." + } + + 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." + } + +} diff -r ae816c83f082 packages/devs/adc/arm/at91/current/src/adc_at91.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/packages/devs/adc/arm/at91/current/src/adc_at91.c Tue May 25 23:10:24 2010 +0200 @@ -0,0 +1,521 @@ +//========================================================================== +// +// 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 +// Updated for Atmel AT91 device, ccoutand +// Contributors: +// Date: 2010-02-15 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + + +//========================================================================== +// INCLUDES +//========================================================================== +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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_MAX_ADC_CHAN 8 // maximum number of channels for AT91 device + +#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_vector_t adc_vector; // interrupt vector number + 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_uint8 prescal; // ADC prescal value + 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 ); + +// ------------------------------------------------------------------------- +// Device instance: +static at91_adc_info at91_adc_info0 = +{ + .adc_base = AT91_ADC, + .adc_vector = CYGNUM_HAL_INTERRUPT_ADC, + .timer_base = AT91_TC, + .tc_base = AT91_TC + (AT91_TC_TC_SIZE * CYGNUM_DEVS_ADC_ARM_AT91_SELECT_TIMER), + .timer_vector = CYGNUM_HAL_INTERRUPT_TC0 + CYGNUM_DEVS_ADC_ARM_AT91_SELECT_TIMER, + .timer_intprio = CYGNUM_DEVS_ADC_ARM_AT91_INTPRIO, + .int_handle = 0, +#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_adc_device, + &at91_adc_funs, + &at91_adc_info0, + CYGNUM_DEVS_ADC_ARM_AT91_DEFAULT_RATE); + +// ------------------------------------------------------------------------- +// Channel instances: + +#define AT91_ADC_CHANNEL( __chan ) \ +CYG_ADC_CHANNEL( at91_adc_channel##__chan, \ + __chan, \ + CYGDAT_DEVS_ADC_ARM_AT91_CHANNEL##__chan##_BUFSIZE, \ + &at91_adc_device ); \ + \ +DEVTAB_ENTRY( at91_adc_channel##__chan##_device, \ + CYGDAT_DEVS_ADC_ARM_AT91_CHANNEL##__chan##_NAME, \ + 0, \ + &cyg_io_adc_devio, \ + at91_adc_init, \ + at91_adc_lookup, \ + &at91_adc_channel##__chan ); + +#ifdef CYGPKG_DEVS_ADC_ARM_AT91_CHANNEL0 +AT91_ADC_CHANNEL(0); +#endif +#ifdef CYGPKG_DEVS_ADC_ARM_AT91_CHANNEL1 +AT91_ADC_CHANNEL(1); +#endif +#ifdef CYGPKG_DEVS_ADC_ARM_AT91_CHANNEL2 +AT91_ADC_CHANNEL(2); +#endif +#ifdef CYGPKG_DEVS_ADC_ARM_AT91_CHANNEL3 +AT91_ADC_CHANNEL(3); +#endif +#ifdef CYGPKG_DEVS_ADC_ARM_AT91_CHANNEL4 +AT91_ADC_CHANNEL(4); +#endif +#ifdef CYGPKG_DEVS_ADC_ARM_AT91_CHANNEL5 +AT91_ADC_CHANNEL(5); +#endif +#ifdef CYGPKG_DEVS_ADC_ARM_AT91_CHANNEL6 +AT91_ADC_CHANNEL(6); +#endif +#ifdef CYGPKG_DEVS_ADC_ARM_AT91_CHANNEL7 +AT91_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 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) << CYGNUM_DEVS_ADC_ARM_AT91_SELECT_TIMER)); + + // + // 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), \ + ( ( CYGNUM_DEVS_ADC_ARM_AT91_PRESCAL << AT91_ADC_MR_PRESCAL_SHIFT ) & \ + AT91_ADC_MR_PRESCAL_MASK ) | \ + ( ( CYGNUM_DEVS_ADC_ARM_AT91_STARTUP_TIME << AT91_ADC_MR_STARTUP_SHIFT ) & \ + AT91_ADC_MR_STARTUP_MASK ) | \ + ( ( CYGNUM_DEVS_ADC_ARM_AT91_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 diff -r ae816c83f082 packages/devs/adc/arm/at91/current/tests/at91_adc_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/packages/devs/adc/arm/at91/current/tests/at91_adc_test.c Tue May 25 23:10:30 2010 +0200 @@ -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 +// Updated for Atmel AT91 device, ccoutand +// Contributors: +// Date: 2010-02-15 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include + +#include // test macros +#include // assertion macros +#include +#include +#include // CYGNUM_HAL_STACK_SIZE_TYPICAL + +// Package requirements +#if defined(CYGPKG_IO_ADC) && defined(CYGPKG_KERNEL) + +#include +#include +#include +#include + +// Package option requirements +#if defined(CYGFUN_KERNEL_API_C) + +#include + +#if CYGINT_DEVS_ADC_ARM_AT91_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_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