Name

eCos Support for Analog/Digital Converters — Overview

Introduction

ADC support in eCos is based around the standard character device interface. Hence all device IO function, or file IO functions may be used to access ADC devices.

ADC devices are presented as read-only serial channels that generate samples at a given rate. The size of each sample is hardware specific and is defined by the cyg_adc_sample_t type. The sample rate may be set at runtime by the application. Most ADC devices support several channels which are all sampled at the same rate. Therefore setting the rate for one channel will usually change the rate for all channels on that device.

Examples

The use of the ADC devices is best shown by example. The following is a simple example of using the eCos device interface to access the ADC:

int res;
cyg_io_handle_t handle;

// Get a handle for ADC device 0 channel 0
res = cyg_io_lookup( "/dev/adc00", &handle );

if( res != ENOERR )
    handle_error(err);

for(;;)
{
    cyg_adc_sample_t sample;
    cyg_uint32 len = sizeof(sample);

    // read a sample from the channel
    res = cyg_io_read( handle, &sample, &len );

    if( res != ENOERR )
        handle_error(err);

    use_sample( sample );
}

In this example, the required channel is looked up and a handle on it acquired. Conventionally ADC devices are named "/dev/adcXY" where X is the device number and Y the channel within that device. Following this, samples are read from the device sequentially.

ADC devices may also be accessed using FILEIO operations. These allow more sophisticated usage. The following example shows select() being used to gather samples from several devices.

int fd1, fd2;

// open channels, non-blocking
fd1 = open( "/dev/adc01", O_RDONLY|O_NONBLOCK );
fd2 = open( "/dev/adc02", O_RDONLY|O_NONBLOCK );

if( fd1 < 0 || fd2 < 0 )
    handle_error( errno );

for(;;)
{
    fd_set rd;
    int maxfd = 0;
    int err;
    cyg_adc_sample_t samples[128];
    int len;

    FD_ZERO( &rd );

    FD_SET( fd1, &rd );
    FD_SET( fd2, &rd );
    maxfd = max(fd1,fd2);

    // select on available data on each channel.
    err = select( maxfd+1, &rd, NULL, NULL, NULL );

    if( err < 0 )
        handle_error(errno);

    // If channel 1 has data, handle it
    if( FD_ISSET( fd1, &rd ) )
    {
        len = read( fd1, &samples, sizeof(samples) );

        if( len > 0 )
            handle_samples_chan1( &samples, len/sizeof(sample[0]) );
    }

    // If channel 2 has data, handle it
    if( FD_ISSET( fd2, &rd ) )
    {
        len = read( fd2, &samples, sizeof(samples) );

        if( len > 0 )
            handle_samples_chan2( &samples, len/sizeof(sample[0]) );
    }

}

This test uses FILEIO operations to access ADC channels. It starts by opening two channels for reading only and with blocking disabled. It then falls into a loop using select to wake up whenever either channel has samples available.

Details

As indicated, the main interface to ADC devices is via the standard character device interface. However, there are a number of aspects that are ADC specific.

Sample Type

Samples can vary in size depending on the underlying hardware and is often a non-standard number of bits. The actual number of bits is defined by the hardware driver package, and the generic ADC package uses this to define a type cyg_adc_sample_t which can contain at least the required number of bits. All reads from an ADC channel should be expressed in multiples of this type, and actual bytes read will also always be a multiple.

Sample Rate

The sample rate of an ADC device can be varied by calling a set_config function, either at the device IO API level or at the FILEIO level. The following two functions show how this is done at each:

int set_rate_io( cyg_io_handle_t handle, int rate )
{
    cyg_adc_info_t info;
    cyg_uint32 len = sizeof(info);

    info.rate = rate;

    return cyg_io_set_config( handle,
                              CYG_IO_SET_CONFIG_ADC_RATE,
                              &info,
                              &len);
}

int set_rate_fileio( int fd, int rate )
{
    cyg_adc_info_t info;

    info.rate = rate;

    return cyg_fs_fsetinfo( fd,
                            CYG_IO_SET_CONFIG_ADC_RATE,
                            &info,
                            sizeof(info) );
}

Enabling a Channel

Channels are initialized in a disabled state and generate no samples. When a channel is first looked up or opened, then it is automatically enabled and samples start to accumulate. A channel may then be disable or re-enabled via a set_config function:

int disable_io( cyg_io_handle_t handle )
{
    return cyg_io_set_config( handle,
                              CYG_IO_SET_CONFIG_ADC_DISABLE,
                              NULL,
                              NULL);
}

int enable_io( cyg_io_handle_t handle )
{
    return cyg_io_set_config( handle,
                              CYG_IO_SET_CONFIG_ADC_DISABLE,
                              NULL,
                              NULL);
}

Flushing a channel

After any run-time channel re-configuration it may desirable (depending on the application) to flush any buffered data that may be present from prior to the channel config update. For example, this can be done at the IO API level by using the CYG_IO_SET_CONFIG_ADC_FLUSH config key:

int flush_io( cyg_io_handle_t handle )
{
    return cyg_io_set_config( handle,
                              CYG_IO_SET_CONFIG_ADC_FLUSH,
                              NULL,
                              NULL);
}

Configuration

The ADC package defines a number of generic configuration options that apply to all ADC implementations:

cdl_component CYGPKG_IO_ADC_DEVICES
This option enables the hardware device drivers for the current platform. ADC devices will only be enabled if this option is itself enabled.
cdl_option CYGNUM_IO_ADC_SAMPLE_SIZE
This option defines the sample size for the ADC devices. Given in bits, it will be rounded up to 8, 16 or 32 to define the cyg_adc_sample_t type. This option is usually set by the hardware device driver.
cdl_option CYGPKG_IO_ADC_SELECT_SUPPORT
This option enables support for the select() API function on all ADC devices. This option can be disabled if the select() is not used, saving some code and data space.
cdl_component CYGIMP_IO_ADC_INSTRUMENTATION

If the system instrumentation support is enabled for the active configuration then this option can be used to enable the ADC I/O specific instrumentation support.

Instrumentation records will only be generated if this option is itself enabled, and if the relevant individual event code sub-options are enabled. The default state is for all the instrumentation to be disabled. Some options will generate a lot of instrumentation records in a heavily loaded system and so care may need to be taken regarding the instrumentation enabled vs the instrumentation recording mechanism. Depending on why the ADC I/O driver instrumentation is being enabled (debugging, timing validation, etc.) the user can choose which events they wish to record by enabling the specific CDL option.

In addition to the generic options, each hardware device driver defines some parameters for each device and channel. The exact names of the following option depends on the hardware device driver, but options of this form should be available in all drivers.

cdl_option CYGDAT_IO_ADC_EXAMPLE_CHANNELN_NAME
This option specifies the name of the device for an ADC channel. Channel names should be of the form "/dev/adcXY" where X is the device number and Y the channel within that device.
cdl_option CYGNUM_IO_ADC_EXAMPLE_CHANNELN_BUFSIZE
This option specifies the buffer size for an ADC channel. The value is expressed in multiples of cyg_adc_sample_t rather than bytes. The default value is 128.
cdl_option CYGNUM_IO_ADC_EXAMPLE_DEFAULT_RATE
This option defines the initial default sample rate for all channels. The hardware driver may place constraints on the range of values this option may take.