Introduction
The data that we use for programming a microcontroller normally deals with digital signals. But there are situations where a microcontroller has to deal with inputs from external devices that gives an analog output. In such cases, we can interface the microcontroller with an external device such as an ADC0808 to convert the analog signal to a digital signal. But in more advanced and powerful microcontrollers such as LPC1768, these processes are handled internally rather than externally, using an internal ADC module. In this tutorial, we will learn the basic functionality of the built-in ADC module of the LPC1768 ARM controller. A potentiometer will be used to take the input and the measured value will be processed by the built-in ADC module and the output will be displayed in the serial terminal via UART. More info on UART, refer UART Communication.
Features
- The ADC module in the LPC1768 uses the technique of successive approximation to convert signals from analog to digital values. The internal SAR (Successive Approximation Register) is designed to take the input from a voltage comparator of the internal module to give a 12-bit output resulting in a high precision result.
- The 12-bit conversion rate is clocked at 200 kHz.
- This speed is achieved with 8 multiplexed channels.
- The measurement range is set between Vrefn and Vrefp which is usually 3v and should not exceed the Vdd voltage level.
- The module supports burst conversion mode as well.
- The clock required for analog to digital converter is provided by the APB clock and is scaled to the clock required for the successive approximation process using a programmable divider that is included in each converter.
Configuration
- The power to the ADC module must be given initially. The reset value for PCADC or the power control for ADC bit in the PCONP register is 0. Therefore, it is mandatory that this step must not be skipped in the software.
- The clock to the ADC module must be set.
- The corresponding pins in the PINSEL register must be selected to function as ADC pins.
- Control the ADC operation using the ADC control register, ADCR. The basic operational flow is to start the conversion process, read the result and stop after conversion and reading is completed.
Firmware
- The required definitions for the ADC registers and pins must be defined initially.
#define ADC_CLOCK 1000000 //(SHOULD BE LESS THAN OR EQUAL TO 13MHz) /* These are the pin definitions for the ADC pins defined under PINSELECT1 */ #define AD0_0 14 #define AD0_1 16 #define AD0_2 18 #define AD0_3 20 /* These are the pin definitions for the AD control 32 bit register ADCR */ #define ADCR_SEL0 0 #define ADCR_SEL1 1 #define ADCR_SEL2 2 #define ADCR_SEL3 3 #define ADCR_SEL4 4 #define ADCR_SEL5 5 #define ADCR_SEL6 6 #define ADCR_SEL7 7 #define ADCR_CLKDIV 8 #define ADCR_BURST 16 #define ADCR_PDN 21 #define ADCR_START 24 #define ADCR_EDGE 27 /* These are the pin definitions for the AD result and status*/ #define ADC_OFFSET (1<<4) #define ADC_RESULT 4 #define ADC_DONE (1<<31) #define ADC_OVERRUN (1<<30)
- Inside the main function, we must first initialize the ADC module. The initial steps are powering the module and selecting the required pins in the PINSEL register, that will be used for the ADC conversion process.
LPC_SC->PCONP |= (1 << 12); // Power up the ADC module LPC_PINCON->PINSEL1 &= ~0x002FC000; /* Funtions as ADC (0-3) pins when 01 is selected resp. under PINSEL1 reg. P0.23 (15,14), P0.24 (17,16), P0.25 (19,18), P0.26 (21,20)*/ LPC_PINCON->PINSEL1 |= (0x01 << AD0_0); // We will be using AD0 channel only.
- The clock required for the module is set in the ADCR register. The peripheral clock selection for ADC is configured through bits 24 & 25 in the PCLKSEL0 register. The reset value for these bits is 00. In our program, we will be using the default value itself i.e. (SystemFrequency/4).
The formula to calculate the value to be set in the CLKDIV pins of the ADCR register is ( (clock/ADC_CLOCK) – 1) where clock = SystemFrequency/4 and ADC_CLOCK is the value that we assign as the frequency of operation. The value for ADC_CLOCK that we have chosen is 1MHz and it should not exceed 13MHz.Also, in our program, the A/D converter is in operational mode (PDN is set as 1) where the conversion is software dependent (BURST is set as 0). The conversion starts on the rising edge (EDGE is set as 0).clock = SystemFrequency/4; LPC_ADC->ADCR |= (1 << ADCR_SEL0); // Select channel 0 on ADC0 LPC_ADC->ADCR |= ((clock/ADC_CLOCK - 1) << ADCR_CLKDIV); // CLKDIV = (clock/ADC_CLOCK - 1) LPC_ADC->ADCR |= ((0 << ADCR_BURST) | (1 << ADCR_PDN) | (0 << ADCR_START) | (0 << ADCR_EDGE));
- Now, the ADC module has been initialized. The start and the reading process of the ADC will be done using the control register.
The start of conversion takes place when the START operation is set in the ADCR register. Along with this, the corresponding channel will be selected. (In our program, we are only using channel 0).LPC_ADC->ADCR &= 0xFFFFFF00; LPC_ADC->ADCR |= (1 << ADCR_START) | (1 << ADCR_SEL0); //Select AD0 channel and start the conversion process.
- Next, we must read the value from the data register. This register contains the value of the last converted data along with the flags that indicate when the conversion has been completed and when any conversion overrun has occurred. We will use a while loop that iterates until the conversion has been completed and the data has been read.
The DataReg variable is cast as a volatile unsigned long pointer. It refers to the address or the location where the required data and flag information has been stored. The referenced DataReg pointer is then dereferenced to get the value that the variable is pointing to.do{ DataReg = *(volatile unsigned long *)(LPC_ADC_BASE + ADC_OFFSET + ADC_RESULT * channelNum); }while(!(DataReg & ADC_DONE)); // When ADC_DONE is 1, the conversion is complete.
- After the conversion is completed, the ADC conversion has to be stopped and finally the converted data has to be taken out from the DataReg variable that contains the flag information as well.
LPC_ADC->ADCR &= 0xF8FFFFFF; //Stop AD0 conversion process. ADC_Data = (DataReg>>ADC_RESULT)&0xFFF; // The max value for the result will be in the range Vrefp (0xfff) and Vrefn (0x000)
- The data that we finally acquire cannot be used directly to be displayed through a UART or LCD. It must be converted to a 4 digit data. And for this, we pass the data over to a function to split the numerical places of the data.
void split(unsigned char s) { unsigned char a[4]; int i=0; while(i<4){ a[i] = s%10; s = s/10; i++; } do { --i; Write_UART_Char(a[i]+48); }while(i); }
Summary
This program only serves as a reference to set up the most basic functionality of the ADC module.
Normally, the flag values have to be checked to make the code more efficient.
The converted digital data has been acquired through the ADC module of the LPC1768 controller. This data is displayed on the serial monitor using the UART module of the LPC1768.
The code based on this tutorial is available in the Code Library under the section ARM.