* RE: Update to CYGPKG_IO_ADC
2010-05-25 20:21 ` Sergei Gavrikov
@ 2010-05-25 21:32 ` Christophe Coutand
2010-05-26 7:20 ` Sergei Gavrikov
2010-05-26 6:53 ` Sergei Gavrikov
1 sibling, 1 reply; 7+ messages in thread
From: Christophe Coutand @ 2010-05-25 21:32 UTC (permalink / raw)
To: Sergei Gavrikov; +Cc: eCos Patches
[-- Attachment #1: Type: text/plain, Size: 3684 bytes --]
Hi Sergei,
Thanks for your inputs. Attached is the updated patch. Let me know if more changes are required.
Christophe
-----Original Message-----
From: Sergei Gavrikov [mailto:sergei.gavrikov@gmail.com]
Sent: 25. mai 2010 22:21
To: Christophe Coutand
Cc: eCos Patches
Subject: RE: Update to CYGPKG_IO_ADC
On Tue, 25 May 2010, Christophe Coutand wrote:
> Hi Sergei,
>
> I have generated a new patch using CYG_IO_SET_CONFIG_ADC_DATA_FLUSH
> instead.
Hi Christophe,
Thank you, I will take a look.
> The second patch is pending. I have fixed the compilation error due to
> CYGPKG_DEVS_ADC_ARM_AT91_DEBUG_LEVEL == 0, remove the CRs and cleanup
> the CDL file.
Okay, no issue.
> I am however not sure what you mean by placing
> CYGNUM_IO_ADC_SAMPLE_SIZE inside a CDL component.
> CYGNUM_IO_ADC_SAMPLE_SIZE is defined from the IO/ADC package, am I
> allowed to redefine it inside a CDL component in the DEVS/ADC?
There are 2 lines on top-level the package:
requires {CYGNUM_IO_ADC_SAMPLE_SIZE <= 12}
requires {CYGNUM_IO_ADC_SAMPLE_SIZE >= 10}
And I had a thought about some CDL wrapping the limit, e.g.
cdl_component CYGSEM_DEVS_ADC_ARM_AT91_SAMPLE_SIZE_LIMIT {
display "Sample size limit"
flavor bool
calculated 1
requires {CYGNUM_IO_ADC_SAMPLE_SIZE >= 10}
requires {CYGNUM_IO_ADC_SAMPLE_SIZE <= 12}
description "
Tell user about the limitation."
}
> Also I never use tabulation so if you can pin-point where you have
> find one, I will investigate.
I believe that you don't, but your $EDITOR does. I attach those lines if you ask. It exists many ways to catch TABs/CRs, the simplest CLI way (on Linux I think):
grep '[press ^V][press TAB]' input ;# to catch TABs
grep '[press ^V][press RETURN]' input ;# to catch CRs
Sometimes you can see in a pager [more|less] a wrong indenting lines (my editor can highlight TABS too if I want).
Regards,
Sergei
> Regards,
> Christophe
>
> -----Original Message-----
> From: Sergei Gavrikov [mailto:sergei.gavrikov@gmail.com]
> Sent: 25. mai 2010 12:50
> To: Christophe Coutand
> Cc: ecos-patches@ecos.sourceware.org
> Subject: Re: Update to CYGPKG_IO_ADC
>
> On Sat, 22 May 2010, Christophe Coutand wrote:
>> Added option to flush the ADC sample buffer.
>>
>> Christophe
>
> Hi Christophe,
>
> First, thank you for your contribution! Some things so far (first look
> on both patches)
>
> 1) I could not compile the driver, if cdl_option
> CYGPKG_DEVS_ADC_ARM_AT91_DEBUG_LEVEL != 0: (test target to build the
> driver was sam7ex256):
>
> ecos/packages/devs/adc/arm/at91/current/src/adc_at91.c: In function ‘at91_adc_enable’:
> ecos/packages/devs/adc/arm/at91/current/src/adc_at91.c:342: error:
> ‘at91_adc_info’ has no member named ‘zero_time’
>
> Could you fix this, please?
>
> 2) Minor
>
> Could you please, clean-up the first patch (src), i.e. remove CRs,
> expand TABs, fix some indents there; format (wrap on) a few long lines in CDL.
>
> It seemed for me those direct requirements of a range ([10; 12]) for
> CYGNUM_IO_ADC_SAMPLE_SIZE on top your CDL can be placed in a separate
> CDL component.
>
> About new I/O key for config_key.h (your second patch), I would prefer
> rename your CYG_IO_SET_CONFIG_ADC_FLUSH_DATABUF, because all *flush*
> key names end itself on _FLUSH. What would you say about:
> CYG_IO_SET_CONFIG_ADC_DATA_FLUSH?
>
> Note: In the next patches do not diff ecos.db, please. Send new
> db-entries as a separate file.
>
> Thank you,
> Sergei
>
[-- Attachment #2: at91_adc_v2 --]
[-- Type: application/octet-stream, Size: 41677 bytes --]
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 <ccoutand@stmi.com>
+
+ * 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 <uwe_kindler@web.de>
+// Updated for Atmel AT91 device, ccoutand <ccoutand@stmi.com>
+// Contributors:
+// Date: 2010-02-15
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+
+//==========================================================================
+// INCLUDES
+//==========================================================================
+#include <pkgconf/system.h>
+#include <pkgconf/devs_adc_arm_at91.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+#include <cyg/io/adc.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/drv_api.h>
+
+#if CYGPKG_DEVS_ADC_ARM_AT91_DEBUG_LEVEL > 0
+ #define at91_adc_printf(args...) diag_printf(args)
+#else
+ #define at91_adc_printf(args...)
+#endif
+
+#define AT91_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 <uwe_kindler@web.de>
+// Updated for Atmel AT91 device, ccoutand <ccoutand@stmi.com>
+// Contributors:
+// Date: 2010-02-15
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+
+#include <cyg/infra/testcase.h> // test macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_diag.h>
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+// Package requirements
+#if defined(CYGPKG_IO_ADC) && defined(CYGPKG_KERNEL)
+
+#include <pkgconf/kernel.h>
+#include <cyg/io/io.h>
+#include <cyg/io/adc.h>
+#include <pkgconf/devs_adc_arm_at91.h>
+
+// Package option requirements
+#if defined(CYGFUN_KERNEL_API_C)
+
+#include <cyg/kernel/kapi.h>
+
+#if CYGINT_DEVS_ADC_ARM_AT91_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
[-- Attachment #3: at91_adc.db --]
[-- Type: application/octet-stream, Size: 306 bytes --]
package CYGPKG_DEVS_ADC_ARM_AT91 {
alias { "AT91 ADC driver" }
hardware
directory devs/adc/arm/at91
script adc_at91.cdl
description "
This packages provides an ADC driver for the on-chip
ADC provided by the Atmel AT91 processor family."
}
^ permalink raw reply [flat|nested] 7+ messages in thread