i.mx28 HSADC

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.mx28 HSADC

5,106 Views
mx28
Contributor II

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

Tags (1)
17 Replies

3,166 Views
9crkzhou
Contributor III

is there any official code examples ?

I can't get the HSADC work.

this is my code:

initial:______________________________________________________________________________

writel(0x50000000, clk_base + HW_CLKCTRL_HSADC); /* M = 18;RST=High; */

  *((u8*)(clk_base + HW_CLKCTRL_FRAC1 + 1)) = 30; /* HSADC=480*(M/N)=288MHz */

  *((u8*)(clk_base + HW_CLKCTRL_FRAC1_CLR + 1)) = 0x80; /* clear HSADC_CLK_GATE */

  writel(0xF0000000, hsadc_base + HW_HSADC_CTRL0_CLR); /* normal run;trigger is sw */

  writel(0x0000000F, hsadc_base + HW_HSADC_CTRL2_SET); /* precharge before convert */

                                                                                             /* set pin to HSADC */

  writel(0x00000003, hsadc_base + HW_HSADC_SEQUENCE_SAMPLES_NUM);/* 1 sample per sequence */

  writel(0x00000003, hsadc_base + HW_HSADC_SEQUENCE_NUM); /* 1 sequence per trig */

  writel(0xFC000000, hsadc_base + HW_HSADC_CTRL1_CLR); /* disable all interrupt */

  writel(0x01C00001, hsadc_base + HW_HSADC_CTRL0_SET); /* 4 discard & 12bit mode */

                                                                                             /* get the HSADC running */

read the value:________________________________________________________________________

// while((readl(hsadc_base + HW_HSADC_CTRL1) & 0x00000020)){ /* if empty then */

  writel(0x08000000, hsadc_base + HW_HSADC_CTRL0_SET); /* trig it! */

// }

  iRes = readl(hsadc_base + HW_HSADC_FIFO_DATA);

it just not work...

any help will be apreciated...

0 Kudos
Reply

3,166 Views
imravi
Contributor II

Were you able to read sampled data from HSADC. I was able to configure the adc properly but i am unable to understand the data read from the HW_HSADC_FIFO_DATA register. Is it the sampled data or some setting register regarding DMA.

0 Kudos
Reply

3,166 Views
michaelkoelbl
Contributor III

Hello Ravi,

its a long time ago and we stopped using the HSADC as the measurement quality was too bad for our purpose. What I can remember is that you only can read the sample correctly if all settings concerning Trigger Mode / Single Mode / Loop Modes are OK. Otherwise the HSADC does not work.

0 Kudos
Reply

3,166 Views
imravi
Contributor II

HI Michel

Regarding setting the modes correctly i will try to set it properly. But do you have some sample code from your past work then it will be really very helpful.

I am able to read data from the HW_HSADC_FIFO_DATA register but the overflow bit for fifo is also getting set when i am trying to capture a single samle in one sequence and one sequence only.

IF you can help me with the data reading part from the hsadc as not much is given in the documentation other than that for this purpose DMA has to be used.

0 Kudos
Reply

3,166 Views
Gilles
Contributor I

Hello to all,

I will soon use the imx28 HSADC.

I see Mike and Iranna's works concerning the HSADC, and wonder if since that time, Freescale has created a Linux driver for the part.

Shall I write mine like Mike Z and Iranna did, or did Freescale release an official HSADC Linux driver ?

Thanks in advance for your answers and links.

Kind regards,

Gilles.

0 Kudos
Reply

3,166 Views
greyorbit
Contributor I

Hi
      Ref Voltage can be configured by  HW_HSADC_CTRL2_bit.SAH_GAIN_ADJ. I am writing HSADC driver, and the HSADC work correctly now. At first, I used 8 bits mode,  but always get a wrong voltage from HSADC ; finally, I found ADC_SAMPLE_SHIFT_BITS_NUM must be 4 in 8 bits mode. In your code , you did nothing with ADC_SAMPLE_SHIFT_BITS_NUM, but you can get a right voltage , I don't know why. Now,I have one question, sample rate =  480M*(18/HW_CLKCTRL_FRAC1.HSADCFRAC) /HW_CLKCTRL_HSADC.FREQDIV/16, (where HSADCFRAC = 18-35). when HW_CLKCTRL_FRAC1.HSADCFRAC = 35 and HW_CLKCTRL_HSADC.FREQDIV = 3(Divide by 72), sample rate = 214K, is the lowest sample rate . Is this correct? How to get a lower sample rate than 214K?

Thanks

sheng

0 Kudos
Reply

3,166 Views
iranna
Contributor II

Hi

        I modified code as you mentioned above, But still I am getting varying voltages, As follows

                Voltage at HSADC pin              -  0.83                   0.54               1.02

                FIfo data value  (in HEX)          -  AD to B2          6E to 73          92 to 96

                Voltage calculated(Vref = 1.3)   -  0.877                 0.55                  0.75  

Electrical specifications of HSADC, DC voltage can be used for HSADC is 0.5 to VDDA-0.5 (VDDA =  1.8V). So I am using 1.3V as Ref Voltage. Is this correct?

Thanks

Iranna

0 Kudos
Reply

3,166 Views
mx28
Contributor II

Iranna,

I see two problems in your code:

1. You didn't initial HSADC registers in your init() function.

    // 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;
    
    // ADC triggerd by software
    writel((0x03 << 28), HW_HSADC_CTRL0_CLR);

    // Discard first 2 samples
    writel((0x01 << 20), HW_HSADC_CTRL0_CLR);
    writel((0x01 << 19), HW_HSADC_CTRL0_SET);

    if (bit == '0')
    {
        // 8 bit sample data
        writel((0x01 << 18), HW_HSADC_CTRL0_CLR);
        writel((0x01 << 17), HW_HSADC_CTRL0_CLR);
    }
    else if (bit == '1')
    {
         // 10 bit sample data
        writel((0x01 << 18), HW_HSADC_CTRL0_CLR);
        writel((0x01 << 17), HW_HSADC_CTRL0_SET);
    }
    else
    {
        // 12 bit sample data
        writel((0x01 << 18), HW_HSADC_CTRL0_SET);
        writel((0x01 << 17), HW_HSADC_CTRL0_CLR);
    }
   
    // Little endian sample data
    writel((0x01 << 16), HW_HSADC_CTRL0_CLR);

    // Delay 3 cycle after trigger
    writel((0x03 << 1), HW_HSADC_CTRL0_SET);

    // sampling at gain 4
    writel((0x01 << 12), HW_HSADC_CTRL2_CLR);
    writel((0x01 << 11), HW_HSADC_CTRL2_SET);
    writel((0x01 << 10), HW_HSADC_CTRL2_SET);


     // use HSADC0 pin as analog input
        writel((0x01 << 3), HW_HSADC_CTRL2_SET);
        writel((0x01 << 2), HW_HSADC_CTRL2_SET);
        writel((0x01 << 1), HW_HSADC_CTRL2_SET);

    // adjust headroom of current source
    writel((0x01 << 9), HW_HSADC_CTRL2_CLR);

    // adjust current
    writel((0x01 << 8), HW_HSADC_CTRL2_CLR);

    // 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;

    // One (0x01) sample per sequence
    writel((0x01), HW_HSADC_SEQUENCE_SAMPLES_NUM);

    // One (0x01)squence per conversion
    writel((0x01), HW_HSADC_SEQUENCE_NUM);


    // 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);

    return 0;
}

2. It's better read FIFO data after you confirm you get ADC_DONE flag. If you get other flag (like timeout), you shall skip FIFO data, it just has garbage data there.

Hope these helps.

Michael

3,166 Views
imravi
Contributor II

Hi

Were you able to read sampled data from HSADC. I was able to configure the adc properly but i am unable to understand the data read from the HW_HSADC_FIFO_DATA register. Is it the sampled data or some setting register regarding DMA. I have configured the HSADC as per the code given here and the registers show the values as set in the code later if i read those registers.

Is DMA the only way of reading data from the HSADC ?

0 Kudos
Reply

3,166 Views
Gilles
Contributor I

Hello Mike, hello to all,

It has been a while you did it, but maybe you could help me.

I try to get hsadc working. After many analyses, I suspect the HSADC analog block not working.

Signs :

  1. HSADC_RUN bit disapear as soon as I soft-trigger the block
  2. I get the INTERRUPT_TIMEOUT_STATUS as soon as I soft-trigger
  3. I never get the ADC_DONE bit.

My clocks/power settings are the followings :

CLKCTRL_BASE_ADDR + HW_CLKCTRL_HSADC = 0x60000000

CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC1 = 0x00925292

REGS_POWER_BASE + HW_POWER_ANACLKCTRL = 0x84000626

And my registers settings just before soft-trigger are :

HW_HSADC_CTRL0 = 0x000c0049

HW_HSADC_CTRL1 = 0xc0000020

HW_HSADC_CTRL2 = 0x00001f8f

HW_HSADC_SEQUENCES_NUM = 0x00000001

HW_HSADC_SEQUENCE_SAMPLES_NUM = 0x0000000a

And just after soft-trigger :

HW_HSADC_CTRL0 = 0x000c0048

HW_HSADC_CTRL1 = 0xc0000002

HW_HSADC_CTRL2 = 0x00001f8f

HW_HSADC_SEQUENCES_NUM = 0x00000001

HW_HSADC_SEQUENCE_SAMPLES_NUM = 0x0000000a

I am sure I am missing something obvious to switch on the analog block, but it has been 3 days now, and I am banging my head on my keyboard...

If someone could help me to make my HSADC analog block run, I would be grateful.

Thanks in advance,

Gilles.

[edit : add registers after trigger ]

0 Kudos
Reply

3,165 Views
iranna
Contributor II

Hi mike

         As you said HSADC is working in your board, Kindly Help me in this. what is the HSADC reference voltage and CTRL register values.

Thanks

Iranna

mike z said:

To make HSADC working, you need first implement this work around for a chip hardware problem. Here is the errata link:

http://cache.freescale.com/files/32bit/doc/errata/IMX28CE.pdf

You need check ENGR116296.

After implemented this, I got HSADC going and I can read data from FIFO register.

0 Kudos
Reply

3,166 Views
iranna
Contributor II

Hi,
I have tried writing HSADC driver, Using IOCTL call to read ADC converted value on HSADC0 channel,
that inside calls mxs_read_general() in which enabling interrupts(END_SEQ, ADC_DONE and TIMEOUT), setting RUN bit in Ctrl0 reg and triggring it.
and waiting for interrupt(ADC_DONE or END_SEQ or TIMEOUT). if TIMEOUT comes again caling mxs_read_general().
So now I am getting ADC_DONE interrupt and Reading FIFO_DATA reg for value in interrupt handler. but the values are different every time with same voltage.
Please help me in this any where I am going wrong.

static int mxs_hsadc_module_probe(struct platform_device *pdev)
{
int ret = 0;
struct device *temp_class;
struct resource *res;
void __iomem *base;

/* ioremap the base address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "No HSADC base address provided\n");
goto err_out0;
}

base = (void __iomem *)IO_ADDRESS(res->start);
if (base == NULL) {
dev_err(&pdev->dev, "Failed to rebase HSADC base address\n");
goto err_out0;
}

hsadc_base = (unsigned int)base;

/* create the chrdev */
mxs_hsadc_major = register_chrdev(0, "mxs-hsadc", &mxs_hsadc_fops);

if (mxs_hsadc_major < 0) {
dev_err(&pdev->dev, "Unable to get a major for mxs_hsadc\n");
return mxs_hsadc_major;
}

/*creating hsadc class */
mxs_hsadc_class = class_create(THIS_MODULE, "mxs-hsadc");
if (IS_ERR(mxs_hsadc_class)) {
dev_err(&pdev->dev, "Error creating mxs_hsadc class.\n");
ret = PTR_ERR(mxs_hsadc_class);
goto err_out1;
}

/*Creating device node */
temp_class = device_create(mxs_hsadc_class, NULL,
MKDEV(mxs_hsadc_major, 0), NULL, "mxs-hsadc");
if (IS_ERR(temp_class)) {
dev_err(&pdev->dev, "Error creating mxs_hsadc class device.\n");
ret = PTR_ERR(temp_class);
goto err_out2;
}

adc_data = kmalloc(sizeof(struct mxs_hsadc_data), GFP_KERNEL);
if (adc_data == NULL)
return -ENOMEM;

/* requesting hsadc irq */
adc_data->irq = platform_get_irq(pdev, 0);

ret = request_irq(adc_data->irq, mxs_hsadc_interrupt, 0, MOD_NAME, MOD_NAME);
if (ret) {
printk(KERN_DEBUG"HSADC : %s : irq registration failed %d\n",__FILE__,ret);
return ret;
}

if (ret != MXS_HSADC_SUCCESS) {
dev_err(&pdev->dev, "Error in mxs_hsadc_init.\n");
goto err_out4;
}

/*HSADC initialization */
ret = mxs_hsadc_init();

/* By default, devices should wakeup if they can */
/* So HSADC is set as "should wakeup" as it can */
device_init_wakeup(&pdev->dev, 1);

return ret;

err_out4:
device_destroy(mxs_hsadc_class, MKDEV(mxs_hsadc_major, 0));
err_out2:
class_destroy(mxs_hsadc_class);
err_out1:
unregister_chrdev(mxs_hsadc_major, "mxs-hsadc");
err_out0:
return ret;
}

int mxs_hsadc_init()
{

int i;
unsigned int reg;
// mxs_hsadc_clk_enable();

__raw_writel(BF_CLKCTRL_FRAC1_HSADCFRAC(0x3f), HW_CLKCTRL_BASE_ADDRESS+HW_CLKCTRL_FRAC1_CLR); /* Clear */

__raw_writel(BF_CLKCTRL_FRAC1_HSADCFRAC(30), HW_CLKCTRL_BASE_ADDRESS+HW_CLKCTRL_FRAC1_SET); /* Set to 288 MHz*/
/* Clear the clock gate*/
__raw_writel(BM_CLKCTRL_FRAC1_CLKGATEHSADC, HW_CLKCTRL_BASE_ADDRESS+HW_CLKCTRL_FRAC1_CLR);

/* Set the HSADC CLK ADC divider to ge the Operation clock of 16 MHz*/
__raw_writel(BM_CLKCTRL_HSADC_RESETB | BF_CLKCTRL_HSADC_FREQDIV( 1 /*CLKCTRL_HSADC_FREQDIV_18*/), HW_CLKCTRL_BASE_ADDRESS+HW_CLKCTRL_HSADC);

/* 1st workaround for HSADC */
__raw_writel(HSADC_CTRL0_RESET,hsadc_base + HSADC_CTRL0_CLR);

for (i = 0; i < 10000; i++) {
reg = __raw_readl(hsadc_base + HSADC_CTRL0);
if (!(reg & HSADC_CTRL0_RESET))
break;
udelay(3);
}
__raw_writel(HSADC_CTRL0_RESET & (~HSADC_CTRL0_CLKGATE_OFF), hsadc_base + HSADC_CTRL0_SET);

__raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_SET);
__raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_CLR);
__raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_SET);
/* 1st workaround for HSADC */

// __raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_CLR);
__raw_writel(HSADC_CTRL0_RESET,hsadc_base + HSADC_CTRL0_CLR);

for (i = 0; i < 10000; i++) {
reg = __raw_readl(hsadc_base + HSADC_CTRL0);
if (!(reg & HSADC_CTRL0_RESET))
break;
udelay(3);
}
__raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_CLR);

/*Disable the interrupts*/
__raw_writel(HSADC_INTR_CTRL_TIMEOUT_ENB ,hsadc_base + HSADC_CTRL1_CLR);
__raw_writel(HSADC_INTR_CTRL_END_SEQ_ENB,hsadc_base + HSADC_CTRL1_CLR);
__raw_writel(HSADC_INTR_CTRL_ADC_DONE_ENB,hsadc_base + HSADC_CTRL1_CLR);
__raw_writel(HSADC_INTR_CTRL_FIFO_OVFW_ENB,hsadc_base + HSADC_CTRL1_CLR);
__raw_writel(HSADC_INTR_CLR,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_STATUS_CLR,hsadc_base + HSADC_CTRL1_SET);

/* HSADC is set to SINGLE Mode*/
reg = 0x1;
__raw_writel(reg , hsadc_base +HSADC_SEQ_NUM);

/*Number of samples*/
reg = 0x1;
__raw_writel(reg , hsadc_base +HSADC_SEQ_SAM_NUM);

/*Power Register config */
reg =0x84000626;
__raw_writel(reg , REGS_POWER_BASE + HW_POWER_ANACLKCTRL);

/* Wake up from power down mode */
__raw_writel(HSADC_CTRL2_POWER_DOWN,hsadc_base + HSADC_CTRL2_CLR);

/*Set PreCharge Enable */
__raw_writel(HSADC_CTRL2_PRECHARGE,hsadc_base + HSADC_CTRL2_SET);

/*Set HSADC_RUN mode*/
__raw_writel(HSADC_CTRL0_RUN,hsadc_base + HSADC_CTRL0_SET);

return 0;
}

/* interrupt handler */
static irqreturn_t mxs_hsadc_interrupt(int irq, void *dev_id)
{
unsigned long reg=0;

hsadc_value = __raw_readl(hsadc_base + HSADC_FIFO_DATA);
printk(KERN_DEBUG"HSADC : value %x\n",hsadc_value);
reg = __raw_readl(hsadc_base + HSADC_CTRL1) & HSADC_INTR_STATUS_END_SEQ;
if(reg)
{
printk(KERN_DEBUG"%s : reg value HSADC_INTR_STATUS_END_SEQ %d\n",__FILE__,(int)reg);

goto ADC_DONE

}

reg = __raw_readl(hsadc_base + HSADC_CTRL1) & HSADC_INTR_STATUS_ADC_DONE;
if(reg)
{
printk(KERN_DEBUG"%s : reg value HSADC_INTR_STATUS_ADC_DONE %d\n",__FILE__,(int)reg);
goto ADC_DONE
}

reg = __raw_readl(hsadc_base + HSADC_CTRL1) & HSADC_INTR_STATUS_TIMEOUT;
if (reg)
{
/*Disable timeout interrupt*/
__raw_writel(HSADC_INTR_CTRL_TIMEOUT_ENB,hsadc_base + HSADC_CTRL1_CLR);
/*Clear interrupt status and pending interrupts*/
__raw_writel(HSADC_INTR_CLR,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_STATUS_CLR,hsadc_base + HSADC_CTRL1_CLR);
printk(KERN_DEBUG"%s : reg value HSADC_INTR_STATUS_TIMEOUT %d\n",__FILE__,(int)reg);
timeout = 1;
hsadc_conversion=1;

return IRQ_HANDLED;
}

ADC_DONE:

/*Clear interrupt status and pending interrupts*/
__raw_writel(HSADC_INTR_CLR,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_STATUS_CLR,hsadc_base + HSADC_CTRL1_CLR);

timeout = 0;
hsadc_conversion=1;
return IRQ_HANDLED;
}

enum MXS_HSADC_STATUS mxs_hsadc_read_general()
{
unsigned long reg = 0;
hsadc_conversion=0;

/*channel selection */
__raw_writel((7 << 1), hsadc_base + HSADC_CTRL2_SET );

/*Clear interrupt status and pending interrupts*/

__raw_writel(HSADC_INTR_CLR,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_STATUS_CLR,hsadc_base + HSADC_CTRL1_SET);

/*Enabling the interrupts*/
__raw_writel(HSADC_INTR_CTRL_END_SEQ_ENB,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_CTRL_ADC_DONE_ENB,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_CTRL_FIFO_OVFW_ENB,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_CTRL_TIMEOUT_ENB,hsadc_base + HSADC_CTRL1_SET);

/*Delay cycles*/
reg = 4 << 1;
__raw_writel(reg, hsadc_base + HSADC_CTRL0_SET);

/*Set HSADC_RUN bit*/
__raw_writel(HSADC_CTRL0_RUN,hsadc_base + HSADC_CTRL0_SET);

mdelay(100);
__raw_writel(HSADC_CTRL0_SW_TRIGGER, hsadc_base + HSADC_CTRL0_SET);
mdelay(10);
__raw_writel(HSADC_CTRL0_SW_TRIGGER, hsadc_base + HSADC_CTRL0_SET);

while(!hsadc_conversion)
{
/*Waiting for the interrupt to occur*/
mdelay(100);
}
/*Disable the RUN Bit*/
__raw_writel(HSADC_CTRL0_RUN,hsadc_base + HSADC_CTRL0_CLR);

if(timeout)
return MXS_HSADC_ERROR;
else
return MXS_HSADC_SUCCESS;

}

Thanks,

Iranna

3,166 Views
fabio_estevam
NXP Employee
NXP Employee

Mike,

Maybe you could post your HSADC driver somewhere?

Thanks,

Fabio Estevam

mike z said:

To make HSADC working, you need first implement this work around for a chip hardware problem. Here is the errata link:

http://cache.freescale.com/files/32bit/doc/errata/IMX28CE.pdf

You need check ENGR116296.

After implemented this, I got HSADC going and I can read data from FIFO register.

0 Kudos
Reply

3,166 Views
iranna
Contributor II

Hi,

        I am getting ADC_DONE interrupt properly, but not getting constant values, Different values (FIFO reg value) every time when I execute the binary. Is there any thing to be taken care from driver side or Its hardware fault.

                    we are giving 3.3V as reference and ADC input voltage is 1.68V, getting values around 1.5V to 2.3V. Please reply me.

Best regards

Iranna

0 Kudos
Reply

3,166 Views
michaelkoelbl
Contributor III

Hello iranna,

were facing also the problem that we don't get constant values. For test purpose I switched the HSADC to LRADC2-pin (via HW_HSADC_CTRL2) where I have a simple voltage divider (10k/3,5k to 3.3V) with an 100nF capacitor to GND.

I get 12bit values beween about 0x7b0 and 0x880. Most values are near 0x810 but about every 10th value is strange smaller or greater. I write 0x385 in HW_HSADC_CTRL2.

When I bypass ADC sample and hold logics by writing 0x395 in HW_HSADC_CTRL2 I get nearly constant values (0x7ef..0x7f2). Therefore I think I have wrong values for sample and hold logic in HW_HSADC_CTRL2.

Can you help me?

3,166 Views
mx28
Contributor II

To make HSADC working, you need first implement this work around for a chip hardware problem. Here is the errata link:

http://cache.freescale.com/files/32bit/doc/errata/IMX28CE.pdf

You need check ENGR116296.

After implemented this, I got HSADC going and I can read data from FIFO register.

0 Kudos
Reply

3,165 Views
iranna
Contributor II

Hi,

    I am also facing the same problem while implementing HSADC on imx28 processor and linux-2.6.35.3 kernel. If you found solution please reply me.

best regds

iranna

0 Kudos
Reply