Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Thread

A/D converter: a conversion is never completed

A/D converter: a conversion is never completed

2005-11-09 by Joerg Sommer

Hi,

I have a LPC2292 and want to use some analog input channels (Ain0, Ain1,
Ain6) to get data from analog sensors. I use this routine to initialize
the sensors:

#v+
void sensors_init(void)
{
    /* setup the A/D converter
     * use Ain0, Ain1, Ain6: 0x1 + 0x2 + 0x40
     * divide the PCLK by 13+1 to get 4.5MHz: 0xD00
     * repeat the evaluation: 0x10000
     * 11 bits accuracy: bit 17--19 cleared
     * enable: 0x200000
     * start with timer 0 match 2: 0x2000000 (configured in rtc.c)
     */
    write_reg(ADCR, 0x2210D43);

    /* set the usage of P0.27--P0.28 as Ain for brightness and temperature */
    write_reg(PINSEL1, (read_reg(PINSEL1) & 0xFC3FFFFF) | 0x1400000);

    /* no need to set the usage of P3.29 as Ain6 for voltage, because this is
       done by the fix BOOT value of 01 */

    /* P1.24 and P1.25 are GPIO input pins by default; nothing to change */

    /* set the interrupt routine */
    write_reg(VICVectCntl12, 0x32);
    write_reg(VICVectAddr12, (uint32_t)interrupt_handler);
    write_reg(VICIntEnable, 0x40000);	  /* enable A/D conv. interrupt line */
}
#v-

and this routine as interrupt handler:

#v+
static void
#if defined(__arm__) && defined(__GNUC__)
  __attribute__ ((interrupt ("IRQ") ))
#endif
    interrupt_handler(void)
{
    uint32_t reg = read_reg(ADDR);

    if ( (reg & 1<<31) != 0 ) {
        /* no value available, the A/D converter need some time */
        update_VIC();
        return;
    }

    uint16_t val = (reg >> 6) & 0x3FF;
    switch ( (reg >> 24) & 0x7 ) {
      case 0:
        if (sensors_get_brightness() != val) {
            uint8_t tmp = sensors_get_brightness();
            sensors_last_brightness = val;

            if ( ! sensors_is_standby() && (tmp / 32) != (val / 32) )
              display_set_dimming( nvram_sensors_cfg->dim_level[val/32] );
        }
        break;
      case 1:
        if (sensors_get_temperature() != val) {
            sensors_last_temp = val;

            if (val > nvram_sensors_cfg->temp_threshold)
              display_set_dimming( 0 );
        }
        break;
      case 6:
        if (sensors_get_voltage() != val) {
            sensors_last_voltage = val;
        }
        break;
    }

    update_VIC();
}
#v-

If I poll the ADDR register I see the DONE bit is never set. The Match
0.1 works, because this triggers an interrupt and I get this one. What is
wrong? Why the DONE bit is never set and the interrupt handler is never
called. Any ideas?

Bye, Joerg.
-- 
And 1.1.81 is officially BugFree(tm), so if you receive any bug-reports
on it, you know they are just evil lies.
         -- Linus Torvalds

RE: [lpc2000] A/D converter: a conversion is never completed

2005-11-10 by Gromann, Klaus

Hi Joerg,

you have set the BURST-bit (0x00010000)in the ADCR. I never tried this
but the manual says that if this bit is set the ADC does repeated
conversions at a rate defined by the CLKS bits (000 = 11 clock cycles).
I think that the DONE bit will be never set in this mode.

Second suggestion : Try to set the START bits to "start conversion now"
(001) by your code to see if the interrupt handler works as you want. I
use this mode and do a polling of the DONE bit and everything works
fine.

My configuration :

PINSEL the same as yours.
ADCR = 0x1200401;

regards
Klaus
Show quoted textHide quoted text
-----Original Message-----
From: lpc2000@yahoogroups.com [mailto:lpc2000@yahoogroups.com] On Behalf
Of Joerg Sommer
Sent: Wednesday, November 09, 2005 11:25 PM
To: lpc2000@yahoogroups.com
Subject: [lpc2000] A/D converter: a conversion is never completed


Hi,

I have a LPC2292 and want to use some analog input channels (Ain0, Ain1,
Ain6) to get data from analog sensors. I use this routine to initialize
the sensors:

#v+
void sensors_init(void)
{
    /* setup the A/D converter
     * use Ain0, Ain1, Ain6: 0x1 + 0x2 + 0x40
     * divide the PCLK by 13+1 to get 4.5MHz: 0xD00
     * repeat the evaluation: 0x10000
     * 11 bits accuracy: bit 17--19 cleared
     * enable: 0x200000
     * start with timer 0 match 2: 0x2000000 (configured in rtc.c)
     */
    write_reg(ADCR, 0x2210D43);

    /* set the usage of P0.27--P0.28 as Ain for brightness and
temperature */
    write_reg(PINSEL1, (read_reg(PINSEL1) & 0xFC3FFFFF) | 0x1400000);

    /* no need to set the usage of P3.29 as Ain6 for voltage, because
this is
       done by the fix BOOT value of 01 */

    /* P1.24 and P1.25 are GPIO input pins by default; nothing to change
*/

    /* set the interrupt routine */
    write_reg(VICVectCntl12, 0x32);
    write_reg(VICVectAddr12, (uint32_t)interrupt_handler);
    write_reg(VICIntEnable, 0x40000);	  /* enable A/D conv. interrupt
line */
}
#v-

and this routine as interrupt handler:

#v+
static void
#if defined(__arm__) && defined(__GNUC__)
  __attribute__ ((interrupt ("IRQ") ))
#endif
    interrupt_handler(void)
{
    uint32_t reg = read_reg(ADDR);

    if ( (reg & 1<<31) != 0 ) {
        /* no value available, the A/D converter need some time */
        update_VIC();
        return;
    }

    uint16_t val = (reg >> 6) & 0x3FF;
    switch ( (reg >> 24) & 0x7 ) {
      case 0:
        if (sensors_get_brightness() != val) {
            uint8_t tmp = sensors_get_brightness();
            sensors_last_brightness = val;

            if ( ! sensors_is_standby() && (tmp / 32) != (val / 32) )
              display_set_dimming( nvram_sensors_cfg->dim_level[val/32]
);
        }
        break;
      case 1:
        if (sensors_get_temperature() != val) {
            sensors_last_temp = val;

            if (val > nvram_sensors_cfg->temp_threshold)
              display_set_dimming( 0 );
        }
        break;
      case 6:
        if (sensors_get_voltage() != val) {
            sensors_last_voltage = val;
        }
        break;
    }

    update_VIC();
}
#v-

If I poll the ADDR register I see the DONE bit is never set. The Match
0.1 works, because this triggers an interrupt and I get this one. What
is wrong? Why the DONE bit is never set and the interrupt handler is
never called. Any ideas?

Bye, Joerg.
-- 
And 1.1.81 is officially BugFree(tm), so if you receive any bug-reports
on it, you know they are just evil lies.
         -- Linus Torvalds



 
Yahoo! Groups Links

Re: [lpc2000] A/D converter: a conversion is never completed

2005-11-10 by Tom Walsh

Gromann, Klaus wrote:

>Hi Joerg,
>
>you have set the BURST-bit (0x00010000)in the ADCR. I never tried this
>but the manual says that if this bit is set the ADC does repeated
>conversions at a rate defined by the CLKS bits (000 = 11 clock cycles).
>I think that the DONE bit will be never set in this mode.
>
>Second suggestion : Try to set the START bits to "start conversion now"
>(001) by your code to see if the interrupt handler works as you want. I
>use this mode and do a polling of the DONE bit and everything works
>  
>
This is my ADC routines on the LPC2138:

============ begin setup ===============
void initADC(void)
{ // setup converter to run continuously.
      // connect VIC to A/D Convertor.
   VICVectAddr1 = (uint32_t)adc0ISR;    // address of the ISR
   VICVectCntl1 = VIC_ENABLE | VIC_ADC0;
   VICIntSelect &= ~VIC_BIT(VIC_ADC0);  // ADC0 selected as IRQ
   VICIntEnable = VIC_BIT(VIC_ADC0);    // ADC0 interrupt enabled
      // set pins for AD0.0 .. AD0.3 to A/D function.
   PINSEL1 = (PINSEL1 & 0xc03fffff) | (0x15400000);
      // accuracy to 10bits.
   adcSetValue = (
      (ADC_CHN_0 | ADC_CHN_1 | ADC_CHN_2 | ADC_CHN_3) |
      (ADC_CLK_DIVISOR(14)) |    /* approx 4.2MHz conversion rate. */
      (ADC_BURST_ON) |        /* run continuously. */
      (ADC_RESOLVE_10) |      /* 10 bit resolution. */
      (ADC_POWER_ON) |        /* enabled. */
      (ADC_START_0)) &        /* no, we are bursting. */
      (~ADC_RESERVED_CONTROL_BITS); /* write 0's to reserverd bits. */
   ADCR0 = adcSetValue;
}
============ snip ================


=========== begin ISR ==============
unsigned int adcData [4];

void adc0ISR(void)
{// keep continuous update of A/D pin values.
unsigned int temp;
   temp = ADDR0;     // read conversion info.
   switch (ADC_CHANNEL(temp)) {
      case 0:
         adcData[0] = ADC_VALUE(temp);
         break;
      case 1:
         adcData[1] = ADC_VALUE(temp);
         break;
      case 2:
         adcData[2] = ADC_VALUE(temp);
         break;
      case 3:
         adcData[3] = ADC_VALUE(temp);
         break;
      default:    // do nothing on overranges.
         break;
   }
   VICVectAddr = 0x00000000;             // clear this interrupt from 
the VIC
}
=========== snip =================

=========== begin Macros ===========
#define  ADC_VALUE_MASK    (0x0000ffc0)
#define  ADC_VALUE(A)      ((A >> 6) & 0x3ff)
#define  ADC_CHANNEL_MASK  (0x07000000)
#define  ADC_CHANNEL(A)    ((A >> 24) & 0x7)
#define  ADC_OVERRUN_MASK  (0x40000000)
#define  ADC_DONE_MASK     (0x80000000)

============ snip ================

Hope this helps.

TomW

-- 
Tom Walsh - WN3L - Embedded Systems Consultant
http://openhardware.net, http://cyberiansoftware.com
"Windows? No thanks, I have work to do..."
----------------------------------------------------

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.