ROC-RK3328-CC Buy Specs

Firefly first ultra-small open-source main board, unique USB3.0 and DDR4 to make its performance faster and more stable. The ultra-affordable ROC-RK3328-CC is your first choice for exploring the programming world.

ADC

Update time:2018-04-13 Views:1497

Introduction

ROC-RK3328-CC development board has two types of AD interfaces: Temperature Sensor(TS-ADC) and SAR-ADC(Successive Approximation Register):

  • TS-ADC(Temperature Sensor):Embedded 2 channel TS-ADC in RK3328, TS-ADC clock must be less than 800KHZ

  • SAR-ADC(Successive Approximation Register):6-channel single-ended 10-bit SAR analog-to-digital converter,SAR-ADC clock must be less than 13MHZ

Linux kernel controls the ADC via industrial I/O subsystem, which is intended to provide support for ADC or DAC devices. Take the SAR-ADC as an example to introduce the basic configuration of the ADC method.

Data Structure

iio_channel structural morphology

struct iio_channel {
    struct iio_dev *indio_dev;
    const struct iio_chan_spec *channel;
    void *data;
    };

iio_dev structural morphology

The structure is mainly used to describe the equipment belonging to the IO port, which is defined as follows:

struct iio_dev {
    int             id;
    int             modes;
    int             currentmode;
    struct device           dev;
    struct iio_event_interface  *event_interface;
    struct iio_buffer       *buffer;
    struct list_head        buffer_list;
    int             scan_bytes;
    struct mutex            mlock;
    const unsigned long     *available_scan_masks;
    unsigned            masklength;
    const unsigned long     *active_scan_mask;
    bool                scan_timestamp;
    unsigned            scan_index_timestamp;
    struct iio_trigger      *trig;
    struct iio_poll_func        *pollfunc;
    struct iio_chan_spec const  *channels;
    int             num_channels;
    struct list_head        channel_attr_list;
    struct attribute_group      chan_attr_group;
    const char          *name;
    const struct iio_info       *info;
    struct mutex            info_exist_lock;
    const struct iio_buffer_setup_ops   *setup_ops;
    struct cdev         chrdev;
    #define IIO_MAX_GROUPS 6
    const struct attribute_group    *groups[IIO_MAX_GROUPS + 1];
    int             groupcounter;
    unsigned long           flags;
    #if defined(CONFIG_DEBUG_FS)
    struct dentry           *debugfs_dentry;
    unsigned            cached_reg_addr;
    #endif
    };

iio_chan_spec structural morphology

The structure is mainly used to describe the attributes of a single channel, which is defined as follows:

struct iio_chan_spec {
    enum iio_chan_type  type; 
    int         channel; 
    int         channel2; 
    unsigned long       address; 
    int         scan_index;
    struct {
        char    sign;
        u8  realbits;
        u8  storagebits;
        u8  shift;
        enum iio_endian endianness;
    } scan_type;
    long            info_mask;
    long            info_mask_separate;
    long            info_mask_shared_by_type;
    long            event_mask;
    const struct iio_chan_spec_ext_info *ext_info;
    const char      *extend_name;
    const char      *datasheet_name;
    unsigned        modified:1;
    unsigned        indexed:1;
    unsigned        output:1;
    unsigned        differential:1;
    };

DTS Config

Config DTS Node

The DTS device node of the ADC is already defined in file kernel/arch/arm64/boot/dts/rk322xh.dtsi, as follows:

adc: adc@ff280000 {
          compatible = "rockchip,saradc";
          reg = <0x0 0xff280000 0x0 0x100>;
          interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
          #io-channel-cells = <1>;
          io-channel-ranges;
          rockchip,adc-vref = <1800>;
          clock-frequency = <1000000>;
          clocks = <&clk_gates2 14>, <&clk_gates17 15>;
          clock-names = "saradc", "pclk_saradc";
          status = "disabled";
     };

To begin with, you need to add resource description to the dts (Device Tree) file:

kernel/arch/arm64/boot/dts/rk3328-roc-cc.dts:
   &adc {
      status = "okay";
      rk_key: rockchip-key {
          compatible = "rockchip,key";
          io-channels = <&adc 0>;
          status = "okay";
  
          vol-up-key {
              linux,code = <113>;
              label = "F12";
             rockchip,adc_value = <4>;
          };
  
          power-key {
             linux,code = <116>;
             label = "POWER";
             rockchip,adc_value = <4>;
         };
     };
 };

Here to apply for the ADC zero channel.

Match the DTS node in the driver file

The of_device_id structure array is defined in the driver file kernel/drivers/input/keyboard/rk_keys.c:

static const struct of_device_id rk_key_match[] = {
     { .compatible = "rockchip,key", .data = NULL},                                                                                         
     {},
 };

Next, fill the .of_match_table member of platform_driver with  firefly_adc_match:

 static struct platform_driver keys_device_driver = {
     .probe      = keys_probe,                                                                                                              
     .remove     = keys_remove,
     .driver     = {
         .name   = "rk-keypad",
         .owner  = THIS_MODULE,
         .of_match_table = rk_key_match,
 #ifdef CONFIG_PM
          .pm = &keys_pm_ops,
 #endif
     }
 };

Driving instructions

Get the AD channel

struct iio_channel *chan; //Define IIO channel structure
chan = iio_channel_get(&pdev->dev, NULL); //Get IIO channel structure

Note: iio_channel_get gets the channel from the pdev which is paramter of the probe function shown below:

static int XXX_probe(struct platform_device *pdev);

Read Raw Data from Channel

int val,ret;
ret = iio_read_channel_raw(chan, &val);

Call iio_read_channel_raw to read the raw data from the channel and store the result in val parameter.

Convert the Raw Data to Voltage

Use the standard voltage to convert the raw data to the result voltage. The equation is shown as below:

Vref / (2^n-1) = Vresult / raw

Note:

  1. Vref is the standard voltage

  2. n is the AD conversion accuracy, such as 10 bits or 12 bits.

  3. Vresult is the conversion result of the voltage.

  4. raw is the raw data read from function iio_read_channel_raw.

For example, the standard voltage is 1.8V, n is 10 bits, raw data is 568. The conversion expression is:

Vresult = (1800mv * 568) / 1023;

Interface specification

/**
 * iio_channel_get() - get description of all that is needed to access channel.
 * @dev:        Pointer to consumer device. Device name must match
 *          the name of the device as provided in the iio_map
 *          with which the desired provider to consumer mapping
 *          was registered.
 * @consumer_channel:   Unique name to identify the channel on the consumer
 *          side. This typically describes the channels use within
 *          the consumer. E.g. 'battery_voltage'
 */
 struct iio_channel *iio_channel_get(struct device *dev, const char *consumer_channel);
/**
 * iio_channel_release() - release channels obtained via iio_channel_get
 * @chan:       The channel to be released.
 */
 void iio_channel_release(struct iio_channel *chan);


/**
 * iio_read_channel_raw() - read from a given channel
 * @chan:       The channel being queried.
 * @val:        Value read back.
 *
 * Note raw reads from iio channels are in adc counts and hence
 * scale will need to be applied if standard units required.
 */
 int iio_read_channel_raw(struct iio_channel *chan, int *val);