Lecture 18: ADC Implementation Lecturers: Professor John Devlin.

27
Lecture 18: ADC Implementation http://www.analog.com/library/analogDialogue/archives/39-06/ data_conversion_handbook.html Lecturers: Professor John Devlin Mr Robert Ross

Transcript of Lecture 18: ADC Implementation Lecturers: Professor John Devlin.

Page 1: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

Lecture 18: ADC Implementation

http://www.analog.com/library/analogDialogue/archives/39-06/data_conversion_handbook.html

Lecturers:Professor John Devlin

Mr Robert Ross

Page 2: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

Overview

• Using a MAX1111

• Using the internal ADC

2

Page 3: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MAX1111

• If a microprocessor (or a microcontroller without an ADC) is used, an external ADC will be required (like the MAX1111)

• Features of the MAX1111– 8 Bit– Successive Approximation Conversion– 8 Channel– SPI Interface– Max Conversion time: 20μs

3

Page 4: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MAX1111 Architecture

4

Page 5: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MAX1111 – Analog Input MUX

• MAX1111 has 8 input channels which are multiplexed to a hold circuit

• The user can alternately select any channel for sampling

5

Page 6: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MAX1111 – REF Voltage

• A +2.048V Reference voltage is internally generated and can be connected to REFIN to be used as the reference voltage

• Alternately a different reference voltage may be used

6

Page 7: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MAX1111 – T/H

• Track/Hold Circuitry• When not converting,

tracks the analog input voltage

• While converting holds and stores the value of the analog input voltage

7

Page 8: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

Track and Hold Circuits

• Holds input voltage constant for the conversion period.

8

Page 9: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MAX1111 – SAR ADC

• Successive Approximation Block

• Performs Binary search

• Uses REFIN as the reference voltage

• Supplies result to output shift register

9

Page 10: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MAX1111 - Circuit

10

Page 11: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MSP430 Internal ADC

• The MSP430F2013 has a 16 Bit sigma-delta ADC

• 8 Channel

• Internal temperature sensor

• Internal reference (1.2V)

• Input range = 0-600mV (Gain = 1)

• Internal Clock divider

11

Page 12: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MSP430 ADC – Internal View

12

Page 13: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

#include <msp430x20x3.h>#define ADCDeltaOn 31 static unsigned int LastADCVal;

void main(void){BCSCTL2 |= DIVS_3; WDTCTL = WDT_MDLY_32; IE1 |= WDTIE; P1DIR |= 0x01; SD16CTL = SD16REFON +SD16SSEL_1; SD16INCTL0 = SD16INCH_6; SD16CCTL0 = SD16SNGL + SD16IE ; _BIS_SR(LPM0_bits + GIE);}

MSP430 ADC – CodeLED Temp increase display

Page 14: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

#pragma vector=SD16_VECTOR__interrupt void SD16ISR(void){if (SD16MEM0 <= LastADCVal + ADCDeltaOn)P1OUT &= ~0x01; elseP1OUT |= 0x01; LastADCVal = SD16MEM0; }// Watchdog Timer interrupt service routine#pragma vector=WDT_VECTOR__interrupt void watchdog_timer(void){SD16CCTL0 |= SD16SC; }

MSP430 ADC – CodeLED Temp increase display

Interrupt routines

Page 15: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MSP430 ADC – Circuit Diagram

MSP430F20131K

4.7K

3.3V

A4: P1.1

15

Page 16: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MSP430 ADC – CodeRESET

MOV.W #0280h,SP ; Set stackpointer (128B RAM device)stopWDT

MOV.W #WDTPW+WDTHOLD,&WDTCTL ; Stop watchdog timersetupP1

MOV.B #11111101b,&P1DIR ; Set P1.0 -> P1.7 as outputs, P1.1 as inputBIS.B #00010010b,&P1SEL ; P1.1 and P1.4 TA/SMCLK options

setupP2 BIS.B #0C0h,&P2DIR ; Set P2.6 -> P2.7 as outputs

Set_clock ; Set to calibrated 1MHz Clock MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Set range; DCO = 1 MHz MOV.B &CALDCO_1MHZ,&DCOCTL ; Set DCO step + modulationsetupADC

MOV.W #0000000011010100b,&SD16CTL ; SMCLK, Ref OnMOV.W #0001000000000010b,&SD16CCTL0 ; Unipolar, Start conversionMOV.B #00000100b,&SD16INCTL0 ; A4 (connected to P1.1)

16

Page 17: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

MSP430 ADC – CodeMOV.W #0FFFFh, R7

init MOV.W #04h, R6 ;

AND SD16CCTL0, R6 ; Mask out other bits to get SD16IFG JNZ read_adc ; ADC conversion completedinit2 MOV.W R7, R4 XOR.B #01h, &P1OUT ; Toggle Pinmain DEC R4 JNZ main JMP init

read_adc MOV.W &SD16MEM0, R7 ; Read ADC value from MEM0

JMP init2

17

Page 18: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

Summary

• The MAX1111 is an example of an external 8 bit serial ADC

• Most microcontrollers have an internal ADC, which is simple to setup and use.

• The MSP430F2013 has a 16 bit, 8 channel ADC

18

Page 19: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

19

Page 20: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

// eZ430led2.c - self-dimming LED on P1.0 in eZ430 using SD16A // PWM controlled by software, about 100Hz from ACLK = VLO,// SD16A measures light during off phase of PWM// Calibrated 8MHz DCO, no crystal, ACLK from VLO, power from JTAG (SBW)// J H Davies, 2007-09-30; IAR Kickstart version 3.42A PAGE 469 => LED TOUCH MOVIE , SLAC136//----------------------------------------------------------------------#include <io430x20x3.h> // Header file for this device#include <intrinsics.h> // Intrinsic functions#include <stdint.h> // Standard integer types

#define LED_OUT P1OUT_bit.P1OUT_0 // Output to LED on P1.0#define LED_ANALOG SD16AE_bit.SD16AE0 // Enable analog input from LED#define RANGE 4096 // Dynamic range of values from SD16#define PWM_MAX 128 // Maximum value of duty cycle#define DIVISOR (RANGE/PWM_MAX) // For converting SD16 -> PWM#define SENSE_TIME 2 // Cycles of TACLK needed for SD16

uint16_t dutyCycle = PWM_MAX; // Duty cycle computed from SD16// Start at maximum (but LED off)

void main (void){

WDTCTL = WDTPW | WDTHOLD; // Stop watchdogBCSCTL1 = CALBC1_8MHZ; // Calibrated range for DCODCOCTL = CALDCO_8MHZ; // Calibrated tap and modulationBCSCTL2 = DIVS_3; // SMCLK = DCO / 8 = 1MHzBCSCTL3 = LFXT1S_2; // Select ACLK from VLO (no crystal)P2SEL = 0; // Digital i/o rather than crystalP2REN = BIT6|BIT7; // Pull Rs on unused pins (6 and 7)P1REN = ~BIT0; // Pull Rs on all pins except 0P1DIR = BIT0; // To drive LED on P1.0LED_OUT = 0; // LED initially off (active high)

// Configure SD16A: clock from SMCLK, no division, internal reference onSD16CTL = SD16XDIV_0 | SD16DIV_0 | SD16SSEL_1 | SD16REFON;

// Unipolar, single convs, OSR = 32, interrupts on finishSD16CCTL0 = SD16UNI | SD16SNGL | SD16OSR_32 | SD16IE;

// PGA gain = 16, input channel A0+/-, result after 4th conversionSD16INCTL0 = SD16GAIN_16 | SD16INCH_0 | SD16INTDLY_0;

// Timer_A for software-assisted PWM using channel 1, up to TACCR0 modeTACCR0 = PWM_MAX + SENSE_TIME; // Overall periodTACCR1 = dutyCycle; // Initial duty cycleTACCTL1 = CCIE; // Interrupts on compare

// Start Timer_A from ACLK, undivided, up mode, clear, interruptsTACTL = TASSEL_1 | ID_0 | MC_1 | TACLR | TAIE;for (;;) { // Loop forever

__low_power_mode_3(); // All action in interrupts}

}20

Page 21: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

//----------------------------------------------------------------------// Interrupt service routine for CCIFG1 and TAIFG; share vector//----------------------------------------------------------------------#pragma vector = TIMERA1_VECTOR__interrupt void TIMERA1_ISR (void) // Shared ISR for CCIFG1 and TAIFG{

switch (__even_in_range(TAIV, TAIV_TAIFG)) { // Acknowledges intcase 0: // No interrupt pending

break; // No actioncase TAIV_TAIFG: // TAIFG vector

// Start PWM duty cycle by turning LED on and updating duty cycleLED_OUT = 1; // Turn LED on; duty cycle always > 0TACCR1 = dutyCycle; // Update duty cycle from SD16 readingbreak;

case TAIV_CCIFG1: // CCIFG1 vector// Finish PWM duty cycle by turning off LED, then measuring light level

LED_OUT = 0; // End of duty cycle: Turn off LEDLED_ANALOG = 1; // Switch LED to SD16A input A0+SD16CCTL0_bit.SD16SC = 1; // Start SD16A conversion

// Change mode from LPM3 to LPM0 on exit to provide SMCLK for SD16__bic_SR_register_on_exit(LPM3_bits);__bis_SR_register_on_exit(LPM0_bits);break;

default: // Should not be possible: ignorebreak;

}}//----------------------------------------------------------------------// ISR for SD16A: compute new duty cycle in range [1, PWM_MAX]//----------------------------------------------------------------------#pragma vector = SD16_VECTOR__interrupt void SD16_ISR (void) // Acknowledged when SD16MEM0 read{

static uint16_t floor = 0xFFFF - RANGE; // Dark reading from SD16

LED_ANALOG = 0; // Switch LED back to digital outputif (SD16MEM0 < floor) { // Update floor if new reading is lower

floor = SD16MEM0;dutyCycle = 1; // Minimum value; never go down to 0

} else if (SD16MEM0 >= (floor + RANGE - DIVISOR)) {dutyCycle = PWM_MAX; // Maximum value (saturates)

} else {dutyCycle = (SD16MEM0 - floor) / DIVISOR + 1;

}// Change mode from LPM0 to LPM3 on exit: SMCLK no longer needed

__bic_SR_register_on_exit(LPM0_bits); // (not really necessary)__bis_SR_register_on_exit(LPM3_bits);

} 21

Page 22: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

//******************************************************************************// MSP430F20x3 Demo - SD16A, Obtain LED-generated voltage, set LED// brightness accordingly//// Description: The voltage generated by the LED is measured using the// SD16_A. Based on the result, the LED brightness is adjusted using PWM.// The LED PWM frequency is 50Hz. An LED voltage reading is obtained// every 200ms. Based on the defined "Min" and "Max" reference values,// the LED active duty cycle is adjusted according to the current light// conditions. The darker the ambient light is, the brigther the LED will// get illuminated. After starting the code, the board must be exposed// to darkness for a short moment in order to calibrate the LED's offset// voltage. The VLO is used to clock Timer_A, which is used for both// PWM generation but also to derive the timings. A calibration process// is implemented to accomodate for the variations in VLO frequency.// Normal operating mode is LPM3.//// ACLK = VLO ~ 12kHz, MCLK = SMCLK = SD16CLK = Calibrated 1MHz//// MSP430F20x3// ------------------// /|\| XIN|-// | | |// --|RST XOUT|- \ | / Light// | | \|/ Source// | | ----O----// | P1.0/A0+|<-->LED /|\// | | / | \//// Andreas Dannenberg// Texas Instruments Inc.// June 2007// Built with IAR Embedded Workbench Version: 3.42A//******************************************************************************

22

Page 23: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

23

#include "msp430x20x3.h"

// RESULT_MIN determines the SD16 result that is equivalent to maximum// LED brightness. With increasing ambient light intensity, RESULT_DELTA// determines after how many SD16 LSB counts based on RESULT_MIN the LED// is switched off completely.#define RESULT_MIN 10000#define RESULT_DELTA 230

extern unsigned int Measure_VLO_SW(void); // External function to measure // speed of the VLO // (implemented in Measure_VLO_SW.s43)

int Log[16]; // Debug bufferunsigned int LogPtr = 0;

void main(void){ unsigned int VLO_Period_Length; int Temp; int Min = RESULT_MIN; // Assign initial limits int Max = RESULT_MIN + RESULT_DELTA;

WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

// Setup GPIO P1DIR = 0xFF; // All P1.x outputs P1OUT = 0; // All P1.x reset P2DIR = 0xFF; // All P2.x outputs P2OUT = 0; // All P2.x reset

Page 24: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

24

// Setup Clock System VLO_Period_Length = Measure_VLO_SW(); // Determine VLO period in us BCSCTL1 = CALBC1_1MHZ; // Set DCO = 1MHz DCOCTL = CALDCO_1MHZ; BCSCTL3 |= LFXT1S_2; // ACLK = VLO

// Setup Timer_A TACCR0 = 20000 / VLO_Period_Length - 1; // Period length = 20ms, f = 50Hz TACCTL1 = CCIE; // TACCR1 interrupt enabled TACTL = TASSEL_1 + MC_1 + TAIE; // ACLK, Up mode, Overflow int

// Setup SD16_A SD16CTL = SD16SSEL_1; // Use SMCLK SD16INCTL0 = SD16GAIN_4 + SD16INCH_0; // Use channel A0, gain 4x SD16CCTL0 = SD16SNGL + SD16DF + SD16IE; // Single conversion, 2s compl., // 256OSR, enable interrupts

Page 25: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

25

while (1) { __bis_SR_register(LPM3_bits + GIE); // Wait for conversion result Temp = SD16MEM0; // Get result

Log[LogPtr++] = Temp; // Log data for test purposes LogPtr &= 0x0f; // Wrap buffer pointer

// Re-adjust boundaries in case of a new low-light condition if (Temp < Min) // Lower minimum found? { Min = Temp; // Re-adjust boundaries Max = Temp + RESULT_DELTA; }

// Limit measured value to Max boundary if (Temp > Max) Temp = Max;

// Calculate PWM duty cycle based on the relative brightness compared // to the Min / Max limits and assign result to TACCR1. // // TACCR1 Max - SD16_Result // -------- = ------------------- // TACCR0 Max - Min TACCR1 = (long)TACCR0 * ((long)Max - Temp) / ((long)Max - Min); }}

Page 26: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

// Timer_A interrupt service routine#pragma vector=TIMERA1_VECTOR__interrupt void Timer_A1_ISR(void){ static unsigned int TA_PrdCtr = 0;

switch (__even_in_range(TAIV, 0x0e)) { case 0x02 : // TACCR1 CCIFG P1OUT &= ~0x01; // Disable LED on P1.0 TA_PrdCtr++; // Increment Timer_A period counter if (TA_PrdCtr == 10) // 200ms wrap (50Hz / 10 = 5Hz) { TA_PrdCtr = 0; // Reset Timer_A period counter SD16AE |= SD16AE0; // Enable analog function for P1.0 SD16CTL |= SD16REFON; // Enable SD16_A 1.2V Vref SD16CCTL0 |= SD16SC; // Start 1st SD16 conversion

// Switch over to LPM0 on exit, as the DCO is sourcing the SD16_A __bic_SR_register_on_exit(LPM3_bits); __bis_SR_register_on_exit(LPM0_bits); } break; case 0x0a : // TAIFG if (TACCR1) // LED duty cycle > 0? { P1OUT |= 0x01; // Enable LED on P1.0 } break; }}

26

Page 27: Lecture 18: ADC Implementation  Lecturers: Professor John Devlin.

// SD16_A interrupt service routine#pragma vector = SD16_VECTOR__interrupt void SD16_ISR(void){ static unsigned char Flag = 0; // Flag is used to distinguish // between 1st and 2nd conversion

if (Flag) // Flag set? -> "Real Conversion" { SD16AE &= ~SD16AE0; // Disable analog function for P1.0 SD16CTL &= ~SD16REFON; // Disable voltage reference __bic_SR_register_on_exit(LPM0_bits); // Wake-up MCU } else // Flag clear? -> "Settling Timer" { SD16CCTL0 |= SD16SC; // Start 2nd SD16 conversion } // (this is our "real" conversion)

Flag ^= 0xff; SD16CCTL0 &= ~SD16IFG; // Clear interrupt flag}

27