Difference between revisions of "ADC overo 2.6.38-"

From Gumstix User Wiki
Jump to: navigation, search
m
m (fixed some bugs in the example program)
 
Line 211: Line 211:
 
     {
 
     {
 
         printf("could not open device /dev/twl4030-madc \n");
 
         printf("could not open device /dev/twl4030-madc \n");
         EXIT_FAILURE;
+
         exit(EXIT_FAILURE);
 
     }
 
     }
 
     struct twl4030_madc_user_parms *par;
 
     struct twl4030_madc_user_parms *par;
 
     par = malloc(sizeof(struct twl4030_madc_user_parms));
 
     par = malloc(sizeof(struct twl4030_madc_user_parms));
 +
    int j;
 
     for (j = 0; j < (sizeof(channels)/sizeof(struct adc_channel)); j++)
 
     for (j = 0; j < (sizeof(channels)/sizeof(struct adc_channel)); j++)
 
     {
 
     {
Line 227: Line 228:
 
         else
 
         else
 
         {
 
         {
              if (par->status == -1)
+
            if (par->status == -1)
 +
            {
 
                 printf("Channel %d (%s) timed out!\n", j, channels[j].name);
 
                 printf("Channel %d (%s) timed out!\n", j, channels[j].name);
              printf("ERROR\n");
+
                printf("ERROR\n");
              exit(1);
+
                exit(EXIT_FAILURE);
 +
            }
 
         }
 
         }
 
     }
 
     }

Latest revision as of 08:19, 10 January 2012

For overo's running kernel 2.6.38 and earlier

Use /dev/twl4030 to access the adc's

See Scott Ellis' page

http://www.jumpnowtek.com/index.php?option=com_content&view=article&id=79&Itemid=91


The source code uses the ‘twl4030’ as a name - which is also an older chip from TI. The TPS65950 on the OMAP board is pin-compatible and uses the same/similar ADC module so the older code works nicely (no need to reinvent the wheel).

You can support the ‘twl4030’ in Linux is via a kernel module, which is the way you can access it directly via /dev/twl4030. The TPS65950 talks to the OMAP chip via I2C bus.

Save both files in the same directory then build

twl4030-madc.h


/* 
* include/linux/i2c/twl4030-madc.h 
* 
* TWL4030 MADC module driver header 
* 
* Copyright (C) 2008 Nokia Corporation 
* Mikko Ylinen <mikko.k.ylinen@...> 
* 
* This program is free software; you can redistribute it and/or 
* modify it under the terms of the GNU General Public License 
* version 2 as published by the Free Software Foundation. 
* 
* 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 St, Fifth Floor, Boston, MA 
* 02110-1301 USA 
* 
*/ 
#ifndef _TWL4030_MADC_H 
#define _TWL4030_MADC_H 
struct twl4030_madc_conversion_method { 
       u8 sel; 
       u8 avg; 
       u8 rbase; 
       u8 ctrl; 
}; 
#define TWL4030_MADC_MAX_CHANNELS 16 
struct twl4030_madc_request { 
       u16 channels; 
       u16 do_avg; 
       u16 method; 
       u16 type; 
       int active; 
       int result_pending; 
       int rbuf[TWL4030_MADC_MAX_CHANNELS]; 
       void (*func_cb)(int len, int channels, int *buf); 
}; 
enum conversion_methods { 
       TWL4030_MADC_RT, 
       TWL4030_MADC_SW1, 
       TWL4030_MADC_SW2, 
       TWL4030_MADC_NUM_METHODS 
}; 
enum sample_type { 
       TWL4030_MADC_WAIT, 
       TWL4030_MADC_IRQ_ONESHOT, 
       TWL4030_MADC_IRQ_REARM 
}; 
#define TWL4030_MADC_CTRL1	 0x00 
#define TWL4030_MADC_CTRL2	 0x01 
#define TWL4030_MADC_RTSELECT_LSB	0x02 
#define TWL4030_MADC_SW1SELECT_LSB	0x06 
#define TWL4030_MADC_SW2SELECT_LSB	0x0A 
#define TWL4030_MADC_RTAVERAGE_LSB	0x04 
#define TWL4030_MADC_SW1AVERAGE_LSB	0x08 
#define TWL4030_MADC_SW2AVERAGE_LSB	0x0C 
#define TWL4030_MADC_CTRL_SW1	 0x12 
#define TWL4030_MADC_CTRL_SW2	 0x13 
#define TWL4030_MADC_RTCH0_LSB	 0x17 
#define TWL4030_MADC_GPCH0_LSB	 0x37 
#define TWL4030_MADC_MADCON	 (1<<0)	/* MADC power on */ 
#define TWL4030_MADC_BUSY	 (1<<0)	/* MADC busy */ 
#define TWL4030_MADC_EOC_SW	 (1<<1)	/* MADC conversion completion */ 
#define TWL4030_MADC_SW_START	 (1<<5)      /* MADC SWx start conversion */ 
#define	TWL4030_MADC_ADCIN0	 (1<<0) 
#define	TWL4030_MADC_ADCIN1	 (1<<1) 
#define	TWL4030_MADC_ADCIN2	 (1<<2) 
#define	TWL4030_MADC_ADCIN3	 (1<<3) 
#define	TWL4030_MADC_ADCIN4	 (1<<4) 
#define	TWL4030_MADC_ADCIN5	 (1<<5) 
#define	TWL4030_MADC_ADCIN6	 (1<<6) 
#define	TWL4030_MADC_ADCIN7	 (1<<7) 
#define	TWL4030_MADC_ADCIN8	 (1<<8) 
#define	TWL4030_MADC_ADCIN9	 (1<<9) 
#define	TWL4030_MADC_ADCIN10	 (1<<10) 
#define	TWL4030_MADC_ADCIN11	 (1<<11) 
#define	TWL4030_MADC_ADCIN12	 (1<<12) 
#define	TWL4030_MADC_ADCIN13	 (1<<13) 
#define	TWL4030_MADC_ADCIN14	 (1<<14) 
#define	TWL4030_MADC_ADCIN15	 (1<<15) 
/* Fixed channels */ 
#define TWL4030_MADC_BTEMP	 TWL4030_MADC_ADCIN1 
#define TWL4030_MADC_VBUS	 TWL4030_MADC_ADCIN8 
#define TWL4030_MADC_VBKB	 TWL4030_MADC_ADCIN9 
#define	TWL4030_MADC_ICHG	 TWL4030_MADC_ADCIN10 
#define TWL4030_MADC_VCHG	 TWL4030_MADC_ADCIN11 
#define	TWL4030_MADC_VBAT	 TWL4030_MADC_ADCIN12 
/* BCI related - XXX To be moved elsewhere */ 
#define TWL4030_BCI_BCICTL1	 0x23 
#define	TWL4030_BCI_MESBAT	 (1<<1) 
#define	TWL4030_BCI_TYPEN	 (1<<4) 
#define	TWL4030_BCI_ITHEN	 (1<<3) 
#define TWL4030_MADC_IOC_MAGIC '`' 
#define TWL4030_MADC_IOCX_ADC_RAW_READ	 _IO(TWL4030_MADC_IOC_MAGIC, 0) 
struct twl4030_madc_user_parms { 
       int channel; 
       int average; 
       int status; 
       u16 result; 
}; 
int twl4030_madc_conversion(struct twl4030_madc_request *conv); 
#endif

Main program

/* Test code for the MADC function
*
* Hugo Vincent, May 2009
*/
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
typedef uint8_t	 u8;
typedef uint16_t	u16;
#include "twl4030-madc.h"
/* Note: (very weird) the madc driver seems to crash if you've got driver debugging
* turned on in your defconfig... */
/* Channel numbering:
* ADC0-1 : to do with battery charging, not relevant on Overo
*   ADC2-7 : general purpose, input range = 0 - 2.5V.
*            On Overo, ADC2 seems to read as ~0.4 and ADC7 as ~1.4V (?).
*   ADC8 : USB OTG port bus voltage.
*   ADC9-11 : more battery charging stuff, not relevant.
*   ADC12 : main battery voltage.
*           This will be the system 3.3V rail in our case
*   ADC13-15: reserved or not relevant.
*/
struct adc_channel {
       int number;
       char name[16];
       float input_range;
};
struct adc_channel channels[] = {
       {
               .number = 2,
               .name = "ADCIN2",
               .input_range = 2.5,
       },
       {
               .number = 3,
               .name = "ADCIN3",
               .input_range = 2.5,
       },
       {
               .number = 4,
               .name = "ADCIN4",
               .input_range = 2.5,
       },
       {
               .number = 5,
               .name = "ADCIN5",
               .input_range = 2.5,
       },
       {
               .number = 6,
               .name = "ADCIN6",
               .input_range = 2.5,
       },
       {
               .number = 7,
               .name = "ADCIN7",
               .input_range = 2.5,
       },
       {
               .number = 8,
               .name = "VBUS_USB_OTG",
               .input_range = 7.0,
       },
       {
               .number = 12,
               .name = "VBATT/3.3V_RAIL",
               .input_range = 6.0,
       },
};
int main(int argc, char **argv)
{
    int d = open("/dev/twl4030-madc", O_RDWR | O_NONBLOCK);
    if (d == -1)
    {
        printf("could not open device /dev/twl4030-madc \n");
        exit(EXIT_FAILURE);
    }
    struct twl4030_madc_user_parms *par;
    par = malloc(sizeof(struct twl4030_madc_user_parms));
    int j;
    for (j = 0; j < (sizeof(channels)/sizeof(struct adc_channel)); j++)
    {
        memset(par, 0, sizeof(struct twl4030_madc_user_parms));
        par->channel = channels[j].number;
        int ret = ioctl(d, TWL4030_MADC_IOCX_ADC_RAW_READ, par);
        float result = ((unsigned int)par->result) / 1024.f;/* 10 bit ADC -> 1024 */
        if (ret == 0 && par->status != -1)
        {
        printf("%s (channel %d): %f\n", channels[j].name, channels[j].number,result * channels[j].input_range);  
        }
        else
        {
            if (par->status == -1)
            {
                printf("Channel %d (%s) timed out!\n", j, channels[j].name);
                printf("ERROR\n");
                exit(EXIT_FAILURE);
            }
        }
    }	
    return 0;
}


compile it

gcc –o madc madc.c

root@overo:~# ./madc
ADCIN2 (channel 2): 0.673828
ADCIN3 (channel 3): 0.087891
ADCIN4 (channel 4): 0.612793
ADCIN5 (channel 5): 0.090332
ADCIN6 (channel 6): 0.341797
ADCIN7 (channel 7): 1.374512
VBUS_USB_OTG (channel 8): 5.154297
VBATT/3.3V_RAIL (channel 12): 3.275391
root@overo:~#

when using the ADCs you may/will need to scale values. To connect up circuits running at higher than 2.5V you will need to use a voltage divider (resistors)

Vincent, H. (2009) ADC Code Example – Help with Overo ADC. http://old.nabble.com/Re%3A-Help-with-Overo-ADC-td24174607.html

TI TPS65950 Integrated Power Management/Audio Codec Data Manual http://focus.ti.com/lit/ds/symlink/tps65950.pdf

TI TPS65950 OMAP Power Management and System Companion Device Version G Technical Reference Manual http://focus.ti.com/lit/ug/swcu050g/swcu050g.pdf