This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Code to read voltage of battery with ADC of AM335x

Other Parts Discussed in Thread: AM3359, SYSCONFIG

Hi, we connected a battery to the ADC of a AM3359 (via a resistor divider).

Where i can find a simple code source to setup the ADC and to know the voltage of the battery.

I am not using a Linux Kernel, just U-boot.

Regards

  • So, here it is:

    In file pll.c

     /* ADC clock enable */
     __raw_writel(PRCM_MOD_EN, CM_WKUP_ADC_TSC_CLKCTRL);
     while (__raw_readl(CM_WKUP_ADC_TSC_CLKCTRL) != PRCM_MOD_EN);

    In myapplication.c file

     /* Unprotect step registers, TSC_ADC_SS module disabled because configuration in progress */
     __raw_writel(0x00000004, TSC_ADC_SS_CTRL);
     while((__raw_readl(TSC_ADC_SS_CTRL) & 0x00000001) !=0);
     /* No idle mode */
     __raw_writel(0x00000004, TSC_ADC_SS_SYSCONFIG);
     /* ADC clock 100KHz. Master clock is 24 MHz */
     __raw_writel((24000000)/100000, TSC_ADC_SS_ADC_CLKDIV);
     /* Enable step 1 (because it is the first one) */
     __raw_writel(0x00000002, TSC_ADC_SS_STEPENABLE);
     /* VREFN, AIN7, VREFP, Data in FIFO 16 samples average, SW enabled, continuous */
     __raw_writel(0x01BFB011, TSC_ADC_SS_STEPCONFIG1);
     /* TSC_ADC_SS module enabled */
     __raw_writel(0x00000001, TSC_ADC_SS_CTRL);
     while((__raw_readl(TSC_ADC_SS_CTRL) & 0x00000001)==0);

     /* Wait for a value in FIFO */
     tempo=5000; /* 5 msec */
            while((__raw_readl(TSC_ADC_SS_FIFO0COUNT) & 0x7F)==0 && --tempo)
      udelay(1);
     if(tempo==0)
      {printf("!!! Error: ADC stuck... in IDLE step ?\n\n");return(-1);}

     /* Displays the voltage being given VREFP=1800 mV VREFN=0 */
     voltage=(1800*(__raw_readl(TSC_ADC_SS_FIFO0DATA) & 0xFFF))/0xFFF;
     printf("Voltage is %d mV\n",voltage);

     Defines are

    #define ADC_TSC    (PRCM_BASE + 0xD000)
    #define CM_WKUP_ADC_TSC_CLKCTRL  (CM_WKUP + 0xBC)/* ADC */
    #define TSC_ADC_SS_SYSCONFIG  (ADC_TSC + 0x010)  /* SYSCONFIG   */
    #define TSC_ADC_SS_CTRL   (ADC_TSC + 0x040)  /* CTRL        */
    #define TSC_ADC_SS_ADC_CLKDIV  (ADC_TSC + 0x04C)  /* ADC_CLKDIV  */
    #define TSC_ADC_SS_STEPENABLE  (ADC_TSC + 0x054)  /* STEPENABLE  */
    #define TSC_ADC_SS_STEPCONFIG1  (ADC_TSC + 0x064)  /* STEPCONFIG1 */
    #define TSC_ADC_SS_FIFO0COUNT  (ADC_TSC + 0x0E4)  /* FIFO0COUNT  */
    #define TSC_ADC_SS_FIFO0DATA  (ADC_TSC + 0x100)  /* FIFO0DATA   */
    Critics are welcome.
  • Sorry  I disturb you , If I use kernel , so how to I read ADC ?

  • Hi, there is this post with some code. It calls API from Texas Instrument.

    http://e2e.ti.com/support/dsp/sitara_arm174_microprocessors/f/791/t/196266.aspx

    Regards

  • Thanks so much for your code!

    I made small changes in your code, now it can be used as a driver (of course with reduced posibilities, just read adc in oneshot mode).

    I use u-boot version 3.2 (TI SDK 6), I created folder /drivers/adc/ and put there the following 3 files:

    Makefile -> http://pastebin.com/GbxbTwi8

    adc_am335x.h -> http://pastebin.com/zTW5WJ9X

    adc_am335x.c -> http://pastebin.com/0KBXG5bn

    I also changed the Makefile in srcdir, I added the following line:

    ...
    LIBS-y += post/libpost.o
    LIBS-y += test/libtest.o
    LIBS-y += drivers/adc/libadc.o
    ...

    For PLL I made the following changes:

    in file arch/arm/include/asm/arch-am33xx/cpu.h I added:

    /* Encapsulating core pll registers */
    struct cm_wkuppll {
    unsigned int wkclkstctrl; /* offset 0x00 */
    ...

    unsigned int wkup_i2c0ctrl; /* offset 0xB8 */
    unsigned int wkup_adc_tsc_ctrl; /* offset 0xBC */
    unsigned int resv12[6];
    unsigned int divm6dpllcore; /* offset 0xD8 */
    };

    In file arch/arm/cpu/armv7/am33xx/clock.c I added:

    /*
    * Enable the peripheral clock for required peripherals
    */
    static void enable_per_clocks(void)
    {

    ...

    /* ADC clock enable */
    writel(PRCM_MOD_EN, &cmwkup->wkup_adc_tsc_ctrl);
    while (readl(&cmwkup->wkup_adc_tsc_ctrl) != PRCM_MOD_EN)
    ;
    }

     

    You can include header and use the driver in the following way:

    int adc_voltage=am335x_adc_get_voltage(AIN5);
    if(adc_voltage<0)
    {
    	puts("Error reading from ADC!\n");
    	return;
    }
    printf("Battery voltage: %d mV\n", adc_voltage);

     

  • I was able to get Radu's code working for u-boot 2013.10 with the following changes:

    Instead of changing
    arch/arm/cpu/armv7/am33xx/clock.c ,
    I added this line:
    &cmwkup->wkup_adc_tsc_ctrl,
    to
    arch/arm/cpu/armv7/am33xx/clock_am33xx.c
    function enable_basic_clocks()

    My version of u-boot expected makefiles with a capital 'M' and failed with the helpful message:
    "No rule to make target .depend"
    if you used a makefile with a lowercase 'm'.

    Also I moved the prototypes and channel enum from adc_am335x.h into a new file, adc.h in include/asm/arch

    Other than those minor changes, it worked out of the box, thanks!