Mi Z

i.mx28 HSADC

Discussion created by Mi Z on Dec 20, 2011
Latest reply on Aug 8, 2015 by ravi kumar

Hi everyone,

 

I am trying to use HSADC pin to read adc input. By reading mx28 datasheet, I understand this HSADC is designed for driving the linear image scanner sensor, we just want to use it as a normal 12 bit ADC. So no triggering from PWM, and no need to channel on DMA. What we need just read the value periodically via software. During the past weekend, I was trying to verify this concept. But I couldn't get HSADC to read any values. What I got is always a timeout interrupt (bit 1 and bit 0) read from HW_HSADC_CTRL1.

 

Here is my code snippet. Maybe you guys can quickly find out what I missed. Any suggestion or comment is welcomed. Thank you.

 

int hsadc_init(void)

{

    int i;

    int ret = 0;

    unsigned int read = 0;

 

    // Set Power bit for all PLL0

    writel((0x01 << 17), HW_CLKCTRL_PLL0CTRL0_SET);

 

    // Clear clk fraction divider gate

    writel((0x01 << 15), HW_CLKCTRL_FRAC1_CLR);

 

    // set hsadc trigger as GPIO

    writel((0x03 << 14), HW_PINCTRL_MUXSEL1_SET);

 

    // set another hsadc trigger as GPIO

    writel((0x03 << 10), HW_PINCTRL_MUXSEL8_SET);

 

    // HSADC clk divider normal work, divided by 72

    writel(0x70000000, HW_CLKCTRL_HSADC);

 

    // Clk gate cleared

    writel((0x01 << 31), HW_POWER_ANACLKCTRL_CLR);

    writel((0x01 << 26), HW_POWER_ANACLKCTRL_CLR);

 

    // INDIV set to 0x02, 1.5 MHz sampling rate

    writel((0x01 << 1), HW_POWER_ANACLKCTRL_SET);

   writel((0x01 << 0), HW_POWER_ANACLKCTRL_CLR);

 

    // INCLK_SHIFT

    writel((0x01 << 5), HW_POWER_ANACLKCTRL_SET);

    writel((0x01 << 4), HW_POWER_ANACLKCTRL_CLR);

 

    /*

     * Set 0x1 to make the configuration INDIV<1:0> and INCLK_SHIFT available,

     * but there would be <= 0.67us timing delay between HSADC start conversion

     * and ‘start run’ command from software trigger or PWM trigger. If this delay

     * is not desired, it is recommended to set INDIV<1:0> to 0x2 and using PWM

     * trigger for HSADC

     */

    writel((0x01 << 9), HW_POWER_ANACLKCTRL_SET);

 

    ret = hsadc_reset();

    if (ret)

        return ret;

 

    // Clear Power Down bit

    writel((0x01 << 13), HW_HSADC_CTRL2_CLR);

    for (i=0; i < 1000; i++)

    {

        udelay(1);

        read = readl(HW_HSADC_CTRL2);

        if (!(read & (0x01 << 13)))

            break;

    }

    if (i >= 1000)

        return -3;

 

    // Set Pre-Charge bit

    writel((0x01 << 0), HW_HSADC_CTRL2_SET);

    for (i=0; i < 1000; i++)

    {

        udelay(1);

        read = readl(HW_HSADC_CTRL2);

        if ((read & (0x01 << 0)))

            break;

    }

    if (i >= 1000)

        return -4;

 

    // Set on chip ground

    writel((0x01 << 5), HW_HSADC_CTRL2_SET);

 

    // use HSADC0 pin as analog input

    writel((0x07 << 1), HW_HSADC_CTRL2_SET);

 

    // One (0x01) sample per sequence

    writel((0x001), HW_HSADC_SEQUENCE_SAMPLES_NUM);

 

    // One (0x01)squence per conversion

    writel((0x001), HW_HSADC_SEQUENCE_NUM);

 

    // all interrupt enabled as default

 

    // ADC triggerd by software

    writel((0x03 << 28), HW_HSADC_CTRL0_CLR);

 

    // 12 bit sample data

   writel((0x01 << 17), HW_HSADC_CTRL0_CLR);

    writel((0x01 << 18), HW_HSADC_CTRL0_SET);

 

    // Big endian sample data

    writel((0x01 << 16), HW_HSADC_CTRL0_SET);

        

    // Clear FIFO data before start

    for (i=0; i<1000; i++)

    {

        read = readl(HW_HSADC_CTRL1_SET);

        if (read & 0x0020)

            break;

    }

    if (i >= 1000)

        return -5;

 

    // Clear interrupt

    writel((0x01 << 27), HW_HSADC_CTRL1_SET);

 

    // Clear all interrupt flags

    writel((0x01 << 26), HW_HSADC_CTRL1_SET);

 

    // Set trigger delay cycles to

    writel((0x03 << 1), HW_HSADC_CTRL0_SET);

 

    // HSADC starts to run

    writel((0x01 << 0), HW_HSADC_CTRL0_SET);

 

    udelay(10);

 

    // Trigger the ADC conversion

    writel((0x01 << 27), HW_HSADC_CTRL0_SET);

         

    // Wait for completion

    for (i=0; i<100000; i++)

    {

        v1 = readl(HW_HSADC_CTRL1);

        if (v1 & 0x01)

            break;

        udelay(1);       

    }

 

    ret = v1;

    hsadc_checkctrlreg();

    hsadc_checkdatareg();

    return ret;

}

 

void hsadc_checkdatareg(void)

{

    unsigned int d0, d1, d2, d3,  d4;

 

    d0 = readl(HW_HSADC_FIFO_DATA);

    d1 = readl(HW_HSADC_DBG_INFO0);

    d2 = readl(HW_HSADC_DBG_INFO1);

    d3 = readl(HW_HSADC_DBG_INFO2);

    d4 = readl(HW_HSADC_VERSION);

 

    printf("data=0x%08x, info0=0x%08x, info1=0x%08x, info2=0x%08x, ver=0x%08x\n",

        d0, d1, d2, d3, d4);

}

 

void hsadc_checkctrlreg(void)

{

    unsigned int v0, v1, v2;

    v0 = readl(HW_HSADC_CTRL0);

    v1 = readl(HW_HSADC_CTRL1);

    v2 = readl(HW_HSADC_CTRL2);

    printf("HW_HSADC_CTRL0 = 0x%08x, HW_HSADC_CTRL1 = 0x%08x, HW_HSADC_CTRL2 = 0x%08x\n",

        v0, v1, v2);

}

 

The debug console output is like this:

 

HW_HSADC_CTRL0 = 0x00050046, HW_HSADC_CTRL1 = 0xf0000023, HW_HSADC_CTRL2 = 0x000000bf

data=0x00000000, info0=0x00000000, info1=0x00000000, info2=0x00000000, ver=0x00010000

Outcomes