# jenswilly.dk

## Measuring battery voltage with ADC on LPC1347

24. October 2012 21:39 by Jens Willy Johannsen
Categories: ARM

For the GPS Tracker project, I need to measure the battery voltage using the ADC but since the raw battery voltage is higher than the MCU's VCC of 3.3 V I need to use a voltage divider to get the maximum voltage below 3.3 V. (See this article on microBuilder.eu on how to do that properly.)

For the breadboard prototype I won't worry too much about power consumption but for the final version I probably should make the kind of controlled voltage divider mentioned in the microBuilder article.

## Resistor values

When picking values for the voltage divider I want to use as much of the ADC's full range as possible to get the highest accuracy without exceeding the VDD level . If I just divided by 50% (e.g. two 10k resistors), the measured battery range would be about 0 to 2.1 V. Ideally the range should be 0 to VDD but even though the pins are 5 V tolerant in digital mode they may not exceed VDD in analog mode so I'll try with the 0 to 2.1 V range and see if that is accurate enough.

I also need to balance power consumption and accuracy. Higher value resistors pass less current through the voltage divider but lower current means lower accuracy in the ADC.
It helps to put a capacitor on the input pin so the ADC can pull current out of the capacitor if it needs more than voltage divider can provide. Like this: E.g. 2 x 1 MΩ resistors and a 0.1 µF capacitor.

With those values, the capacitor will be charged to about ⅔ capacity in 0.2 seconds and that should be ample capacitance for the ADC to perform one measurement and since I'll be doing one-shot ADC conversions the 0.2 secs recharge time (less, actually since the capacitor will not be completely drained by a single conversion) is not a problem.

This is what I need to do in order to perform a one-shot ADC conversion:

1. Configure pin TDI/PIO0_11 as AD0 input pin
`LPC_IOCON->TDI_PIO0_11 = 0x02;`
2. Power up ADC analog block:
`LPC_SYSCON->PDRUNCFG &= ~(1 << 4);`
`LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13);`
4. Configure control register:
```LPC_ADC->CR = b00000000010000000000010000000001; /* _or */
LPC_ADC->CR = (1<< 0) | (4<< 8) | (1<< 22);```

The control registered is configured as follows:

 (0:7) SEL = 1 to select AD0 pin (pin 32 on LQFP48) (8:15) CLKDIV=4 for 72MHz / 4+1 = 14.4 MHz ADC clock speed (16) BURST=0 for software-controlled conversions (17:21) (reserved) (22) LPWRMODE=1 to enable low-power mode that only powers up ADC circuitry when performing a conversion (23) MODE10BIT = 0 for 12 bit resolution (24:26) START = 000 – no conversion until I say so (27) EDGE – not relevant for software-controlled conversions (28:31) (reserved)

Analog power and voltage reference pins are already connected on the LQFP48 package: VFREP is internally tied to VDD and VFREN is tied to VSS. Likewise for VDDa and VSSa.

### Perform the conversion and read the value

```LPC_ADC->CR |= (1 << 24);              /* start A/D convert */
while( LPC_ADC->GDR & (1 << 31) == 0 ) /* wait until end of A/D convert */
; 1 comment »